diff --git a/covimerage/__main__.py b/covimerage/__main__.py index 5da29c46..495ba6fa 100644 --- a/covimerage/__main__.py +++ b/covimerage/__main__.py @@ -1,3 +1,34 @@ -if __name__ == '__main__': +def wrap_for_prefix(f, *args, **kwargs): + import logging + from .logger import handler + + handler.setFormatter(logging.Formatter('covimerage: %(message)s')) + + try: + f(*args, standalone_mode=False, **kwargs) + except Exception as exc: + from click.exceptions import ClickException + if isinstance(exc, ClickException): + import re + import sys + from click.utils import echo + from ._compat import StringIO + + # Use `show()` to get extended message with UsageErrors. + out = StringIO() + exc.show(file=out) + out.seek(0) + msg = re.sub("^Error: ", "covimerage: Error: ", out.read(), + flags=re.MULTILINE) + echo(msg, err=True, nl=False) + sys.exit(exc.exit_code) + raise + + +def main(): from .cli import main + wrap_for_prefix(main.main, prog_name='covimerage') + + +if __name__ == '__main__': main() diff --git a/covimerage/logger.py b/covimerage/logger.py index cfae1782..bb2ce11c 100644 --- a/covimerage/logger.py +++ b/covimerage/logger.py @@ -1,9 +1,6 @@ import logging import sys -logger = logging.getLogger('covimerage') -logger.setLevel(logging.INFO) - class AlwaysStderrHandler(logging.StreamHandler): def __init__(self, level=logging.NOTSET): @@ -18,4 +15,7 @@ def handleError(self, record): raise Exception('Internal logging error') -logger.addHandler(AlwaysStderrHandler()) +handler = AlwaysStderrHandler() +logger = logging.getLogger('covimerage') +logger.setLevel(logging.INFO) +logger.addHandler(handler) diff --git a/setup.py b/setup.py index 30997d7e..bfa14112 100755 --- a/setup.py +++ b/setup.py @@ -73,7 +73,9 @@ def run(self): url='https://github.com/Vimjas/covimerage', packages=['covimerage'], entry_points={ - 'console_scripts': ['covimerage=covimerage.cli:main'], + 'console_scripts': [ + 'covimerage=covimerage.__main__:main', + ], }, use_scm_version={ 'write_to': 'covimerage/__version__.py', diff --git a/tests/test_cli.py b/tests/test_cli.py index b39fe9e7..0e19de08 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -15,7 +15,7 @@ def test_dunder_main_run(capfd): assert call([sys.executable, '-m', 'covimerage']) == 0 out, err = capfd.readouterr() - assert out.startswith('Usage: __main__') + assert out.startswith('Usage: covimerage') def test_dunder_main_run_help(capfd): @@ -67,8 +67,8 @@ def test_cli_run_with_args_fd(capfd): out, err = capfd.readouterr() lines = err.splitlines() assert lines == [ - "Running cmd: echo -- --no-profile %sMARKER --cmd 'profile start /doesnotexist' --cmd 'profile! file ./*' (in {})".format(os.getcwd()), - 'Error: The profile file (/doesnotexist) has not been created.'] + "covimerage: Running cmd: echo -- --no-profile %sMARKER --cmd 'profile start /doesnotexist' --cmd 'profile! file ./*' (in {})".format(os.getcwd()), + 'covimerage: Error: The profile file (/doesnotexist) has not been created.'] assert ret == 1 @@ -259,9 +259,9 @@ def test_cli_run_report_fd(capfd, tmpdir, devnull): '----------------------------------------------------------------', 'tests/test_plugin/conditional_function.vim 13 5 62%'] assert err.splitlines() == [ - 'Running cmd: true (in %s)' % str(os.getcwd()), - 'Parsing profile file %s.' % tmp_profile_fname, - 'Writing coverage file %s.' % data_file] + 'covimerage: Running cmd: true (in %s)' % str(os.getcwd()), + 'covimerage: Parsing profile file %s.' % tmp_profile_fname, + 'covimerage: Writing coverage file %s.' % data_file] # Same, but to some file. ofname = str(tmpdir.join('ofname')) @@ -270,9 +270,9 @@ def test_cli_run_report_fd(capfd, tmpdir, devnull): assert exit_code == 0, err assert out == '' assert err.splitlines() == [ - 'Running cmd: true (in %s)' % str(os.getcwd()), - 'Parsing profile file %s.' % tmp_profile_fname, - 'Writing coverage file %s.' % data_file] + 'covimerage: Running cmd: true (in %s)' % str(os.getcwd()), + 'covimerage: Parsing profile file %s.' % tmp_profile_fname, + 'covimerage: Writing coverage file %s.' % data_file] assert open(ofname).read().splitlines() == [ 'Name Stmts Miss Cover', '----------------------------------------------------------------', @@ -295,14 +295,14 @@ def test_cli_call(capfd): # click after 6.7 (9cfea14) includes: 'Try "covimerage --help" for help.' assert err_lines[-2:] == [ '', - 'Error: No such command "file not found".'] + 'covimerage: Error: No such command "file not found".'] assert out == '' assert call(['covimerage', 'write_coverage', 'file not found']) == 2 out, err = capfd.readouterr() err_lines = err.splitlines() assert err_lines[-1] == ( - 'Error: Invalid value for "%s": Could not open file: file not found: No such file or directory' % ( + 'covimerage: Error: Invalid value for "%s": Could not open file: file not found: No such file or directory' % ( "profile_file" if click.__version__ < '7.0' else "[PROFILE_FILE]...",)) assert out == '' @@ -312,38 +312,38 @@ def test_cli_call_verbosity_fd(capfd): out, err = capfd.readouterr() assert out == '' assert err.splitlines() == [ - 'Not writing coverage file: no data to report!', - 'Error: No data to report.'] + 'covimerage: Not writing coverage file: no data to report!', + 'covimerage: Error: No data to report.'] assert call(['covimerage', '-v', 'write_coverage', os.devnull]) == 1 out, err = capfd.readouterr() assert out == '' assert err.splitlines() == [ - 'Parsing file: /dev/null', - 'source_files: []', - 'Not writing coverage file: no data to report!', - 'Error: No data to report.'] + 'covimerage: Parsing file: /dev/null', + 'covimerage: source_files: []', + 'covimerage: Not writing coverage file: no data to report!', + 'covimerage: Error: No data to report.'] assert call(['covimerage', '-vvvv', 'write_coverage', os.devnull]) == 1 out, err = capfd.readouterr() assert out == '' assert err.splitlines() == [ - 'Parsing file: /dev/null', - 'source_files: []', - 'Not writing coverage file: no data to report!', - 'Error: No data to report.'] + 'covimerage: Parsing file: /dev/null', + 'covimerage: source_files: []', + 'covimerage: Not writing coverage file: no data to report!', + 'covimerage: Error: No data to report.'] assert call(['covimerage', '-vq', 'write_coverage', os.devnull]) == 1 out, err = capfd.readouterr() assert out == '' assert err.splitlines() == [ - 'Not writing coverage file: no data to report!', - 'Error: No data to report.'] + 'covimerage: Not writing coverage file: no data to report!', + 'covimerage: Error: No data to report.'] assert call(['covimerage', '-qq', 'write_coverage', os.devnull]) == 1 out, err = capfd.readouterr() assert out == '' - assert err == 'Error: No data to report.\n' + assert err == 'covimerage: Error: No data to report.\n' def test_cli_writecoverage_without_data(runner): @@ -641,7 +641,7 @@ def test_run_handles_exit_code_from_python_fd(capfd): ret = call(['covimerage', 'run', 'python', '-c', 'print("output"); import sys; sys.exit(42)']) out, err = capfd.readouterr() - assert 'Error: Command exited non-zero: 42.' in err.splitlines() + assert 'covimerage: Error: Command exited non-zero: 42.' in err.splitlines() assert out == 'output\n' assert ret == 42 @@ -652,7 +652,7 @@ def test_run_handles_exit_code_from_python_pty_fd(capfd): "import pty; pty.spawn(['/bin/sh', '-c', " "'printf output; exit 42'])"]) out, err = capfd.readouterr() - assert ('Error: The profile file (/not/used) has not been created.' in + assert ('covimerage: Error: The profile file (/not/used) has not been created.' in err.splitlines()) assert out == 'output' assert ret == 1 diff --git a/tests/test_main.py b/tests/test_main.py index 06bd5a7b..6fd3475a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -6,8 +6,15 @@ from covimerage._compat import FileNotFoundError, StringIO -def test_main_import(): - from covimerage import __main__ # noqa: F401 +def test_main_wrap_for_prefix(): + from covimerage.__main__ import wrap_for_prefix + + def f(**kwargs): + raise ValueError("custom") + + with pytest.raises(ValueError) as excinfo: + wrap_for_prefix(f) + assert excinfo.value.args[0] == "custom" def test_profile_repr_lines():