From 339dddc4581f00ee4809556ce2211b3221fb54de Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep Date: Fri, 15 May 2026 14:34:25 +1000 Subject: [PATCH 1/3] feat: added inference for Python wheels that bundle Rust binaries. Signed-off-by: Abhinav Pradeep --- .../common_spec/base_spec.py | 20 +- .../common_spec/pypi_spec.py | 360 +++++++++++++++--- .../dockerfile/pypi_dockerfile_output.py | 6 +- .../schemas/macaron_buildspec_schema.json | 13 +- .../common_spec/test_pypi_spec.py | 3 + .../dockerfile/test_pypi_dockerfile_output.py | 22 +- .../expected_default.buildspec | 15 +- .../expected_default.buildspec | 16 +- .../expected_default.buildspec | 10 +- .../pypi_toga/expected_default.buildspec | 22 +- .../expected_default.buildspec | 25 +- 11 files changed, 438 insertions(+), 74 deletions(-) diff --git a/src/macaron/build_spec_generator/common_spec/base_spec.py b/src/macaron/build_spec_generator/common_spec/base_spec.py index 4d99025c5..b2bb23778 100644 --- a/src/macaron/build_spec_generator/common_spec/base_spec.py +++ b/src/macaron/build_spec_generator/common_spec/base_spec.py @@ -9,6 +9,24 @@ from packageurl import PackageURL +class SpecBuildRequirementDict(TypedDict, total=False): + """ + Initialize build requirement section of the build specification. + + It contains information about tools/packages that must be available before + running a build command. + """ + + #: Build requirement name, e.g., "maturin", "rust", "rustup", "pkg-config". + name: Required[str] + + #: Build requirement version or version constraint, e.g., "1.75.0", ">=1.4,<2". + version: NotRequired[str] + + #: Build requirement installer, e.g., "pip", "rustup", "system", or "bootstrap". + installer: Required[str] + + class SpecBuildCommandDict(TypedDict, total=False): """ Initialize build command section of the build specification. @@ -100,7 +118,7 @@ class BaseBuildSpecDict(TypedDict, total=False): entry_point: NotRequired[str | None] #: The build_requires is the required packages that need to be available in the build environment. - build_requires: NotRequired[dict[str, str]] + build_requires: NotRequired[list[SpecBuildRequirementDict]] #: A "back end" is tool that a "front end" (such as pip/build) would call to #: package the source distribution into the wheel format. build_backends would diff --git a/src/macaron/build_spec_generator/common_spec/pypi_spec.py b/src/macaron/build_spec_generator/common_spec/pypi_spec.py index 6b46a237e..49782672b 100644 --- a/src/macaron/build_spec_generator/common_spec/pypi_spec.py +++ b/src/macaron/build_spec_generator/common_spec/pypi_spec.py @@ -14,7 +14,12 @@ from packaging.specifiers import InvalidSpecifier from packaging.utils import InvalidWheelFilename, parse_wheel_filename -from macaron.build_spec_generator.common_spec.base_spec import BaseBuildSpec, BaseBuildSpecDict, SpecBuildCommandDict +from macaron.build_spec_generator.common_spec.base_spec import ( + BaseBuildSpec, + BaseBuildSpecDict, + SpecBuildCommandDict, + SpecBuildRequirementDict, +) from macaron.config.defaults import defaults from macaron.errors import SourceCodeError, WheelTagError from macaron.json_tools import json_extract @@ -58,13 +63,14 @@ def set_default_build_commands( build_cmd_spec["command"] = "poetry build".split() case "uv": build_cmd_spec["command"] = "uv build".split() - case "flit": # We might also want to deal with existence flit.ini, we can do so via # "python -m flit.tomlify" build_cmd_spec["command"] = "flit build".split() case "hatch": build_cmd_spec["command"] = "hatch build".split() + case "maturin": + build_cmd_spec["command"] = "maturin build --release".split() case _: logger.debug( "There is no default build command available for the build tools %s.", @@ -95,11 +101,10 @@ def resolve_fields(self, purl: PackageURL) -> None: upstream_artifacts: dict[str, list[str]] = {} pypi_package_json = pypi_registry.find_or_create_pypi_asset(purl.name, purl.version, registry_info) build_backends_set: set[str] = set() - parsed_build_requires: dict[str, str] = {} - sdist_build_requires: dict[str, str] = {} + parsed_build_requires: dict[str, SpecBuildRequirementDict] = {} + sdist_build_requires: dict[str, SpecBuildRequirementDict] = {} python_version_set: set[str] = set() wheel_name_python_version_set: set[str] = set() - wheel_name_platforms: set[str] = set() dependency_python_version_set: set[str] = set() # Precautionary fallback to default version chronologically_likeliest_version: str = defaults.get("heuristic.pypi", "default_setuptools") @@ -134,15 +139,21 @@ def resolve_fields(self, purl: PackageURL) -> None: wheel_contents, metadata_contents = self.read_directory(pypi_package_json.wheel_path, purl) generator, version = self.read_generator_line(wheel_contents) if generator != "" and version != "": - parsed_build_requires[generator] = "==" + version.replace(" ", "") + self.add_to_build_requires(parsed_build_requires, generator, "pip", "==" + version.replace(" ", "")) # Apply METADATA heuristics to determine setuptools version. elif "License-File" in metadata_contents: - parsed_build_requires["setuptools"] = "==" + defaults.get( - "heuristic.pypi", "setuptools_version_emitting_license" + self.add_to_build_requires( + parsed_build_requires, + "setuptools", + "pip", + "==" + defaults.get("heuristic.pypi", "setuptools_version_emitting_license"), ) elif "Platform: UNKNOWN" in metadata_contents: - parsed_build_requires["setuptools"] = "==" + defaults.get( - "heuristic.pypi", "setuptools_version_emitting_platform_unknown" + self.add_to_build_requires( + parsed_build_requires, + "setuptools", + "pip", + "==" + defaults.get("heuristic.pypi", "setuptools_version_emitting_platform_unknown"), ) chronologically_likeliest_version = ( pypi_package_json.get_chronologically_suitable_setuptools_version() @@ -153,7 +164,6 @@ def resolve_fields(self, purl: PackageURL) -> None: _, _, _, tags = parse_wheel_filename(pypi_package_json.wheel_filename) for tag in tags: wheel_name_python_version_set.add(tag.interpreter) - wheel_name_platforms.add(tag.platform) if wheel_name_python_version_set: logger.debug( "From wheel name inferred Python constraints: %s", wheel_name_python_version_set @@ -166,13 +176,30 @@ def resolve_fields(self, purl: PackageURL) -> None: except SourceCodeError: logger.debug("Could not download wheel matching this PURL") - logger.debug("From .dist_info:") - logger.debug(parsed_build_requires) + logger.debug("From .dist_info build-requires: %s", parsed_build_requires) try: with pypi_package_json.sourcecode(): upstream_artifacts["sdist"] = [pypi_package_json.sdist_url] logger.debug("sdist url at %s", upstream_artifacts["sdist"]) + + has_maturin = False + cargo_toml_exists = pypi_package_json.file_exists("Cargo.toml") + cargo_toml_content: dict[str, Any] = {} + cargo_lock_content: dict[str, Any] = {} + + try: + cargo_text_bytes = pypi_package_json.get_sourcecode_file_contents("Cargo.toml") + cargo_toml_content = tomli.loads(cargo_text_bytes.decode("utf-8")) + except (SourceCodeError, UnicodeDecodeError, tomli.TOMLDecodeError): + logger.debug("No Cargo.toml found") + + try: + cargo_lock_bytes = pypi_package_json.get_sourcecode_file_contents("Cargo.lock") + cargo_lock_content = tomli.loads(cargo_lock_bytes.decode("utf-8")) + except (SourceCodeError, UnicodeDecodeError, tomli.TOMLDecodeError): + logger.debug("No Cargo.lock found") + try: # Get the build time requirements from ["build-system", "requires"] pyproject_content = pypi_package_json.get_sourcecode_file_contents("pyproject.toml") @@ -180,13 +207,14 @@ def resolve_fields(self, purl: PackageURL) -> None: requires = json_extract(content, ["build-system", "requires"], list) if requires: for requirement in requires: - self.add_parsed_requirement(sdist_build_requires, requirement) + if parsed_requirement := self.add_parsed_python_requirement(sdist_build_requires, requirement): + if parsed_requirement.name.lower() == "maturin": + has_maturin = True # If we cannot find `requires` in `[build-system]`, we lean on the fact that setuptools # was the de-facto build tool, and infer a setuptools version to include. else: - self.add_parsed_requirement( - sdist_build_requires, f"setuptools=={chronologically_likeliest_version}" - ) + self.add_parsed_python_requirement(sdist_build_requires, + f"setuptools=={chronologically_likeliest_version}") backend = json_extract(content, ["build-system", "build-backend"], str) if backend: build_backends_set.add(backend.replace(" ", "")) @@ -202,22 +230,73 @@ def resolve_fields(self, purl: PackageURL) -> None: # Here we have successfully analyzed the pyproject.toml file. Now, if we have a setup.py/cfg, # we also need to infer a setuptools version to infer. if pypi_package_json.file_exists("setup.py") or pypi_package_json.file_exists("setup.cfg"): - self.add_parsed_requirement( - sdist_build_requires, f"setuptools=={chronologically_likeliest_version}" - ) + self.add_parsed_python_requirement(sdist_build_requires, + f"setuptools=={chronologically_likeliest_version}") except TypeError as error: - logger.debug( - "Found a type error while reading the pyproject.toml file from the sdist: %s", error - ) + logger.debug("Found a type error while reading the pyproject.toml file from the sdist: %s", error) except tomli.TOMLDecodeError as error: logger.debug("Failed to read the pyproject.toml file from the sdist: %s", error) except SourceCodeError as error: logger.debug("No pyproject.toml found: %s", error) # Here we do not have a pyproject.toml file. Instead, we lean on the fact that setuptools # was the de-facto build tool, and infer a setuptools version to include. - self.add_parsed_requirement( + self.add_parsed_python_requirement( sdist_build_requires, f"setuptools=={chronologically_likeliest_version}" ) + + if self.is_rust_backed_package(build_backends_set, has_maturin, cargo_toml_exists): + self.add_to_build_requires(sdist_build_requires, "rustup", "bootstrap") + + rust_requirement = self.infer_rust_requirement( + pypi_package_json, + cargo_toml_content, + ) + + self.add_to_build_requires( + sdist_build_requires, + rust_requirement["name"], + rust_requirement["installer"], + rust_requirement.get("version"), + ) + # Look through Cargo.lock first for resolved versions. + cargo_packages = json_extract(cargo_lock_content, ["package"], list) + if cargo_packages: + for package in cargo_packages: + cargo_dependency_name = json_extract(package, ["name"], str) + cargo_dependency_version = json_extract(package, ["version"], str) + if not cargo_dependency_name: + continue + cargo_dependency_version_constraint = ( + f"=={cargo_dependency_version}" if cargo_dependency_version else None + ) + self.add_to_build_requires( + sdist_build_requires, + cargo_dependency_name, + "cargo", + cargo_dependency_version_constraint, + ) + else: + # As a fallback, look through Cargo.toml dependency tables. + for table_name in ["build-dependencies", "dependencies"]: + cargo_dependencies = json_extract(cargo_toml_content, [table_name], dict) + if not cargo_dependencies: + continue + for cargo_dependency_name, cargo_dependency_spec in cargo_dependencies.items(): + cargo_dependency_version_constraint = None + if isinstance(cargo_dependency_spec, str): + cargo_dependency_version_constraint = cargo_dependency_spec + elif isinstance(cargo_dependency_spec, dict): + cargo_dependency_version_constraint = json_extract( + cargo_dependency_spec, ["version"], str + ) + + self.add_to_build_requires( + sdist_build_requires, + cargo_dependency_name, + "cargo", + cargo_dependency_version_constraint, + ) + except SourceCodeError as error: logger.debug("No source distribution found: %s", error) @@ -226,20 +305,33 @@ def resolve_fields(self, purl: PackageURL) -> None: # Merge in pyproject.toml information only when the wheel dist_info does not contain the same. # Hatch is an interesting example of this merge being required. - for requirement_name, specifier in sdist_build_requires.items(): - if requirement_name not in parsed_build_requires: - parsed_build_requires[requirement_name] = specifier - - # If we were not able to find any build and backends, use the default setuptools. + for requirement in sdist_build_requires.values(): + self.add_to_build_requires( + parsed_build_requires, + requirement["name"], + requirement["installer"], + requirement.get("version"), + ) + + # If we were not able to find any build and backends, use the default setuptools. if not parsed_build_requires: - parsed_build_requires["setuptools"] = "==" + defaults.get("heuristic.pypi", "default_setuptools") + self.add_to_build_requires( + parsed_build_requires, + "setuptools", + "pip", + "==" + defaults.get("heuristic.pypi", "default_setuptools"), + ) if not build_backends_set: build_backends_set.add("setuptools.build_meta") - logger.debug("Combined build-requires: %s", parsed_build_requires) + build_requires = sorted(parsed_build_requires.values(), key=lambda requirement: requirement["name"]) - for package, constraint in parsed_build_requires.items(): - package_requirement = package + constraint + logger.debug("Combined build-requires: %s", build_requires) + + for requirement in build_requires: + if requirement["installer"] != "pip": + continue + package_requirement = requirement["name"] + requirement.get("version", "") python_version_constraints = registry.get_python_requires_for_package_requirement(package_requirement) if python_version_constraints: dependency_python_version_set.add(python_version_constraints) @@ -252,43 +344,215 @@ def resolve_fields(self, purl: PackageURL) -> None: else: self.data["language_version"] = sorted(python_version_set) - self.data["build_requires"] = parsed_build_requires - self.data["build_backends"] = list(build_backends_set) - # We do not generate a build command for non-pure packages - if not self.data["has_binaries"]: - for build_cmd_spec in self.data["build_commands"]: - self.set_default_build_commands(build_cmd_spec) - else: - self.data["build_commands"] = [] + self.data["build_requires"] = build_requires + self.data["build_backends"] = sorted(build_backends_set) + for build_cmd_spec in self.data["build_commands"]: + self.set_default_build_commands(build_cmd_spec) self.data["upstream_artifacts"] = upstream_artifacts - def add_parsed_requirement(self, build_requirements: dict[str, str], requirement: str) -> None: + def add_to_build_requires( + self, + build_requirements: dict[str, SpecBuildRequirementDict], + name: str, + installer: str, + version: str | None = None, + ) -> None: + """ + Add requirement to build_requirements with version handling. + + Parameters + ---------- + build_requirements: dict[str, SpecBuildRequirementDict] + Dictionary of build requirements to populate. + name: str + Name of dependency. + installer: str + Installer used for the dependency. + version: str | None + Version specifier for the build requirement, if it exists + """ + if build_requirements.get(name): + # If we do not have version, but current invocation has inferred version, use that version. + if ("version" not in build_requirements[name]) and version: + build_requirements[name]["version"] = version + return + + requirement: SpecBuildRequirementDict = { + "name": name, + "installer": installer, + } + if version: + requirement["version"] = version + build_requirements[name] = requirement + + def add_parsed_python_requirement( + self, + build_requirements: dict[str, SpecBuildRequirementDict], + requirement: str, + ) -> Requirement | None: """ Parse a requirement string and add it to build_requirements, doing appropriate error handling. Parameters ---------- - build_requirements: dict[str,str] + build_requirements: dict[str, SpecBuildRequirementDict] Dictionary of build requirements to populate. requirement: str Requirement string to parse. """ try: parsed_requirement = Requirement(requirement) - if parsed_requirement.name not in build_requirements: - build_requirements[parsed_requirement.name] = str(parsed_requirement.specifier) + self.add_to_build_requires( + build_requirements, + parsed_requirement.name, + "pip", + str(parsed_requirement.specifier), + ) + return parsed_requirement except (InvalidRequirement, InvalidSpecifier) as error: logger.debug("Malformed requirement encountered %s : %s", requirement, error) + return None + + def is_rust_backed_package( + self, + build_backends_set: set[str], + has_maturin: bool, + cargo_toml_exists: bool, + ) -> bool: + """ + Determine if the artifact packages Rust binaries. + + Parameters + ---------- + build_backends_set: set[str] + Inferred set of build backends + has_maturin: bool + Whether maturin is a build requirement of the package + cargo_toml_exists: bool + Whether Cargo.toml exists in the sdist. + + Returns + ------- + bool + True if Rust signal was detected. + """ + return "maturin" in build_backends_set or has_maturin or cargo_toml_exists + + def infer_rust_requirement( + self, + pypi_package_json: pypi_registry.PyPIPackageJsonAsset, + cargo_toml_content: dict[str, Any], + ) -> SpecBuildRequirementDict: + """ + Infer Rust requirement object. + + Parameters + ---------- + pypi_package_json: pypi_registry.PyPIPackageJsonAsset + The PyPI package JSON asset object. + cargo_toml_content: dict[str, Any] + Parsed Cargo.toml data. + + Returns + ------- + SpecBuildRequirementDict + Rust requirement dictionary. + """ + version = self.read_rust_toolchain_version(pypi_package_json) + if version: + return { + "name": "rust", + "version": version, + "installer": "rustup", + } + + cargo_rust_version = json_extract(cargo_toml_content, ["package", "rust-version"], str) + if not cargo_rust_version: + cargo_rust_version = json_extract(cargo_toml_content, ["workspace", "package", "rust-version"], str) + if cargo_rust_version: + return { + "name": "rust", + "version": f">={cargo_rust_version.strip()}", + "installer": "rustup", + } + + return { + "name": "rust", + "installer": "rustup", + } + + def read_rust_toolchain_version(self, pypi_package_json: pypi_registry.PyPIPackageJsonAsset) -> str | None: + """ + Infer Rust toolchain version. + + Parameters + ---------- + pypi_package_json: pypi_registry.PyPIPackageJsonAsset + The PyPI package JSON asset object. + + Returns + ------- + str | None + The inferred Rust toolchain version, or None if unavailable. + """ + for file in ["rust-toolchain.toml", "rust-toolchain"]: + if not pypi_package_json.file_exists(file): + continue + try: + content = pypi_package_json.get_sourcecode_file_contents(file).decode("utf-8") + except (SourceCodeError, UnicodeDecodeError): + continue + + version = self.extract_rust_toolchain_version(content) + if version: + return version + return None + + def extract_rust_toolchain_version(self, content: str) -> str | None: + """ + Extract the Rust toolchain version from rust-toolchain content. + + Parameters + ---------- + content: str + Contents of a rust-toolchain.toml or rust-toolchain file. + + Returns + ------- + str | None + The inferred Rust toolchain version, or None if unavailable. + """ + stripped = content.strip() + if not stripped: + return None + + try: + parsed = tomli.loads(content) + toolchain_version = json_extract(parsed, ["toolchain", "channel"], str) + if toolchain_version: + return toolchain_version.strip() + except tomli.TOMLDecodeError: + pass + + for line in stripped.splitlines(): + sanitized = line.strip().strip('"').strip("'") + if not sanitized or sanitized.startswith("#"): + continue + return sanitized + return None def apply_tool_specific_inferences( - self, build_requirements: dict[str, str], python_version_set: set[str], pyproject_contents: dict[str, Any] + self, + build_requirements: dict[str, SpecBuildRequirementDict], + python_version_set: set[str], + pyproject_contents: dict[str, Any], ) -> None: """ Based on build tools inferred, look into the pyproject.toml for related additional dependencies. Parameters ---------- - build_requirements: dict[str,str] + build_requirements: dict[str, SpecBuildRequirementDict] Dictionary of build requirements to populate. python_version_set: set[str] Set of compatible interpreter versions to populate. @@ -305,7 +569,7 @@ def apply_tool_specific_inferences( dependencies = section.get("dependencies") if dependencies: for requirement in dependencies: - self.add_parsed_requirement(build_requirements, requirement) + self.add_parsed_python_requirement(build_requirements, requirement) # If we have flit as a build_tool, we will check if the legacy header [tool.flit.metadata] exists, # and if so, check to see if we can use its "requires-python". if "flit" in self.data["build_tools"]: diff --git a/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py b/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py index 7a3cf9539..1491a1011 100644 --- a/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py +++ b/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py @@ -365,7 +365,11 @@ def build_backend_commands(buildspec: BaseBuildSpecDict) -> list[str]: if not buildspec["build_requires"]: return [] commands: list[str] = [] - for backend, version_constraint in buildspec["build_requires"].items(): + for requirement in buildspec["build_requires"]: + if requirement["installer"] != "pip": + continue + backend = requirement["name"] + version_constraint = requirement.get("version", "") if backend == "setuptools": commands.append("/deps/bin/pip install --upgrade setuptools") else: diff --git a/src/macaron/resources/schemas/macaron_buildspec_schema.json b/src/macaron/resources/schemas/macaron_buildspec_schema.json index d2e7f1255..c54986493 100644 --- a/src/macaron/resources/schemas/macaron_buildspec_schema.json +++ b/src/macaron/resources/schemas/macaron_buildspec_schema.json @@ -111,8 +111,17 @@ "description": "Entry point script, class, or binary for running the project." }, "build_requires": { - "type": "object", - "additionalProperties": { "type": "string" }, + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "version": { "type": "string" }, + "installer": { "type": "string" } + }, + "required": ["name", "installer"], + "additionalProperties": false + }, "description": "Required packages that must be available in the build environment." }, "build_backends": { diff --git a/tests/build_spec_generator/common_spec/test_pypi_spec.py b/tests/build_spec_generator/common_spec/test_pypi_spec.py index a1a6e7a0f..41fd2756e 100644 --- a/tests/build_spec_generator/common_spec/test_pypi_spec.py +++ b/tests/build_spec_generator/common_spec/test_pypi_spec.py @@ -12,9 +12,12 @@ @pytest.mark.parametrize( ("build_tool", "expected_command"), [ + ("pip", ["python", "-m", "build", "--wheel", "-n"]), ("poetry", ["poetry", "build"]), ("flit", ["flit", "build"]), ("uv", ["uv", "build"]), + ("hatch", ["hatch", "build"]), + ("maturin", ["maturin", "build", "--release"]), ], ) def test_set_default_build_commands_for_pypi_tools(build_tool: str, expected_command: list[str]) -> None: diff --git a/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py b/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py index c2b03fcab..eab37840f 100644 --- a/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py +++ b/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py @@ -8,7 +8,7 @@ import pytest from macaron.build_spec_generator.common_spec.base_spec import BaseBuildSpecDict, SpecBuildCommandDict -from macaron.build_spec_generator.dockerfile.pypi_dockerfile_output import gen_dockerfile +from macaron.build_spec_generator.dockerfile.pypi_dockerfile_output import build_backend_commands, gen_dockerfile @pytest.fixture(name="pypi_build_spec") @@ -37,7 +37,10 @@ def fixture_base_build_spec() -> BaseBuildSpecDict: confidence_score=1.0, ) ], - "build_requires": {"setuptools": "==80.9.0", "wheel": ""}, + "build_requires": [ + {"name": "setuptools", "version": "==80.9.0", "installer": "pip"}, + {"name": "wheel", "installer": "pip"}, + ], "build_backends": ["setuptools.build_meta"], "upstream_artifacts": { "wheels": [ @@ -56,3 +59,18 @@ def fixture_base_build_spec() -> BaseBuildSpecDict: def test_successful_generation(snapshot: str, pypi_build_spec: BaseBuildSpecDict) -> None: """Ensure that dockerfile is correctly generated for pypi_build_spec""" assert gen_dockerfile(pypi_build_spec) == snapshot + + +def test_build_backend_commands_only_uses_pip_requirements(pypi_build_spec: BaseBuildSpecDict) -> None: + """Ensure non-pip build requirements are ignored in pip installation commands.""" + pypi_build_spec["build_requires"] = [ + {"name": "setuptools", "version": "==80.9.0", "installer": "pip"}, + {"name": "wheel", "installer": "pip"}, + {"name": "rustup", "installer": "bootstrap"}, + {"name": "rust", "version": "1.75.0", "installer": "rustup"}, + ] + + assert build_backend_commands(pypi_build_spec) == [ + '/deps/bin/pip install "wheel"', + "/deps/bin/pip install --upgrade setuptools", + ] diff --git a/tests/integration/cases/pypi_cachetools/expected_default.buildspec b/tests/integration/cases/pypi_cachetools/expected_default.buildspec index b42ad0c86..62bd081d7 100644 --- a/tests/integration/cases/pypi_cachetools/expected_default.buildspec +++ b/tests/integration/cases/pypi_cachetools/expected_default.buildspec @@ -30,10 +30,17 @@ } ], "has_binaries": false, - "build_requires": { - "setuptools": "==80.9.0", - "wheel": "" - }, + "build_requires": [ + { + "name": "setuptools", + "version": "==80.9.0", + "installer": "pip" + }, + { + "name": "wheel", + "installer": "pip" + } + ], "build_backends": [ "setuptools.build_meta" ], diff --git a/tests/integration/cases/pypi_markdown-it-py/expected_default.buildspec b/tests/integration/cases/pypi_markdown-it-py/expected_default.buildspec index 971e98935..140c9216a 100644 --- a/tests/integration/cases/pypi_markdown-it-py/expected_default.buildspec +++ b/tests/integration/cases/pypi_markdown-it-py/expected_default.buildspec @@ -29,10 +29,18 @@ } ], "has_binaries": false, - "build_requires": { - "flit": "==3.12.0", - "flit_core": "<4,>=3.4" - }, + "build_requires": [ + { + "name": "flit", + "version": "==3.12.0", + "installer": "pip" + }, + { + "name": "flit_core", + "version": "<4,>=3.4", + "installer": "pip" + } + ], "build_backends": [ "flit_core.buildapi" ], diff --git a/tests/integration/cases/pypi_pytesseract/expected_default.buildspec b/tests/integration/cases/pypi_pytesseract/expected_default.buildspec index 90e2b4752..f18c8111f 100644 --- a/tests/integration/cases/pypi_pytesseract/expected_default.buildspec +++ b/tests/integration/cases/pypi_pytesseract/expected_default.buildspec @@ -30,9 +30,13 @@ } ], "has_binaries": false, - "build_requires": { - "setuptools": "==67.7.2" - }, + "build_requires": [ + { + "name": "setuptools", + "version": "==67.7.2", + "installer": "pip" + } + ], "build_backends": [ "setuptools.build_meta" ], diff --git a/tests/integration/cases/pypi_toga/expected_default.buildspec b/tests/integration/cases/pypi_toga/expected_default.buildspec index d729267f0..0f01c7c7c 100644 --- a/tests/integration/cases/pypi_toga/expected_default.buildspec +++ b/tests/integration/cases/pypi_toga/expected_default.buildspec @@ -31,11 +31,23 @@ } ], "has_binaries": false, - "build_requires": { - "setuptools": "==80.3.1", - "setuptools_scm": "==8.3.1", - "setuptools_dynamic_dependencies": "==1.0.0" - }, + "build_requires": [ + { + "name": "setuptools", + "version": "==80.3.1", + "installer": "pip" + }, + { + "name": "setuptools_dynamic_dependencies", + "version": "==1.0.0", + "installer": "pip" + }, + { + "name": "setuptools_scm", + "version": "==8.3.1", + "installer": "pip" + } + ], "build_backends": [ "setuptools.build_meta" ], diff --git a/tests/integration/cases/pypi_tree-sitter/expected_default.buildspec b/tests/integration/cases/pypi_tree-sitter/expected_default.buildspec index a67a019b1..3cbe61eb3 100644 --- a/tests/integration/cases/pypi_tree-sitter/expected_default.buildspec +++ b/tests/integration/cases/pypi_tree-sitter/expected_default.buildspec @@ -15,11 +15,28 @@ "build_tools": [ "pip" ], - "build_commands": [], + "build_commands": [ + { + "build_tool": "pip", + "command": [ + "python", + "-m", + "build", + "--wheel", + "-n" + ], + "build_config_path": "pyproject.toml", + "confidence_score": 1.0 + } + ], "has_binaries": true, - "build_requires": { - "setuptools": ">=43" - }, + "build_requires": [ + { + "name": "setuptools", + "version": ">=43", + "installer": "pip" + } + ], "build_backends": [ "setuptools.build_meta" ], From 661be1e9555556211e35030a5580030c6b3c0d67 Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep Date: Fri, 15 May 2026 15:26:57 +1000 Subject: [PATCH 2/3] fix: code style issue. Signed-off-by: Abhinav Pradeep --- .../build_spec_generator/common_spec/pypi_spec.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/macaron/build_spec_generator/common_spec/pypi_spec.py b/src/macaron/build_spec_generator/common_spec/pypi_spec.py index 49782672b..277ce8b51 100644 --- a/src/macaron/build_spec_generator/common_spec/pypi_spec.py +++ b/src/macaron/build_spec_generator/common_spec/pypi_spec.py @@ -522,23 +522,13 @@ def extract_rust_toolchain_version(self, content: str) -> str | None: str | None The inferred Rust toolchain version, or None if unavailable. """ - stripped = content.strip() - if not stripped: - return None - try: parsed = tomli.loads(content) toolchain_version = json_extract(parsed, ["toolchain", "channel"], str) if toolchain_version: return toolchain_version.strip() except tomli.TOMLDecodeError: - pass - - for line in stripped.splitlines(): - sanitized = line.strip().strip('"').strip("'") - if not sanitized or sanitized.startswith("#"): - continue - return sanitized + logger.debug("Failed to infer Rust toolchain version") return None def apply_tool_specific_inferences( From 0d0bd9b85986f3381e8ab86a69e9316ac631005d Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep Date: Fri, 15 May 2026 15:53:48 +1000 Subject: [PATCH 3/3] test: add integration test for ruff. Signed-off-by: Abhinav Pradeep --- .../pypi_ruff/expected_default.buildspec | 2545 +++++++++++++++++ tests/integration/cases/pypi_ruff/test.yaml | 37 + 2 files changed, 2582 insertions(+) create mode 100644 tests/integration/cases/pypi_ruff/expected_default.buildspec create mode 100644 tests/integration/cases/pypi_ruff/test.yaml diff --git a/tests/integration/cases/pypi_ruff/expected_default.buildspec b/tests/integration/cases/pypi_ruff/expected_default.buildspec new file mode 100644 index 000000000..b378c2bbc --- /dev/null +++ b/tests/integration/cases/pypi_ruff/expected_default.buildspec @@ -0,0 +1,2545 @@ +{ + "macaron_version": "0.24.0", + "group_id": null, + "artifact_id": "ruff", + "version": "0.15.13", + "git_repo": "https://github.com/astral-sh/ruff", + "git_tag": "2afb467ce397e4a89c13a0a814c62cfecb0e9e49", + "newline": "lf", + "language_version": [ + ">=3.7" + ], + "ecosystem": "pypi", + "purl": "pkg:pypi/ruff@0.15.13", + "language": "python", + "build_tools": [ + "uv", + "pip" + ], + "build_commands": [ + { + "build_tool": "uv", + "command": [ + "uv", + "build" + ], + "build_config_path": "pyproject.toml", + "confidence_score": 1.0 + } + ], + "has_binaries": true, + "build_requires": [ + { + "name": "adler2", + "installer": "cargo", + "version": "==2.0.1" + }, + { + "name": "aho-corasick", + "installer": "cargo", + "version": "==1.1.4" + }, + { + "name": "alloca", + "installer": "cargo", + "version": "==0.4.0" + }, + { + "name": "allocator-api2", + "installer": "cargo", + "version": "==0.2.21" + }, + { + "name": "android_system_properties", + "installer": "cargo", + "version": "==0.1.5" + }, + { + "name": "anes", + "installer": "cargo", + "version": "==0.1.6" + }, + { + "name": "annotate-snippets", + "installer": "cargo", + "version": "==0.11.5" + }, + { + "name": "anstream", + "installer": "cargo", + "version": "==0.6.21" + }, + { + "name": "anstyle", + "installer": "cargo", + "version": "==1.0.14" + }, + { + "name": "anstyle-lossy", + "installer": "cargo", + "version": "==1.1.4" + }, + { + "name": "anstyle-parse", + "installer": "cargo", + "version": "==0.2.7" + }, + { + "name": "anstyle-query", + "installer": "cargo", + "version": "==1.1.4" + }, + { + "name": "anstyle-svg", + "installer": "cargo", + "version": "==0.1.11" + }, + { + "name": "anstyle-wincon", + "installer": "cargo", + "version": "==3.0.10" + }, + { + "name": "anyhow", + "installer": "cargo", + "version": "==1.0.102" + }, + { + "name": "approx", + "installer": "cargo", + "version": "==0.5.1" + }, + { + "name": "arc-swap", + "installer": "cargo", + "version": "==1.9.1" + }, + { + "name": "argfile", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "arrayvec", + "installer": "cargo", + "version": "==0.7.6" + }, + { + "name": "assert_fs", + "installer": "cargo", + "version": "==1.1.3" + }, + { + "name": "attribute-derive", + "installer": "cargo", + "version": "==0.10.3" + }, + { + "name": "attribute-derive-macro", + "installer": "cargo", + "version": "==0.10.3" + }, + { + "name": "autocfg", + "installer": "cargo", + "version": "==1.5.0" + }, + { + "name": "bincode", + "installer": "cargo", + "version": "==2.0.1" + }, + { + "name": "bincode_derive", + "installer": "cargo", + "version": "==2.0.1" + }, + { + "name": "bit-set", + "installer": "cargo", + "version": "==0.8.0" + }, + { + "name": "bit-vec", + "installer": "cargo", + "version": "==0.8.0" + }, + { + "name": "bitflags", + "installer": "cargo", + "version": "==1.3.2" + }, + { + "name": "bitvec", + "installer": "cargo", + "version": "==1.0.1" + }, + { + "name": "block-buffer", + "installer": "cargo", + "version": "==0.10.4" + }, + { + "name": "block2", + "installer": "cargo", + "version": "==0.6.2" + }, + { + "name": "boxcar", + "installer": "cargo", + "version": "==0.2.14" + }, + { + "name": "bstr", + "installer": "cargo", + "version": "==1.12.1" + }, + { + "name": "bumpalo", + "installer": "cargo", + "version": "==3.19.0" + }, + { + "name": "byteorder", + "installer": "cargo", + "version": "==1.5.0" + }, + { + "name": "cachedir", + "installer": "cargo", + "version": "==0.3.1" + }, + { + "name": "camino", + "installer": "cargo", + "version": "==1.2.2" + }, + { + "name": "cast", + "installer": "cargo", + "version": "==0.3.0" + }, + { + "name": "castaway", + "installer": "cargo", + "version": "==0.2.4" + }, + { + "name": "cc", + "installer": "cargo", + "version": "==1.2.38" + }, + { + "name": "cfg-if", + "installer": "cargo", + "version": "==1.0.3" + }, + { + "name": "cfg_aliases", + "installer": "cargo", + "version": "==0.2.1" + }, + { + "name": "chacha20", + "installer": "cargo", + "version": "==0.10.0" + }, + { + "name": "chrono", + "installer": "cargo", + "version": "==0.4.44" + }, + { + "name": "ciborium", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "ciborium-io", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "ciborium-ll", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "clap", + "installer": "cargo", + "version": "==4.6.1" + }, + { + "name": "clap_builder", + "installer": "cargo", + "version": "==4.6.0" + }, + { + "name": "clap_complete", + "installer": "cargo", + "version": "==4.5.58" + }, + { + "name": "clap_complete_command", + "installer": "cargo", + "version": "==0.6.1" + }, + { + "name": "clap_complete_nushell", + "installer": "cargo", + "version": "==4.5.8" + }, + { + "name": "clap_derive", + "installer": "cargo", + "version": "==4.6.1" + }, + { + "name": "clap_lex", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "clearscreen", + "installer": "cargo", + "version": "==4.0.6" + }, + { + "name": "codspeed", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "codspeed-criterion-compat", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "codspeed-criterion-compat-walltime", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "codspeed-divan-compat", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "codspeed-divan-compat-macros", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "codspeed-divan-compat-walltime", + "installer": "cargo", + "version": "==4.4.1" + }, + { + "name": "collection_literals", + "installer": "cargo", + "version": "==1.0.2" + }, + { + "name": "colorchoice", + "installer": "cargo", + "version": "==1.0.4" + }, + { + "name": "colored", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "compact_str", + "installer": "cargo", + "version": "==0.9.0" + }, + { + "name": "condtype", + "installer": "cargo", + "version": "==1.3.0" + }, + { + "name": "console", + "installer": "cargo", + "version": "==0.16.1" + }, + { + "name": "console_error_panic_hook", + "installer": "cargo", + "version": "==0.1.7" + }, + { + "name": "console_log", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "core-foundation-sys", + "installer": "cargo", + "version": "==0.8.7" + }, + { + "name": "countme", + "installer": "cargo", + "version": "==3.0.1" + }, + { + "name": "cpufeatures", + "installer": "cargo", + "version": "==0.2.17" + }, + { + "name": "crc32fast", + "installer": "cargo", + "version": "==1.5.0" + }, + { + "name": "criterion", + "installer": "cargo", + "version": "==0.8.2" + }, + { + "name": "criterion-plot", + "installer": "cargo", + "version": "==0.5.0" + }, + { + "name": "crossbeam", + "installer": "cargo", + "version": "==0.8.4" + }, + { + "name": "crossbeam-channel", + "installer": "cargo", + "version": "==0.5.15" + }, + { + "name": "crossbeam-deque", + "installer": "cargo", + "version": "==0.8.6" + }, + { + "name": "crossbeam-epoch", + "installer": "cargo", + "version": "==0.9.18" + }, + { + "name": "crossbeam-queue", + "installer": "cargo", + "version": "==0.3.12" + }, + { + "name": "crossbeam-utils", + "installer": "cargo", + "version": "==0.8.21" + }, + { + "name": "crunchy", + "installer": "cargo", + "version": "==0.2.4" + }, + { + "name": "crypto-common", + "installer": "cargo", + "version": "==0.1.6" + }, + { + "name": "csv", + "installer": "cargo", + "version": "==1.4.0" + }, + { + "name": "csv-core", + "installer": "cargo", + "version": "==0.1.12" + }, + { + "name": "ctrlc", + "installer": "cargo", + "version": "==3.5.2" + }, + { + "name": "darling", + "installer": "cargo", + "version": "==0.23.0" + }, + { + "name": "darling_core", + "installer": "cargo", + "version": "==0.23.0" + }, + { + "name": "darling_macro", + "installer": "cargo", + "version": "==0.23.0" + }, + { + "name": "dashmap", + "installer": "cargo", + "version": "==6.1.0" + }, + { + "name": "datatest-stable", + "installer": "cargo", + "version": "==0.3.3" + }, + { + "name": "derive-where", + "installer": "cargo", + "version": "==1.6.0" + }, + { + "name": "diff", + "installer": "cargo", + "version": "==0.1.13" + }, + { + "name": "difflib", + "installer": "cargo", + "version": "==0.4.0" + }, + { + "name": "digest", + "installer": "cargo", + "version": "==0.10.7" + }, + { + "name": "dirs", + "installer": "cargo", + "version": "==6.0.0" + }, + { + "name": "dirs-sys", + "installer": "cargo", + "version": "==0.5.0" + }, + { + "name": "dispatch2", + "installer": "cargo", + "version": "==0.3.0" + }, + { + "name": "displaydoc", + "installer": "cargo", + "version": "==0.2.5" + }, + { + "name": "divan-macros", + "installer": "cargo", + "version": "==0.1.17" + }, + { + "name": "doc-comment", + "installer": "cargo", + "version": "==0.3.3" + }, + { + "name": "drop_bomb", + "installer": "cargo", + "version": "==0.1.5" + }, + { + "name": "dunce", + "installer": "cargo", + "version": "==1.0.5" + }, + { + "name": "dyn-clone", + "installer": "cargo", + "version": "==1.0.20" + }, + { + "name": "either", + "installer": "cargo", + "version": "==1.15.0" + }, + { + "name": "encode_unicode", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "equivalent", + "installer": "cargo", + "version": "==1.0.2" + }, + { + "name": "errno", + "installer": "cargo", + "version": "==0.3.14" + }, + { + "name": "escape8259", + "installer": "cargo", + "version": "==0.5.3" + }, + { + "name": "escargot", + "installer": "cargo", + "version": "==0.5.15" + }, + { + "name": "etcetera", + "installer": "cargo", + "version": "==0.11.0" + }, + { + "name": "fancy-regex", + "installer": "cargo", + "version": "==0.14.0" + }, + { + "name": "fastrand", + "installer": "cargo", + "version": "==2.3.0" + }, + { + "name": "fern", + "installer": "cargo", + "version": "==0.7.1" + }, + { + "name": "filetime", + "installer": "cargo", + "version": "==0.2.27" + }, + { + "name": "find-msvc-tools", + "installer": "cargo", + "version": "==0.1.2" + }, + { + "name": "flate2", + "installer": "cargo", + "version": "==1.1.2" + }, + { + "name": "fnv", + "installer": "cargo", + "version": "==1.0.7" + }, + { + "name": "foldhash", + "installer": "cargo", + "version": "==0.1.5" + }, + { + "name": "form_urlencoded", + "installer": "cargo", + "version": "==1.2.2" + }, + { + "name": "fs-err", + "installer": "cargo", + "version": "==3.3.0" + }, + { + "name": "fsevent-sys", + "installer": "cargo", + "version": "==4.1.0" + }, + { + "name": "funty", + "installer": "cargo", + "version": "==2.0.0" + }, + { + "name": "generic-array", + "installer": "cargo", + "version": "==0.14.7" + }, + { + "name": "get-size-derive2", + "installer": "cargo", + "version": "==0.8.0" + }, + { + "name": "get-size2", + "installer": "cargo", + "version": "==0.8.0" + }, + { + "name": "getopts", + "installer": "cargo", + "version": "==0.2.24" + }, + { + "name": "getrandom", + "installer": "cargo", + "version": "==0.2.16" + }, + { + "name": "glob", + "installer": "cargo", + "version": "==0.3.3" + }, + { + "name": "globset", + "installer": "cargo", + "version": "==0.4.18" + }, + { + "name": "globwalk", + "installer": "cargo", + "version": "==0.9.1" + }, + { + "name": "half", + "installer": "cargo", + "version": "==2.6.0" + }, + { + "name": "hashbrown", + "installer": "cargo", + "version": "==0.14.5" + }, + { + "name": "hashlink", + "installer": "cargo", + "version": "==0.10.0" + }, + { + "name": "heck", + "installer": "cargo", + "version": "==0.5.0" + }, + { + "name": "hermit-abi", + "installer": "cargo", + "version": "==0.5.2" + }, + { + "name": "html-escape", + "installer": "cargo", + "version": "==0.2.13" + }, + { + "name": "iana-time-zone", + "installer": "cargo", + "version": "==0.1.64" + }, + { + "name": "iana-time-zone-haiku", + "installer": "cargo", + "version": "==0.1.2" + }, + { + "name": "icu_collections", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_locale_core", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_normalizer", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_normalizer_data", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_properties", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_properties_data", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "icu_provider", + "installer": "cargo", + "version": "==2.2.0" + }, + { + "name": "id-arena", + "installer": "cargo", + "version": "==2.3.0" + }, + { + "name": "ident_case", + "installer": "cargo", + "version": "==1.0.1" + }, + { + "name": "idna", + "installer": "cargo", + "version": "==1.1.0" + }, + { + "name": "idna_adapter", + "installer": "cargo", + "version": "==1.2.1" + }, + { + "name": "ignore", + "installer": "cargo", + "version": "==0.4.25" + }, + { + "name": "imara-diff", + "installer": "cargo", + "version": "==0.2.0" + }, + { + "name": "imperative", + "installer": "cargo", + "version": "==1.0.7" + }, + { + "name": "indexmap", + "installer": "cargo", + "version": "==2.14.0" + }, + { + "name": "indicatif", + "installer": "cargo", + "version": "==0.18.4" + }, + { + "name": "indoc", + "installer": "cargo", + "version": "==2.0.7" + }, + { + "name": "inotify", + "installer": "cargo", + "version": "==0.11.0" + }, + { + "name": "inotify-sys", + "installer": "cargo", + "version": "==0.1.5" + }, + { + "name": "insta", + "installer": "cargo", + "version": "==1.47.2" + }, + { + "name": "insta-cmd", + "installer": "cargo", + "version": "==0.6.0" + }, + { + "name": "interpolator", + "installer": "cargo", + "version": "==0.5.0" + }, + { + "name": "intrusive-collections", + "installer": "cargo", + "version": "==0.9.7" + }, + { + "name": "inventory", + "installer": "cargo", + "version": "==0.3.24" + }, + { + "name": "is-macro", + "installer": "cargo", + "version": "==0.3.7" + }, + { + "name": "is-terminal", + "installer": "cargo", + "version": "==0.4.16" + }, + { + "name": "is_terminal_polyfill", + "installer": "cargo", + "version": "==1.70.1" + }, + { + "name": "itertools", + "installer": "cargo", + "version": "==0.10.5" + }, + { + "name": "itoa", + "installer": "cargo", + "version": "==1.0.15" + }, + { + "name": "jiff", + "installer": "cargo", + "version": "==0.2.24" + }, + { + "name": "jiff-static", + "installer": "cargo", + "version": "==0.2.24" + }, + { + "name": "jiff-tzdb", + "installer": "cargo", + "version": "==0.1.4" + }, + { + "name": "jiff-tzdb-platform", + "installer": "cargo", + "version": "==0.1.3" + }, + { + "name": "jobserver", + "installer": "cargo", + "version": "==0.1.34" + }, + { + "name": "jod-thread", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "js-sys", + "installer": "cargo", + "version": "==0.3.82" + }, + { + "name": "kqueue", + "installer": "cargo", + "version": "==1.1.1" + }, + { + "name": "kqueue-sys", + "installer": "cargo", + "version": "==1.0.4" + }, + { + "name": "lazy_static", + "installer": "cargo", + "version": "==1.5.0" + }, + { + "name": "leb128fmt", + "installer": "cargo", + "version": "==0.1.0" + }, + { + "name": "libc", + "installer": "cargo", + "version": "==0.2.186" + }, + { + "name": "libcst", + "installer": "cargo", + "version": "==1.8.6" + }, + { + "name": "libcst_derive", + "installer": "cargo", + "version": "==1.8.6" + }, + { + "name": "libmimalloc-sys", + "installer": "cargo", + "version": "==0.1.47" + }, + { + "name": "libredox", + "installer": "cargo", + "version": "==0.1.10" + }, + { + "name": "libtest-mimic", + "installer": "cargo", + "version": "==0.7.3" + }, + { + "name": "linux-raw-sys", + "installer": "cargo", + "version": "==0.12.1" + }, + { + "name": "litemap", + "installer": "cargo", + "version": "==0.8.0" + }, + { + "name": "lock_api", + "installer": "cargo", + "version": "==0.4.13" + }, + { + "name": "log", + "installer": "cargo", + "version": "==0.4.29" + }, + { + "name": "lsp-server", + "installer": "cargo", + "version": "==0.7.9" + }, + { + "name": "lsp-types", + "installer": "cargo", + "version": "==0.95.1" + }, + { + "name": "manyhow", + "installer": "cargo", + "version": "==0.11.4" + }, + { + "name": "manyhow-macros", + "installer": "cargo", + "version": "==0.11.4" + }, + { + "name": "markdown", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "matchers", + "installer": "cargo", + "version": "==0.2.0" + }, + { + "name": "matchit", + "installer": "cargo", + "version": "==0.9.2" + }, + { + "name": "maturin", + "installer": "pip", + "version": "<2.0,>=1.9.3" + }, + { + "name": "mdtest", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "memchr", + "installer": "cargo", + "version": "==2.8.0" + }, + { + "name": "memoffset", + "installer": "cargo", + "version": "==0.9.1" + }, + { + "name": "mimalloc", + "installer": "cargo", + "version": "==0.1.50" + }, + { + "name": "minicov", + "installer": "cargo", + "version": "==0.3.7" + }, + { + "name": "minimal-lexical", + "installer": "cargo", + "version": "==0.2.1" + }, + { + "name": "miniz_oxide", + "installer": "cargo", + "version": "==0.8.9" + }, + { + "name": "mio", + "installer": "cargo", + "version": "==1.0.4" + }, + { + "name": "natord", + "installer": "cargo", + "version": "==1.0.9" + }, + { + "name": "newtype-uuid", + "installer": "cargo", + "version": "==1.3.2" + }, + { + "name": "nix", + "installer": "cargo", + "version": "==0.31.2" + }, + { + "name": "nom", + "installer": "cargo", + "version": "==7.1.3" + }, + { + "name": "normalize-line-endings", + "installer": "cargo", + "version": "==0.3.0" + }, + { + "name": "notify", + "installer": "cargo", + "version": "==8.2.0" + }, + { + "name": "notify-types", + "installer": "cargo", + "version": "==2.0.0" + }, + { + "name": "nu-ansi-term", + "installer": "cargo", + "version": "==0.50.1" + }, + { + "name": "num-traits", + "installer": "cargo", + "version": "==0.2.19" + }, + { + "name": "num_cpus", + "installer": "cargo", + "version": "==1.17.0" + }, + { + "name": "objc2", + "installer": "cargo", + "version": "==0.6.3" + }, + { + "name": "objc2-encode", + "installer": "cargo", + "version": "==4.1.0" + }, + { + "name": "once_cell", + "installer": "cargo", + "version": "==1.21.3" + }, + { + "name": "once_cell_polyfill", + "installer": "cargo", + "version": "==1.70.1" + }, + { + "name": "oorandom", + "installer": "cargo", + "version": "==11.1.5" + }, + { + "name": "option-ext", + "installer": "cargo", + "version": "==0.2.0" + }, + { + "name": "ordermap", + "installer": "cargo", + "version": "==1.2.0" + }, + { + "name": "os_pipe", + "installer": "cargo", + "version": "==1.2.2" + }, + { + "name": "os_str_bytes", + "installer": "cargo", + "version": "==7.1.1" + }, + { + "name": "page_size", + "installer": "cargo", + "version": "==0.6.0" + }, + { + "name": "parking_lot", + "installer": "cargo", + "version": "==0.12.4" + }, + { + "name": "parking_lot_core", + "installer": "cargo", + "version": "==0.9.11" + }, + { + "name": "paste", + "installer": "cargo", + "version": "==1.0.15" + }, + { + "name": "path-absolutize", + "installer": "cargo", + "version": "==3.1.1" + }, + { + "name": "path-dedot", + "installer": "cargo", + "version": "==3.1.1" + }, + { + "name": "path-slash", + "installer": "cargo", + "version": "==0.2.1" + }, + { + "name": "pathdiff", + "installer": "cargo", + "version": "==0.2.3" + }, + { + "name": "peg", + "installer": "cargo", + "version": "==0.8.5" + }, + { + "name": "peg-macros", + "installer": "cargo", + "version": "==0.8.5" + }, + { + "name": "peg-runtime", + "installer": "cargo", + "version": "==0.8.5" + }, + { + "name": "pep440_rs", + "installer": "cargo", + "version": "==0.7.3" + }, + { + "name": "pep508_rs", + "installer": "cargo", + "version": "==0.9.2" + }, + { + "name": "percent-encoding", + "installer": "cargo", + "version": "==2.3.2" + }, + { + "name": "pest", + "installer": "cargo", + "version": "==2.8.2" + }, + { + "name": "pest_derive", + "installer": "cargo", + "version": "==2.8.2" + }, + { + "name": "pest_generator", + "installer": "cargo", + "version": "==2.8.2" + }, + { + "name": "pest_meta", + "installer": "cargo", + "version": "==2.8.2" + }, + { + "name": "phf", + "installer": "cargo", + "version": "==0.11.3" + }, + { + "name": "phf_codegen", + "installer": "cargo", + "version": "==0.11.3" + }, + { + "name": "phf_generator", + "installer": "cargo", + "version": "==0.11.3" + }, + { + "name": "phf_shared", + "installer": "cargo", + "version": "==0.11.3" + }, + { + "name": "pin-project-lite", + "installer": "cargo", + "version": "==0.2.16" + }, + { + "name": "pkg-config", + "installer": "cargo", + "version": "==0.3.32" + }, + { + "name": "portable-atomic", + "installer": "cargo", + "version": "==1.13.1" + }, + { + "name": "portable-atomic-util", + "installer": "cargo", + "version": "==0.2.4" + }, + { + "name": "potential_utf", + "installer": "cargo", + "version": "==0.1.3" + }, + { + "name": "ppv-lite86", + "installer": "cargo", + "version": "==0.2.21" + }, + { + "name": "predicates", + "installer": "cargo", + "version": "==3.1.3" + }, + { + "name": "predicates-core", + "installer": "cargo", + "version": "==1.0.9" + }, + { + "name": "predicates-tree", + "installer": "cargo", + "version": "==1.0.12" + }, + { + "name": "pretty_assertions", + "installer": "cargo", + "version": "==1.4.1" + }, + { + "name": "prettyplease", + "installer": "cargo", + "version": "==0.2.37" + }, + { + "name": "proc-macro-crate", + "installer": "cargo", + "version": "==3.4.0" + }, + { + "name": "proc-macro-utils", + "installer": "cargo", + "version": "==0.10.0" + }, + { + "name": "proc-macro2", + "installer": "cargo", + "version": "==1.0.106" + }, + { + "name": "pyproject-toml", + "installer": "cargo", + "version": "==0.13.7" + }, + { + "name": "quick-junit", + "installer": "cargo", + "version": "==0.6.0" + }, + { + "name": "quick-xml", + "installer": "cargo", + "version": "==0.38.4" + }, + { + "name": "quickcheck", + "installer": "cargo", + "version": "==1.1.0" + }, + { + "name": "quickcheck_macros", + "installer": "cargo", + "version": "==1.2.0" + }, + { + "name": "quote", + "installer": "cargo", + "version": "==1.0.45" + }, + { + "name": "quote-use", + "installer": "cargo", + "version": "==0.8.4" + }, + { + "name": "quote-use-macros", + "installer": "cargo", + "version": "==0.8.4" + }, + { + "name": "r-efi", + "installer": "cargo", + "version": "==5.3.0" + }, + { + "name": "radium", + "installer": "cargo", + "version": "==0.7.0" + }, + { + "name": "rand", + "installer": "cargo", + "version": "==0.8.5" + }, + { + "name": "rand_chacha", + "installer": "cargo", + "version": "==0.3.1" + }, + { + "name": "rand_core", + "installer": "cargo", + "version": "==0.6.4" + }, + { + "name": "rayon", + "installer": "cargo", + "version": "==1.12.0" + }, + { + "name": "rayon-core", + "installer": "cargo", + "version": "==1.13.0" + }, + { + "name": "redox_syscall", + "installer": "cargo", + "version": "==0.5.17" + }, + { + "name": "redox_users", + "installer": "cargo", + "version": "==0.5.2" + }, + { + "name": "ref-cast", + "installer": "cargo", + "version": "==1.0.25" + }, + { + "name": "ref-cast-impl", + "installer": "cargo", + "version": "==1.0.25" + }, + { + "name": "regex", + "installer": "cargo", + "version": "==1.12.3" + }, + { + "name": "regex-automata", + "installer": "cargo", + "version": "==0.4.14" + }, + { + "name": "regex-lite", + "installer": "cargo", + "version": "==0.1.7" + }, + { + "name": "regex-syntax", + "installer": "cargo", + "version": "==0.8.10" + }, + { + "name": "ron", + "installer": "cargo", + "version": "==0.12.0" + }, + { + "name": "ruff", + "installer": "cargo", + "version": "==0.15.13" + }, + { + "name": "ruff_annotate_snippets", + "installer": "cargo", + "version": "==0.1.0" + }, + { + "name": "ruff_benchmark", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_cache", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_db", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_dev", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_diagnostics", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_formatter", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_graph", + "installer": "cargo", + "version": "==0.1.0" + }, + { + "name": "ruff_index", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_linter", + "installer": "cargo", + "version": "==0.15.13" + }, + { + "name": "ruff_macros", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_markdown", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_memory_usage", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_notebook", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_options_metadata", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_ast", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_ast_integration_tests", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_codegen", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_formatter", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_importer", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_index", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_literal", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_parser", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_semantic", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_stdlib", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_trivia", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_python_trivia_integration_tests", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_server", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "ruff_source_file", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_text_size", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ruff_wasm", + "installer": "cargo", + "version": "==0.15.13" + }, + { + "name": "ruff_workspace", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "rust", + "installer": "rustup", + "version": ">=1.93" + }, + { + "name": "rust-stemmers", + "installer": "cargo", + "version": "==1.2.0" + }, + { + "name": "rustc-hash", + "installer": "cargo", + "version": "==2.1.2" + }, + { + "name": "rustc-stable-hash", + "installer": "cargo", + "version": "==0.1.2" + }, + { + "name": "rustix", + "installer": "cargo", + "version": "==1.1.4" + }, + { + "name": "rustup", + "installer": "bootstrap" + }, + { + "name": "rustversion", + "installer": "cargo", + "version": "==1.0.22" + }, + { + "name": "ryu", + "installer": "cargo", + "version": "==1.0.20" + }, + { + "name": "salsa", + "installer": "cargo", + "version": "==0.26.2" + }, + { + "name": "salsa-macro-rules", + "installer": "cargo", + "version": "==0.26.2" + }, + { + "name": "salsa-macros", + "installer": "cargo", + "version": "==0.26.2" + }, + { + "name": "same-file", + "installer": "cargo", + "version": "==1.0.6" + }, + { + "name": "schemars", + "installer": "cargo", + "version": "==1.2.1" + }, + { + "name": "schemars_derive", + "installer": "cargo", + "version": "==1.2.1" + }, + { + "name": "scopeguard", + "installer": "cargo", + "version": "==1.2.0" + }, + { + "name": "seahash", + "installer": "cargo", + "version": "==4.1.0" + }, + { + "name": "semver", + "installer": "cargo", + "version": "==1.0.27" + }, + { + "name": "serde", + "installer": "cargo", + "version": "==1.0.228" + }, + { + "name": "serde-wasm-bindgen", + "installer": "cargo", + "version": "==0.6.5" + }, + { + "name": "serde_core", + "installer": "cargo", + "version": "==1.0.228" + }, + { + "name": "serde_derive", + "installer": "cargo", + "version": "==1.0.228" + }, + { + "name": "serde_derive_internals", + "installer": "cargo", + "version": "==0.29.1" + }, + { + "name": "serde_json", + "installer": "cargo", + "version": "==1.0.149" + }, + { + "name": "serde_repr", + "installer": "cargo", + "version": "==0.1.20" + }, + { + "name": "serde_spanned", + "installer": "cargo", + "version": "==1.1.1" + }, + { + "name": "serde_test", + "installer": "cargo", + "version": "==1.0.177" + }, + { + "name": "serde_with", + "installer": "cargo", + "version": "==3.19.0" + }, + { + "name": "serde_with_macros", + "installer": "cargo", + "version": "==3.19.0" + }, + { + "name": "sha2", + "installer": "cargo", + "version": "==0.10.9" + }, + { + "name": "sharded-slab", + "installer": "cargo", + "version": "==0.1.7" + }, + { + "name": "shellexpand", + "installer": "cargo", + "version": "==3.1.2" + }, + { + "name": "shlex", + "installer": "cargo", + "version": "==1.3.0" + }, + { + "name": "similar", + "installer": "cargo", + "version": "==2.7.0" + }, + { + "name": "siphasher", + "installer": "cargo", + "version": "==1.0.1" + }, + { + "name": "smallvec", + "installer": "cargo", + "version": "==1.15.1" + }, + { + "name": "snapbox", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "snapbox-macros", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "stable_deref_trait", + "installer": "cargo", + "version": "==1.2.0" + }, + { + "name": "static_assertions", + "installer": "cargo", + "version": "==1.1.0" + }, + { + "name": "statrs", + "installer": "cargo", + "version": "==0.18.0" + }, + { + "name": "strip-ansi-escapes", + "installer": "cargo", + "version": "==0.2.1" + }, + { + "name": "strsim", + "installer": "cargo", + "version": "==0.11.1" + }, + { + "name": "strum", + "installer": "cargo", + "version": "==0.28.0" + }, + { + "name": "strum_macros", + "installer": "cargo", + "version": "==0.28.0" + }, + { + "name": "supports-hyperlinks", + "installer": "cargo", + "version": "==3.2.0" + }, + { + "name": "syn", + "installer": "cargo", + "version": "==2.0.117" + }, + { + "name": "synstructure", + "installer": "cargo", + "version": "==0.13.2" + }, + { + "name": "tap", + "installer": "cargo", + "version": "==1.0.1" + }, + { + "name": "tempfile", + "installer": "cargo", + "version": "==3.27.0" + }, + { + "name": "termcolor", + "installer": "cargo", + "version": "==1.4.1" + }, + { + "name": "terminal_size", + "installer": "cargo", + "version": "==0.4.3" + }, + { + "name": "terminfo", + "installer": "cargo", + "version": "==0.9.0" + }, + { + "name": "termtree", + "installer": "cargo", + "version": "==0.5.1" + }, + { + "name": "test-case", + "installer": "cargo", + "version": "==3.3.1" + }, + { + "name": "test-case-core", + "installer": "cargo", + "version": "==3.3.1" + }, + { + "name": "test-case-macros", + "installer": "cargo", + "version": "==3.3.1" + }, + { + "name": "thin-vec", + "installer": "cargo", + "version": "==0.2.14" + }, + { + "name": "thiserror", + "installer": "cargo", + "version": "==1.0.69" + }, + { + "name": "thiserror-impl", + "installer": "cargo", + "version": "==1.0.69" + }, + { + "name": "thread_local", + "installer": "cargo", + "version": "==1.1.9" + }, + { + "name": "threadpool", + "installer": "cargo", + "version": "==1.8.1" + }, + { + "name": "tikv-jemalloc-sys", + "installer": "cargo", + "version": "==0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" + }, + { + "name": "tikv-jemallocator", + "installer": "cargo", + "version": "==0.6.1" + }, + { + "name": "tinystr", + "installer": "cargo", + "version": "==0.8.3" + }, + { + "name": "tinytemplate", + "installer": "cargo", + "version": "==1.2.1" + }, + { + "name": "tinyvec", + "installer": "cargo", + "version": "==1.10.0" + }, + { + "name": "tinyvec_macros", + "installer": "cargo", + "version": "==0.1.1" + }, + { + "name": "toml", + "installer": "cargo", + "version": "==0.9.12+spec-1.1.0" + }, + { + "name": "toml_datetime", + "installer": "cargo", + "version": "==0.7.5+spec-1.1.0" + }, + { + "name": "toml_edit", + "installer": "cargo", + "version": "==0.23.6" + }, + { + "name": "toml_parser", + "installer": "cargo", + "version": "==1.1.2+spec-1.1.0" + }, + { + "name": "toml_writer", + "installer": "cargo", + "version": "==1.1.1+spec-1.1.0" + }, + { + "name": "tracing", + "installer": "cargo", + "version": "==0.1.44" + }, + { + "name": "tracing-attributes", + "installer": "cargo", + "version": "==0.1.31" + }, + { + "name": "tracing-core", + "installer": "cargo", + "version": "==0.1.36" + }, + { + "name": "tracing-flame", + "installer": "cargo", + "version": "==0.2.0" + }, + { + "name": "tracing-indicatif", + "installer": "cargo", + "version": "==0.3.14" + }, + { + "name": "tracing-log", + "installer": "cargo", + "version": "==0.2.0" + }, + { + "name": "tracing-subscriber", + "installer": "cargo", + "version": "==0.3.23" + }, + { + "name": "tryfn", + "installer": "cargo", + "version": "==1.0.0" + }, + { + "name": "ty", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_combine", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_completion_bench", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_completion_eval", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_ide", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_module_resolver", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_project", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_python_core", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_python_semantic", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_server", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_site_packages", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_static", + "installer": "cargo", + "version": "==0.0.1" + }, + { + "name": "ty_test", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_vendored", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "ty_wasm", + "installer": "cargo", + "version": "==0.0.0" + }, + { + "name": "typed-arena", + "installer": "cargo", + "version": "==2.0.2" + }, + { + "name": "typeid", + "installer": "cargo", + "version": "==1.0.3" + }, + { + "name": "typenum", + "installer": "cargo", + "version": "==1.18.0" + }, + { + "name": "ucd-trie", + "installer": "cargo", + "version": "==0.1.7" + }, + { + "name": "unicode-id", + "installer": "cargo", + "version": "==0.3.6" + }, + { + "name": "unicode-ident", + "installer": "cargo", + "version": "==1.0.24" + }, + { + "name": "unicode-normalization", + "installer": "cargo", + "version": "==0.1.24" + }, + { + "name": "unicode-width", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "unicode-xid", + "installer": "cargo", + "version": "==0.2.6" + }, + { + "name": "unicode_names2", + "installer": "cargo", + "version": "==1.3.0" + }, + { + "name": "unicode_names2_generator", + "installer": "cargo", + "version": "==1.3.0" + }, + { + "name": "unit-prefix", + "installer": "cargo", + "version": "==0.5.1" + }, + { + "name": "unscanny", + "installer": "cargo", + "version": "==0.1.0" + }, + { + "name": "unty", + "installer": "cargo", + "version": "==0.0.4" + }, + { + "name": "url", + "installer": "cargo", + "version": "==2.5.8" + }, + { + "name": "urlencoding", + "installer": "cargo", + "version": "==2.1.3" + }, + { + "name": "utf8-width", + "installer": "cargo", + "version": "==0.1.7" + }, + { + "name": "utf8_iter", + "installer": "cargo", + "version": "==1.0.4" + }, + { + "name": "utf8parse", + "installer": "cargo", + "version": "==0.2.2" + }, + { + "name": "uuid", + "installer": "cargo", + "version": "==1.23.1" + }, + { + "name": "valuable", + "installer": "cargo", + "version": "==0.1.1" + }, + { + "name": "version-ranges", + "installer": "cargo", + "version": "==0.1.1" + }, + { + "name": "version_check", + "installer": "cargo", + "version": "==0.9.5" + }, + { + "name": "virtue", + "installer": "cargo", + "version": "==0.0.18" + }, + { + "name": "vt100", + "installer": "cargo", + "version": "==0.16.2" + }, + { + "name": "vte", + "installer": "cargo", + "version": "==0.14.1" + }, + { + "name": "wait-timeout", + "installer": "cargo", + "version": "==0.2.1" + }, + { + "name": "walkdir", + "installer": "cargo", + "version": "==2.5.0" + }, + { + "name": "wasi", + "installer": "cargo", + "version": "==0.11.1+wasi-snapshot-preview1" + }, + { + "name": "wasip2", + "installer": "cargo", + "version": "==1.0.1+wasi-0.2.4" + }, + { + "name": "wasip3", + "installer": "cargo", + "version": "==0.4.0+wasi-0.3.0-rc-2026-01-06" + }, + { + "name": "wasm-bindgen", + "installer": "cargo", + "version": "==0.2.105" + }, + { + "name": "wasm-bindgen-futures", + "installer": "cargo", + "version": "==0.4.55" + }, + { + "name": "wasm-bindgen-macro", + "installer": "cargo", + "version": "==0.2.105" + }, + { + "name": "wasm-bindgen-macro-support", + "installer": "cargo", + "version": "==0.2.105" + }, + { + "name": "wasm-bindgen-shared", + "installer": "cargo", + "version": "==0.2.105" + }, + { + "name": "wasm-bindgen-test", + "installer": "cargo", + "version": "==0.3.55" + }, + { + "name": "wasm-bindgen-test-macro", + "installer": "cargo", + "version": "==0.3.55" + }, + { + "name": "wasm-encoder", + "installer": "cargo", + "version": "==0.244.0" + }, + { + "name": "wasm-metadata", + "installer": "cargo", + "version": "==0.244.0" + }, + { + "name": "wasmparser", + "installer": "cargo", + "version": "==0.244.0" + }, + { + "name": "web-sys", + "installer": "cargo", + "version": "==0.3.82" + }, + { + "name": "web-time", + "installer": "cargo", + "version": "==1.1.0" + }, + { + "name": "which", + "installer": "cargo", + "version": "==8.0.2" + }, + { + "name": "wild", + "installer": "cargo", + "version": "==2.2.1" + }, + { + "name": "winapi", + "installer": "cargo", + "version": "==0.3.9" + }, + { + "name": "winapi-i686-pc-windows-gnu", + "installer": "cargo", + "version": "==0.4.0" + }, + { + "name": "winapi-util", + "installer": "cargo", + "version": "==0.1.11" + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "installer": "cargo", + "version": "==0.4.0" + }, + { + "name": "windows-core", + "installer": "cargo", + "version": "==0.62.0" + }, + { + "name": "windows-implement", + "installer": "cargo", + "version": "==0.60.0" + }, + { + "name": "windows-interface", + "installer": "cargo", + "version": "==0.59.1" + }, + { + "name": "windows-link", + "installer": "cargo", + "version": "==0.1.3" + }, + { + "name": "windows-result", + "installer": "cargo", + "version": "==0.4.0" + }, + { + "name": "windows-strings", + "installer": "cargo", + "version": "==0.5.0" + }, + { + "name": "windows-sys", + "installer": "cargo", + "version": "==0.52.0" + }, + { + "name": "windows-targets", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_aarch64_gnullvm", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_aarch64_msvc", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_i686_gnu", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_i686_gnullvm", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_i686_msvc", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_x86_64_gnu", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_x86_64_gnullvm", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "windows_x86_64_msvc", + "installer": "cargo", + "version": "==0.52.6" + }, + { + "name": "winnow", + "installer": "cargo", + "version": "==0.7.13" + }, + { + "name": "wit-bindgen", + "installer": "cargo", + "version": "==0.46.0" + }, + { + "name": "wit-bindgen-core", + "installer": "cargo", + "version": "==0.51.0" + }, + { + "name": "wit-bindgen-rust", + "installer": "cargo", + "version": "==0.51.0" + }, + { + "name": "wit-bindgen-rust-macro", + "installer": "cargo", + "version": "==0.51.0" + }, + { + "name": "wit-component", + "installer": "cargo", + "version": "==0.244.0" + }, + { + "name": "wit-parser", + "installer": "cargo", + "version": "==0.244.0" + }, + { + "name": "writeable", + "installer": "cargo", + "version": "==0.6.2" + }, + { + "name": "wyz", + "installer": "cargo", + "version": "==0.5.1" + }, + { + "name": "yansi", + "installer": "cargo", + "version": "==1.0.1" + }, + { + "name": "yoke", + "installer": "cargo", + "version": "==0.8.2" + }, + { + "name": "yoke-derive", + "installer": "cargo", + "version": "==0.8.2" + }, + { + "name": "zerocopy", + "installer": "cargo", + "version": "==0.8.27" + }, + { + "name": "zerocopy-derive", + "installer": "cargo", + "version": "==0.8.27" + }, + { + "name": "zerofrom", + "installer": "cargo", + "version": "==0.1.6" + }, + { + "name": "zerofrom-derive", + "installer": "cargo", + "version": "==0.1.6" + }, + { + "name": "zerotrie", + "installer": "cargo", + "version": "==0.2.4" + }, + { + "name": "zerovec", + "installer": "cargo", + "version": "==0.11.6" + }, + { + "name": "zerovec-derive", + "installer": "cargo", + "version": "==0.11.3" + }, + { + "name": "zip", + "installer": "cargo", + "version": "==0.6.6" + }, + { + "name": "zmij", + "installer": "cargo", + "version": "==1.0.10" + }, + { + "name": "zstd", + "installer": "cargo", + "version": "==0.11.2+zstd.1.5.2" + }, + { + "name": "zstd-safe", + "installer": "cargo", + "version": "==5.0.2+zstd.1.5.2" + }, + { + "name": "zstd-sys", + "installer": "cargo", + "version": "==2.0.16+zstd.1.5.7" + } + ], + "build_backends": [ + "maturin" + ], + "upstream_artifacts": { + "sdist": [ + "https://files.pythonhosted.org/packages/24/21/a7d5c126d5b557715ef81098f3db2fe20f622a039ff2e626af28d674ab80/ruff-0.15.13.tar.gz" + ] + } +} diff --git a/tests/integration/cases/pypi_ruff/test.yaml b/tests/integration/cases/pypi_ruff/test.yaml new file mode 100644 index 000000000..6f6363972 --- /dev/null +++ b/tests/integration/cases/pypi_ruff/test.yaml @@ -0,0 +1,37 @@ +# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. + +description: | + Test buildspec generation for a non-pure wheel that bundles Ruff. + +tags: +- macaron-python-package + +steps: +- name: Run macaron analyze + kind: analyze + options: + command_args: + - -purl + - pkg:pypi/ruff@0.15.13 +- name: Generate the buildspec + kind: gen-build-spec + options: + command_args: + - -purl + - pkg:pypi/ruff@0.15.13 +- name: Compare Buildspec. + kind: compare + options: + kind: default_build_spec + result: output/buildspec/pypi/ruff/macaron.buildspec + expected: expected_default.buildspec +- name: Generate the buildspec + kind: gen-build-spec + expect_fail: true + options: + command_args: + - -purl + - pkg:pypi/ruff@0.15.13 + - --output-format + - dockerfile