Recursion limit serves two roles. First, it is a guard against stack overflow. Unfortunately, there is no standard way to determine the size of the stack, how much stack is available, and how much is needed for the next C call. So this is left for the end user.
Second, it is a guard against programming errors causing infinite recursions (they are common for beginners). Normal program does not have too deep recursion. If it exceeds any reasonable limit, there is a good chance that there is a bug in your program.
Unfortunately, there is no standard way to determine the size of the stack, how much stack is available, and how much is needed for the next C call. So this is left for the end user.
But the behaviour seems to be different for genuine recursion versus import chains. If I set a high recursion limit I can get a function to recurse, say, a million times. But there seems to be a different mechanism for import chains - very high recursion limits are ignored, and it raises a RecursionError anyway after a chain of 1,249 imports. I tried to get it to stack overflow in this case and it couldn’t. Do you see what I mean?
Maybe it would be useful to document this behaviour at least, if it is intentional.
RecursionError is somewhat of a misnomer. The problem is that the arbitrary limit to the depth of the call stack is reached, which is most commonly due to recursion, but in the OP’s case it’s due to too many nested imports.
Ah, yes, there is also Py_C_RECURSION_LIMIT. It is not documented and not configurable, so I forgot about it. The only way to change it is to modify the CPython source code. It limits the total recursion depth for the compiler. It does not distinguish Python frames from C frames, so it limits you even if the real stack consumption is small.
This is a part of a complex problem. We have no solution.
Indeed it should have been call CallDepthLimitError as its not recursion that triggers it. I do know that but fell into the trap of use “recursion” as a call depth on the imports.
To me, the behaviour seems reasonable to document at least. I’ve raised an issue here which suggests adding some docs, which I’m happy to do assuming the maintainers agree.
Good news. I’ve come up with a solution that resolves any RecursionError resulted from nested imports by iteratively retrying failing imports in reverse order, and if any import incurs a RecursionError while being retried in reverse order, the failing nested imports will keep stacking up and getting retried in reverse order until the original import succeeds: