neithere / argh

An argparse wrapper that doesn't make you say "argh" each time you deal with it.
http://argh.rtfd.org
GNU Lesser General Public License v3.0
369 stars 55 forks source link

Tests fail on Python 3.7.0b3 #128

Closed hroncok closed 6 years ago

hroncok commented 6 years ago

Hi. I'm rebuilding important Fedora packages with Python 3.7, so we get ready for the switch to 3.7 in Fedora 29. Argh belongs to the group (being in the dependency chain for critical components).

However, the tests fail. I can reproduce the failures on master with tox -e py37.

platform linux -- Python 3.7.0b3, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/churchyard/Dokumenty/argh, inifile:
plugins: xdist-1.22.2, forked-0.2, cov-2.5.1
collected 88 items

test/test_assembling.py .....ssFF.......                                 [ 18%]
test/test_decorators.py ......                                           [ 25%]
test/test_dispatching.py ..                                              [ 27%]
test/test_integration.py x.......xxx............FF...F.................. [ 80%]
                                                                         [ 80%]
test/test_interaction.py ...                                             [ 84%]
test/test_regressions.py .......                                         [ 92%]
test/test_utils.py .......                                               [100%]

full log with tracebacks

encukou commented 6 years ago

This is actually an issue in Python: https://bugs.python.org/issue29298 It was exposed by a bugfix in Python 3.7: https://bugs.python.org/issue26510 However, that bugfix proved problematic. It will be reverted for Python 3.7.0rc1: https://bugs.python.org/issue33109

So... try again with Python 3.7.0rc1 when it is released.

hroncok commented 6 years ago

I've tried to apply https://github.com/python/cpython/pull/3680 to python 3.7.0b4 and rerun the tests.

============================= test session starts ==============================
platform linux -- Python 3.7.0b4, pytest-3.6.0, py-1.5.3, pluggy-0.6.0
rootdir: /home/churchyard/Dokumenty/argh, inifile:
plugins: xdist-1.22.2, forked-0.2, cov-2.5.1
collected 88 items                                                             

test/test_assembling.py .....ssFF.......                                 [ 18%]
test/test_decorators.py ......                                           [ 25%]
test/test_dispatching.py ..                                              [ 27%]
test/test_integration.py x.......xxx............FF...F.F................ [ 80%]
                                                                         [ 80%]
test/test_interaction.py ...                                             [ 84%]
test/test_regressions.py .......                                         [ 92%]
test/test_utils.py .......                                               [100%]

=================================== FAILURES ===================================
__________ test_add_subparsers_when_default_command_exists__supported __________

    @pytest.mark.skipif(sys.version_info < (3,4), reason='supported since Python 3.4')
    def test_add_subparsers_when_default_command_exists__supported():

        def one(): return 1
        def two(): return 2

        p = argh.ArghParser()
        p.set_default_command(one)
        p.add_commands([two])

>       ns_one = p.parse_args([])

test/test_assembling.py:132: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
argh/helpers.py:64: in parse_args
    return super(ArghParser, self).parse_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1747: in parse_args
    args, argv = self.parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1779: in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:2014: in _parse_known_args
    ', '.join(required_actions))
/usr/lib64/python3.7/argparse.py:2499: in error
    self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = ArghParser(prog='py.test', usage=None, description=None, formatter_class=<class 'argh.constants.CustomFormatter'>, conflict_handler='error', add_help=True)
status = 2
message = 'py.test: error: the following arguments are required: {two}\n'

    def exit(self, status=0, message=None):
        if message:
            self._print_message(message, _sys.stderr)
>       _sys.exit(status)
E       SystemExit: 2

/usr/lib64/python3.7/argparse.py:2486: SystemExit
----------------------------- Captured stderr call -----------------------------
usage: py.test [-h] {two} ...
py.test: error: the following arguments are required: {two}
__________ test_set_default_command_when_subparsers_exist__supported ___________

    @pytest.mark.skipif(sys.version_info < (3,4), reason='supported since Python 3.4')
    def test_set_default_command_when_subparsers_exist__supported():
        def one(): return 1
        def two(): return 2

        p = argh.ArghParser()
        p.add_commands([one])
        p.set_default_command(two)

>       ns_two = p.parse_args([])

test/test_assembling.py:148: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
argh/helpers.py:64: in parse_args
    return super(ArghParser, self).parse_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1747: in parse_args
    args, argv = self.parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1779: in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:2014: in _parse_known_args
    ', '.join(required_actions))
/usr/lib64/python3.7/argparse.py:2499: in error
    self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = ArghParser(prog='py.test', usage=None, description=None, formatter_class=<class 'argh.constants.CustomFormatter'>, conflict_handler='error', add_help=True)
status = 2
message = 'py.test: error: the following arguments are required: {one}\n'

    def exit(self, status=0, message=None):
        if message:
            self._print_message(message, _sys.stderr)
>       _sys.exit(status)
E       SystemExit: 2

/usr/lib64/python3.7/argparse.py:2486: SystemExit
----------------------------- Captured stderr call -----------------------------
usage: py.test [-h] {one} ...
py.test: error: the following arguments are required: {one}
___________________________ test_command_not_chosen ____________________________

    def test_command_not_chosen():
        def cmd(args):
            return 1

        p = DebugArghParser()
        p.add_commands([cmd])

        if sys.version_info < (3,3):
            # Python before 3.3 exits with an error
            assert 'too few arguments' in run(p, '', exit=True)
        else:
            # Python since 3.3 returns a help message and doesn't exit
>           assert 'usage:' in run(p, '').out

test/test_integration.py:368: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/base.py:72: in run
    return call_cmd(parser, command_string, **kwargs)
test/base.py:48: in call_cmd
    result = parser.dispatch(args, **kwargs)
argh/helpers.py:55: in dispatch
    return dispatch(self, *args, **kwargs)
argh/dispatching.py:152: in dispatch
    namespace_obj = parse_args(argv, namespace=namespace)
argh/helpers.py:64: in parse_args
    return super(ArghParser, self).parse_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1747: in parse_args
    args, argv = self.parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:1779: in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
/usr/lib64/python3.7/argparse.py:2014: in _parse_known_args
    ', '.join(required_actions))
test/base.py:24: in error
    self.exit(2, message)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = DebugArghParser(prog='py.test', usage=None, description=None, formatter_class=<class 'argh.constants.CustomFormatter'>, conflict_handler='error', add_help=True)
status = 2, message = 'the following arguments are required: {cmd}'

    def exit(self, status=0, message=None):
>       raise SystemExit(message)
E       SystemExit: the following arguments are required: {cmd}

test/base.py:21: SystemExit
_____________________________ test_invalid_choice ______________________________

    def test_invalid_choice():
        def cmd(args):
            return 1

        # root level command

        p = DebugArghParser()
        p.add_commands([cmd])

>       assert run(p, 'bar', exit=True).startswith('invalid choice')
E       assert False
E        +  where False = <built-in method startswith of str object at 0x7f94621170a0>('invalid choice')
E        +    where <built-in method startswith of str object at 0x7f94621170a0> = "argument {cmd}: invalid choice: 'bar' (choose from 'cmd')".startswith
E        +      where "argument {cmd}: invalid choice: 'bar' (choose from 'cmd')" = run(DebugArghParser(prog='py.test', usage=None, description=None, formatter_class=<class 'argh.constants.CustomFormatter'>, conflict_handler='error', add_help=True), 'bar', exit=True)

test/test_integration.py:380: AssertionError
_____________________________ test_bare_namespace ______________________________

    def test_bare_namespace():
        "A command can be resolved to a function, not a namespace."

        def hello():
            return 'hello world'

        p = DebugArghParser()
        p.add_commands([hello], namespace='greet')

        # without arguments

        if sys.version_info < (3,3):
            # Python before 3.3 exits with an error
            assert run(p, 'greet', exit=True) == 'too few arguments'
        else:
            # Python since 3.3 returns a help message and doesn't exit
>           assert 'usage:' in run(p, 'greet', exit=True).out
E           AttributeError: 'str' object has no attribute 'out'

test/test_integration.py:466: AttributeError
____________________________ test_explicit_cmd_name ____________________________

    def test_explicit_cmd_name():

        @argh.named('new-name')
        def orig_name():
            return 'ok'

        p = DebugArghParser()
        p.add_commands([orig_name])
>       assert run(p, 'orig-name', exit=True).startswith('invalid choice')
E       assert False
E        +  where False = <built-in method startswith of str object at 0x7f94620eb730>('invalid choice')
E        +    where <built-in method startswith of str object at 0x7f94620eb730> = "argument {new-name}: invalid choice: 'orig-name' (choose from 'new-name')".startswith
E        +      where "argument {new-name}: invalid choice: 'orig-name' (choose from 'new-name')" = run(DebugArghParser(prog='py.test', usage=None, description=None, formatter_class=<class 'argh.constants.CustomFormatter'>, conflict_handler='error', add_help=True), 'orig-name', exit=True)

test/test_integration.py:514: AssertionError
========== 6 failed, 76 passed, 2 skipped, 4 xfailed in 0.71 seconds ===========
hroncok commented 6 years ago

This is already in b5 https://github.com/python/cpython/pull/7089 and the test pass.