Skip to content

Commit

Permalink
Enabling version bumps for path dependencies when using `UvPyprojectH…
Browse files Browse the repository at this point in the history
…andler` (#303)

* Adding `set_path_dependencies_to_version` for `UvPyprojectHandler`

* Adding TODO

* fmt

* mute mypy complaints

* changelog entry

* Update kraken-build/src/kraken/std/python/buildsystem/uv.py

Co-authored-by: Scott Stevenson <[email protected]>

* adding check for "sources" to exist before pop

* Updating pyproject.toml

* Remove default value from relative dependecy

* Fallback from removing `tool.uv.sources`

* Adding test

* Using `formatted_project_name = project_name.replace("-", "_")`

* Removing TODO related to test

* Add a dedicated uv project to test relative import build

* Update examples/uv-project-relative-import/.kraken.py

Co-authored-by: Antoine Broyelle <[email protected]>

* trimming test

* removing custom index

* Update kraken-build/src/kraken/std/python/buildsystem/uv.py

Co-authored-by: Scott Stevenson <[email protected]>

* Changing version bump

---------

Co-authored-by: Scott Stevenson <[email protected]>
Co-authored-by: Antoine Broyelle <[email protected]>
  • Loading branch information
3 people authored Jan 28, 2025
1 parent bba14b5 commit ae4fad4
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changelog/_unreleased.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,9 @@ id = "4d8e2872-d32f-4747-b2d6-aa5c1cb4ec75"
type = "fix"
description = "Rename deprecated tool.poetry.dev-dependencies section"
author = "[email protected]"

[[entries]]
id = "e3edc5a7-39ec-4e05-89c8-d06bf8cb0ee8"
type = "feature"
description = "Enabling `UvPyprojectHandler` to properly bump versions for path dependencies"
author = "[email protected]"
3 changes: 3 additions & 0 deletions examples/uv-project-relative-import/.kraken.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from kraken.std import python

python.install()
16 changes: 16 additions & 0 deletions examples/uv-project-relative-import/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[project]
name = "uv-project-relative-import"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.10"
dependencies = [
"tqdm>=4.66.5",
"uv-project",
]

[tool.uv.sources]
uv-project = { path = "../uv-project", editable = true }

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from uv_project import hello


def main() -> None:
hello()
52 changes: 52 additions & 0 deletions examples/uv-project-relative-import/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions kraken-build/src/kraken/std/python/buildsystem/uv.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,50 @@ def get_packages(self) -> list[PyprojectHandler.Package]:
package_name = self.raw["project"]["name"]
return [self.Package(include=package_name.replace("-", "_").replace(".", "_"))]

def _get_sources(self) -> dict[str, dict[str, Any]]:
return self.raw.get("tool", {}).get("uv", {}).get("sources", {}) # type: ignore [no-any-return]

def _get_dependencies(self) -> list[str]:
"""Fetches dependencies following [PEP631](https://peps.python.org/pep-0631/) format."""
return self.raw.get("project", {}).get("dependencies", []) # type: ignore [no-any-return]

def _get_dependency_groups(self) -> dict[str, list[str]]:
return self.raw.get("project", {}).get("dependency-groups", {}) # type: ignore [no-any-return]

def _get_optional_dependencies(self) -> dict[str, list[str]]:
return self.raw.get("project", {}).get("optional-dependencies", {}) # type: ignore [no-any-return]

def set_path_dependencies_to_version(self, version: str) -> None:
"""
Walks through the `[project.dependencies]`, `[project.dependency-groups]`
and `[project.optional-dependencies]` groups to replace all path and workspace sources
with proper index dependencies using the specified `version` string.
Based on [PEP631](https://peps.python.org/pep-0631/) for dependencies and optional-dependencies,
and [PEP735](https://peps.python.org/pep-0735/) for dependency-groups.
"""

sources = self._get_sources()
dependencies = self._get_dependencies()
dependency_groups = self._get_dependency_groups()
optional_dependencies = self._get_optional_dependencies()
sources_to_rm: list[str] = []
for source, params in sources.items():
# TODO(Ghelfi): Check if entry with `path` is within the current project
if "workspace" in params or "path" in params:
sources_to_rm.append(source)
if (index := dependencies.index(source)) is not None:
dependencies[index] = f"{source}=={version}"
for key, deps in dependency_groups.items():
if (index := deps.index(source)) is not None:
dependency_groups[key][index] = f"{source}=={version}"
for key, deps in optional_dependencies.items():
if (index := deps.index(source)) is not None:
optional_dependencies[key][index] = f"{source}=={version}"

for elem in sources_to_rm:
sources.pop(elem)


class UvPythonBuildSystem(PythonBuildSystem):
"""
Expand Down
28 changes: 28 additions & 0 deletions kraken-build/tests/kraken_std/integration/python/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,34 @@ def test__python_project_upgrade_python_version_string(
assert build_as_version == tomli.loads(conf_file.read().decode("UTF-8"))["tool"]["poetry"]["version"]


@unittest.mock.patch.dict(os.environ, {})
def test__python_project__upgrade_relative_import_version(
kraken_ctx: Context,
kraken_project: Project,
) -> None:
tempdir = kraken_project.directory

build_as_version = "0.1.1"
project_name = "uv-project-relative-import"
original_dir = example_dir(project_name)
project_dist = kraken_project.build_directory / "python-dist"

# Copy the projects to the temporary directory.
shutil.copytree(original_dir, tempdir, dirs_exist_ok=True)
python.build(as_version=build_as_version, project=kraken_project)
kraken_ctx.execute([":build"])

# Check if generated files are named following proper version.
formatted_project_name = project_name.replace("-", "_")
assert Path(project_dist / f"{formatted_project_name}-{build_as_version}.tar.gz").is_file()
assert Path(project_dist / f"{formatted_project_name}-{build_as_version}-py3-none-any.whl").is_file()
with tarfile.open(project_dist / f"{formatted_project_name}-{build_as_version}.tar.gz", "r:gz") as tar:
# Check if generated files store proper version.
metadata_file = tar.extractfile(f"{formatted_project_name}-{build_as_version}/PKG-INFO")
assert metadata_file is not None, ".tar.gz file does not contain an 'PKG-INFO'"
assert f"Requires-Dist: uv-project=={build_as_version}" in metadata_file.read().decode("UTF-8")


M = TypeVar("M", PdmPyprojectHandler, PoetryPyprojectHandler)


Expand Down

0 comments on commit ae4fad4

Please sign in to comment.