Skip to content
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
2 changes: 1 addition & 1 deletion .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Report the PR URL back to the user, and remind them that **merging the PR into `
- `version-check.yml` — the `pyproject.toml` version must match the `release/vX.Y.Z` branch name.
- `changelog-check.yml` — `CHANGELOG.md` must contain a `## [vX.Y.Z] -` entry for the new version.
- `package-check.yml` — `uv.lock` must be in sync with `pyproject.toml` (`uv lock --locked`).
- `tests-check.yml` — the test matrix must pass on every supported Python version (3.10 through 3.14).
- `tests-check.yml` — the test matrix must pass on every supported Python version (3.11 through 3.14).
- `lint-check.yml` — ruff format, ruff lint, pyright, and mypy merge checks across the same Python matrix (the same gates as `make agent-check`).
- `guard-branches.yml` — only `release/vX.Y.Z` branches may target `main`.
- `cla.yml` — the PR author must have signed the Pipelex CLA (maintainers are allow-listed; an external first-time author will be prompted to sign before the PR can merge).
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
env:
VIRTUAL_ENV: ${{ github.workspace }}/.venv

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
# Least privilege: this job runs untrusted PR code and never uses OIDC, so it must not
# be able to mint an id-token. Read-only contents is all the test steps need.
permissions:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [v0.4.0] - 2026-07-06

### Changed

- **Dropped Python 3.10 support (breaking).** The minimum supported Python is now 3.11, matching the `mthds>=0.8.1` base. `requires-python` is now `>=3.11,<3.15`, and the 3.10 leg is removed from the CI lint/test matrices. Deleted the `pipelex_sdk._compat` StrEnum/`Self` backport shim and dropped the `backports.strenum` dependency (and its mypy override) — `StrEnum` now imports directly from the stdlib `enum`. *(Migration: run on Python 3.11 or newer.)*
- Bumped the `mthds` dependency from `>=0.7.1` to `>=0.8.1`.
- Bumped the dev-only `pytest` constraint to `>=9.0.3` (from `>=8.0.0,<9.0.0`) and moved its `pyproject.toml` config from `[tool.pytest.ini_options]` to the newer `[tool.pytest]` table with `minversion = "9.0"`, matching `mthds-python`.

## [v0.3.0] - 2026-07-05

### Changed
Expand Down
8 changes: 3 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ It is the **hosted superset**: the five normative MTHDS Protocol routes (inherit

## Python Version Compatibility

- Target Python 3.10+. Never use features introduced after Python 3.10 without a compatibility fallback.
- Target Python 3.11+. Never use features introduced after Python 3.11 without a compatibility fallback.
- `StrEnum` (`from enum import StrEnum`), `Self` (`from typing import Self`), `datetime.UTC`, `tomllib`, and `ExceptionGroup` / `except*` are all available at 3.11 — use them directly, no shim.
- Common pitfalls:
- `datetime.UTC` was added in Python 3.11. Use `datetime.timezone.utc` instead.
- `StrEnum` was added in Python 3.11. Import it from the local `pipelex_sdk._compat` shim.
- `type` statement (PEP 695) was added in Python 3.12. Use `TypeAlias` from `typing` instead.
- `ExceptionGroup` / `except*` was added in Python 3.11. Avoid unless using the `exceptiongroup` backport.

## Variables, Loops and Indexes

Expand All @@ -48,7 +46,7 @@ It is the **hosted superset**: the five normative MTHDS Protocol routes (inherit

## Enums

- When defining enums related to string values, always inherit from `StrEnum` (from `pipelex_sdk._compat`).
- When defining enums related to string values, always inherit from `StrEnum` (`from enum import StrEnum`).
- When you need the enum value as a string, don't use `str(enum_var)` or `enum_var.value`, just use `enum_var` itself — that is the point of using StrEnum.
- Never test equality to an enum value: use match/case, even to single out 1 case out of 10 cases. To avoid heavy match/case code in awkward places, add `@property` methods to the enum class such as `is_foobar()`. This prevents bugs: when new enum values are added the linter will complain about non-exhaustive matches. Use the `|` operator to group cases.
- Match/case constructs over enums should always be exhaustive. NEVER add a default `case _: ...`.
Expand Down
2 changes: 1 addition & 1 deletion docs/HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ Note: `mthds-python` does **not** currently carry the `/v1/build/*` helpers (the
- Port target / philosophy reference: `pipelex-sdk-js/` (`PipelexApiClient`, `product-models.ts`).
- Protocol base to depend on: `mthds-python/` (`MthdsAPIClient`, `protocol/`).
- Normative boundary: `mthds/docs/spec/protocol.md` + `openapi/mthds-protocol.openapi.yaml`.
- Python coding standards: `mthds-python/CLAUDE.md` (target 3.10+, Pydantic v2, StrEnum rules, etc.) — apply the same here.
- Python coding standards: `mthds-python/CLAUDE.md` (target 3.11+, Pydantic v2, StrEnum rules, etc.) — apply the same here.
2 changes: 1 addition & 1 deletion docs/ci-cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The GitHub Actions workflows under `.github/workflows/` mirror the `mthds-python

| Workflow | Trigger | What it enforces |
| --- | --- | --- |
| `lint-check.yml` | `pull_request` | Runs `make merge-check-ruff-format`, `merge-check-ruff-lint`, `merge-check-pyright`, `merge-check-mypy` across the full Python matrix (3.10–3.14). A `lint-all` aggregator is the single required status check. |
| `lint-check.yml` | `pull_request` | Runs `make merge-check-ruff-format`, `merge-check-ruff-lint`, `merge-check-pyright`, `merge-check-mypy` across the full Python matrix (3.11–3.14). A `lint-all` aggregator is the single required status check. |
| `tests-check.yml` | `pull_request` | Runs `make gha-tests` across the same matrix; `tests-all` aggregates. Concurrency-cancels superseded runs on the same branch. |
| `package-check.yml` | `pull_request` | `uv lock --locked` must leave `uv.lock` unchanged. |
| `changelog-check.yml` | `pull_request → main` | `CHANGELOG.md` must contain a `## [v<version>] - …` entry matching `pyproject.toml`'s `version`. |
Expand Down
10 changes: 0 additions & 10 deletions pipelex_sdk/_compat.py

This file was deleted.

2 changes: 1 addition & 1 deletion pipelex_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ async def wait_for_result(self, run_id: str, options: WaitForResultOptions | Non

try:
state = await asyncio.wait_for(self.get_run_result(run_id), timeout=remaining)
except asyncio.TimeoutError as exc: # noqa: UP041 — on Python 3.10 asyncio.TimeoutError is its own class, distinct from builtin TimeoutError.
except TimeoutError as exc:
raise RunTimeoutError(_timeout_message(run_id, opts.timeout_seconds), run_id=run_id, timeout_seconds=opts.timeout_seconds) from exc

if isinstance(state, RunResultCompleted):
Expand Down
2 changes: 1 addition & 1 deletion pipelex_sdk/product_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@

from __future__ import annotations

from enum import StrEnum
from typing import Any

from pydantic import BaseModel, ConfigDict

from pipelex_sdk._compat import StrEnum
from pipelex_sdk.runs import RunStatus

# ── User profile (`/v1/me`) ─────────────────────────────────────────────
Expand Down
3 changes: 1 addition & 2 deletions pipelex_sdk/runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@
from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from typing import TYPE_CHECKING, Annotated, Any, Literal, TypeAlias

from pydantic import BaseModel, ConfigDict, Field

from pipelex_sdk._compat import StrEnum

if TYPE_CHECKING:
from collections.abc import Callable

Expand Down
2 changes: 1 addition & 1 deletion pipelex_sdk/validation_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@

from __future__ import annotations

from enum import StrEnum
from typing import Annotated, Any, TypeAlias

from mthds.protocol.models import InvalidValidationReport, ValidationDiagnostic, ValidationReport
from pydantic import BaseModel, ConfigDict, Field, TypeAdapter

from pipelex_sdk._compat import StrEnum
from pipelex_sdk._pydantic_utils import empty_list_factory_of


Expand Down
22 changes: 7 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
[project]
name = "pipelex-sdk"
version = "0.3.0"
version = "0.4.0"
description = "The Python client for the Pipelex hosted API — the MTHDS Protocol surface plus the durable run lifecycle and the Pipelex product surface, built on the `mthds` protocol base."
authors = [{ name = "Evotis S.A.S.", email = "oss@pipelex.com" }]
maintainers = [{ name = "Pipelex staff", email = "oss@pipelex.com" }]
license = "MIT"
readme = "README.md"
requires-python = ">=3.10,<3.15"
requires-python = ">=3.11,<3.15"
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Expand All @@ -19,20 +18,19 @@ classifiers = [
]

dependencies = [
"mthds>=0.7.1",
"mthds>=0.8.1",
"pydantic>=2.10.6,<3.0.0",
"backports.strenum>=1.3.0 ; python_version < '3.11'",
"typing-extensions>=4.0.0",
"httpx>=0.23.0,<1.0.0",
]

[project.optional-dependencies]
dev = [
"mypy==1.19.1",
"pyright==1.1.408",
"pyright==1.1.411",
"pylint==4.0.4",
"ruff==0.14.13",
"pytest>=8.0.0,<9.0.0",
"pytest>=9.0.3",
"pytest-mock>=3.12.0,<4.0.0",
"pytest-sugar>=1.0.0",
]
Expand All @@ -47,7 +45,8 @@ Repository = "https://github.com/Pipelex/pipelex-sdk-python"
Documentation = "https://github.com/Pipelex/pipelex-sdk-python"
Changelog = "https://github.com/Pipelex/pipelex-sdk-python/blob/main/CHANGELOG.md"

[tool.pytest.ini_options]
[tool.pytest]
minversion = "9.0"
testpaths = ["tests"]
pythonpath = ["."]

Expand All @@ -61,12 +60,6 @@ python_version = "3.11"
warn_return_any = true
warn_unused_configs = true

[[tool.mypy.overrides]]
ignore_missing_imports = true
module = [
"backports.strenum",
]

[tool.pyright]
pythonVersion = "3.11"
include = ["pipelex_sdk", "tests"]
Expand Down Expand Up @@ -312,7 +305,6 @@ ignore = [
"TRY300", # Consider moving this statement to an `else` block
"UP035", # `typing.List` is deprecated, use `list` instead
"RET503", # Missing explicit `return` at the end of function able to return non-`None` value
"UP017", # Use `datetime.UTC` alias - but UTC only available in Python 3.11+
]

[tool.ruff.lint.flake8-type-checking]
Expand Down
Loading
Loading