Skip to content

Adds support for wheel bins#276

Merged
arcanis merged 3 commits intomainfrom
mael/python-tests
Apr 9, 2026
Merged

Adds support for wheel bins#276
arcanis merged 3 commits intomainfrom
mael/python-tests

Conversation

@arcanis
Copy link
Copy Markdown
Member

@arcanis arcanis commented Apr 8, 2026

Wheels can provide entry points which essentially are the equivalent of scripts in the JS world. Until now the ContentFlags were default-generated for Python packages, but this diff addresses that by reading the .dist-info/entry_points.txt file.


Note

Medium Risk
Adds new parsing/execution paths for PyPI wheel entry_points.txt and changes how binaries are represented/executed, which could affect script execution behavior across platforms. Risk is mitigated by strict parsing/validation and added acceptance/unit tests but still touches command execution and linker behavior.

Overview
Adds support for PyPI wheel console-script binaries by parsing .dist-info/entry_points.txt during ContentFlags extraction and storing them as a new ContentFlags::Binary::Python variant.

Updates binary handling end-to-end to support both node path bins and python entry points: Project::package_self_binaries now builds script::Binary::PythonEntryPoint, ScriptEnvironment can execute them via python -c wrapper snippets, while the nm linker continues to only symlink Node-style bins. yarn bin <name> now errors for Python entry points instead of printing a filesystem path.

Also includes small behavior fixes and test coverage: Path::strip_prefix now treats an empty prefix as a no-op, adds new Rust deps (pep-508, rust-ini) and acceptance fixtures/tests that dynamically serve wheel zips and verify entry-point binaries are discoverable/executable in venv islands.

Reviewed by Cursor Bugbot for commit 0bbc6fd. Bugbot is set up for automated code reviews on this repo. Configure here.

@arcanis
Copy link
Copy Markdown
Member Author

arcanis commented Apr 8, 2026

@cursor review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

⏱️ Benchmark Results

gatsby install-full-cold

Metric Base Head Difference
Mean 2.412s 2.409s -0.10% ✅
Median 2.412s 2.403s -0.40% ✅
Min 2.371s 2.364s
Max 2.443s 2.603s
Std Dev 0.017s 0.040s
📊 Raw benchmark data (gatsby install-full-cold)

Base times: 2.400s, 2.407s, 2.423s, 2.413s, 2.400s, 2.410s, 2.416s, 2.373s, 2.416s, 2.413s, 2.389s, 2.419s, 2.404s, 2.408s, 2.417s, 2.435s, 2.412s, 2.434s, 2.428s, 2.402s, 2.424s, 2.390s, 2.405s, 2.417s, 2.443s, 2.438s, 2.409s, 2.436s, 2.371s, 2.405s

Head times: 2.603s, 2.409s, 2.391s, 2.411s, 2.402s, 2.407s, 2.405s, 2.409s, 2.364s, 2.429s, 2.412s, 2.406s, 2.404s, 2.398s, 2.448s, 2.416s, 2.385s, 2.401s, 2.399s, 2.390s, 2.372s, 2.395s, 2.429s, 2.412s, 2.399s, 2.403s, 2.398s, 2.402s, 2.385s, 2.395s


gatsby install-cache-and-lock (warm, with lockfile)

Metric Base Head Difference
Mean 0.352s 0.356s +1.30% ⚠️
Median 0.349s 0.355s +1.77% ⚠️
Min 0.346s 0.344s
Max 0.398s 0.397s
Std Dev 0.010s 0.010s
📊 Raw benchmark data (gatsby install-cache-and-lock (warm, with lockfile))

Base times: 0.348s, 0.348s, 0.349s, 0.350s, 0.347s, 0.346s, 0.351s, 0.350s, 0.349s, 0.374s, 0.348s, 0.348s, 0.346s, 0.347s, 0.354s, 0.350s, 0.354s, 0.349s, 0.349s, 0.353s, 0.352s, 0.347s, 0.350s, 0.350s, 0.348s, 0.348s, 0.347s, 0.347s, 0.351s, 0.398s

Head times: 0.352s, 0.380s, 0.352s, 0.361s, 0.353s, 0.357s, 0.354s, 0.356s, 0.360s, 0.354s, 0.358s, 0.355s, 0.355s, 0.354s, 0.357s, 0.351s, 0.355s, 0.357s, 0.354s, 0.362s, 0.397s, 0.355s, 0.350s, 0.351s, 0.349s, 0.347s, 0.348s, 0.350s, 0.356s, 0.344s

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0bbc6fd. Configure here.


format!(
"import importlib, sys\nsys.path.insert(0, {package_path})\nmodule = importlib.import_module({module})\nentry = module\nfor part in {object}.split('.'):\n entry = getattr(entry, part)\nsys.argv[0] = {binary_name}\nsys.exit(entry())"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Multi-line Python snippet breaks Windows .cmd wrappers

Medium Severity

make_python_entry_point_snippet produces a string with literal newline characters (\n). When this snippet flows through with_package into make_executable_wrapper, the Windows .cmd generation path embeds it verbatim into a single-line batch script. Newlines inside the argument break the .cmd file into multiple lines, each interpreted as a separate batch command, completely breaking the wrapper. The Unix shell path works because POSIX single-quoted strings can span multiple lines.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0bbc6fd. Configure here.

Err(err) => return Err(err),
};
let result
= env.run_exec("python", &self.args).await?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removed python3 fallback breaks non-venv systems

Low Severity

The fallback from python to python3 when spawning fails was removed. On systems where only python3 is available (common on Debian/Ubuntu without python-is-python3), yarn python now fails instead of gracefully falling back. This regression is unrelated to the PR's wheel bins feature.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0bbc6fd. Configure here.

@arcanis arcanis merged commit 5a31f34 into main Apr 9, 2026
14 checks passed
@arcanis arcanis deleted the mael/python-tests branch April 9, 2026 11:18
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