Skip to content
Open
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
6 changes: 5 additions & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ jobs:
restore-keys: |
${{ runner.os }}-pip

- name: Build, verify, and upload to PyPI
- name: Validate models against live API specs
run: |
pip install --upgrade nox
nox -s validate_models

- name: Build, verify, and upload to PyPI
run: |
nox -s build publish_pypi
env:
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
18 changes: 18 additions & 0 deletions docs/get-started/upgrading-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,22 @@ should be preferred to the use of Planet API keys.
* Deprecated `planet.subscription_request.clip_tool()` method for defining custom clip AOIs with requests to create subscriptions. Subscriptions API no longer supports custom clip AOIs; instead users can opt-in to clip to their subscription source geometry by including kwarg `clip_to_source=True` when constructing requests via `planet.subscription_request.build_request()`. See [PR #1169](https://github.com/planetlabs/planet-client-python/pull/1169) for implementation details.
* Renamed `planet.cli.subscriptions.request_pv()` to `planet.cli.subscriptions.request_source()`, and removed `var_type` positional argument from the signature. This change, in effect renames the CLI argument `planet subscriptions request-pv` to `planet subscriptions request-source`. Also renamed `planet.subscription_request.planetary_variable_source()` to `planet.subscription_request.subscription_source()`. Source type positional arguments are removed from these methods in favor of `source_id`. See [PR #1170](https://github.com/planetlabs/planet-client-python/pull/1170) for implementation details.

* The Destinations API methods on `DestinationsClient` and `DestinationsAPI` now return Pydantic models generated from Planet's OpenAPI spec instead of plain dictionaries. `list_destinations()` returns a `DestinationsResponse`; `get_destination()`, `create_destination()`, `patch_destination()`, `set_default_destination()` and `get_default_destination()` return a `Destination`. Attribute access replaces subscript access:

```python
# Version 2
resp = pl.destinations.list_destinations()
for d in resp["destinations"]:
print(d["id"])

# Version 3
resp = pl.destinations.list_destinations()
for d in resp.destinations:
print(d.id)
```

Call `.model_dump(mode="json", by_alias=True)` on any of these to recover a
JSON-compatible dictionary. The models allow unknown fields, so destinations
returned by a newer version of the API still parse.

----
66 changes: 63 additions & 3 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
import shutil
import sys

import nox

Expand All @@ -9,6 +10,8 @@
nox.options.sessions = ['lint', 'analyze', 'test', 'coverage', 'docs']

source_files = ("planet", "examples", "tests", "setup.py", "noxfile.py")
# Generated code — excluded from linting and formatting checks
generated_dirs = ("planet/api_models", )

BUILD_DIRS = ['build', 'dist']

Expand All @@ -17,7 +20,11 @@
def analyze(session):
session.install(".[lint]")

session.run("mypy", "--ignore-missing", "planet")
session.run("mypy",
"--ignore-missing",
"--exclude",
"|".join(generated_dirs),
"planet")


@nox.session
Expand Down Expand Up @@ -63,8 +70,13 @@ def test(session):
def lint(session):
session.install("-e", ".[lint]")

session.run("flake8", *source_files)
session.run('yapf', '--diff', '-r', *source_files)
session.run("flake8",
f"--exclude={','.join(generated_dirs)}",
*source_files)
# yapf --exclude is a repeatable flag taking one fnmatch pattern; a bare
# directory name matches nothing, so the trailing /* is required.
yapf_excludes = [f"--exclude={d}/*" for d in generated_dirs]
session.run('yapf', '--diff', '-r', *yapf_excludes, *source_files)


@nox.session
Expand Down Expand Up @@ -114,6 +126,54 @@ def examples(session):
session.run('pytest', '--no-cov', 'examples/', '-s', *options)


@nox.session
def generate_models(session):
"""Re-generate Pydantic models for the Destinations API in planet/api_models/.

Uses the same pinned datamodel-code-generator as `nox -s validate_models`,
so the committed output is byte-identical to what the drift check
regenerates. Do not reformat the result.

Run after a known API spec change to refresh the models, then re-run
validate_models to confirm compatibility.
"""
session.install("-e", ".[validate_models]")

sys.path.insert(0, str(Path(__file__).parent / "tests" / "drift"))
import codegen_config

for name, url in codegen_config.SPECS.items():
output = Path("planet/api_models") / f"{name}.py"
session.run(*codegen_config.codegen_argv(url, output))


@nox.session
def validate_models(session):
"""Validate committed Pydantic models match the live API specs.

Fetches live OpenAPI specs from Planet's API and compares against committed
snapshots. Fails if any spec has changed. No API key required.

To refresh snapshots after a deliberate API change, run:
nox -s generate_models
Intended as a pre-release gate; not included in the default nox session list.
"""
session.install("-e", ".[validate_models]")
session.run(
"pytest",
"tests/drift/validate_models.py",
# Stop conftest discovery below tests/, whose conftest imports the
# full test-suite dependencies that this extra deliberately omits.
"--confcutdir=tests/drift",
# setup.cfg addopts injects --cov, but this extra deliberately omits
# pytest-cov; clear addopts rather than pull in the full test deps.
"-o",
"addopts=",
"-v",
"--tb=short",
)


@nox.session
def build(session):
"""Build package"""
Expand Down
Empty file added planet/api_models/__init__.py
Empty file.
Loading
Loading