Skip to content

feat: Add --meta uv for generating astral-sh/uv compatible packages. #1286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ htmlcov/
# Generated end to end test data
my-test-api-client/
custom-e2e/
3-1-features-client
3-1-features-client
tests/tmp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "A client library for accessing My Test API"
authors = []
readme = "README.md"
packages = [
{include = "my_test_api_client"},
{ include = "my_test_api_client" },
]
include = ["CHANGELOG.md", "my_test_api_client/py.typed"]


[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
Expand Down
3 changes: 1 addition & 2 deletions end_to_end_tests/golden-record/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "A client library for accessing My Test API"
authors = []
readme = "README.md"
packages = [
{include = "my_test_api_client"},
{ include = "my_test_api_client" },
]
include = ["CHANGELOG.md", "my_test_api_client/py.typed"]


[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
Expand Down
3 changes: 1 addition & 2 deletions end_to_end_tests/literal-enums-golden-record/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "A client library for accessing My Enum API"
authors = []
readme = "README.md"
packages = [
{include = "my_enum_api_client"},
{ include = "my_enum_api_client" },
]
include = ["CHANGELOG.md", "my_enum_api_client/py.typed"]


[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
Expand Down
3 changes: 1 addition & 2 deletions end_to_end_tests/metadata_snapshots/poetry.pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "A client library for accessing Test 3.1 Features"
authors = []
readme = "README.md"
packages = [
{include = "test_3_1_features_client"},
{ include = "test_3_1_features_client" },
]
include = ["CHANGELOG.md", "test_3_1_features_client/py.typed"]


[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
Expand Down
36 changes: 36 additions & 0 deletions end_to_end_tests/metadata_snapshots/uv.pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[project]
name = "test-3-1-features-client"
version = "0.1.0"
description = "A client library for accessing Test 3.1 Features"
authors = []
requires-python = "~=3.9"
readme = "README.md"
dependencies = [
"httpx>=0.23.0,<0.29.0",
"attrs>=22.2.0",
"python-dateutil>=2.8.0,<3",
]

[tool.hatch.build.targets.sdist]
include = [
"test_3_1_features_client",
"CHANGELOG.md",
"test_3_1_features_client/py.typed",
]

[tool.hatch.build.targets.wheel]
include = [
"test_3_1_features_client",
"CHANGELOG.md",
"test_3_1_features_client/py.typed",
]

[build-system]
requires = ["hatchling"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we use the official uv_build backend instead, which is the default for projects created with uv now?

https://docs.astral.sh/uv/concepts/build-backend/#choosing-a-build-backend

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point 🙌 It became the default 4 days ago in uv==0.8.0.

I offer this PR #1290 to resolve that. 🙏

build-backend = "hatchling.build"

[tool.ruff]
line-length = 120

[tool.ruff.lint]
select = ["F", "I", "UP"]
2 changes: 1 addition & 1 deletion end_to_end_tests/regen_golden_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def regen_metadata_snapshots():
output_path = Path.cwd() / "test-3-1-features-client"
snapshots_dir = Path(__file__).parent / "metadata_snapshots"

for (meta, file, rename_to) in (("setup", "setup.py", "setup.py"), ("pdm", "pyproject.toml", "pdm.pyproject.toml"), ("poetry", "pyproject.toml", "poetry.pyproject.toml")):
for (meta, file, rename_to) in (("setup", "setup.py", "setup.py"), ("pdm", "pyproject.toml", "pdm.pyproject.toml"), ("poetry", "pyproject.toml", "poetry.pyproject.toml"), ("uv", "pyproject.toml", "uv.pyproject.toml")):
_regenerate(
spec_file_name="3.1_specific.openapi.yaml",
output_dir="test-3-1-features-client",
Expand Down
3 changes: 1 addition & 2 deletions end_to_end_tests/test-3-1-golden-record/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "A client library for accessing Test 3.1 Features"
authors = []
readme = "README.md"
packages = [
{include = "test_3_1_features_client"},
{ include = "test_3_1_features_client" },
]
include = ["CHANGELOG.md", "test_3_1_features_client/py.typed"]


[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
Expand Down
3 changes: 2 additions & 1 deletion end_to_end_tests/test_end_to_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def test_literal_enums_end_to_end():
("setup", "setup.py", "setup.py"),
("pdm", "pyproject.toml", "pdm.pyproject.toml"),
("poetry", "pyproject.toml", "poetry.pyproject.toml"),
("uv", "pyproject.toml", "uv.pyproject.toml"),
)
)
def test_meta(meta: str, generated_file: Optional[str], expected_file: Optional[str]):
Expand Down Expand Up @@ -284,7 +285,7 @@ def test_update_integration_tests():
import mypy.api

out, err, status = mypy.api.run([str(temp_dir), "--strict"])
assert status == 0, f"Type checking client failed: {out}"
assert status == 0, f"Type checking client failed: {out=} {err=}"

finally:
shutil.rmtree(temp_dir)
2 changes: 1 addition & 1 deletion openapi_python_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def _build_metadata(self) -> None:
readme = self.project_dir / "README.md"
readme_template = self.env.get_template("README.md.jinja")
readme.write_text(
readme_template.render(poetry=self.config.meta_type == MetaType.POETRY),
readme_template.render(meta=self.config.meta_type),
encoding=self.config.file_encoding,
)

Expand Down
1 change: 1 addition & 0 deletions openapi_python_client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class MetaType(str, Enum):
POETRY = "poetry"
SETUP = "setup"
PDM = "pdm"
UV = "uv"


class ConfigFile(BaseModel):
Expand Down
15 changes: 14 additions & 1 deletion openapi_python_client/templates/README.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ client = Client(
client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030"))
```

{% if poetry %}
{% if meta == "poetry" %}
## Building / publishing this package
This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics:
1. Update the metadata in pyproject.toml (e.g. authors, version)
Expand All @@ -123,4 +123,17 @@ If you want to install this client into another project without publishing it (e
1. If that project is not using Poetry:
1. Build a wheel with `poetry build -f wheel`
1. Install that wheel from the other project `pip install <path-to-wheel>`
{% elif meta == 'uv' %}
## Building / publishing this package
This project uses [uv](https://github.com/astral-sh/uv) to manage dependencies and packaging. Here are the basics:
1. Update the metadata in `pyproject.toml` (e.g. authors, version).
2. If you're using a private repository: https://docs.astral.sh/uv/guides/integration/alternative-indexes/
3. Build a distribution with `uv build`, builds `sdist` and `wheel` by default.
1. Publish the client with `uv publish`, see documentation for publishing to private indexes.

If you want to install this client into another project without publishing it (e.g. for development) then:
1. If that project **is using uv**, you can simply do `uv add <path-to-this-client>` from that project
1. If that project is not using uv:
1. Build a wheel with `uv build --wheel`.
1. Install that wheel from the other project `pip install <path-to-wheel>`.
{% endif %}
52 changes: 6 additions & 46 deletions openapi_python_client/templates/pyproject.toml.jinja
Original file line number Diff line number Diff line change
@@ -1,49 +1,9 @@
{% set poetry = meta == "poetry" %}
{% set pdm = meta == "pdm" %}
{% if poetry or pdm %}
{% if poetry %}[tool.poetry]
{% elif pdm %}[project]
{% if meta == "poetry" %}
{% include "pyproject_poetry.toml.jinja" %}
{% elif meta == "pdm" %}
{% include "pyproject_pdm.toml.jinja" %}
{% elif meta == "uv" %}
{% include "pyproject_uv.toml.jinja" %}
{% endif %}
name = "{{ project_name }}"
version = "{{ package_version }}"
description = "{{ package_description }}"
authors = []
readme = "README.md"
{% if pdm %}requires-python = ">=3.9,<4.0"{% endif %}
{% if poetry %}
packages = [
{include = "{{ package_name }}"},
]
include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]
{% endif %}

{% if pdm %}
dependencies = [
"httpx>=0.23.0,<0.29.0",
"attrs>=22.2.0",
"python-dateutil>=2.8.0",
]

[tool.pdm]
distribution = true
{% endif %}
{% if poetry %}

[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
attrs = ">=22.2.0"
python-dateutil = "^2.8.0"
{% endif %}

[build-system]
{% if poetry %}
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
{% elif pdm %}
requires = ["pdm-backend"]
build-backend = "pdm.backend"
{% endif %}
{% endif %}{# poetry or pdm #}

{% include "pyproject_ruff.toml.jinja" %}
19 changes: 19 additions & 0 deletions openapi_python_client/templates/pyproject_pdm.toml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[project]
name = "{{ project_name }}"
version = "{{ package_version }}"
description = "{{ package_description }}"
authors = []
readme = "README.md"
requires-python = ">=3.9,<4.0"
dependencies = [
"httpx>=0.23.0,<0.29.0",
"attrs>=22.2.0",
"python-dateutil>=2.8.0",
]

[tool.pdm]
distribution = true

[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
20 changes: 20 additions & 0 deletions openapi_python_client/templates/pyproject_poetry.toml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[tool.poetry]
name = "{{ project_name }}"
version = "{{ package_version }}"
description = "{{ package_description }}"
authors = []
readme = "README.md"
packages = [
{ include = "{{ package_name }}" },
]
include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]

[tool.poetry.dependencies]
python = "^3.9"
httpx = ">=0.23.0,<0.29.0"
attrs = ">=22.2.0"
python-dateutil = "^2.8.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
30 changes: 30 additions & 0 deletions openapi_python_client/templates/pyproject_uv.toml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[project]
name = "{{ project_name }}"
version = "{{ package_version }}"
description = "{{ package_description }}"
authors = []
requires-python = "~=3.9"
readme = "README.md"
dependencies = [
"httpx>=0.23.0,<0.29.0",
"attrs>=22.2.0",
"python-dateutil>=2.8.0,<3",
]

[tool.hatch.build.targets.sdist]
include = [
"{{ package_name }}",
"CHANGELOG.md",
"{{ package_name }}/py.typed",
]

[tool.hatch.build.targets.wheel]
include = [
"{{ package_name }}",
"CHANGELOG.md",
"{{ package_name }}/py.typed",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Loading