Skip to content

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Dec 26, 2025

fix #6273

Summary by CodeRabbit

  • New Features
    • Added support for executing pre-compiled Python (.pyc) files.
    • Improved file loader to auto-detect and run both source and compiled Python files.
    • Exposed the .pyc magic number constant to Python via the import machinery for clearer introspection.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 26, 2025

📝 Walkthrough

Walkthrough

Adds CPython-aligned .pyc magic constants, detects and executes .pyc files via a sourceless loader in the compiler path, removes dynamic git-derived MAGIC_NUMBER setup in import initialization, and exposes the pyc magic token to Python via the _imp module attribute.

Changes

Cohort / File(s) Summary
PYC magic constants
crates/vm/src/version.rs
Added public constants: PYC_MAGIC_NUMBER: u16, PYC_MAGIC_NUMBER_TOKEN: u32, and PYC_MAGIC_NUMBER_BYTES: [u8;4].
Pyc detection & execution
crates/vm/src/vm/compile.rs
Added maybe_pyc_file (and maybe_pyc_file_with_magic) to detect .pyc by extension/magic; branched execution to use SourcelessFileLoader for .pyc and SourceFileLoader for source; updated set_main_loader to accept loader_name.
Import init cleanup
crates/vm/src/import.rs
Removed code that computed/assigned a dynamic 4-byte MAGIC_NUMBER from the git revision and the get_git_revision import; zipimport initialization unchanged.
Expose magic to Python
crates/vm/src/stdlib/imp.rs
Added pyc_magic_number_token attribute to the _imp module, sourced from version::PYC_MAGIC_NUMBER_TOKEN.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant CLI as RustPython CLI
    participant Detector as Pyc Detector (compile.rs)
    participant Loader as Import Loader (Sourceless/SourceFileLoader)
    participant VM as VirtualMachine

    CLI->>Detector: execute_file(path)
    Detector->>Detector: check extension and PYC magic
    alt .pyc detected
        Detector->>Loader: set_main_loader(..., "SourcelessFileLoader")
        Loader->>VM: get_code(module_name="__main__")
        VM->>VM: execute PyCode (bytecode)
    else source file
        Detector->>Loader: set_main_loader(..., "SourceFileLoader")
        Loader->>Loader: read source -> compile to PyCode
        Loader->>VM: run compiled PyCode
    end
    VM-->>CLI: execution result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇
I sniffed the bytes and found the cue,
Magic stamped in four-byte blue,
Sourceless hops — the bytecode runs,
A rabbit's cheer for faster fun! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: implementing maybe_pyc_file function and enabling .pyc file execution, which directly matches the file-level changes in compile.rs and the PR objectives.
Linked Issues check ✅ Passed All coding requirements from issue #6273 are met: the PR detects .pyc files via maybe_pyc_file, handles .pyc execution with SourcelessFileLoader, and executes compiled code appropriately.
Out of Scope Changes check ✅ Passed All changes are scoped to .pyc file support: version.rs adds magic number constants, compile.rs implements detection and execution, import.rs removes dynamic magic number setup, and imp.rs exposes the constant to Python.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone youknowone force-pushed the pyc branch 2 times, most recently from 0299bef to c979a0b Compare December 26, 2025 08:05
@youknowone youknowone marked this pull request as ready for review December 26, 2025 11:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/vm/src/vm/compile.rs (1)

172-181: Consider using read_exact and clarify the half-magic rationale.

  1. read_exact(&mut buf) is more idiomatic than checking the return value of read().
  2. The "half magic" (2 bytes) comparison is unusual—CPython checks all 4 bytes. If this is intentional for some compatibility reason, the docstring should explain why.
🔎 Suggested improvement
-    let mut file = std::fs::File::open(path)?;
-    let mut buf = [0u8; 2];
-
-    use std::io::Read;
-    if file.read(&mut buf)? != 2 || magic_number.len() < 2 {
+    use std::io::Read;
+    let mut file = std::fs::File::open(path)?;
+    let mut buf = [0u8; 4];
+
+    if file.read_exact(&mut buf).is_err() || magic_number.len() < 4 {
         return Ok(false);
     }
 
-    // Compare with first 2 bytes of magic number (half magic)
-    Ok(buf == magic_number[..2])
+    // Compare full 4-byte magic number
+    Ok(buf == magic_number[..4])
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9bf8df and c979a0b.

⛔ Files ignored due to path filters (2)
  • Lib/test/test_cmd_line_script.py is excluded by !Lib/**
  • Lib/test/test_compileall.py is excluded by !Lib/**
📒 Files selected for processing (2)
  • crates/vm/src/version.rs
  • crates/vm/src/vm/compile.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Follow the default rustfmt code style by running cargo fmt to format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust

Files:

  • crates/vm/src/version.rs
  • crates/vm/src/vm/compile.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Use `cargo run -- script.py` instead of the standard `python` command to run and test Python code with RustPython
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to **/*.rs : Use the macro system (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Use `cargo run -- script.py` instead of the standard `python` command to run and test Python code with RustPython

Applied to files:

  • crates/vm/src/vm/compile.rs
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to **/*.rs : Use the macro system (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust

Applied to files:

  • crates/vm/src/vm/compile.rs
🧬 Code graph analysis (2)
crates/vm/src/version.rs (2)
crates/literal/src/float.rs (1)
  • rand (255-255)
crates/common/src/rand.rs (1)
  • os_random (9-13)
crates/vm/src/vm/compile.rs (1)
crates/vm/src/version.rs (1)
  • get_magic_number (131-138)
🔇 Additional comments (3)
crates/vm/src/vm/compile.rs (3)

78-88: Pyc execution flow looks correct, assuming upstream magic number issue is resolved.

The flow correctly:

  • Sets up SourcelessFileLoader for .pyc files
  • Retrieves get_code method and calls it
  • Downcasts to PyCode with appropriate error handling
  • Executes via run_code_obj

135-149: LGTM!

Clean refactoring to parameterize the loader type. The function correctly imports machinery, retrieves the loader class by name, and instantiates it with the module name and filename.


151-163: Logic is sound for the detection strategy.

The two-tier approach (extension check, then magic check) is reasonable. However, the effectiveness depends on resolving the magic number issues noted in version.rs.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/vm/src/vm/compile.rs (1)

151-162: Consider logging IO errors during .pyc detection.

Line 161 silently treats IO errors as "not a .pyc file" via unwrap_or(false). While defensive, this can make debugging harder if a .pyc file exists but cannot be read due to permissions or filesystem issues.

💡 Optional improvement: log IO errors
-    maybe_pyc_file_with_magic(path, &crate::version::PYC_MAGIC_NUMBER_BYTES).unwrap_or(false)
+    match maybe_pyc_file_with_magic(path, &crate::version::PYC_MAGIC_NUMBER_BYTES) {
+        Ok(result) => result,
+        Err(e) => {
+            warn!("Error checking if {} is a .pyc file: {}", path, e);
+            false
+        }
+    }
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c979a0b and b804ffa.

⛔ Files ignored due to path filters (4)
  • Lib/test/test_cmd_line_script.py is excluded by !Lib/**
  • Lib/test/test_compileall.py is excluded by !Lib/**
  • Lib/test/test_importlib/source/test_file_loader.py is excluded by !Lib/**
  • Lib/test/test_importlib/test_util.py is excluded by !Lib/**
📒 Files selected for processing (4)
  • crates/vm/src/import.rs
  • crates/vm/src/stdlib/imp.rs
  • crates/vm/src/version.rs
  • crates/vm/src/vm/compile.rs
💤 Files with no reviewable changes (1)
  • crates/vm/src/import.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Follow the default rustfmt code style by running cargo fmt to format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust

Files:

  • crates/vm/src/version.rs
  • crates/vm/src/stdlib/imp.rs
  • crates/vm/src/vm/compile.rs
🧠 Learnings (5)
📚 Learning: 2025-06-27T14:47:28.810Z
Learnt from: moreal
Repo: RustPython/RustPython PR: 5847
File: vm/src/stdlib/stat.rs:547-567
Timestamp: 2025-06-27T14:47:28.810Z
Learning: In RustPython's stat module implementation, platform-specific constants like SF_SUPPORTED and SF_SYNTHETIC should be conditionally declared only for the platforms where they're available (e.g., macOS), following CPython's approach of optional declaration using #ifdef checks rather than providing fallback values for other platforms.

Applied to files:

  • crates/vm/src/version.rs
📚 Learning: 2025-06-27T14:47:28.810Z
Learnt from: moreal
Repo: RustPython/RustPython PR: 5847
File: vm/src/stdlib/stat.rs:547-567
Timestamp: 2025-06-27T14:47:28.810Z
Learning: In RustPython's stat module implementation, platform-specific constants like SF_SUPPORTED and SF_SYNTHETIC should be conditionally declared only for the platforms where they're available (e.g., macOS), following CPython's approach of optional declaration rather than providing fallback values for other platforms.

Applied to files:

  • crates/vm/src/version.rs
📚 Learning: 2025-08-09T22:56:24.527Z
Learnt from: jackoconnordev
Repo: RustPython/RustPython PR: 6086
File: benches/microbenchmarks/sort.py:1-3
Timestamp: 2025-08-09T22:56:24.527Z
Learning: In RustPython's microbenchmarks (benches/microbenchmarks/*.py), the variable `ITERATIONS` is intentionally used without being defined in the Python files. It is injected by the cargo bench harness at runtime. This pattern should be maintained for consistency across all microbenchmarks, and F821 lint warnings for undefined `ITERATIONS` are expected and acceptable in this context.

Applied to files:

  • crates/vm/src/version.rs
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Use `cargo run -- script.py` instead of the standard `python` command to run and test Python code with RustPython

Applied to files:

  • crates/vm/src/vm/compile.rs
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to **/*.rs : Use the macro system (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust

Applied to files:

  • crates/vm/src/vm/compile.rs
🧬 Code graph analysis (1)
crates/vm/src/stdlib/imp.rs (2)
crates/vm/src/vm/mod.rs (1)
  • import (571-575)
crates/vm/src/stdlib/sys.rs (1)
  • version (241-243)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run tests under miri
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Check the WASM package and demo
  • GitHub Check: Check Rust code with clippy
🔇 Additional comments (5)
crates/vm/src/version.rs (1)

133-139: LGTM! Correct CPython-compatible .pyc magic format.

The token construction correctly follows CPython's format: magic_number | ('\r' << 16) | ('\n' << 24), protecting against text-mode corruption. The little-endian byte representation aligns with CPython's .pyc header format.

crates/vm/src/stdlib/imp.rs (1)

88-88: LGTM! Correctly exposes pyc magic number to Python.

The constant is properly imported from the version module and exposed via the _imp module with appropriate Python naming conventions, matching CPython's approach for bytecode magic number access.

Also applies to: 97-98

crates/vm/src/vm/compile.rs (3)

78-88: LGTM! Correct .pyc execution flow.

The implementation properly detects .pyc files, configures the appropriate loader (SourcelessFileLoader), obtains the code object, and handles downcasting errors with a clear message. This matches CPython's sourceless execution path.


135-149: LGTM! Loader parameterization enables .pyc handling.

The updated signature correctly accepts loader_name as a parameter, enabling the selection between SourceFileLoader and SourcelessFileLoader based on file type. All call sites have been updated appropriately.


164-184: LGTM! Correct magic number detection with text-mode safeguard.

The 2-byte magic check (lines 176-183) correctly implements CPython's detection strategy, which only examines the first 2 bytes to avoid text-mode corruption issues with \r\n bytes. The comment clearly documents this rationale.

Comment on lines +130 to +131
// Must be aligned to Lib/importlib/_bootstrap_external.py
pub const PYC_MAGIC_NUMBER: u16 = 3531;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Python 3.13.0 alpha pyc magic number

💡 Result:

Python 3.13 (alpha) .pyc magic number: bytes = 0xF3 0x0D 0x0D 0x0A (i.e. little-endian 2‑byte value 3571 then b'\r\n'). [1][2]

Sources:

  • importlib._bootstrap_external MAGIC_NUMBER definition (CPython 3.13 source snapshot). [1]
  • importlib.util.MAGIC_NUMBER (docs). [2]

Change the magic number from 3531 to 3571 to match Python 3.13.0alpha.

The hardcoded value must be 3571 (bytes 0xF3 0x0D 0x0D 0x0A in little-endian) to align with CPython's Python 3.13.0alpha magic number. The current value 3531 is incorrect and will cause .pyc file incompatibility.

🤖 Prompt for AI Agents
In crates/vm/src/version.rs around lines 130 to 131, the PYC_MAGIC_NUMBER
constant is incorrectly set to 3531; update its value to 3571 to match Python
3.13.0alpha (ensure the constant uses the new numeric value 3571 so generated
.pyc files use the correct magic number).

@youknowone youknowone merged commit 7f4d308 into RustPython:main Dec 26, 2025
13 checks passed
@youknowone youknowone deleted the pyc branch December 26, 2025 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RustPython CLI cannot run .pyc file

1 participant