diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 834684c1..220c0901 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,6 +37,15 @@ jobs: - "3.12" - "3.13" - "3.14" + pydantic-version: + - "v2" + include: + - python-version: "3.8" + pydantic-version: "v1" + - python-version: "3.9" + pydantic-version: "v1" + - python-version: "3.10" + pydantic-version: "v1" fail-fast: false steps: - name: Dump GitHub context @@ -64,18 +73,21 @@ jobs: limit-access-to-actor: true - name: Install Dependencies run: uv pip install -r requirements-tests.txt + - name: Install Pydantic v1 + if: matrix.pydantic-version == 'v1' + run: uv pip install "pydantic<2.0.0" - name: Lint run: bash scripts/lint.sh - run: mkdir coverage - name: Test run: bash scripts/test.sh env: - COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }} - CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }} + COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-pydantic-${{ matrix.pydantic-version }} + CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-pydantic-${{ matrix.pydantic-version }} - name: Store coverage files uses: actions/upload-artifact@v5 with: - name: coverage-${{ matrix.python-version }} + name: coverage-${{ matrix.python-version }}-pydantic-${{ matrix.pydantic-version }} path: coverage include-hidden-files: true diff --git a/src/fastapi_cli/config.py b/src/fastapi_cli/config.py index 58710c68..f5304bad 100644 --- a/src/fastapi_cli/config.py +++ b/src/fastapi_cli/config.py @@ -2,13 +2,17 @@ from pathlib import Path from typing import Any, Dict, Optional -from pydantic import BaseModel +from pydantic import BaseModel, StrictStr +from pydantic.version import VERSION as PYDANTIC_VERSION logger = logging.getLogger(__name__) +PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2]) +PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2 + class FastAPIConfig(BaseModel): - entrypoint: Optional[str] = None + entrypoint: Optional[StrictStr] = None @classmethod def _read_pyproject_toml(cls) -> Dict[str, Any]: @@ -39,4 +43,8 @@ def resolve(cls, entrypoint: Optional[str] = None) -> "FastAPIConfig": if entrypoint is not None: config["entrypoint"] = entrypoint - return FastAPIConfig.model_validate(config) + # Pydantic v2 uses model_validate, v1 uses parse_obj + if not PYDANTIC_V2: + return cls.parse_obj(config) # type: ignore[no-any-return, unused-ignore] + + return cls.model_validate(config) # type: ignore[no-any-return, unused-ignore, attr-defined]