rules_python icon indicating copy to clipboard operation
rules_python copied to clipboard

`ruff` package does not have an entrypoint generated for it

Open lopopolo opened this issue 2 years ago β€’ 5 comments

🐞 bug report

Affected Rule

The issue is caused by the rule:
load("@py_deps_tools_ruff//:requirements.bzl", "entry_point")

Is this a regression?

I don't know.

Description

A clear and concise description of the problem...

rules_python does not generate an entry point for the ruff package.

πŸ”¬ Minimal Reproduction

https://github.com/lopopolo/ruff_entry_point_reproducer

πŸ”₯ Exception or Error

$ bazel run //:ruff
ERROR: /Users/lopopolo/dev/repos/ruff_entry_point_reproducer/tools/ruff/BUILD.bazel:18:6: no such target '@py_deps_tools_ruff_ruff//:rules_python_wheel_entry_point_ruff': target 'rules_python_wheel_entry_point_ruff' not declared in package '' defined by /private/var/tmp/_bazel_lopopolo/698235a6d86310c30fae5a78f4b7ba7c/external/py_deps_tools_ruff_ruff/BUILD.bazel (Tip: use `query "@py_deps_tools_ruff_ruff//:*"` to see all the targets in that package) and referenced by '//tools/ruff:entry'
ERROR: Analysis of target '//:ruff' failed; build aborted:
INFO: Elapsed time: 7.256s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (5 packages loaded, 48 targets configured)
    Fetching repository @local_config_xcode; Fetching the default Xcode version
ERROR: Build failed. Not running target

the results of the suggested query:

$ bazel query "@py_deps_tools_ruff_ruff//:*"
@py_deps_tools_ruff_ruff//:BUILD.bazel
@py_deps_tools_ruff_ruff//:data
@py_deps_tools_ruff_ruff//:dist_info
@py_deps_tools_ruff_ruff//:pkg
@py_deps_tools_ruff_ruff//:ruff-0.0.228-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
@py_deps_tools_ruff_ruff//:site-packages/__init__.py
@py_deps_tools_ruff_ruff//:site-packages/ruff-0.0.228.dist-info/INSTALLER
@py_deps_tools_ruff_ruff//:site-packages/ruff-0.0.228.dist-info/METADATA
@py_deps_tools_ruff_ruff//:site-packages/ruff-0.0.228.dist-info/RECORD
@py_deps_tools_ruff_ruff//:site-packages/ruff-0.0.228.dist-info/WHEEL
@py_deps_tools_ruff_ruff//:site-packages/ruff-0.0.228.dist-info/license_files/LICENSE
@py_deps_tools_ruff_ruff//:site-packages/ruff/__init__.py
@py_deps_tools_ruff_ruff//:site-packages/ruff/__main__.py
@py_deps_tools_ruff_ruff//:whl
Loading: 0 packages loaded

There is no entrypoint in the target list.

🌍 Your Environment

Operating System:

  
$ sw_vers
ProductName:            macOS
ProductVersion:         13.1
BuildVersion:           22C65
  

Output of bazel version:

  
$ bazel version
Bazelisk version: development
Build label: 6.0.0
Build target: bazel-out/darwin-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: Mon Dec 19 16:07:42 2022 (1671466062)
Build timestamp: 1671466062
Build timestamp as int: 1671466062
  

Rules_python version:

  
http_archive(
    name = "rules_python",
    sha256 = "497ca47374f48c8b067d786b512ac10a276211810f4a580178ee9b9ad139323a",
    strip_prefix = "rules_python-0.16.1",
    url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.16.1.tar.gz",
)
  

Anything else relevant?

ruff is almost entirely written in Rust. The python package only contains an empty __init__.py and a __main__.py which invokes the embedded ruff binary: https://github.com/charliermarsh/ruff/tree/v0.0.228/python/ruff

lopopolo avatar Jan 20 '23 23:01 lopopolo

Just encountered this as well. I assume this require fixup in the ruff packaging configuration, but it raises an interesting question: is there any mechanism in rules_python to allow overriding the generated BUILD.bazel or applying repo patches? Mostly asking if there's any solution to make a Python dependency Bazel-compatible without requiring an upstream patch and release.

ClintLiddick avatar Jan 23 '23 16:01 ClintLiddick

I ran into a similar problem with py-spy as well and I think this issue is related to #801. From what I can tell, maturin, the build system that these rust-based projects use, seems to generate a script instead of a console script. Console scripts have to be python code, but scripts can be arbitrary executables. I can't speak for the maintainers, but I imagine generating entrypoints for scripts would require a fair bit more complexity than what was needed to generate entrypoints for console scripts.

ArmaanT avatar Jan 24 '23 16:01 ArmaanT

To add some context from the maturin side: maturin doesn't use entrypoints (such as console_scripts would be), but puts the binary (e.g. py-spy or ruff) into the {distribution}-{version}.data/scripts folder. A wheel installer will move those to .venv/bin (or Scripts on windows) and activating the venv will add this directory to PATH. From my perspective it would make most sense to just use that file from the scripts directory instead of trying to find an entrypoint.

konstin avatar Jul 12 '23 19:07 konstin

Just encountered this as well. I assume this require fixup in the ruff packaging configuration, but it raises an interesting question: is there any mechanism in rules_python to allow overriding the generated BUILD.bazel or applying repo patches? Mostly asking if there's any solution to make a Python dependency Bazel-compatible without requiring an upstream patch and release.

About this, for anyone else who finds themselves here, the answer is sorta yes - with one of the approaches from here depending on rules_python version, and then something like

package_annotation(
    additive_build_content="""
filegroup(
    name = "ruff_binary",
    srcs = ["bin/ruff"],
)
""",
    data = [":ruff_binary"],
    patches = ["//path/to/patch:ruff__bin_path.patch"],
    patch_args = ["-p1"],
)

and the patch being something like

diff --git a/ruff/__main__.py b/ruff/__main__.py
index 44384bc..192266e 100644
--- a/ruff/__main__.py
+++ b/ruff/__main__.py
@@ -7,27 +7,11 @@ from pathlib import Path

 def find_ruff_bin() -> Path:
     """Return the ruff binary path."""
+    path = Path(__file__).parent.parent.parent / "bin/ruff"
+    if not path.is_file():
+        raise FileNotFoundError(path)

-    ruff_exe = "ruff" + sysconfig.get_config_var("EXE")
-
-    path = Path(sysconfig.get_path("scripts")) / ruff_exe
-    if path.is_file():
-        return path
-
-    if sys.version_info >= (3, 10):
-        user_scheme = sysconfig.get_preferred_scheme("user")
-    elif os.name == "nt":
-        user_scheme = "nt_user"
-    elif sys.platform == "darwin" and sys._framework:
-        user_scheme = "osx_framework_user"
-    else:
-        user_scheme = "posix_user"
-
-    path = Path(sysconfig.get_path("scripts", scheme=user_scheme)) / ruff_exe
-    if path.is_file():
-        return path
-
-    raise FileNotFoundError(path)
+    return path


 if __name__ == "__main__":

aaron-skydio avatar Dec 18 '23 23:12 aaron-skydio

I think this might be fixed by #1730

aignas avatar Apr 17 '24 08:04 aignas