Commit d81e534c authored by ∞'s avatar 💻

Avoid running tests in subprocess, to get coverage reports

parent 697f5416
Pipeline #1793 passed with stages
in 35 seconds
......@@ -6,7 +6,7 @@ qa:
pytest:
stage: test
image: yourlabs/python
script: pip install -e . && py.test -v
script: pip install -e . && py.test --cov . -v
pypi:
stage: deploy
......
......@@ -8,13 +8,17 @@ import copy
import collections
import importlib
import inspect
import io
import os
import pkg_resources
import pprint
import re
import shlex
import sys
import textwrap
import types
import subprocess
from unittest import mock
import colorama
......@@ -80,39 +84,58 @@ def autotest(path, cmd, ignore=None):
'auth.User'
)
"""
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
test_out, test_err = proc.communicate()
name = cmd.split(' ')[0]
for ep in pkg_resources.iter_entry_points('console_scripts'):
if ep.name == name:
break
if ep.name != name:
raise Exception('Could not find entrypoint {name}')
console_script = ep.load()
console_script.argv = shlex.split(cmd)[1:]
@mock.patch('sys.stderr', new_callable=io.StringIO)
@mock.patch('sys.stdout', new_callable=io.StringIO)
def test(mock_stdout, mock_stderr):
console_script()
return mock_stdout, mock_stderr
out, err = test()
out.seek(0)
test_out = out.read()
err.seek(0)
test_err = err.read()
fixture = b'\n'.join([
b'command: ' + cmd.encode('utf8'),
b'retcode: ' + str(proc.returncode).encode('utf8'),
b'stdout:',
fixture = '\n'.join([
'command: ' + cmd,
'retcode: ' + str(console_script.exit_code),
'stdout:',
test_out,
])
if test_err:
fixture += b'\n'.join([
b'stderr:',
fixture += '\n'.join([
'stderr:',
test_err,
])
fixture = fixture.decode('utf8')
for r in ignore or []:
fixture = re.compile(r).sub(f'redacted', fixture)
fixture = fixture.encode('utf8')
if not os.path.exists(path):
dirname = '/'.join(path.split('/')[:-1])
if not os.path.exists(dirname):
os.makedirs(dirname)
with open(path, 'wb+') as f:
with open(path, 'w+') as f:
f.write(fixture)
raise type('FixtureCreated', (Exception,), {})(
f'''
{path} was not in workding and was created with:
{fixture.decode("utf-8")}
{fixture}
'''.strip(),
)
......@@ -125,7 +148,7 @@ def autotest(path, cmd, ignore=None):
shell=True
)
diff_out, diff_err = proc.communicate(input=fixture)
diff_out, diff_err = proc.communicate(input=fixture.encode('utf8'))
if diff_out:
raise type(f'''
DiffFound
......
This diff is collapsed.
"""Example cli2 compatible module.
Dummy script used for demonstration and testing purposes.
"""
import cli2
def run(*args, **kwargs):
from cli2 import console_script
return console_script.__dict__
def test(*args, **kwargs):
"""Test command"""
return 'I am being tested !'
test._cli2_exclude = True # noqa
class Foo:
bar = {'baz': [lambda *a, **k: 'test']}
nested = Foo()
nested.bar = lambda: 'bar'
nested.lulz = lambda: 'lulz'
console_script = cli2.ConsoleScript().add_module('cli2_example')
import sys
from types import ModuleType
from unittest.mock import Mock
from bunch import Bunch
import cli2
import cli2_example
import pytest
def test_command_factory_cli2_example():
group = cli2.Group('cli2-example')
assert list(group.commands.keys()) == [
'alias',
'dead',
'run',
'help',
]
assert group.commands['run'].target == 'cli2_example.run'
def test_command_call():
cmd = cli2.Command(
'* = cli2.help:cli2_example',
'cli2.help',
['cli2-example']
)
cmd.path.callable = Mock()
cmd()
cmd.path.callable.assert_called_once_with('cli2-example')
def test_group_command_alias():
group = cli2.Group('a', [
Bunch(
module_name='cli2.run',
name='a b',
attrs=None
)
])
assert len(list(group.commands.keys())) == 2
assert group.commands['a b'].line == 'a b'
assert group.commands['a b'].target == 'cli2.run'
def test_group_doc():
group = cli2.Group('cli2-example')
result = '\n'.join([*group.doc])
assert 'Dummy script' in result
assert 'dead' in result
assert 'alias' in result
def test_path_resolve_callable():
path = cli2.Path('cli2.run')
assert path.module == cli2
assert path.callable == cli2.run
def test_path_resolve_module():
path = cli2.Path('cli2')
assert path.module == cli2
assert path.callable is None
def test_path_empty_string():
path = cli2.Path('')
assert path.module is None
def test_path_resolve_nested_attribute():
path = cli2.Path('cli2_example.Foo.bar.baz.0')
assert path.callable == cli2_example.Foo.bar['baz'][0]
assert path.module == cli2_example
def test_path_resolve_submodule():
package = ModuleType('package')
package.__file__ = 'package/__init__.py'
sys.modules[package.__name__] = package
module = ModuleType('module')
module.__file__ = 'package/module.py'
sys.modules['.'.join((package.__name__, module.__name__))] = module
module.foo = lambda: True
path = cli2.Path('package.module.foo')
assert path.module == module
assert path.callable == module.foo
def test_path_unresolvable():
path = cli2.Path('cli2.aoeuaoeuaoeu')
assert path.module == cli2
assert path.callable is None
@pytest.mark.parametrize('fixture', ['cli2', 'cli2.run', 'cli2.MISSING'])
def test_path_module_name(fixture):
path = cli2.Path(fixture)
assert path.module_name == 'cli2'
def test_path_module_callables():
path = cli2.Path('cli2.run')
assert 'console_script' not in path.module_callables
assert 'run' in path.module_callables
def test_path_module_docstring():
assert 'Example' in cli2.Path('cli2_example').module_docstring
def test_path_callable_docstring():
assert 'Test' in cli2.Path('cli2_example.test').callable_docstring
def test_path_docstring():
assert 'Example' in cli2.Path('cli2_example').docstring
assert 'Test' in cli2.Path('cli2_example.test').docstring
def test_path_str():
assert 'cli2_example.test' == str(cli2.Path('cli2_example.test'))
def test_consolescript_valid_command_with_args():
cs = cli2.ConsoleScript(['/cli2', 'run', 'foo.bar'])
assert str(cs.command) == 'cli2.run'
assert cs.command.path.module == cli2
assert cs.command.path.callable == cli2.run
assert cs.argv_extra == ['foo.bar']
def test_parser_init():
parser = cli2.Parser(['a', 'b=c', '-d', '--e=g'])
assert parser.funcargs == ['a']
assert parser.funckwargs == dict(b='c')
assert parser.dashargs == ['d']
assert parser.dashkwargs == dict(e='g')
@pytest.mark.parametrize('fixture', [
['aoeu'],
['help', 'aoeu'],
[],
])
def test_console_script_resolve_help(fixture):
cs = cli2.ConsoleScript(['/cli2-example'] + fixture)
assert str(cs.command.target) == 'cli2.help'
def test_console_script_resolve():
cs = cli2.ConsoleScript(['cli2-example', 'run'])
assert str(cs.command.target) == f'cli2_example.run'
def test_console_script_resolve_alias():
cs = cli2.ConsoleScript(['cli2-example', 'alias'])
assert str(cs.command.target) == f'cli2_example.test'
def test_docfile():
assert 'callback' in cli2.docfile('cli2.py')
def test_docfile_none():
assert cli2.docfile('test_cli2.py') is None
def test_help_module():
return
assert ' '.join(list(cli2.help('cli2'))) == '''
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
'''.lstrip()
import cli2
def test_help():
import pytest
@pytest.mark.parametrize('name,command', [
('cli2', ''),
('help', 'help'),
('help_debug', 'help debug'),
('run_help', 'run cli2.help'),
('run_help_debug', 'run cli2.help debug'),
('run_help_implicit', 'cli2.help'),
('docmod', 'docmod cli2'),
('docfile', 'docfile cli2.py'),
('debug', 'debug cli2.run to see=how -it --parses=me'),
])
def test_djcli(name, command):
cli2.autotest(
f'tests/{name}.txt',
'cli2 ' + command,
)
def test_autotest():
cli2.autotest('tests/cli2_help.txt', 'cli2 help')
......
command: cli2
retcode: 1
stdout:
Missing arguments: callback
Signature: run(callback, *args, **kwargs)
Execute a python callback on the command line.
To call your.module.callback('arg1', 'argN', kwarg1='foo'):
cli2 your.module.callback arg1 argN kwarg1=foo
You can also prefix arguments with a dash, those that contain equal sign
will end in dict your_console_script.parser.dashkwargs, those without equal
sign will end up in a list in your_console_script.parser.dashargs.
If you're using the default cli2.console_script then you can import it. If
you don't know what console_script instance, use
cli2.guess_console_script() which will inspect the call stack and return
what it believes is the ConsoleScript instance currently in use.
For examples, try `cli2 debug`.
For other commands, try `cli2 help`.
command: cli2 help
retcode: 0
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
......
command: cli2 debug cli2.run to see=how -it --parses=me
retcode: 1
stdout:
Callable: cli2.run
Args: ('to',)
Kwargs: {'see': 'how'}
console_script.parser.dashargs: ['it']
console_script.parser.dashkwargs: {'parses': 'me'}
command: cli2 docfile cli2.py
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
command: cli2 docmod cli2
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
help Get help for a command.
config config(**config)
debug Dump parsed variables.
docfile Docstring for a file path.
docmod Docstring for a module in dotted path.
run Execute a python callback on the command line.
command: cli2 help
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
help Get help for a command.
config config(**config)
debug Dump parsed variables.
docfile Docstring for a file path.
docmod Docstring for a module in dotted path.
run Execute a python callback on the command line.
command: cli2 help debug
retcode: 1
stdout:
Signature: debug(callback, *args, **kwargs)
Dump parsed variables.
Example usage::
cli2 debug test to=see --how -it=parses
command: cli2 run cli2.help
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
help Get help for a command.
config config(**config)
debug Dump parsed variables.
docfile Docstring for a file path.
docmod Docstring for a module in dotted path.
run Execute a python callback on the command line.
command: cli2 run cli2.help debug
retcode: 1
stdout:
Signature: debug(callback, *args, **kwargs)
Dump parsed variables.
Example usage::
cli2 debug test to=see --how -it=parses
command: cli2 cli2.help
retcode: 1
stdout:
cli2 makes your python callbacks work on CLI too !
cli2 provides sub-commands to introspect python modules or callables docstrings
or to execute callables or help working with cli2 itself.
help Get help for a command.
config config(**config)
debug Dump parsed variables.
docfile Docstring for a file path.
docmod Docstring for a module in dotted path.
run Execute a python callback on the command line.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment