Provide detailed error for circular `from` imports by ever0de · Pull Request #5972 · RustPython/RustPython
💡 Verification agent
🧩 Analysis chain
Critical: Disconnect between internal initializing field and Python-level __spec__._initializing attribute.
The refactored import logic looks correct, but there's a fundamental issue: this code checks __spec__._initializing (line 1389 via is_module_initializing), but the import_code_obj function in import.rs only sets the internal PyModule.initializing field. There's no code that exposes this internal state to Python as __spec__._initializing.
Without this connection, the circular import detection won't work as intended.
Consider either:
- Setting
__spec__._initializinginimport_code_objwhen setting the internal field - Modifying
is_module_initializingto check the internalPyModule.initializingfield instead
Run the following script to verify if __spec__._initializing is set anywhere in the codebase:
🏁 Script executed:
#!/bin/bash # Search for any code that sets _initializing on spec objects rg -A 5 "_initializing.*=" # Search for any references to the initializing field on PyModule ast-grep --pattern 'initializing'
Length of output: 62
🏁 Script executed:
#!/bin/bash set -e # Search for any occurrences of the internal `initializing` field in Rust code rg -n "initializing" -t rs # Search for any usage of `__spec__` or `_initializing` on spec objects rg -n "__spec__" -t rs rg -n "_initializing" -t rs
Length of output: 62
🏁 Script executed:
#!/bin/bash set -e # Search for occurrences of 'initializing' in all Rust source files rg -n "initializing" --glob '*.rs' # Search for any usage of '__spec__' in Rust source rg -n "__spec__" --glob '*.rs' # Search for any explicit '_initializing' assignments or checks in Rust source rg -n "_initializing" --glob '*.rs'
Length of output: 1656
Critical: Circular‐import detection is broken—spec._initializing is never set
The new is_module_initializing path in vm/src/frame.rs (lines 1389, 2405–2415) checks the Python‐level __spec__._initializing flag, but no code ever assigns _initializing on the module’s __spec__. We only toggle the internal PyModule.initializing field in vm/src/import.rs (lines 168, 172), so the “partially initialized module” branch will never fire.
To resolve this, choose one of the following fixes:
• In vm/src/import.rs (around lines 168–172), after calling
module.initializing.store(true/false, Ordering::Relaxed);
also set the Python‐level flag:
let spec = module.get_attr(&vm.ctx.new_str("__spec__"), vm)?; spec.set_attr(&vm.ctx.new_str("_initializing"), vm.ctx.new_bool(true), vm)?;
(and similarly for false)
• Or in vm/src/frame.rs’s is_module_initializing (lines 2405–2415), downcast module to PyModule and read its internal initializing flag directly instead of querying __spec__.
Add appropriate tests to verify circular‐import error messages now appear.
🤖 Prompt for AI Agents
In vm/src/frame.rs lines 1363 to 1408, the circular-import detection relies on
the Python-level __spec__._initializing flag, but this flag is never set,
causing the detection to fail. To fix this, either update vm/src/import.rs
around lines 168-172 to set the _initializing attribute on the module's __spec__
object whenever the internal PyModule.initializing flag is changed, or modify
the is_module_initializing function in vm/src/frame.rs (lines 2405-2415) to
downcast the module to PyModule and check the internal initializing field
directly. Additionally, add tests to confirm that circular-import errors are
correctly detected and reported.