Skip to content

add --compile-only flag for syntax/compile validation#6943

Closed
Jawfish wants to merge 7 commits intoRustPython:mainfrom
Jawfish:add-compile-only-flag
Closed

add --compile-only flag for syntax/compile validation#6943
Jawfish wants to merge 7 commits intoRustPython:mainfrom
Jawfish:add-compile-only-flag

Conversation

@Jawfish
Copy link

@Jawfish Jawfish commented Feb 1, 2026

Adds a --compile-only CLI flag that compiles Python files without executing them.

Use case: Catch compile-phase errors (syntax errors, duplicate parameters, break outside loop, etc.) without the overhead of execution. This is similar to python -m py_compile but leverages RustPython.

Usage:

rustpython --compile-only file1.py file2.py ...

Exits 0 on success, 1 if any file fails to compile. Errors are printed to stderr.

rustpython -m py_compile works, but there are differences:

Aspect -m py_compile --compile-only
Creates .pyc files Yes No
Performance (100 files) ~55ms ~19ms
Module import overhead Yes No
Discoverable in --help No Yes

Implementation:

  • New RunMode::CompileOnly(Vec<String>) variant
  • --compile-only flag terminates option parsing (remaining args are files)
  • Uses existing vm.compile() with Mode::Exec
  • Includes unit tests for valid code, syntax errors, duplicate params, and break outside loop

Note: also documents existing --install-pip [ensurepip|get-pip] flag which was missing from help text.

Summary by CodeRabbit

  • New Features

    • Added a --compile-only CLI option to validate files' compilation without running them; reports per-file diagnostics and exits with a non-zero code on any failure (also exits non-zero if no files provided).
  • Tests

    • Added comprehensive tests covering successful compilation, syntax errors, and related validation scenarios.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Adds a compile-only execution mode: a new RunMode::CompileOnly(Vec<String>), a --compile-only CLI flag, argument parsing to produce that mode, and runtime handling that compiles listed files without executing them, returning exit code 1 on any compilation/read error.

Changes

Cohort / File(s) Summary
Runtime / CLI
src/lib.rs, src/settings.rs
Added RunMode::CompileOnly(Vec<String>); CLI flag --compile-only emits that mode; runtime run_rustpython now handles CompileOnly by reading and attempting to compile each file, printing per-file errors and returning exit code 1 on any failure; sys.path initialization treats CompileOnly like Script/InstallPip.
Tests
src/lib.rs (tests module), tests/*
Added unit tests covering successful compilation and failure cases (syntax error, duplicate parameters, invalid control flow), and test coverage for compile-only CLI behavior.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant CLI
participant Runner
participant FS as Filesystem
participant VM
CLI->>Runner: parse args -> RunMode::CompileOnly(files)
Runner->>FS: read(file1)
FS-->>Runner: content or read error
Runner->>VM: compile_with_opts(content)
VM-->>Runner: success or compile error
alt compile error
Runner->>CLI: print stderr, mark failure
else success
Runner->>CLI: continue to next file
end
Note over Runner,CLI: final result -> exit code 0 (all success) or 1 (any failure)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • pythonrun #6643: Refactors/exposes compile/run helpers used by this PR to perform file compilation.

Poem

🐰 I nibble bytes and hop on keys,
I check the code with careful ease.
No running now—just tidy sights,
I catch the bugs in silent nights.
Compile-only—hooray, no fright!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a --compile-only flag for syntax validation. It is specific, directly related to the core feature, and accurately represents the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/settings.rs (1)

37-56: ⚠️ Potential issue | 🟠 Major

--compile-only doesn't actually terminate option parsing, contradicting its documented behavior.

The flag only sets a boolean at line 156, allowing lexopt to continue parsing subsequent args as options. This breaks the documented "terminates option list" behavior specified at line 105 of USAGE_STRING (e.g., --compile-only -V file.py will trigger version() instead of treating -V as a filename). The fix should return early and collect remaining raw args as files, matching the pattern used by -c and -m flags. This also eliminates the unnecessary compile_only field and related conditional branches.

🤖 Fix all issues with AI agents
In `@src/lib.rs`:
- Around line 292-295: The current --compile-only path returns Ok(()) when the
files list is empty; change it to signal a usage error so the process exits
non‑zero: in the block that checks files.is_empty() (the --compile-only
handling), replace the Ok(()) return with a non‑zero failure return (e.g.,
return an Err or otherwise cause process exit code 1) and keep the eprintln!
message; update the surrounding function’s error/return handling (the main or
run function that contains files.is_empty()) so the non‑zero exit propagates to
the process.

@Jawfish Jawfish changed the title add --compile-only flag for syntax/compile validation add --compile-only flag for syntax/compile validation Feb 1, 2026
@youknowone
Copy link
Member

@Jawfish Could you tell me more about the motivation of this optimization? Usually compile step is very fast, as you described, only 55ms. Are you compiling massive amount of files before running?

@Jawfish
Copy link
Author

Jawfish commented Feb 1, 2026

@Jawfish Could you tell me more about the motivation of this optimization? Usually compile step is very fast, as you described, only 55ms. Are you compiling massive amount of files before running?

This isn't meant as a micro-optimization of compile time (55ms is totally fine). The motivation is to have a supported, side-effect-free "compile check" mode for CI/pre-commit: validate that a set of .py files reaches the compiler successfully. This brings CPython's python -m py_compile/compileall workflow as a first-class CLI flag without writing .pyc files. This flow is useful because linters and parsers are not a perfect substitute for "run the compiler". For example, Ruff doesn't catch this:

[i for i in (j := [1, 2, 3])]
# SyntaxError: assignment expression cannot be used in a comprehension iterable expression

This is a compile-phase semantic check that occurs after parsing succeeds. Linters cover many cases with lint rules, but not all compile-phase validations.

@fanninpm
Copy link
Contributor

fanninpm commented Feb 2, 2026

This brings CPython's python -m py_compile/compileall workflow as a first-class CLI flag without writing .pyc files.

Have you tried to add this to CPython?

@youknowone
Copy link
Member

Could you share more what python -m py_compile cannot support but --compile-only can support?

If -m py_compile is enough, rustpython -m py_compile must also fit. (otherwise it is a bug)

@Jawfish
Copy link
Author

Jawfish commented Feb 2, 2026

Could you share more what python -m py_compile cannot support but --compile-only can support?

If -m py_compile is enough, rustpython -m py_compile must also fit. (otherwise it is a bug)

@youknowone to be clearer: the motivation is specifically to guarantee compilation with no .pyc file side effects, which rustpython -m py_compile produces.

Have you tried to add this to CPython?

@fanninpm Per the project goals: "Full Python-3 environment entirely in Rust (not CPython bindings)". A --compile-only flag would provide compile validation as a first-class RustPython feature, without side effects.

@youknowone
Copy link
Member

youknowone commented Feb 2, 2026

Edit: I withdraw this comment


Thank you for your patient. So what you need is compiling python code and see the error output, but not actually creating .pyc, right?

Because rustpython binary is a python binary, I don't think adding a niche subcommand there is ideal. Here are my 2 suggestions, which are independent each other.

  1. Open an issue on CPython to ask if they are open to add python -m py_compile --check-only or somewhat doing that. Probably the needs not to create .pyc but only check compiling could be overlooked; otherwise they will help to find why it was rejected before.
  2. Rather than adding the option to rustpython binary, create a compiler binary under crates/compiler. The new binary may be named like rustpython-compiler.

@youknowone
Copy link
Member

@Jawfish If you don't care about performance, actually python -m dis also compile it

@Jawfish Jawfish closed this Feb 5, 2026
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.

3 participants