Thanks to visit codestin.com
Credit goes to github.com

Skip to content
5 changes: 5 additions & 0 deletions mypy/dmypy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from mypy.dmypy_os import alive, kill
from mypy.dmypy_util import DEFAULT_STATUS_FILE, receive, send
from mypy.ipc import IPCClient, IPCException
from mypy.main import RECURSION_LIMIT
from mypy.util import check_python_version, get_terminal_width, should_force_color
from mypy.version import __version__

Expand Down Expand Up @@ -267,6 +268,10 @@ class BadStatus(Exception):
def main(argv: list[str]) -> None:
"""The code is top-down."""
check_python_version("dmypy")

# set recursion limit consistent with mypy/main.py
sys.setrecursionlimit(RECURSION_LIMIT)

args = parser.parse_args(argv)
if not args.action:
parser.print_usage()
Expand Down
24 changes: 24 additions & 0 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,29 @@ def parse(
strip_function_bodies=strip_function_bodies,
path=fnam,
).visit(ast)

except RecursionError as e:
# For very complex expressions it is possible to hit recursion limit
# before reaching a leaf node.
# Should reject at top level instead at bottom, since bottom would already
# be at the threshold of the recursion limit, and may fail again later.
# E.G. x1+x2+x3+...+xn -> BinOp(left=BinOp(left=BinOp(left=...
try:
# But to prove that is the cause of this particular recursion error,
# try to walk the tree using builtin visitor
ast3.NodeVisitor().visit(ast)
except RecursionError:
errors.report(
-1, -1, "Source expression too complex to parse", blocker=False, code=codes.MISC
)

tree = MypyFile([], [], False, {})

else:
# re-raise original recursion error if it *can* be unparsed,
# maybe this is some other issue that shouldn't be silenced/misdirected
raise e

except SyntaxError as e:
# alias to please mypyc
is_py38_or_earlier = sys.version_info < (3, 9)
Expand Down Expand Up @@ -414,6 +437,7 @@ def visit(self, node: AST | None) -> Any:
method = "visit_" + node.__class__.__name__
visitor = getattr(self, method)
self.visitor_cache[typeobj] = visitor

return visitor(node)

def set_line(self, node: N, n: AstNode) -> N:
Expand Down
3 changes: 2 additions & 1 deletion mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

orig_stat: Final = os.stat
MEM_PROFILE: Final = False # If True, dump memory profile
RECURSION_LIMIT: Final = 2**14


def stat_proxy(path: str) -> os.stat_result:
Expand Down Expand Up @@ -63,7 +64,7 @@ def main(
util.check_python_version("mypy")
t0 = time.time()
# To log stat() calls: os.stat = stat_proxy
sys.setrecursionlimit(2**14)
sys.setrecursionlimit(RECURSION_LIMIT)
if args is None:
args = sys.argv[1:]

Expand Down