From b499d67f3e872ba0ccefa3fea906632012500af2 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 5 May 2025 11:43:26 +0200 Subject: [PATCH] Configure Python build system (#8) Co-authored-by: Zanie Blue --- CONTRIBUTING.md | 8 ++++ LICENSE-MIT | 21 +++++++++++ pyproject.toml | 23 +++++++++--- python/ty/__init__.py | 0 python/ty/__main__.py | 86 +++++++++++++++++++++++++++++++++++++++++++ ruff | 2 +- src/ty/__init__.py | 2 - 7 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 LICENSE-MIT create mode 100644 python/ty/__init__.py create mode 100644 python/ty/__main__.py delete mode 100644 src/ty/__init__.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7da4d66..ba3da16 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,3 +26,11 @@ Then, ensure the submodule is initialized: ``` git submodule update --init --recursive ``` + +## Building the Python package + +The Python package can be built with any Python build frontend (Maturin is used as a backend), e.g.: + +``` +uv build +``` diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..0148351 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Astral Software Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pyproject.toml b/pyproject.toml index 911226d..fc9bfef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,26 @@ [project] name = "ty" version = "0.0.0a1" -description = "This project is coming soon." +description = "An extremely fast Python type checker, written in Rust." readme = "README.md" authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] requires-python = ">=3.8" dependencies = [] -[project.scripts] -ty = "ty:main" - [build-system] -requires = ["uv_build>=0.7.1,<0.8"] -build-backend = "uv_build" +requires = ["maturin>=1.0,<2.0"] +build-backend = "maturin" + +[tool.maturin] +bindings = "bin" +manifest-path = "ruff/crates/ty/Cargo.toml" +module-name = "ty" +python-source = "python" +strip = true +include = [ + { path = "ruff/rust-toolchain.toml", format = [ + "sdist", + "wheel", + ] }, + { path = "LICENSE-MIT", format = "sdist" }, +] diff --git a/python/ty/__init__.py b/python/ty/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python/ty/__main__.py b/python/ty/__main__.py new file mode 100644 index 0000000..47c44e3 --- /dev/null +++ b/python/ty/__main__.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import os +import sys +import sysconfig + + +def find_ty_bin() -> str: + """Return the ty binary path.""" + + ty_exe = "ty" + sysconfig.get_config_var("EXE") + + scripts_path = os.path.join(sysconfig.get_path("scripts"), ty_exe) + if os.path.isfile(scripts_path): + return scripts_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" + + user_path = os.path.join(sysconfig.get_path("scripts", scheme=user_scheme), ty_exe) + if os.path.isfile(user_path): + return user_path + + # Search in `bin` adjacent to package root (as created by `pip install --target`). + pkg_root = os.path.dirname(os.path.dirname(__file__)) + target_path = os.path.join(pkg_root, "bin", ty_exe) + if os.path.isfile(target_path): + return target_path + + # Search for pip-specific build environments. + # + # Expect to find ty in /pip-build-env-/overlay/bin/ty + # Expect to find a "normal" folder at /pip-build-env-/normal + # + # See: https://github.com/pypa/pip/blob/102d8187a1f5a4cd5de7a549fd8a9af34e89a54f/src/pip/_internal/build_env.py#L87 + paths = os.environ.get("PATH", "").split(os.pathsep) + if len(paths) >= 2: + + def get_last_three_path_parts(path: str) -> list[str]: + """Return a list of up to the last three parts of a path.""" + parts = [] + + while len(parts) < 3: + head, tail = os.path.split(path) + if tail or head != path: + parts.append(tail) + path = head + else: + parts.append(path) + break + + return parts + + maybe_overlay = get_last_three_path_parts(paths[0]) + maybe_normal = get_last_three_path_parts(paths[1]) + if ( + len(maybe_normal) >= 3 + and maybe_normal[-1].startswith("pip-build-env-") + and maybe_normal[-2] == "normal" + and len(maybe_overlay) >= 3 + and maybe_overlay[-1].startswith("pip-build-env-") + and maybe_overlay[-2] == "overlay" + ): + # The overlay must contain the ty binary. + candidate = os.path.join(paths[0], ty_exe) + if os.path.isfile(candidate): + return candidate + + raise FileNotFoundError(scripts_path) + + +if __name__ == "__main__": + ty = os.fsdecode(find_ty_bin()) + if sys.platform == "win32": + import subprocess + + completed_process = subprocess.run([ty, *sys.argv[1:]]) + sys.exit(completed_process.returncode) + else: + os.execvp(ty, [ty, *sys.argv[1:]]) diff --git a/ruff b/ruff index 675a5af..2485afe 160000 --- a/ruff +++ b/ruff @@ -1 +1 @@ -Subproject commit 675a5af89af5b786a6c99870fe0cf7f841454271 +Subproject commit 2485afe640a3d6c294244c6e11bd7bb2398d3593 diff --git a/src/ty/__init__.py b/src/ty/__init__.py deleted file mode 100644 index 25be6da..0000000 --- a/src/ty/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -def main() -> None: - print("Hello from ty!")