diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caf7479..aa8f256 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15'] steps: - uses: actions/checkout@v6.0.2 @@ -33,7 +33,7 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v6.0.1 - if: matrix.python-version == '3.14' + if: matrix.python-version == '3.15' with: files: ./coverage.xml flags: unittests diff --git a/.github/workflows/publish-schema.yml b/.github/workflows/publish-schema.yml index c19f763..5af4c4b 100644 --- a/.github/workflows/publish-schema.yml +++ b/.github/workflows/publish-schema.yml @@ -36,23 +36,23 @@ jobs: uses: astral-sh/setup-uv@v8.1.0 - name: Set up Python - run: uv python install 3.12 + run: uv python install 3.14 - name: Validate schema JSON run: python -m json.tool docuchango/templates/docs-project.schema.json > /dev/null - name: Generate security audit report run: | - uv export --python 3.12 --all-extras --no-emit-project --format requirements-txt --no-hashes --output-file requirements-audit.txt + uv export --python 3.14 --all-extras --no-emit-project --format requirements-txt --no-hashes --output-file requirements-audit.txt set +e - uv tool run --python 3.12 pip-audit --requirement requirements-audit.txt --no-deps --disable-pip --format json --output security-report.json + uv tool run --python 3.14 pip-audit --requirement requirements-audit.txt --no-deps --disable-pip --format json --output security-report.json audit_status=$? set -e printf '%s\n' "$audit_status" > security-audit-exit-code.txt if [ ! -s security-report.json ]; then printf '{"dependencies": [], "audit_error": "pip-audit did not produce a report", "audit_exit_code": %s}\n' "$audit_status" > security-report.json else - uv run --python 3.12 python - <<'PY' + uv run --python 3.14 python - <<'PY' import json from pathlib import Path @@ -64,7 +64,7 @@ jobs: fi - name: Build static site - run: uv run --python 3.12 python scripts/build_static_site.py + run: uv run --python 3.14 python scripts/build_static_site.py - name: Validate generated frontmatter schemas run: python -m json.tool site/schemas/frontmatter/adr.schema.json > /dev/null diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 646390f..5357419 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,7 +41,7 @@ jobs: version: "0.11.16" - name: Set up Python - run: uv python install 3.12 + run: uv python install 3.14 - name: Build package run: uv build @@ -136,7 +136,7 @@ jobs: env: PYAPP_PROJECT_NAME: docuchango PYAPP_EXEC_MODULE: docuchango.cli:main - PYAPP_PYTHON_VERSION: "3.12" + PYAPP_PYTHON_VERSION: "3.14" run: | # Strip 'v' prefix from version tag VERSION="${{ github.ref_name }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9608310..ae6f517 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: uses: astral-sh/setup-uv@v8.1.0 - name: Set up Python - run: uv python install 3.12 + run: uv python install 3.14 - name: Python Semantic Release id: release diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 0b86bbf..c5a04b4 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -191,7 +191,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: '3.14' - name: Install uv run: pip install uv diff --git a/README.md b/README.md index 3a4482b..34df605 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PyPI version](https://badge.fury.io/py/docuchango.svg)](https://pypi.org/project/docuchango/) [![CI](https://github.com/jrepp/docuchango/workflows/CI/badge.svg)](https://github.com/jrepp/docuchango/actions) [![codecov](https://codecov.io/gh/jrepp/docuchango/branch/main/graph/badge.svg)](https://codecov.io/gh/jrepp/docuchango) -[![Python Version](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/downloads/) +[![Python Version](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14%20%7C%203.15-blue)](https://www.python.org/downloads/) [![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0) [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff) @@ -300,7 +300,7 @@ pytest -v # Verbose output # • 628 passing tests (with textstat installed) # • 569 core tests + 59 readability tests # • Zero flaky or xfail tests -# • Full Python 3.10-3.14 compatibility +# • Full Python 3.10-3.15 compatibility # • Comprehensive edge case coverage (frontmatter, links, timestamps, bulk updates) # Lint diff --git a/docs-cms/prd/prd-001-validation-framework.md b/docs-cms/prd/prd-001-validation-framework.md index 325e524..35f103a 100644 --- a/docs-cms/prd/prd-001-validation-framework.md +++ b/docs-cms/prd/prd-001-validation-framework.md @@ -154,7 +154,7 @@ docuchango validate **Testing:** - 61 tests covering validation, fixing, and schemas -- Runs in CI on Python 3.10-3.14 +- Runs in CI on Python 3.10-3.15 ## Why Docuchango? diff --git a/docuchango/fixes/timestamps.py b/docuchango/fixes/timestamps.py index 5406bb6..d7229b8 100644 --- a/docuchango/fixes/timestamps.py +++ b/docuchango/fixes/timestamps.py @@ -45,7 +45,7 @@ def get_git_dates(file_path: Path) -> tuple[str | None, str | None]: return None, None first_commit = commits[0] - # Replace 'Z' with '+00:00' for Python 3.10 compatibility (Python 3.11+ handles 'Z' natively) + # Normalize UTC suffixes before converting to UTC. first_commit = first_commit.replace("Z", "+00:00") # Convert to UTC and format as ISO 8601 datetime created_dt = datetime.fromisoformat(first_commit).astimezone(timezone.utc) @@ -63,7 +63,7 @@ def get_git_dates(file_path: Path) -> tuple[str | None, str | None]: if not last_commit: return created_datetime, created_datetime - # Replace 'Z' with '+00:00' for Python 3.10 compatibility (Python 3.11+ handles 'Z' natively) + # Normalize UTC suffixes before converting to UTC. last_commit = last_commit.replace("Z", "+00:00") # Convert to UTC and format as ISO 8601 datetime updated_dt = datetime.fromisoformat(last_commit).astimezone(timezone.utc) diff --git a/docuchango/schemas.py b/docuchango/schemas.py index 90d4c02..78c08a3 100644 --- a/docuchango/schemas.py +++ b/docuchango/schemas.py @@ -4,14 +4,34 @@ These schemas enforce consistent metadata across ADRs, RFCs, and Memos. """ -from __future__ import annotations - import datetime +import inspect import re +import typing +from collections.abc import Callable from importlib.metadata import PackageNotFoundError, version -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator +from typing import Any, Literal, cast + +_eval_type_candidate = getattr(typing, "_eval_type", None) +_eval_type_parameters = inspect.signature(_eval_type_candidate).parameters if _eval_type_candidate is not None else {} +if "type_params" in _eval_type_parameters and "prefer_fwd_module" not in _eval_type_parameters: + _eval_type = cast(Callable[..., Any], _eval_type_candidate) + + def _eval_type_compat( + t: Any, + globalns: dict[str, Any] | None, + localns: dict[str, Any] | None, + type_params: Any = None, + *, + prefer_fwd_module: bool = False, + **kwargs: Any, + ) -> Any: + _ = prefer_fwd_module + return _eval_type(t, globalns, localns, type_params, **kwargs) + + typing._eval_type = _eval_type_compat # type: ignore[attr-defined] + +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator # noqa: E402 try: CURRENT_DOCUCHANGO_VERSION = version("docuchango") diff --git a/pyproject.toml b/pyproject.toml index d052108..1eb53f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "docuchango" version = "1.18.1" description = "Docusaurus validation and repair framework for opinionated micro-CMS documentation, designed for human-agent collaboration workflows" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.10,<3.16" authors = [ { name = "Jacob Repp", email = "jacobrepp@gmail.com" } ] @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Topic :: Documentation", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Quality Assurance", diff --git a/uv.lock b/uv.lock index 27904d4..176e754 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.10" +requires-python = ">=3.10, <3.16" resolution-markers = [ "python_full_version >= '3.15'", "python_full_version < '3.15'",