Skip to content

Commit

Permalink
revert: Add back support for optional lists (#1053)
Browse files Browse the repository at this point in the history
  • Loading branch information
tefra authored Jun 16, 2024
1 parent 25cea60 commit 1f42a6a
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 34 deletions.
2 changes: 2 additions & 0 deletions docs/models/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ collections are also supported.
| Case | Example |
| -------------- | --------------------------------------------------------------------------------- |
| List | `value: List[str] = field(default_factory=list)` |
| Optional List | `value: Optional[List[str]] = field(default=None)` |
| List Union | `value: List[Union[str, int]] = field(default_factory=list)` |
| Tokens List | `value: List[str] = field(default_factory=list, metadata={"tokens": True})` |
| List of Tokens | `value: List[List[str]] = field(default_factory=list, metadata={"tokens": True})` |
Expand All @@ -36,6 +37,7 @@ collections are also supported.
| Case | Example |
| --------------- | ---------------------------------------------------------------------------------------------- |
| Tuple | `value: Tuple[str, ...] = field(default_factory=tuple)` |
| Optional Tuple | `value: Optional[Tuple[str, ...]] = field(default=None)` |
| Tuple Union | `value: Tuple[Union[str, int], ...] = field(default_factory=tuple)` |
| Tokens Tuple | `value: Tuple[str, ...] = field(default_factory=tuple, metadata={"tokens": True})` |
| Tuple of Tokens | `value: Tuple[Tuple[str, ...], ...] = field(default_factory=tuple, metadata={"tokens": True})` |
Expand Down
64 changes: 32 additions & 32 deletions tests/fixtures/books/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from tests.fixtures.books import Books, BookForm
from tests.fixtures.books import BookForm, Books
from xsdata.models.datatype import XmlDate

books = Books(
Expand All @@ -24,37 +24,37 @@
]
)
events = [
('start-ns', 'brk', 'urn:books'),
('start', '{urn:books}books', {}, {'brk': 'urn:books'}),
('start', 'book', {'id': 'bk001', 'lang': 'en'}, {'brk': 'urn:books'}),
('start', 'author', {}, {'brk': 'urn:books'}),
('end', 'author', 'Hightower, Kim', '\n '),
('start', 'title', {}, {'brk': 'urn:books'}),
('end', 'title', 'The First Book', '\n '),
('start', 'genre', {}, {'brk': 'urn:books'}),
('end', 'genre', 'Fiction', '\n '),
('start', 'price', {}, {'brk': 'urn:books'}),
('end', 'price', '44.95', '\n '),
('start', 'pub_date', {}, {'brk': 'urn:books'}),
('end', 'pub_date', '2000-10-01', '\n '),
('start', 'review', {}, {'brk': 'urn:books'}),
('end', 'review', 'An amazing story of nothing.', '\n '),
('end', 'book', '\n ', '\n '),
('start', 'book', {'id': 'bk002', 'lang': 'en'}, {'brk': 'urn:books'}),
('start', 'author', {}, {'brk': 'urn:books'}),
('end', 'author', 'Nagata, Suanne', '\n '),
('start', 'title', {}, {'brk': 'urn:books'}),
('end', 'title', 'Becoming Somebody', '\n '),
('start', 'genre', {}, {'brk': 'urn:books'}),
('end', 'genre', 'Biography', '\n '),
('start', 'price', {}, {'brk': 'urn:books'}),
('end', 'price', '33.95', '\n '),
('start', 'pub_date', {}, {'brk': 'urn:books'}),
('end', 'pub_date', '2001-01-10', '\n '),
('start', 'review', {}, {'brk': 'urn:books'}),
('end', 'review', 'A masterpiece of the fine art of gossiping.', '\n '),
('end', 'book', '\n ', '\n'),
('end', '{urn:books}books', '\n ', None)
("start-ns", "brk", "urn:books"),
("start", "{urn:books}books", {}, {"brk": "urn:books"}),
("start", "book", {"id": "bk001", "lang": "en"}, {"brk": "urn:books"}),
("start", "author", {}, {"brk": "urn:books"}),
("end", "author", "Hightower, Kim", "\n "),
("start", "title", {}, {"brk": "urn:books"}),
("end", "title", "The First Book", "\n "),
("start", "genre", {}, {"brk": "urn:books"}),
("end", "genre", "Fiction", "\n "),
("start", "price", {}, {"brk": "urn:books"}),
("end", "price", "44.95", "\n "),
("start", "pub_date", {}, {"brk": "urn:books"}),
("end", "pub_date", "2000-10-01", "\n "),
("start", "review", {}, {"brk": "urn:books"}),
("end", "review", "An amazing story of nothing.", "\n "),
("end", "book", "\n ", "\n "),
("start", "book", {"id": "bk002", "lang": "en"}, {"brk": "urn:books"}),
("start", "author", {}, {"brk": "urn:books"}),
("end", "author", "Nagata, Suanne", "\n "),
("start", "title", {}, {"brk": "urn:books"}),
("end", "title", "Becoming Somebody", "\n "),
("start", "genre", {}, {"brk": "urn:books"}),
("end", "genre", "Biography", "\n "),
("start", "price", {}, {"brk": "urn:books"}),
("end", "price", "33.95", "\n "),
("start", "pub_date", {}, {"brk": "urn:books"}),
("end", "pub_date", "2001-01-10", "\n "),
("start", "review", {}, {"brk": "urn:books"}),
("end", "review", "A masterpiece of the fine art of gossiping.", "\n "),
("end", "book", "\n ", "\n"),
("end", "{urn:books}books", "\n ", None),
]

events_default_ns = [
Expand Down
3 changes: 2 additions & 1 deletion tests/formats/dataclass/cases/attribute.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Literal, Set, Tuple, Union
from typing import Dict, List, Literal, Optional, Set, Tuple, Union

from tests.formats.dataclass.cases import PY39, PY310
from xsdata.models.enums import Mode
Expand All @@ -14,6 +14,7 @@
(Tuple[int, ...], ((int,), None, tuple)),
(List[int], ((int,), None, list)),
(List[Union[str, int]], ((str, int), None, list)),
(Optional[List[Union[str, int]]], ((str, int), None, list)),
]

not_tokens = [
Expand Down
6 changes: 5 additions & 1 deletion tests/formats/dataclass/cases/element.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Set, Tuple, Union
from typing import Dict, List, Optional, Set, Tuple, Union

from tests.formats.dataclass.cases import PY39

Expand All @@ -7,10 +7,13 @@
(Dict[str, int], False),
(Tuple[str, str], False),
(List[str], ((str,), None, list)),
(Optional[List[str]], ((str,), None, list)),
(Tuple[str, ...], ((str,), None, tuple)),
(List[List[str]], ((str,), list, list)),
(Optional[List[List[Union[str, int]]]], ((str, int), list, list)),
(List[Tuple[str, ...]], ((str,), list, tuple)),
(Tuple[List[str], ...], ((str,), tuple, list)),
(Optional[Tuple[List[str], ...]], ((str,), tuple, list)),
]

not_tokens = [
Expand All @@ -23,6 +26,7 @@
(str, ((str,), None, None)),
(List[str], ((str,), list, None)),
(List[Union[str, int]], ((str, int), list, None)),
(Optional[List[Union[str, int]]], ((str, int), list, None)),
(Tuple[str, ...], ((str,), tuple, None)),
]

Expand Down
28 changes: 28 additions & 0 deletions xsdata/formats/dataclass/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,29 @@ def analyze_token_args(origin: Any, args: Tuple[Any, ...]) -> Tuple[Any]:
raise TypeError


def analyze_optional_origin(
origin: Any, args: Tuple[Any, ...], types: Tuple[Any, ...]
) -> Tuple[Any, ...]:
"""Analyze optional type annotations.
Remove the NoneType, adjust and return the origin, args and types.
Args
origin: The annotation origin
args: The annotation arguments
types: The annotation types
Returns:
The old or new origin args and types.
"""
if origin in UNION_TYPES:
new_args = filter_none_type(args)
if len(new_args) == 1:
return get_origin(new_args[0]), get_args(new_args[0]), new_args

return origin, args, types


def filter_none_type(args: Tuple[Any, ...]) -> Tuple[Any, ...]:
return tuple(arg for arg in args if arg is not NONE_TYPE)

Expand All @@ -105,11 +128,14 @@ def evaluate_text(annotation: Any, tokens: bool = False) -> Result:

def evaluate_attribute(annotation: Any, tokens: bool = False) -> Result:
"""Validate annotations for a xml attribute."""
types = (annotation,)
origin = get_origin(annotation)
args = get_args(annotation)
tokens_factory = None

if tokens:
origin, args, types = analyze_optional_origin(origin, args, types)

args = analyze_token_args(origin, args)
tokens_factory = origin
origin = get_origin(args[0])
Expand Down Expand Up @@ -161,6 +187,8 @@ def evaluate_element(annotation: Any, tokens: bool = False) -> Result:
args = get_args(annotation)
tokens_factory = factory = None

origin, args, types = analyze_optional_origin(origin, args, types)

if tokens:
args = analyze_token_args(origin, args)

Expand Down

0 comments on commit 1f42a6a

Please sign in to comment.