◐ Shell
clean mode source ↗

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:

  1. Setting __spec__._initializing in import_code_obj when setting the internal field
  2. Modifying is_module_initializing to check the internal PyModule.initializing field 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.