Skip to content

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Dec 25, 2025

Summary by CodeRabbit

  • New Features

    • Added a Windows venv launcher that picks and starts the appropriate Python executable, sets up the venv environment, and shows clear errors when virtualenv metadata or executables are missing.
    • Launcher builds for GUI use on Windows to avoid showing a console window for GUI-launched venvs.
  • Bug Fixes

    • Improved executable-path handling so the runtime correctly resolves real and launcher executables and their directories.
  • Chores

    • Expanded spell-check dictionary with new launcher-related terms.
    • Updated packaging and CI manifest/configuration to centralize workspace settings and exclusions.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 25, 2025

📝 Walkthrough

Walkthrough

Adds a new Windows-focused Rust venv launcher crate that discovers a virtualenv via pyvenv.cfg, selects python/pythonw, sets PYVENV_LAUNCHER, re-execs Python, and updates VM path resolution to be launcher-aware preserving the real base executable.

Changes

Cohort / File(s) Summary
Spell Check Dictionary
.cspell.dict/cpython.txt
Added tokens: pythonw, venvlauncher, venvlaunchert, venvw, venvwlauncher, venvwlaunchert.
Venvlauncher Manifest
crates/venvlauncher/Cargo.toml
New Cargo manifest with package metadata, four binary targets (venvlauncher, venvwlauncher, venvlaunchert, venvwlaunchert), Windows-specific dependency features, and workspace lint settings.
Venvlauncher Build Script
crates/venvlauncher/build.rs
New build script that detects venvw-named binaries and adds linker args to set the Windows GUI subsystem and mainCRTStartup entry point to suppress console windows.
Venvlauncher Implementation
crates/venvlauncher/src/main.rs
New Windows-only launcher: derives target exe from its name, locates pyvenv.cfg (walks from Scripts/), parses home= (handles spaces/comments), validates Python executable under discovered home, sets __PYVENV_LAUNCHER__, and execs Python with original args; includes Windows-gated tests for read_home.
VM Path Resolution
crates/vm/src/getpath.rs
Launcher-aware path logic: introduces real_executable, sets paths.executable to the launcher when __PYVENV_LAUNCHER__ is present, preserves base_executable as the real Python, and computes exe_dir from the launcher parent; subsequent venv/prefix calculations unchanged.
CI Workflow
.github/workflows/ci.yaml
Centralized workspace exclusion flags via WORKSPACE_EXCLUDES and replaced duplicated per-command excludes with the env variable.

Sequence Diagram

sequenceDiagram
    autonumber
    actor User
    participant Launcher as venvlauncher (exe)
    participant VenvCfg as pyvenv.cfg
    participant Python as python.exe / pythonw.exe
    participant VM as RustPython VM

    User->>Launcher: start with args
    Launcher->>Launcher: inspect exe name -> choose target (pythonw/python)
    Launcher->>VenvCfg: locate pyvenv.cfg (walk from Scripts/)
    VenvCfg-->>Launcher: return home path (home=...)
    Launcher->>Launcher: validate Python exists under home
    Launcher->>Launcher: set __PYVENV_LAUNCHER__ env
    Launcher->>Python: exec target Python with original args
    Python->>VM: VM startup reads __PYVENV_LAUNCHER__
    Note over VM: VM sets sys.executable=launcher\nand sys._base_executable=real python
    VM-->>User: exit code propagated
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • coolreader18

Poem

🐰 I hop from Scripts to cfg-lined den,
I sniff the home and find the den again.
I set the mark, then nudge Python on,
Silent windows, a quiet dawn.
Hoppity launch — rust and carrot song! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'venvlauncher' is too generic and vague; it only names a component without conveying what changes or improvements are being made. Provide a more descriptive title that explains the main change, such as 'Implement Windows venv launcher with pyvenv.cfg parsing' or 'Add venvlauncher binary targets and launcher-aware path detection'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 marked this pull request as ready for review December 25, 2025 13:45
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: 7

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

123-132: Consider validating the launcher path before use.

The code reads __PYVENV_LAUNCHER__ and uses it directly without verifying that the path is valid or exists. While this mirrors CPython's behavior, consider whether RustPython should add defensive validation to prevent potential issues with malformed or non-existent launcher paths.

🔎 Potential validation approach
 let exe_dir = if let Ok(launcher) = env::var("__PYVENV_LAUNCHER__") {
+    let launcher_path = PathBuf::from(&launcher);
+    if !launcher_path.exists() {
+        // Log warning or fallback to non-launcher behavior
+    }
     paths.executable = launcher.clone();
     paths.base_executable = real_executable;
     PathBuf::from(&launcher).parent().map(PathBuf::from)
crates/venvlauncher/Cargo.toml (1)

19-19: Clarify or remove misleading comment about free-threading.

The comment mentions "Free-threaded variants (RustPython uses Py_GIL_DISABLED=true)" but the launcher implementation doesn't contain any free-threading logic. The launcher simply delegates to the Python executable, so the 't' suffix in the binary name is purely conventional (to match CPython's naming). Consider clarifying that these launchers merely forward to free-threaded Python builds rather than implementing free-threading themselves.

🔎 Suggested clarification
-# Free-threaded variants (RustPython uses Py_GIL_DISABLED=true)
+# Launcher variants for free-threaded Python builds (suffix 't' matches CPython convention)
crates/venvlauncher/src/main.rs (3)

82-86: Consider handling inline comments in configuration values.

The read_home() function doesn't handle inline comments (e.g., home = /path # this is the Python home). While this may not be common in pyvenv.cfg, it could cause issues if users add comments.

🔎 Enhanced parsing with inline comment support
         if let Some(rest) = line.strip_prefix("home") {
             let rest = rest.trim_start();
             if let Some(value) = rest.strip_prefix('=') {
-                return Ok(value.trim().to_string());
+                let value = value.trim();
+                // Strip inline comments
+                let value = value.split('#').next().unwrap_or(value).trim();
+                return Ok(value.to_string());
             }
         }

99-99: Redundant type casting in exit code handling.

The code casts Option<i32> to u32 after unwrapping. Since status.code() returns Option<i32>, the pattern could be simplified.

🔎 Simplified version
-    Ok(status.code().unwrap_or(1) as u32)
+    Ok(status.code().unwrap_or(1).max(0) as u32)

Also consider handling negative exit codes (though rare) by clamping to 0.


112-120: Test cleanup may fail on panic.

If the test panics before fs::remove_file(), the temporary file will be left behind. Consider using RAII or test fixtures for cleanup.

🔎 Use drop guard for cleanup
struct TempFile(PathBuf);
impl Drop for TempFile {
    fn drop(&mut self) {
        let _ = fs::remove_file(&self.0);
    }
}

#[test]
fn test_read_home() {
    let cfg_path = std::env::temp_dir().join("test_pyvenv.cfg");
    let _guard = TempFile(cfg_path.clone());
    
    let mut file = fs::File::create(&cfg_path).unwrap();
    // ... rest of test
    // No manual cleanup needed
}
📜 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 61ddd98 and ec93177.

⛔ Files ignored due to path filters (5)
  • Cargo.lock is excluded by !**/*.lock
  • Lib/venv/scripts/nt/venvlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvlaunchert.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlaunchert.exe is excluded by !**/*.exe, !Lib/**
📒 Files selected for processing (5)
  • .cspell.dict/cpython.txt
  • crates/venvlauncher/Cargo.toml
  • crates/venvlauncher/build.rs
  • crates/venvlauncher/src/main.rs
  • crates/vm/src/getpath.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/venvlauncher/src/main.rs
  • crates/venvlauncher/build.rs
  • crates/vm/src/getpath.rs
🧠 Learnings (4)
📚 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: Run `cargo test --workspace --exclude rustpython_wasm` to execute Rust unit tests

Applied to files:

  • crates/venvlauncher/Cargo.toml
📚 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/venvlauncher/Cargo.toml
📚 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/venvlauncher/src/main.rs
📚 Learning: 2025-06-28T16:31:03.991Z
Learnt from: arihant2math
Repo: RustPython/RustPython PR: 5790
File: build.rs:2-2
Timestamp: 2025-06-28T16:31:03.991Z
Learning: In Cargo build scripts (build.rs), the environment variable CARGO_CFG_TARGET_OS is guaranteed to exist and is automatically set by Cargo during the build process, making unwrap() safe to use when accessing this variable.

Applied to files:

  • crates/venvlauncher/build.rs
🧬 Code graph analysis (2)
crates/venvlauncher/src/main.rs (1)
crates/venvlauncher/build.rs (1)
  • main (5-18)
crates/vm/src/getpath.rs (2)
crates/vm/src/stdlib/sys.rs (1)
  • executable (176-178)
crates/vm/src/stdlib/posix.rs (1)
  • env (1149-1167)
🔇 Additional comments (3)
.cspell.dict/cpython.txt (1)

51-51: LGTM!

The dictionary entries correctly reflect the new venv launcher binary variants introduced in this PR.

Also applies to: 69-73

crates/vm/src/getpath.rs (1)

113-132: Approve the launcher path handling logic.

The implementation correctly separates launcher-based and non-launcher flows, setting sys.executable to the launcher path and sys._base_executable to the real Python executable when launched from a venv. The logic aligns with CPython's venv launcher behavior.

crates/venvlauncher/Cargo.toml (1)

11-26: LGTM: Binary target configuration is appropriate.

Using a single main.rs for all four launcher variants is the correct approach, as the launcher determines behavior based on its invocation name at runtime.

Comment on lines 1 to 14
//! RustPython venv launcher
//!
//! A lightweight launcher that reads pyvenv.cfg and delegates execution
//! to the actual Python interpreter. This mimics CPython's venvlauncher.c.
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::ExitCode;

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 | 🟠 Major

Add platform guard for Windows-only launcher.

The launcher implementation hardcodes Windows-specific behavior (.exe extensions, path assumptions) but lacks #[cfg(windows)] guards. This will cause compilation or runtime issues on non-Windows platforms.

🔎 Proposed fix

Add at the top of the file:

 //! to the actual Python interpreter. This mimics CPython's venvlauncher.c.
 
+#[cfg(not(windows))]
+compile_error!("venvlauncher is only supported on Windows");
+
 use std::env;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//! RustPython venv launcher
//!
//! A lightweight launcher that reads pyvenv.cfg and delegates execution
//! to the actual Python interpreter. This mimics CPython's venvlauncher.c.
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
//! RustPython venv launcher
//!
//! A lightweight launcher that reads pyvenv.cfg and delegates execution
//! to the actual Python interpreter. This mimics CPython's venvlauncher.c.
#[cfg(not(windows))]
compile_error!("venvlauncher is only supported on Windows");
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
🤖 Prompt for AI Agents
In crates/venvlauncher/src/main.rs lines 1-10, the file implements a
Windows-specific venv launcher but lacks platform guards; wrap the Windows-only
implementation with #[cfg(windows)] so it is only compiled on Windows, and add a
#[cfg(not(windows))] counterpart (a minimal stub main that returns a clear
build/runtime error or no-op) so non-Windows targets compile cleanly; ensure any
Windows-specific imports or code (like ".exe" handling and path assumptions) are
inside the #[cfg(windows)] section and conditionalize or provide alternatives in
the not-windows stub.


fn main() -> ExitCode {
match run() {
Ok(code) => ExitCode::from(code as u8),
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 | 🟡 Minor

Exit code truncation may lose information.

Casting u32 to u8 truncates exit codes greater than 255. While most programs use codes 0-127, this could lose information for programs that use higher exit codes.

🔎 Consider clamping instead of truncating
-        Ok(code) => ExitCode::from(code as u8),
+        Ok(code) => ExitCode::from(code.min(255) as u8),

Or document that exit codes > 255 are intentionally truncated per POSIX conventions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Ok(code) => ExitCode::from(code as u8),
Ok(code) => ExitCode::from(code.min(255) as u8),
🤖 Prompt for AI Agents
In crates/venvlauncher/src/main.rs around line 13, the Ok(code) =>
ExitCode::from(code as u8) cast truncates u32 exit codes above 255; replace the
blind cast with a clamp-to-255 approach (e.g., take min(code, 255) and convert
that to u8) so values >255 map to 255 instead of wrapping, and optionally log or
comment that higher exit codes are being clamped per POSIX convention.

Comment on lines +60 to +67
// SAFETY: We are in a single-threaded context (program entry point)
unsafe {
env::set_var("__PYVENV_LAUNCHER__", &exe_path);
}
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 | 🟠 Major

Unsafe environment variable modification has race condition risk.

The comment claims "single-threaded context" but this isn't guaranteed. If the Rust runtime or any dependency spawns threads before main() runs, or if future code changes introduce threading, this unsafe block becomes unsound. Rust's env::set_var is unsafe precisely because it's not thread-safe.

Consider using the safe alternative:

🔎 Safe alternative using Command::env
-    // 6. Set __PYVENV_LAUNCHER__ environment variable
-    // This tells Python it was launched from a venv
-    // SAFETY: We are in a single-threaded context (program entry point)
-    unsafe {
-        env::set_var("__PYVENV_LAUNCHER__", &exe_path);
-    }
-
     // 7. Launch Python with same arguments
     let args: Vec<String> = env::args().skip(1).collect();
-    launch_process(&python_path, &args)
+    launch_process(&python_path, &args, &exe_path)
 }
 
-fn launch_process(exe: &Path, args: &[String]) -> Result<u32, Box<dyn std::error::Error>> {
+fn launch_process(exe: &Path, args: &[String], launcher_path: &Path) -> Result<u32, Box<dyn std::error::Error>> {
     use std::process::Command;
 
-    let status = Command::new(exe).args(args).status()?;
+    let status = Command::new(exe)
+        .args(args)
+        .env("__PYVENV_LAUNCHER__", launcher_path)
+        .status()?;

This approach is safer and avoids the race condition entirely.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/venvlauncher/src/main.rs around lines 60-63, the code unsafely sets a
process-wide env var with an unsafe block which risks a race condition; remove
the unsafe env::set_var call and instead set the variable on the child process
invocation (use Command::env to pass "__PYVENV_LAUNCHER__" => exe_path when
spawning the Python process) so no global env mutation is needed; if a global is
truly required, ensure it is done deterministically before any threads start
(e.g., perform std::env::set_var during single-threaded early init guarded by a
Once) but prefer Command::env to avoid thread-safety issues entirely.

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: 0

♻️ Duplicate comments (2)
crates/venvlauncher/src/main.rs (2)

15-23: Exit code truncation may lose information.

Casting u32 to u8 on line 17 silently truncates exit codes > 255. Consider clamping to preserve meaningful error indication.


62-67: Prefer Command::env over unsafe env::set_var.

The unsafe block for env::set_var is risky—the single-threaded assumption isn't guaranteed by Rust's runtime. The safer approach is to set the environment variable on the child process via Command::env().

🔎 Proposed fix

Modify launch_process to accept the launcher path and set the env var there:

-fn launch_process(exe: &Path, args: &[String]) -> Result<u32, Box<dyn std::error::Error>> {
+fn launch_process(exe: &Path, args: &[String], launcher_path: &Path) -> Result<u32, Box<dyn std::error::Error>> {
     use std::process::Command;
 
-    let status = Command::new(exe).args(args).status()?;
+    let status = Command::new(exe)
+        .args(args)
+        .env("__PYVENV_LAUNCHER__", launcher_path)
+        .status()?;
 
     Ok(status.code().unwrap_or(1) as u32)
 }

Then in run():

-    // 6. Set __PYVENV_LAUNCHER__ environment variable
-    // This tells Python it was launched from a venv
-    // SAFETY: We are in a single-threaded context (program entry point)
-    unsafe {
-        env::set_var("__PYVENV_LAUNCHER__", &exe_path);
-    }
-
     // 7. Launch Python with same arguments
     let args: Vec<String> = env::args().skip(1).collect();
-    launch_process(&python_path, &args)
+    launch_process(&python_path, &args, &exe_path)
🧹 Nitpick comments (1)
crates/venvlauncher/src/main.rs (1)

106-125: Test isolation could be improved for parallel execution.

The tests use fixed temp file names (test_pyvenv.cfg, test_pyvenv2.cfg, etc.) in the shared temp directory. If tests run in parallel, they could interfere with each other. Consider using tempfile crate or unique names.

🔎 Proposed improvement using tempfile
use tempfile::NamedTempFile;

#[test]
fn test_read_home() {
    let mut file = NamedTempFile::new().unwrap();
    writeln!(file, "home = C:\\Python313").unwrap();
    writeln!(file, "include-system-site-packages = false").unwrap();
    writeln!(file, "version = 3.13.0").unwrap();

    let home = read_home(file.path()).unwrap();
    assert_eq!(home, "C:\\Python313");
    // File is automatically deleted when `file` goes out of scope
}

This requires adding tempfile as a dev-dependency in Cargo.toml.

📜 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 ec93177 and 5f84ae3.

⛔ Files ignored due to path filters (5)
  • Cargo.lock is excluded by !**/*.lock
  • Lib/venv/scripts/nt/venvlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvlaunchert.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlaunchert.exe is excluded by !**/*.exe, !Lib/**
📒 Files selected for processing (5)
  • .cspell.dict/cpython.txt
  • crates/venvlauncher/Cargo.toml
  • crates/venvlauncher/build.rs
  • crates/venvlauncher/src/main.rs
  • crates/vm/src/getpath.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/vm/src/getpath.rs
  • crates/venvlauncher/Cargo.toml
  • crates/venvlauncher/build.rs
  • .cspell.dict/cpython.txt
🧰 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/venvlauncher/src/main.rs
🧠 Learnings (4)
📚 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/venvlauncher/src/main.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/venvlauncher/src/main.rs
📚 Learning: 2025-06-28T16:31:03.991Z
Learnt from: arihant2math
Repo: RustPython/RustPython PR: 5790
File: build.rs:2-2
Timestamp: 2025-06-28T16:31:03.991Z
Learning: In Cargo build scripts (build.rs), the environment variable CARGO_CFG_TARGET_OS is guaranteed to exist and is automatically set by Cargo during the build process, making unwrap() safe to use when accessing this variable.

Applied to files:

  • crates/venvlauncher/src/main.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 Lib/test/**/*.py : When modifying test files in `Lib/test/`, use `unittest.skip("TODO: RustPython <reason>")` or `unittest.expectedFailure` with `# TODO: RUSTPYTHON <reason>` comment to mark unsupported features

Applied to files:

  • crates/venvlauncher/src/main.rs
⏰ 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 snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Check Rust code with clippy
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Check the WASM package and demo
  • GitHub Check: Run snippets and cpython tests on wasm-wasi
🔇 Additional comments (6)
crates/venvlauncher/src/main.rs (6)

1-8: Platform guard properly implemented.

The compile_error! macro ensures this crate only compiles on Windows, addressing the Windows-only nature of this launcher. Documentation is clear.


10-13: LGTM!

Clean and minimal imports, all are used in the implementation.


25-41: LGTM!

The launcher name detection logic correctly differentiates between GUI (pythonw.exe) and console (python.exe) variants. Path discovery from Scripts/ to venv root follows the expected Windows venv layout.


74-95: LGTM!

The read_home parser correctly handles whitespace variations (home = value vs home=value), skips comments and empty lines, and uses idiomatic Rust string processing. This aligns with CPython's pyvenv.cfg format expectations.


97-104: LGTM!

Simple and correct process delegation. The unwrap_or(1) fallback for abnormal termination is reasonable.


127-155: LGTM!

Good test coverage for parsing variations. The #[cfg(all(test, windows))] guard ensures these Windows-path-dependent tests only run on Windows.

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: 2

📜 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 5f84ae3 and b0360a4.

⛔ Files ignored due to path filters (5)
  • Cargo.lock is excluded by !**/*.lock
  • Lib/venv/scripts/nt/venvlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvlaunchert.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlauncher.exe is excluded by !**/*.exe, !Lib/**
  • Lib/venv/scripts/nt/venvwlaunchert.exe is excluded by !**/*.exe, !Lib/**
📒 Files selected for processing (6)
  • .cspell.dict/cpython.txt
  • .github/workflows/ci.yaml
  • crates/venvlauncher/Cargo.toml
  • crates/venvlauncher/build.rs
  • crates/venvlauncher/src/main.rs
  • crates/vm/src/getpath.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/venvlauncher/build.rs
  • crates/venvlauncher/src/main.rs
  • crates/vm/src/getpath.rs
  • .cspell.dict/cpython.txt
🧰 Additional context used
🧠 Learnings (6)
📚 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: Run `cargo test --workspace --exclude rustpython_wasm` to execute Rust unit tests

Applied to files:

  • .github/workflows/ci.yaml
  • crates/venvlauncher/Cargo.toml
📚 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 : Always run clippy to lint Rust code (`cargo clippy`) before completing tasks and fix any warnings or lints introduced by changes

Applied to files:

  • .github/workflows/ci.yaml
📚 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:

  • .github/workflows/ci.yaml
📚 Learning: 2025-09-28T22:22:55.921Z
Learnt from: reactive-firewall
Repo: RustPython/RustPython PR: 6176
File: .github/workflows/Check_Tests.yml:133-141
Timestamp: 2025-09-28T22:22:55.921Z
Learning: In the RustPython project's CI-5974-Test-RustPython-Integration action, the override-rustpython-path input is marked as required but has runtime fallback logic that defaults to RUSTPYTHONPATH environment variable or "Lib" if neither is provided, making explicit specification unnecessary in most cases.

Applied to files:

  • .github/workflows/ci.yaml
📚 Learning: 2025-06-28T16:31:03.991Z
Learnt from: arihant2math
Repo: RustPython/RustPython PR: 5790
File: build.rs:2-2
Timestamp: 2025-06-28T16:31:03.991Z
Learning: In Cargo build scripts (build.rs), the environment variable CARGO_CFG_TARGET_OS is guaranteed to exist and is automatically set by Cargo during the build process, making unwrap() safe to use when accessing this variable.

Applied to files:

  • .github/workflows/ci.yaml
📚 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/venvlauncher/Cargo.toml
⏰ 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). (10)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Run snippets and cpython tests on wasm-wasi
  • GitHub Check: Check Rust code with clippy
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Check the WASM package and demo
🔇 Additional comments (2)
crates/venvlauncher/Cargo.toml (1)

28-36: LGTM! Windows dependencies are properly scoped.

The Windows-specific dependencies are correctly limited to cfg(windows) targets, and the Win32 feature selection looks appropriate for a venv launcher that needs process creation, environment manipulation, and file system access.

.github/workflows/ci.yaml (1)

143-149: Verify Windows launcher builds and tests execute on Windows CI.

Ensure that once the exclusion logic is fixed, the Windows venv launcher is properly compiled and tested on the windows-latest runner. The launcher should undergo clippy checks and unit tests specific to Windows.

After addressing the exclusion issue, run the following to confirm the launcher is being tested:

#!/bin/bash
# Check if there are any Windows-specific tests for the venv launcher
fd -e rs . crates/venvlauncher --exec rg -l "test|Test" {}

Comment on lines +21 to +25
# Crates excluded from workspace builds:
# - rustpython_wasm: requires wasm target
# - rustpython-compiler-source: deprecated
# - rustpython-venvlauncher: Windows-only
WORKSPACE_EXCLUDES: --exclude rustpython_wasm --exclude rustpython-compiler-source --exclude rustpython-venvlauncher
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 | 🟠 Major

Windows-only crate is excluded on all platforms, including Windows.

The WORKSPACE_EXCLUDES variable includes rustpython-venvlauncher with a "Windows-only" comment, but this exclusion applies to all CI runs, including Windows builds. This means the Windows venv launcher will never be compiled or tested in CI, even on windows-latest runners.

Consider making the exclusion conditional based on the runner OS. For example, you could:

  • Define separate environment variables for Windows vs. non-Windows exclusions
  • Use conditional expressions in the cargo commands to exclude the crate only on non-Windows platforms
🔎 Example approach using conditional exclusion

Define platform-specific exclusion variables:

  # Crates excluded from workspace builds:
  # - rustpython_wasm: requires wasm target
  # - rustpython-compiler-source: deprecated
-  # - rustpython-venvlauncher: Windows-only
-  WORKSPACE_EXCLUDES: --exclude rustpython_wasm --exclude rustpython-compiler-source --exclude rustpython-venvlauncher
+  WORKSPACE_EXCLUDES_COMMON: --exclude rustpython_wasm --exclude rustpython-compiler-source
+  # rustpython-venvlauncher: Windows-only, exclude on non-Windows
+  WORKSPACE_EXCLUDES_NON_WINDOWS: --exclude rustpython-venvlauncher

Then update the clippy and test commands to use conditional exclusions:

      - name: run clippy
-        run: cargo clippy ${{ env.CARGO_ARGS }} --workspace --all-targets ${{ env.WORKSPACE_EXCLUDES }} -- -Dwarnings
+        run: cargo clippy ${{ env.CARGO_ARGS }} --workspace --all-targets ${{ env.WORKSPACE_EXCLUDES_COMMON }} ${{ runner.os != 'Windows' && env.WORKSPACE_EXCLUDES_NON_WINDOWS || '' }} -- -Dwarnings

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +11 to +26
[[bin]]
name = "venvlauncher"
path = "src/main.rs"

[[bin]]
name = "venvwlauncher"
path = "src/main.rs"

# Free-threaded variants (RustPython uses Py_GIL_DISABLED=true)
[[bin]]
name = "venvlaunchert"
path = "src/main.rs"

[[bin]]
name = "venvwlaunchert"
path = "src/main.rs"
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

🏁 Script executed:

# First, check if the file exists and its size
stat crates/venvlauncher/src/main.rs 2>/dev/null || echo "File not found, checking directory structure..."
ls -la crates/venvlauncher/src/ 2>/dev/null || find . -name "main.rs" -path "*/venvlauncher/*" 2>/dev/null

Repository: RustPython/RustPython

Length of output: 280


🏁 Script executed:

cat -n crates/venvlauncher/src/main.rs

Repository: RustPython/RustPython

Length of output: 6052


The main.rs implementation is incomplete—it detects console vs GUI subsystem but does not handle free-threaded mode variants.

The code at lines 37-41 correctly distinguishes between console (python.exe) and GUI (pythonw.exe) variants by checking if the binary name contains "pythonw" or "venvw". However, it does not detect the "t" suffix in venvlaunchert and venvwlaunchert variants that indicate free-threaded mode.

The current implementation will treat all four binary variants identically:

  • venvlauncher → python.exe ✓
  • venvwlauncher → pythonw.exe ✓
  • venvlaunchert → python.exe (should be free-threaded)
  • venvwlaunchert → pythonw.exe (should be free-threaded)

Add logic to detect the "t" suffix and select the appropriate free-threaded Python executable (e.g., pythont.exe / pythonwt.exe) or set an environment variable like PYTHONFREETHREADING=1 when the binary name contains the "t" suffix.

@youknowone youknowone merged commit 40acd55 into RustPython:main Dec 25, 2025
13 checks passed
@youknowone youknowone deleted the venvlauncher branch December 25, 2025 16:30
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.

1 participant