IndexError in Python 3.5

Issue #434 resolved
Theron Luhn
created an issue

When trying to generate HTML report (make html) for https://github.com/luhn/aiopg/tree/async-with in Python 3.5, I get the following exception.

Traceback (most recent call last):
  File "/home/travis/virtualenv/python3.5.0/bin/py.test", line 11, in <module>
    sys.exit(main())
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/config.py", line 48, in main
    return config.hook.pytest_cmdline_main(config=config)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 596, in execute
    res = hook_impl.function(*args)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/main.py", line 115, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/main.py", line 110, in wrap_session
    exitstatus=session.exitstatus)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 595, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 249, in _wrapped_call
    wrap_controller.send(call_outcome)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/terminal.py", line 370, in pytest_sessionfinish
    self.config.hook.pytest_terminal_summary(terminalreporter=self)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 596, in execute
    res = hook_impl.function(*args)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/pytest_cov/plugin.py", line 168, in pytest_terminal_summary
    total = self.cov_controller.summary(terminalreporter.writer)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/pytest_cov/engine.py", line 92, in summary
    total = self.cov.html_report(ignore_errors=True)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/control.py", line 1016, in html_report
    return reporter.report(morfs)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/html.py", line 133, in report
    self.report_files(self.html_file, morfs, self.config.html_dir)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/report.py", line 83, in report_files
    report_fn(fr, self.coverage._analyze(fr))
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/control.py", line 893, in _analyze
    return Analysis(self.data, it)
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/results.py", line 28, in __init__
    self._arc_possibilities = sorted(self.file_reporter.arcs())
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/python.py", line 159, in arcs
    return self.parser.arcs()
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/parser.py", line 238, in arcs
    for l1, l2 in self.byte_parser._all_arcs():
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/parser.py", line 624, in _all_arcs
    arcs.update(bp._arcs())
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/parser.py", line 561, in _arcs
    chunks = self._split_into_chunks()
  File "/home/travis/virtualenv/python3.5.0/lib/python3.5/site-packages/coverage/parser.py", line 493, in _split_into_chunks
    block_stack.pop()
IndexError: pop from empty list

make report works fine.

Comments (11)

  1. Ned Batchelder repo owner

    You may be the first person to try coverage.py with the new 3.5 async support. Coverage.py will have to be updated to handle it. The more tests you can give me for it, the better :)

  2. tehasdf

    Apparently you need to enable branch coverage to trigger this error (and indeed aiopg does include a branch=True in its .coveragerc). For example, this code triggers the error for me:

    async def go():
        async with x:
            pass
    

    Run like:

    coverage run --branch thefile.py
    coverage html
    
  3. Aymeric Augustin

    So, the disassembly of:

    async def a():
        async with b:
            pass
    

    gives:

    >>> dis.dis(asyncbranch.a)
      2           0 LOAD_GLOBAL              0 (b)
                  3 BEFORE_ASYNC_WITH
                  4 GET_AWAITABLE
                  5 LOAD_CONST               0 (None)
                  8 YIELD_FROM
                  9 SETUP_ASYNC_WITH         5 (to 17)
                 12 POP_TOP
    
      3          13 POP_BLOCK
                 14 LOAD_CONST               0 (None)
            >>   17 WITH_CLEANUP_START
                 18 GET_AWAITABLE
                 19 LOAD_CONST               0 (None)
                 22 YIELD_FROM
                 23 WITH_CLEANUP_FINISH
                 24 END_FINALLY
                 25 LOAD_CONST               0 (None)
                 28 RETURN_VALUE
    

    This patch appears to fix the issue for me:

    diff -r b1f870cdcfb5 AUTHORS.txt
    --- a/AUTHORS.txt   Fri Dec 11 09:01:51 2015 -0500
    +++ b/AUTHORS.txt   Thu Dec 17 22:28:34 2015 +0100
    @@ -8,6 +8,7 @@
     Alexander Todorov
     Anthony Sottile
     Arcadiy Ivanov
    +Aymeric Augustin
     Ben Finney
     Bill Hart
     Brandon Rhodes
    diff -r b1f870cdcfb5 CHANGES.rst
    --- a/CHANGES.rst   Fri Dec 11 09:01:51 2015 -0500
    +++ b/CHANGES.rst   Thu Dec 17 22:28:34 2015 +0100
    @@ -15,6 +15,11 @@
    
     .. _issue 131: https://bitbucket.org/ned/coveragepy/issues/131/pragma-on-a-decorator-line-should-affect
    
    +- Fixed a crash in report generation when measuring branch coverage on Python
    +  3.5 code including ``async with`` context managers (`issue 434`_).
    +
    +.. _issue 434: https://bitbucket.org/ned/coveragepy/issues/434/indexerror-in-python-35
    +
    
     Version 4.0.3 --- 2015-11-24
     ----------------------------
    diff -r b1f870cdcfb5 coverage/parser.py
    --- a/coverage/parser.py    Fri Dec 11 09:01:51 2015 -0500
    +++ b/coverage/parser.py    Thu Dec 17 22:28:34 2015 +0100
    @@ -321,7 +321,8 @@
    
     # Opcodes that push a block on the block stack.
     OPS_PUSH_BLOCK = _opcode_set(
    -    'SETUP_LOOP', 'SETUP_EXCEPT', 'SETUP_FINALLY', 'SETUP_WITH'
    +    'SETUP_LOOP', 'SETUP_EXCEPT', 'SETUP_FINALLY', 'SETUP_WITH',
    +#    'SETUP_ASYNC_WITH',
     )
    
     # Block types for exception handling.
    diff -r b1f870cdcfb5 tests/test_parser.py
    --- a/tests/test_parser.py  Fri Dec 11 09:01:51 2015 -0500
    +++ b/tests/test_parser.py  Thu Dec 17 22:28:34 2015 +0100
    @@ -3,6 +3,7 @@
    
     """Tests for coverage.py's code parsing."""
    
    +import sys
     import textwrap
    
     from tests.coveragetest import CoverageTest
    @@ -185,6 +186,18 @@
             self.assertEqual(parser.raw_statements, set([1, 2, 3, 5, 6, 7, 8]))
             self.assertEqual(parser.statements, set([1, 2, 3]))
    
    +    def test_async_with(self):
    +        # https://bitbucket.org/ned/coveragepy/issues/434/indexerror-in-python-35
    +        if sys.version_info < (3, 5):
    +            self.skip("async with syntax was introduced in Python3.5")
    +        parser = self.parse_source("""\
    +            async def a():
    +                async with b:
    +                    pass
    +            """)
    +        # This used to raise IndexError: pop from empty list
    +        self.assertEqual(parser.exit_counts(), {1: 1, 2: 1, 3: 1})
    +
    
     class ParserFileTest(CoverageTest):
         """Tests for coverage.py's code parsing from files."""
    

    (Sorry for the inline diff, I have mostly stopped using hg and I'm too lazy at this time of the night to figure out how to make a pull request on BitBucket.)

  4. Log in to comment