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
13 changes: 8 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: "3.12"

- name: cache poetry install
uses: actions/cache@v4
with:
path: ~/.local
key: poetry-1.4.0-0
# Include Python version to avoid reusing a Poetry self-venv built for a different interpreter (e.g. 3.8 -> missing libpython3.8.so)
key: poetry-1.4.0-0-py312

- name: Install Poetry
uses: snok/install-poetry@v1
Expand All @@ -38,7 +39,9 @@ jobs:
if: steps.cache-deps.outputs.cache-hit != 'true'

- run: poetry install --no-interaction
- run: pip install pydantic==1.*

- name: Install Pydantic v2 for testing
run: poetry run pip install pydantic==2.11.7

- name: Test with pytest
run: poetry run pytest tests/pydantic_v1 tests/common
run: poetry run pytest tests/pydantic_v2 tests/common
5 changes: 5 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## v1.13

### v1.13.1 (2025.8.28)

- fix: add support for UnionType such as `A | B`
- update: upgrade python version to 3.10 in ci

### v1.13.0 (2025.8.27)

feature:
Expand Down
11 changes: 8 additions & 3 deletions pydantic_resolve/utils/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from typing import Type, Union, List
try: # Python 3.10+ provides PEP 604 unions using types.UnionType
from types import UnionType as _UnionType
except ImportError: # pragma: no cover - prior to 3.10
_UnionType = () # sentinel so membership tests still work
from pydantic_resolve.compat import PYDANTIC_V2, OVER_PYTHON_3_7

if OVER_PYTHON_3_7:
Expand Down Expand Up @@ -65,16 +69,17 @@ def _shell_list(_tp):

while True:
orig = _get_origin(tp)
if orig is Union:

if orig in (Union, _UnionType):
args = list(_get_args(tp))
non_none = [a for a in args if a is not type(None)] # noqa: E721
has_none = len(non_none) != len(args)
# Optional[T] case -> keep unwrapping
# Optional[T] case -> keep unwrapping (exactly one real type + None)
if has_none and len(non_none) == 1:
tp = non_none[0]
tp = _shell_list(tp)
continue
# Union (with or without None) -> return tuple of real types
# General union: return all non-None members (order preserved)
if non_none:
return tuple(non_none)
return tuple()
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pydantic-resolve"
version = "1.13.0"
version = "1.13.1"
description = "A business model friendly data orchestration tool, simple way to implement the core concept of clean architecture."
authors = ["tangkikodo <[email protected]>"]
readme = "README.md"
Expand Down
1 change: 0 additions & 1 deletion tests/common/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ def test_is_list(annotation, expected):
)
def test_get_core_types(tp, expected):
result = get_core_types(tp)
print(result)
assert result == expected


Expand Down
33 changes: 33 additions & 0 deletions tests/common/test_union_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

from pydantic_resolve.utils.types import (
get_core_types,
)
from typing import Optional, List
import pytest

@pytest.mark.parametrize(
"tp,expected",
[

# Optional types
(int | None, (int,)),
(None | int, (int,)),

# Union types (multiple non-None types)
(int | str, (int, str)),
(int | str | float, (int, str, float)),
(str | int, (str, int)), # Order matters

# Union with None
(int | str | None, (int, str)),
(None | int | str, (int, str)),
(int | None | str, (int, str)),

# Complex nested types
(List[int | str], (int, str)),
(Optional[List[int | str]], (int, str)),
]
)
def test_get_core_types_3_10(tp, expected):
result = get_core_types(tp)
assert result == expected
4 changes: 2 additions & 2 deletions tests/pydantic_v2/resolver/test_44_union.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union
from typing import Union, List
from pydantic import BaseModel
from pydantic_resolve import Resolver, Loader
import pytest
Expand Down Expand Up @@ -35,7 +35,7 @@ class C(BaseModel):


class Container(BaseModel):
items: list[Item] = []
items: List[Item] = []

def resolve_items(self):
return [A(id='1'), B(id='2', name='Item 2')]
Expand Down
9 changes: 5 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,31 @@ basepython = python3.8
commands_pre =
poetry install --sync
commands =
pytest tests/pydantic_v1 tests/common
# Python <3.10 can't parse PEP 604 union syntax (e.g. int | None); ignore that test file
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v1 tests/common

[testenv:py38pyd2]
commands_pre =
poetry install --sync
pip install pydantic==2.*
basepython = python3.8
commands =
pytest tests/pydantic_v2 tests/common
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v2 tests/common

[testenv:py39pyd1]
basepython = python3.9
commands_pre =
poetry install --sync
commands =
pytest tests/pydantic_v1 tests/common
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v1 tests/common

[testenv:py39pyd2]
commands_pre =
poetry install --sync
pip install pydantic==2.*
basepython = python3.9
commands =
pytest tests/pydantic_v2 tests/common
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v2 tests/common

[testenv:py310pyd1]
basepython = python3.10
Expand Down