Skip to content

Commit 7128666

Browse files
authored
Merge pull request #203 from allmonday/feature/union-fix
fix case of union type
2 parents 8a49884 + 146a598 commit 7128666

File tree

8 files changed

+62
-16
lines changed

8 files changed

+62
-16
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ jobs:
88
steps:
99
- uses: actions/checkout@v4
1010

11-
- name: Set up Python 3.8
11+
- name: Set up Python 3.12
1212
uses: actions/setup-python@v4
1313
with:
14-
python-version: 3.8
14+
python-version: "3.12"
1515

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

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

4041
- run: poetry install --no-interaction
41-
- run: pip install pydantic==1.*
42+
43+
- name: Install Pydantic v2 for testing
44+
run: poetry run pip install pydantic==2.11.7
4245

4346
- name: Test with pytest
44-
run: poetry run pytest tests/pydantic_v1 tests/common
47+
run: poetry run pytest tests/pydantic_v2 tests/common

docs/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## v1.13
44

5+
### v1.13.1 (2025.8.28)
6+
7+
- fix: add support for UnionType such as `A | B`
8+
- update: upgrade python version to 3.10 in ci
9+
510
### v1.13.0 (2025.8.27)
611

712
feature:

pydantic_resolve/utils/types.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
from typing import Type, Union, List
2+
try: # Python 3.10+ provides PEP 604 unions using types.UnionType
3+
from types import UnionType as _UnionType
4+
except ImportError: # pragma: no cover - prior to 3.10
5+
_UnionType = () # sentinel so membership tests still work
26
from pydantic_resolve.compat import PYDANTIC_V2, OVER_PYTHON_3_7
37

48
if OVER_PYTHON_3_7:
@@ -65,16 +69,17 @@ def _shell_list(_tp):
6569

6670
while True:
6771
orig = _get_origin(tp)
68-
if orig is Union:
72+
73+
if orig in (Union, _UnionType):
6974
args = list(_get_args(tp))
7075
non_none = [a for a in args if a is not type(None)] # noqa: E721
7176
has_none = len(non_none) != len(args)
72-
# Optional[T] case -> keep unwrapping
77+
# Optional[T] case -> keep unwrapping (exactly one real type + None)
7378
if has_none and len(non_none) == 1:
7479
tp = non_none[0]
7580
tp = _shell_list(tp)
7681
continue
77-
# Union (with or without None) -> return tuple of real types
82+
# General union: return all non-None members (order preserved)
7883
if non_none:
7984
return tuple(non_none)
8085
return tuple()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pydantic-resolve"
3-
version = "1.13.0"
3+
version = "1.13.1"
44
description = "A business model friendly data orchestration tool, simple way to implement the core concept of clean architecture."
55
authors = ["tangkikodo <[email protected]>"]
66
readme = "README.md"

tests/common/test_types.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ def test_is_list(annotation, expected):
107107
)
108108
def test_get_core_types(tp, expected):
109109
result = get_core_types(tp)
110-
print(result)
111110
assert result == expected
112111

113112

tests/common/test_union_types.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
from pydantic_resolve.utils.types import (
3+
get_core_types,
4+
)
5+
from typing import Optional, List
6+
import pytest
7+
8+
@pytest.mark.parametrize(
9+
"tp,expected",
10+
[
11+
12+
# Optional types
13+
(int | None, (int,)),
14+
(None | int, (int,)),
15+
16+
# Union types (multiple non-None types)
17+
(int | str, (int, str)),
18+
(int | str | float, (int, str, float)),
19+
(str | int, (str, int)), # Order matters
20+
21+
# Union with None
22+
(int | str | None, (int, str)),
23+
(None | int | str, (int, str)),
24+
(int | None | str, (int, str)),
25+
26+
# Complex nested types
27+
(List[int | str], (int, str)),
28+
(Optional[List[int | str]], (int, str)),
29+
]
30+
)
31+
def test_get_core_types_3_10(tp, expected):
32+
result = get_core_types(tp)
33+
assert result == expected

tests/pydantic_v2/resolver/test_44_union.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Union
1+
from typing import Union, List
22
from pydantic import BaseModel
33
from pydantic_resolve import Resolver, Loader
44
import pytest
@@ -35,7 +35,7 @@ class C(BaseModel):
3535

3636

3737
class Container(BaseModel):
38-
items: list[Item] = []
38+
items: List[Item] = []
3939

4040
def resolve_items(self):
4141
return [A(id='1'), B(id='2', name='Item 2')]

tox.ini

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,31 @@ basepython = python3.8
2525
commands_pre =
2626
poetry install --sync
2727
commands =
28-
pytest tests/pydantic_v1 tests/common
28+
# Python <3.10 can't parse PEP 604 union syntax (e.g. int | None); ignore that test file
29+
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v1 tests/common
2930

3031
[testenv:py38pyd2]
3132
commands_pre =
3233
poetry install --sync
3334
pip install pydantic==2.*
3435
basepython = python3.8
3536
commands =
36-
pytest tests/pydantic_v2 tests/common
37+
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v2 tests/common
3738

3839
[testenv:py39pyd1]
3940
basepython = python3.9
4041
commands_pre =
4142
poetry install --sync
4243
commands =
43-
pytest tests/pydantic_v1 tests/common
44+
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v1 tests/common
4445

4546
[testenv:py39pyd2]
4647
commands_pre =
4748
poetry install --sync
4849
pip install pydantic==2.*
4950
basepython = python3.9
5051
commands =
51-
pytest tests/pydantic_v2 tests/common
52+
pytest --ignore=tests/common/test_union_types.py tests/pydantic_v2 tests/common
5253

5354
[testenv:py310pyd1]
5455
basepython = python3.10

0 commit comments

Comments
 (0)