New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Help Taming RecursionError #4406
Comments
I have sent you an email with my logs. For anyone else, I hit this problem with |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I'm having this annoying issue in my main computer. I am able to use pyinstaller in other computers with the same code so it is a computer specific problem. I have a virtual machine in my main computer where it works, It is very strange. Edit: I'm able to generate the exe with Python 3.8.0 and:
Edit 2: Pyinstaller worked but fbs don't, it shows this error: Log``` fbs freeze c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\mpmath\ctx_mp_python.py:892: SyntaxWarning: "is" with a literal. Did you mean "=="? if other is 0: c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\mpmath\ctx_mp_python.py:986: SyntaxWarning: "is" with a literal. Did you mean "=="? if other is 0: Traceback (most recent call last): File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\runpy.py", line 192, in _run_module_as_main return _run_code(code, main_globals, None, File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Users\usuario01\AppData\Local\Programs\Python\Python38-32\Scripts\pyinstaller.exe\__main__.py", line 9, in File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\__main__.py", line 111, in run run_build(pyi_config, spec_file, **vars(args)) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\__main__.py", line 63, in run_build PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\build_main.py", line 838, in main build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build')) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\build_main.py", line 784, in build exec(text, spec_namespace) File "", line 18, in File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\api.py", line 98, in __init__ self.__postinit__() File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\datastruct.py", line 158, in __postinit__ self.assemble() File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\api.py", line 128, in assemble self.code_dict = { File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\api.py", line 129, in key: strip_paths_in_code(code) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\utils.py", line 654, in strip_paths_in_code consts = tuple( File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\utils.py", line 655, in strip_paths_in_code(const_co, new_filename) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\PyInstaller\building\utils.py", line 662, in strip_paths_in_code return code_func(co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize, TypeError: an integer is required (got type bytes) Traceback (most recent call last): File "C:\Users\usuario01\AppData\Local\Programs\Python\Python38-32\Scripts\fbs-script.py", line 11, in load_entry_point('fbs==0.8.6', 'console_scripts', 'fbs')() File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\fbs\__main__.py", line 17, in _main fbs.cmdline.main() File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\fbs\cmdline.py", line 32, in main fn(*args) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\fbs\builtin_commands\__init__.py", line 120, in freeze freeze_windows(debug=debug) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\fbs\freeze\windows.py", line 18, in freeze_windows run_pyinstaller(args, debug) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\site-packages\fbs\freeze\__init__.py", line 47, in run_pyinstaller run(args, check=True) File "c:\users\usuario01\appdata\local\programs\python\python38-32\lib\subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['pyinstaller', '--name', 'Dibujo técnico', '--noupx', '--log-level', 'ERROR', '--noconfirm', '--windowed', '--icon', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\src\\main\\icons\\Icon.ico', '--distpath', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\target', '--specpath', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\target\\PyInstaller', '--workpath', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\target\\PyInstaller', '--additional-hooks-dir', 'c:\\users\\usuario01\\appdata\\local\\programs\\python\\python38-32\\lib\\site-packages\\fbs\\freeze\\hooks', '--runtime-hook', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\target\\PyInstaller\\fbs_pyinstaller_hook.py', 'D:\\Pictures\\Camera Roll\\Windows\\No hay nada no entres\\He dicho que no\\EL QUE AVISA ES AVISADOR\\Pyton\\Prueba fbs\\src\\main\\python\\main.py']' returned non-zero exit status 1. ```Edit 3: I am able to generate the .exe at my main PC, I had never been able to do it until now. I completely reinstalled Python 3.8.2 with the necessary modules and it worked! Modules:
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@Jaime02 crap - I must have acidentally deleted it. (Groan). To replicate: (In a fresh venv)
|
Ok I've traced the subsystem. It's modulegraph (suprise suprise) and the part known to be recursive. I'll let you know more when I have it. |
Ok everyone. A fix is on the way.
Fix: We (The pyinstaller developers) are replacing ModuleGraph... with ModuleGraph 2. A non-recursive implementation. Expect this to take some time. |
@Legorooj
I added The interesting thing is that I don't get that error if I don't use fastapi (It works with Flask for example). Looks like PyInstaller has some issue with fastapi. This is the code in my main python function (for reproducing the error):
|
@smasoudn this is the same error we've all been getting. I got it with |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@AIprototype no, there isn't yet. I'll be getting to work on actually implementing the fix in a few weeks. |
@AIprototype Try using Python 3.8.x in a fresh new environment |
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see pyinstaller#5131, pyinstaller#4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See pyinstaller#4406, closes pyinstaller#5131, pyinstaller#4346.
modulegraph's heritage includes code still based on Python 2.x capabilities on how to find a module and get its source or code. It also contained a anomaly regarding packages and their ``__init__``-file: If a package was detected, it's ``__init__`` file was loaded as a module. This, while being ugly, worked in most cases, but failed if the ``__init__`` module is an extension module (see #5131, #4346), ending in an infinite loop. This was caused by modulegraph distinguishing between the package and its ``__init__`` module. The solution is to switch to "modern" loaders, both being a loader for a specific type of modules (source, extension, etc.) and having a package characteristic (property ``is_package()``) This commit does the following - In ``_find_module_path()`` no longer return "metadata" but a loader. This also removed huge part of this function, making it much easier to understand. As a side effect, this asymmetric closing of a file in a completely other part of the code (``_safe_import_module``) could be removed. - Change ``_load_module`` to use the loaders. - Merge ``_load_package`` into `__load_module``, getting rid of the anomaly described above. - Adjust the test-cases to the new behavior (esp. loader instead of metadata-tuple and filehandle) Please note: Since we plan to change to modulegraph2 soon anyway, I did not spend too much time on creating a clean solution. See #4406, closes #5131, #4346.
@bwoodsend Is there another plan other than the one I had for slowly incorporating modulegraph2? Because I would be willing to take that forward if I had the support of the developers. As expected, the other plans are not working toward a solution. |
I don't see how slowly incorporating modulegraph2 can work. As there is only one API component in modulegraph (namely the |
@bwoodsend What about this: I can incrementally update the ModuleGraph API to match the modulegraph 2 API. There are a few different method names and some changes that need care. This way, modulegraph2 can be closer to a drop-in replacement. I can open a new tracking issue to track the methods that need to be renamed. |
If there's enough symmetry between modulegraph and modulegraph2 that that is possible then that sounds like a good plan. |
Ah no, that's something else entirely. That test is un-runable on Python >= 3.9.6 because of a recursion check added to Python itself so we've had to remove it (see e188739 which tells you the same thing in more words). |
EDIT: Fix en route. Original comment:
If you encounter a "RecursionError:maximum recursion depth exceeded", please help taming this beast. I was not yet able to reproduce this on my system, thus you need to provide data so I can try to fix the issue.
Please follow these instructions, which (hopefully) provide the required information). Thanks!
Now comes the important part:
If this does not fail, ensure the .spec-file does not
sys.setrecursionlimit()
Please try to generate a as minimal as possible version of you application, which will still make PyInstaller run into RecursionError. Ideally the application only consists of on import statement and still fails to freeze.
Please, please take your time for doing so! The TRACE-output you will generate in the next steps will be HUGE and hard to analyze anyway. Please help keeping the data small. Otherwise I will have barely no chance to find the error.
Run PyInstaller in TRACE mode, redirecting the output into a file. The outout will be huge, several thousand lines, so you really want to redirect the output into a file::
then run
pyinstaller main.spec
again. If it fails, increase the number, if it passes, decrease the number. Repeat until you have a lower bound (in steps 10) where PyInstaller passes.I only need these log-file, nothing of the stuff built.
The text was updated successfully, but these errors were encountered: