Closed lee-hodg closed 2 years ago
This sounds weird! Somehow, the coverage configuration object has itself (or some other value) recursively. I have no idea why that would be.
Can you run the tests again with a new branch of coverage.py? I added some debugging to see what the configuration object is like. Install coverage with:
pip install git+https://github.com/nedbat/coveragepy.git@nedbat/debug-1298#egg=coverage==0.0
and run the tests. It should still fail with a recursion error, but we'll have a bit of debug output to look at.
I'm running into a similar issue. Coverage works fine to run my tests but then running coverage html
results in RecursionError: maximum recursion depth exceeded
:
root@52d7bb691933:/src# coverage html
Traceback (most recent call last):
File "/usr/local/bin/coverage", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.10/site-packages/coverage/cmdline.py", line 880, in main
status = CoverageScript().command_line(argv)
File "/usr/local/lib/python3.10/site-packages/coverage/cmdline.py", line 638, in command_line
total = self.coverage.html_report(
File "/usr/local/lib/python3.10/site-packages/coverage/control.py", line 1003, in html_report
ret = reporter.report(morfs)
File "/usr/local/lib/python3.10/site-packages/coverage/html.py", line 208, in report
self.html_file(fr, analysis)
File "/usr/local/lib/python3.10/site-packages/coverage/html.py", line 272, in html_file
file_data = self.datagen.data_for_file(fr, analysis)
File "/usr/local/lib/python3.10/site-packages/coverage/html.py", line 73, in data_for_file
for lineno, tokens in enumerate(fr.source_token_lines(), start=1):
File "/usr/local/lib/python3.10/site-packages/coverage/phystokens.py", line 111, in source_token_lines
match_case_lines = MatchCaseFinder(source).match_case_lines
File "/usr/local/lib/python3.10/site-packages/coverage/phystokens.py", line 76, in __init__
self.visit(ast.parse(source))
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 418, in generic_visit
self.visit(item)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 418, in generic_visit
self.visit(item)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 418, in generic_visit
...
RecursionError: maximum recursion depth exceeded
This started happening after I updated to Python 3.10.1 from 3.8.
@jaredhobbs that looks like a different stack trace. Would you mind opening a new issue, with as many detailed steps as you can give me to reproduce the issue?
@lee-hodg @jaredhobbs Can you provide any more information?
I wasn't able to create a minimal example unfortunately. I was, however, able to get it working by increasing the recursion limit to 1500.
@jaredhobbs is your code public? Or would you be able to add a bit of debugging to the coverage.py source to find the source file that caused it? I would really like to understand what happened. Also, I am very surprised that increasing the limit from 1000 to 1500 made it work.
It's not public, sorry. The code includes a bunch of very large files that were auto-generated from xsd schema files. I imagine the problematic source file is one of those.
That being said, I'd be happy to add some debugging to coverage.py to find the source that created it! Let me know how to do that!
Thanks for persisting with me! :)
Do you have the end of the RecursionError stack trace? I can see we are deep in the ast module, but I'm hoping the final few frames indicate something about coverage.py code.
Do your generated source files use the new 3.10 match/case feature?
You mentioned the files are very large. Can you put some numbers to it? How many lines, and how deep are the nested structures (classes, functions, if-statements, etc, etc)? What's the deepest indentation level?
To find the particular file, you can add print(fr)
just before this line in html.py:
File "/usr/local/lib/python3.10/site-packages/coverage/html.py", line 73, in data_for_file
for lineno, tokens in enumerate(fr.source_token_lines(), start=1):
The end of the stack trace is:
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 420, in generic_visit
self.visit(value)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 420, in generic_visit
self.visit(value)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 414, in generic_visit
for field, value in iter_fields(node):
RecursionError: maximum recursion depth exceeded
The generated source files don't use the match/case feature; they were generated with Python 3.8.
After printing out the file names, I found the file that is being processed before the recursion error. That file is 15,571 lines long. It was generated with generateds version 2.40.6. I didn't see any deeply nested structures in the file. Seems like the deepest nesting was about 4 levels deep.
I'm trying to think how to debug this without the source. If you can email it to me to keep from posting it here publicly, that will work too: ned@nedbatchelder.com
Can you try this program on it?
import ast
class MatchCaseFinder(ast.NodeVisitor):
"""Helper for finding match/case lines."""
def __init__(self, source):
# This will be the set of line numbers that start match or case statements.
self.match_case_lines = set()
self.visit(ast.parse(source))
def visit_Match(self, node):
"""Invoked by ast.NodeVisitor.visit"""
raise Exception("visit_Match shouldn't have been called!")
with open("THAT_FILE") as f:
source = f.read()
print(MatchCaseFinder(source).match_case_lines)
That program also triggers the RecursionError. Here's the output from the top and bottom:
root@43ac68281994:/src# python3 tmp.py
Traceback (most recent call last):
File "/src/tmp.py", line 17, in <module>
print(MatchCaseFinder(source).match_case_lines)
File "/src/tmp.py", line 8, in __init__
self.visit(ast.parse(source))
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 418, in generic_visit
self.visit(item)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 418, in generic_visit
self.visit(item)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
...
File "/usr/local/lib/python3.10/ast.py", line 420, in generic_visit
self.visit(value)
File "/usr/local/lib/python3.10/ast.py", line 410, in visit
return visitor(node)
File "/usr/local/lib/python3.10/ast.py", line 414, in generic_visit
for field, value in iter_fields(node):
File "/usr/local/lib/python3.10/ast.py", line 254, in iter_fields
yield field, getattr(node, field)
RecursionError: maximum recursion depth exceeded while calling a Python object
It sounds like a bug in the ast module, since my code isn't even in the stack there. But unless you can share the file with someone we'll never know what's going wrong.
Describe the bug
I keep getting an infinite recursion exception when running coverage on circleCI, and with unit tests that use python sure
The exception looks like
I've tried multiple versions of coverage from
coverage==4.5.4
to6.1.2
and6.2
and it's the same (sure==1.4.78
anddjango-nose==1.4.7
).The command I run is with Django like
python app/manage.py test tests --cover-html --cover-html-dir=tests/test-reports
and locally (on my laptop virtualenv) it seems to work just fine.To Reproduce How can we reproduce the problem? Please be specific. Don't just link to a failing CI job. Answer the questions below: . What version of Python are you using?
3.8.5
What version of coverage.py shows the problem? The output of
coverage debug sys
is helpful. 4.5.4, 6.1.2, 6.2 showed this problem (maybe others...)What versions of what packages do you have installed? The output of
pip freeze
is helpful.What commands did you run?
Django unit tests on circleCI
python app/manage.py test tests --cover-html --cover-html-dir=tests/test-reports
Expected behavior
A coverage report is generated without hitting an infinite recursion issue.
Additional context