mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-06 17:01:07 -04:00
fb3243475e
on the theme of 2.0/2.1 are relatively similar right now, do some more cleanup removing the py3k suffixes that we dont need anymore. I'm not sure that the logic that would search for these suffixes is even present anymore and I would guess we removed it when we removed py2k support. However, I am planning on possibly bringing it back for some of the py314 stuff, so I still want to be able to do suffix stuff. that will be for another patch. Change-Id: I929e6edd922f8d5f943acce77191fb1e3035b42c
649 lines
21 KiB
Python
649 lines
21 KiB
Python
# NOTE: typing implementation is full of heuristic so unit test it to avoid
|
|
# unexpected breakages.
|
|
|
|
import operator
|
|
import typing
|
|
from typing import cast
|
|
|
|
import typing_extensions
|
|
|
|
from sqlalchemy import Column
|
|
from sqlalchemy.testing import eq_
|
|
from sqlalchemy.testing import fixtures
|
|
from sqlalchemy.testing import is_
|
|
from sqlalchemy.testing import requires
|
|
from sqlalchemy.util import py312
|
|
from sqlalchemy.util import py314
|
|
from sqlalchemy.util import typing as sa_typing
|
|
|
|
TV = typing.TypeVar("TV")
|
|
|
|
|
|
def union_types():
|
|
res = [typing.Union[int, str], int | str]
|
|
return res
|
|
|
|
|
|
def null_union_types():
|
|
res = [
|
|
typing.Optional[typing.Union[int, str]],
|
|
typing.Union[int, str, None],
|
|
typing.Union[int, str, "None"],
|
|
int | str | None,
|
|
typing.Optional[int | str],
|
|
typing.Union[int, str] | None,
|
|
typing.Optional[int] | str,
|
|
]
|
|
return res
|
|
|
|
|
|
def generic_unions():
|
|
res = union_types() + null_union_types()
|
|
if not py314:
|
|
# for py310 through py313, remove new-style unions `int | str` that
|
|
# are not generic
|
|
new_ut = type(int | str)
|
|
res = [t for t in res if not isinstance(t, new_ut)]
|
|
return res
|
|
|
|
|
|
def make_fw_ref(anno: str) -> typing.ForwardRef:
|
|
return typing.Union[anno]
|
|
|
|
|
|
TypeAliasType = getattr(
|
|
typing, "TypeAliasType", typing_extensions.TypeAliasType
|
|
)
|
|
|
|
TA_int = TypeAliasType("TA_int", int)
|
|
TAext_int = typing_extensions.TypeAliasType("TAext_int", int)
|
|
TA_union = TypeAliasType("TA_union", typing.Union[int, str])
|
|
TAext_union = typing_extensions.TypeAliasType(
|
|
"TAext_union", typing.Union[int, str]
|
|
)
|
|
TA_null_union = TypeAliasType("TA_null_union", typing.Union[int, str, None])
|
|
TAext_null_union = typing_extensions.TypeAliasType(
|
|
"TAext_null_union", typing.Union[int, str, None]
|
|
)
|
|
TA_null_union2 = TypeAliasType(
|
|
"TA_null_union2", typing.Union[int, str, "None"]
|
|
)
|
|
TAext_null_union2 = typing_extensions.TypeAliasType(
|
|
"TAext_null_union2", typing.Union[int, str, "None"]
|
|
)
|
|
TA_null_union3 = TypeAliasType(
|
|
"TA_null_union3", typing.Union[int, "typing.Union[None, bool]"]
|
|
)
|
|
TAext_null_union3 = typing_extensions.TypeAliasType(
|
|
"TAext_null_union3", typing.Union[int, "typing.Union[None, bool]"]
|
|
)
|
|
TA_null_union4 = TypeAliasType(
|
|
"TA_null_union4", typing.Union[int, "TA_null_union2"]
|
|
)
|
|
TAext_null_union4 = typing_extensions.TypeAliasType(
|
|
"TAext_null_union4", typing.Union[int, "TAext_null_union2"]
|
|
)
|
|
TA_union_ta = TypeAliasType("TA_union_ta", typing.Union[TA_int, str])
|
|
TAext_union_ta = typing_extensions.TypeAliasType(
|
|
"TAext_union_ta", typing.Union[TAext_int, str]
|
|
)
|
|
TA_null_union_ta = TypeAliasType(
|
|
"TA_null_union_ta", typing.Union[TA_null_union, float]
|
|
)
|
|
TAext_null_union_ta = typing_extensions.TypeAliasType(
|
|
"TAext_null_union_ta", typing.Union[TAext_null_union, float]
|
|
)
|
|
TA_list = TypeAliasType(
|
|
"TA_list", typing.Union[int, str, typing.List["TA_list"]]
|
|
)
|
|
TAext_list = typing_extensions.TypeAliasType(
|
|
"TAext_list", typing.Union[int, str, typing.List["TAext_list"]]
|
|
)
|
|
# these below not valid. Verify that it does not cause exceptions in any case
|
|
TA_recursive = TypeAliasType("TA_recursive", typing.Union["TA_recursive", str])
|
|
TAext_recursive = typing_extensions.TypeAliasType(
|
|
"TAext_recursive", typing.Union["TAext_recursive", str]
|
|
)
|
|
TA_null_recursive = TypeAliasType(
|
|
"TA_null_recursive", typing.Union[TA_recursive, None]
|
|
)
|
|
TAext_null_recursive = typing_extensions.TypeAliasType(
|
|
"TAext_null_recursive", typing.Union[TAext_recursive, None]
|
|
)
|
|
TA_recursive_a = TypeAliasType(
|
|
"TA_recursive_a", typing.Union["TA_recursive_b", int]
|
|
)
|
|
TAext_recursive_a = typing_extensions.TypeAliasType(
|
|
"TAext_recursive_a", typing.Union["TAext_recursive_b", int]
|
|
)
|
|
TA_recursive_b = TypeAliasType(
|
|
"TA_recursive_b", typing.Union["TA_recursive_a", str]
|
|
)
|
|
TAext_recursive_b = typing_extensions.TypeAliasType(
|
|
"TAext_recursive_b", typing.Union["TAext_recursive_a", str]
|
|
)
|
|
TA_generic = TypeAliasType("TA_generic", typing.List[TV], type_params=(TV,))
|
|
TAext_generic = typing_extensions.TypeAliasType(
|
|
"TAext_generic", typing.List[TV], type_params=(TV,)
|
|
)
|
|
TA_generic_typed = TA_generic[int]
|
|
TAext_generic_typed = TAext_generic[int]
|
|
TA_generic_null = TypeAliasType(
|
|
"TA_generic_null", typing.Union[typing.List[TV], None], type_params=(TV,)
|
|
)
|
|
TAext_generic_null = typing_extensions.TypeAliasType(
|
|
"TAext_generic_null",
|
|
typing.Union[typing.List[TV], None],
|
|
type_params=(TV,),
|
|
)
|
|
TA_generic_null_typed = TA_generic_null[str]
|
|
TAext_generic_null_typed = TAext_generic_null[str]
|
|
|
|
|
|
def type_aliases():
|
|
return [
|
|
TA_int,
|
|
TAext_int,
|
|
TA_union,
|
|
TAext_union,
|
|
TA_null_union,
|
|
TAext_null_union,
|
|
TA_null_union2,
|
|
TAext_null_union2,
|
|
TA_null_union3,
|
|
TAext_null_union3,
|
|
TA_null_union4,
|
|
TAext_null_union4,
|
|
TA_union_ta,
|
|
TAext_union_ta,
|
|
TA_null_union_ta,
|
|
TAext_null_union_ta,
|
|
TA_list,
|
|
TAext_list,
|
|
TA_recursive,
|
|
TAext_recursive,
|
|
TA_null_recursive,
|
|
TAext_null_recursive,
|
|
TA_recursive_a,
|
|
TAext_recursive_a,
|
|
TA_recursive_b,
|
|
TAext_recursive_b,
|
|
TA_generic,
|
|
TAext_generic,
|
|
TA_generic_typed,
|
|
TAext_generic_typed,
|
|
TA_generic_null,
|
|
TAext_generic_null,
|
|
TA_generic_null_typed,
|
|
TAext_generic_null_typed,
|
|
]
|
|
|
|
|
|
NT_str = typing.NewType("NT_str", str)
|
|
NT_null = typing.NewType("NT_null", None)
|
|
# this below is not valid. Verify that it does not cause exceptions in any case
|
|
NT_union = typing.NewType("NT_union", typing.Union[str, int])
|
|
|
|
|
|
def new_types():
|
|
return [NT_str, NT_null, NT_union]
|
|
|
|
|
|
A_str = typing.Annotated[str, "meta"]
|
|
A_null_str = typing.Annotated[typing.Union[str, None], "other_meta", "null"]
|
|
A_union = typing.Annotated[typing.Union[str, int], "other_meta"]
|
|
A_null_union = typing.Annotated[
|
|
typing.Union[str, int, None], "other_meta", "null"
|
|
]
|
|
|
|
|
|
def compare_type_by_string(a, b):
|
|
"""python 3.14 has made ForwardRefs not really comparable or reliably
|
|
hashable.
|
|
|
|
As we need to compare types here, including structures like
|
|
`Union["str", "int"]`, without having to dive into cpython's source code
|
|
each time a new release comes out, compare based on stringification,
|
|
which still presents changing rules but at least are easy to diagnose
|
|
and correct for different python versions.
|
|
|
|
See discussion at https://github.com/python/cpython/issues/129463
|
|
for background
|
|
|
|
"""
|
|
|
|
if isinstance(a, (set, list)):
|
|
a = sorted(a, key=lambda x: str(x))
|
|
if isinstance(b, (set, list)):
|
|
b = sorted(b, key=lambda x: str(x))
|
|
|
|
eq_(str(a), str(b))
|
|
|
|
|
|
def annotated_l():
|
|
return [A_str, A_null_str, A_union, A_null_union]
|
|
|
|
|
|
def all_types():
|
|
return (
|
|
union_types()
|
|
+ null_union_types()
|
|
+ type_aliases()
|
|
+ new_types()
|
|
+ annotated_l()
|
|
)
|
|
|
|
|
|
def exec_code(code: str, *vars: str) -> typing.Any:
|
|
assert vars
|
|
scope = {}
|
|
exec(code, None, scope)
|
|
if len(vars) == 1:
|
|
return scope[vars[0]]
|
|
return [scope[name] for name in vars]
|
|
|
|
|
|
class TestGenerics(fixtures.TestBase):
|
|
def test_traversible_is_generic(self):
|
|
"""test #6759"""
|
|
col = Column[int]
|
|
|
|
# looked in the source for typing._GenericAlias.
|
|
# col.__origin__ is Column, but it's not public API.
|
|
# __reduce__ could change too but seems good enough for now
|
|
eq_(cast(object, col).__reduce__(), (operator.getitem, (Column, int)))
|
|
|
|
|
|
class TestTestingThings(fixtures.TestBase):
|
|
def test_unions_are_the_same(self):
|
|
# the point of this test is to reduce the cases to test since
|
|
# some symbols are the same in typing and typing_extensions.
|
|
# If a test starts failing then additional cases should be added,
|
|
# similar to what it's done for TypeAliasType
|
|
|
|
# no need to test typing_extensions.Union, typing_extensions.Optional
|
|
is_(typing.Union, typing_extensions.Union)
|
|
is_(typing.Optional, typing_extensions.Optional)
|
|
|
|
@requires.python312
|
|
def test_make_type_alias_type(self):
|
|
# verify that TypeAliasType('foo', int) it the same as 'type foo = int'
|
|
x_type = exec_code("type x = int", "x")
|
|
x = typing.TypeAliasType("x", int)
|
|
|
|
eq_(type(x_type), type(x))
|
|
eq_(x_type.__name__, x.__name__)
|
|
eq_(x_type.__value__, x.__value__)
|
|
|
|
def test_make_fw_ref(self):
|
|
compare_type_by_string(make_fw_ref("str"), typing.ForwardRef("str"))
|
|
compare_type_by_string(
|
|
make_fw_ref("str|int"), typing.ForwardRef("str|int")
|
|
)
|
|
compare_type_by_string(
|
|
make_fw_ref("Optional[Union[str, int]]"),
|
|
typing.ForwardRef("Optional[Union[str, int]]"),
|
|
)
|
|
|
|
|
|
class TestTyping(fixtures.TestBase):
|
|
def test_is_pep593(self):
|
|
eq_(sa_typing.is_pep593(str), False)
|
|
eq_(sa_typing.is_pep593(None), False)
|
|
eq_(sa_typing.is_pep593(typing_extensions.Annotated[int, "a"]), True)
|
|
eq_(sa_typing.is_pep593(typing.Annotated[int, "a"]), True)
|
|
|
|
for t in annotated_l():
|
|
eq_(sa_typing.is_pep593(t), True)
|
|
for t in (
|
|
union_types() + null_union_types() + type_aliases() + new_types()
|
|
):
|
|
eq_(sa_typing.is_pep593(t), False)
|
|
|
|
def test_is_literal(self):
|
|
eq_(sa_typing.is_literal(typing.Literal["a"]), True)
|
|
eq_(sa_typing.is_literal(typing_extensions.Literal["a"]), True)
|
|
eq_(sa_typing.is_literal(None), False)
|
|
for t in all_types():
|
|
eq_(sa_typing.is_literal(t), False)
|
|
|
|
def test_is_newtype(self):
|
|
eq_(sa_typing.is_newtype(str), False)
|
|
|
|
for t in new_types():
|
|
eq_(sa_typing.is_newtype(t), True)
|
|
for t in (
|
|
union_types() + null_union_types() + type_aliases() + annotated_l()
|
|
):
|
|
eq_(sa_typing.is_newtype(t), False)
|
|
|
|
def test_is_generic(self):
|
|
class W(typing.Generic[TV]):
|
|
pass
|
|
|
|
eq_(sa_typing.is_generic(typing.List[int]), True)
|
|
eq_(sa_typing.is_generic(W), False)
|
|
eq_(sa_typing.is_generic(W[str]), True)
|
|
|
|
if py312:
|
|
t = exec_code("class W[T]: pass", "W")
|
|
eq_(sa_typing.is_generic(t), False)
|
|
eq_(sa_typing.is_generic(t[int]), True)
|
|
|
|
generics = [
|
|
TA_generic_typed,
|
|
TAext_generic_typed,
|
|
TA_generic_null_typed,
|
|
TAext_generic_null_typed,
|
|
*annotated_l(),
|
|
*generic_unions(),
|
|
]
|
|
|
|
for t in all_types():
|
|
if py314:
|
|
exp = any(t == k for k in generics)
|
|
else:
|
|
# use is since union compare equal between new/old style
|
|
exp = any(t is k for k in generics)
|
|
eq_(sa_typing.is_generic(t), exp, t)
|
|
|
|
def test_is_pep695(self):
|
|
eq_(sa_typing.is_pep695(str), False)
|
|
for t in (
|
|
union_types() + null_union_types() + new_types() + annotated_l()
|
|
):
|
|
eq_(sa_typing.is_pep695(t), False)
|
|
for t in type_aliases():
|
|
eq_(sa_typing.is_pep695(t), True)
|
|
|
|
def test_pep695_value(self):
|
|
eq_(sa_typing.pep695_values(int), {int})
|
|
eq_(
|
|
sa_typing.pep695_values(typing.Union[int, str]),
|
|
{typing.Union[int, str]},
|
|
)
|
|
|
|
for t in (
|
|
union_types() + null_union_types() + new_types() + annotated_l()
|
|
):
|
|
eq_(sa_typing.pep695_values(t), {t})
|
|
|
|
eq_(
|
|
sa_typing.pep695_values(typing.Union[int, TA_int]),
|
|
{typing.Union[int, TA_int]},
|
|
)
|
|
eq_(
|
|
sa_typing.pep695_values(typing.Union[int, TAext_int]),
|
|
{typing.Union[int, TAext_int]},
|
|
)
|
|
|
|
eq_(sa_typing.pep695_values(TA_int), {int})
|
|
eq_(sa_typing.pep695_values(TAext_int), {int})
|
|
eq_(sa_typing.pep695_values(TA_union), {int, str})
|
|
eq_(sa_typing.pep695_values(TAext_union), {int, str})
|
|
eq_(sa_typing.pep695_values(TA_null_union), {int, str, None})
|
|
eq_(sa_typing.pep695_values(TAext_null_union), {int, str, None})
|
|
eq_(sa_typing.pep695_values(TA_null_union2), {int, str, None})
|
|
eq_(sa_typing.pep695_values(TAext_null_union2), {int, str, None})
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_null_union3),
|
|
[int, typing.ForwardRef("typing.Union[None, bool]")],
|
|
)
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_null_union3),
|
|
{int, typing.ForwardRef("typing.Union[None, bool]")},
|
|
)
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_null_union4),
|
|
[int, typing.ForwardRef("TA_null_union2")],
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_null_union4),
|
|
{int, typing.ForwardRef("TAext_null_union2")},
|
|
)
|
|
|
|
eq_(sa_typing.pep695_values(TA_union_ta), {int, str})
|
|
eq_(sa_typing.pep695_values(TAext_union_ta), {int, str})
|
|
eq_(sa_typing.pep695_values(TA_null_union_ta), {int, str, None, float})
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_null_union_ta),
|
|
{int, str, None, float},
|
|
)
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_list),
|
|
[int, str, typing.List[typing.ForwardRef("TA_list")]],
|
|
)
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_list),
|
|
{int, str, typing.List[typing.ForwardRef("TAext_list")]},
|
|
)
|
|
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_recursive),
|
|
[str, typing.ForwardRef("TA_recursive")],
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_recursive),
|
|
{typing.ForwardRef("TAext_recursive"), str},
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_null_recursive),
|
|
[str, typing.ForwardRef("TA_recursive"), None],
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_null_recursive),
|
|
{typing.ForwardRef("TAext_recursive"), str, None},
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_recursive_a),
|
|
[int, typing.ForwardRef("TA_recursive_b")],
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_recursive_a),
|
|
{typing.ForwardRef("TAext_recursive_b"), int},
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TA_recursive_b),
|
|
[str, typing.ForwardRef("TA_recursive_a")],
|
|
)
|
|
compare_type_by_string(
|
|
sa_typing.pep695_values(TAext_recursive_b),
|
|
{typing.ForwardRef("TAext_recursive_a"), str},
|
|
)
|
|
|
|
@requires.up_to_date_typealias_type
|
|
def test_pep695_value_generics(self):
|
|
# generics
|
|
|
|
eq_(sa_typing.pep695_values(TA_generic), {typing.List[TV]})
|
|
eq_(sa_typing.pep695_values(TAext_generic), {typing.List[TV]})
|
|
eq_(sa_typing.pep695_values(TA_generic_typed), {typing.List[TV]})
|
|
eq_(sa_typing.pep695_values(TAext_generic_typed), {typing.List[TV]})
|
|
eq_(sa_typing.pep695_values(TA_generic_null), {None, typing.List[TV]})
|
|
eq_(
|
|
sa_typing.pep695_values(TAext_generic_null),
|
|
{None, typing.List[TV]},
|
|
)
|
|
eq_(
|
|
sa_typing.pep695_values(TA_generic_null_typed),
|
|
{None, typing.List[TV]},
|
|
)
|
|
eq_(
|
|
sa_typing.pep695_values(TAext_generic_null_typed),
|
|
{None, typing.List[TV]},
|
|
)
|
|
|
|
def test_is_fwd_ref(self):
|
|
eq_(sa_typing.is_fwd_ref(int), False)
|
|
eq_(sa_typing.is_fwd_ref(make_fw_ref("str")), True)
|
|
eq_(sa_typing.is_fwd_ref(typing.Union[str, int]), False)
|
|
eq_(sa_typing.is_fwd_ref(typing.Union["str", int]), False)
|
|
eq_(sa_typing.is_fwd_ref(typing.Union["str", int], True), True)
|
|
|
|
for t in all_types():
|
|
eq_(sa_typing.is_fwd_ref(t), False)
|
|
|
|
def test_de_optionalize_union_types(self):
|
|
fn = sa_typing.de_optionalize_union_types
|
|
|
|
eq_(
|
|
fn(typing.Optional[typing.Union[int, str]]), typing.Union[int, str]
|
|
)
|
|
eq_(fn(typing.Union[int, str, None]), typing.Union[int, str])
|
|
|
|
eq_(fn(typing.Union[int, str, "None"]), typing.Union[int, str])
|
|
|
|
eq_(fn(make_fw_ref("None")), typing_extensions.Never)
|
|
eq_(fn(make_fw_ref("typing.Union[None]")), typing_extensions.Never)
|
|
eq_(fn(make_fw_ref("Union[None, str]")), typing.ForwardRef("str"))
|
|
|
|
compare_type_by_string(
|
|
fn(make_fw_ref("Union[None, str, int]")),
|
|
typing.Union["str", "int"],
|
|
)
|
|
|
|
compare_type_by_string(
|
|
fn(make_fw_ref("Optional[int]")), typing.ForwardRef("int")
|
|
)
|
|
|
|
compare_type_by_string(
|
|
fn(make_fw_ref("typing.Optional[Union[int | str]]")),
|
|
typing.ForwardRef("Union[int | str]"),
|
|
)
|
|
|
|
for t in null_union_types():
|
|
res = fn(t)
|
|
eq_(sa_typing.is_union(res), True)
|
|
eq_(type(None) not in res.__args__, True)
|
|
|
|
for t in union_types() + type_aliases() + new_types() + annotated_l():
|
|
eq_(fn(t), t)
|
|
|
|
compare_type_by_string(
|
|
fn(make_fw_ref("Union[typing.Dict[str, int], int, None]")),
|
|
typing.Union[
|
|
"typing.Dict[str, int]",
|
|
"int",
|
|
],
|
|
)
|
|
|
|
def test_make_union_type(self):
|
|
eq_(sa_typing.make_union_type(int), int)
|
|
eq_(sa_typing.make_union_type(None), type(None))
|
|
eq_(sa_typing.make_union_type(int, str), typing.Union[int, str])
|
|
eq_(
|
|
sa_typing.make_union_type(int, typing.Optional[str]),
|
|
typing.Union[int, str, None],
|
|
)
|
|
eq_(
|
|
sa_typing.make_union_type(int, typing.Union[str, bool]),
|
|
typing.Union[int, str, bool],
|
|
)
|
|
eq_(
|
|
sa_typing.make_union_type(bool, TA_int, NT_str),
|
|
typing.Union[bool, TA_int, NT_str],
|
|
)
|
|
eq_(
|
|
sa_typing.make_union_type(bool, TAext_int, NT_str),
|
|
typing.Union[bool, TAext_int, NT_str],
|
|
)
|
|
|
|
@requires.up_to_date_typealias_type
|
|
def test_includes_none_generics(self):
|
|
# TODO: these are false negatives
|
|
false_negatives = {
|
|
TA_null_union4, # does not evaluate FW ref
|
|
TAext_null_union4, # does not evaluate FW ref
|
|
}
|
|
|
|
for t in type_aliases() + new_types():
|
|
if t in false_negatives:
|
|
exp = False
|
|
else:
|
|
exp = "null" in t.__name__
|
|
eq_(sa_typing.includes_none(t), exp, str(t))
|
|
|
|
def test_includes_none(self):
|
|
eq_(sa_typing.includes_none(None), True)
|
|
eq_(sa_typing.includes_none(type(None)), True)
|
|
eq_(sa_typing.includes_none(typing.ForwardRef("None")), True)
|
|
eq_(sa_typing.includes_none(int), False)
|
|
for t in union_types():
|
|
eq_(sa_typing.includes_none(t), False)
|
|
|
|
for t in null_union_types():
|
|
eq_(sa_typing.includes_none(t), True, str(t))
|
|
|
|
for t in annotated_l():
|
|
eq_(
|
|
sa_typing.includes_none(t),
|
|
"null" in sa_typing.get_args(t),
|
|
str(t),
|
|
)
|
|
# nested things
|
|
eq_(sa_typing.includes_none(typing.Union[int, "None"]), True)
|
|
eq_(sa_typing.includes_none(typing.Union[bool, TA_null_union]), True)
|
|
eq_(
|
|
sa_typing.includes_none(typing.Union[bool, TAext_null_union]), True
|
|
)
|
|
eq_(sa_typing.includes_none(typing.Union[bool, NT_null]), True)
|
|
# nested fw
|
|
eq_(
|
|
sa_typing.includes_none(
|
|
typing.Union[int, "typing.Union[str, None]"]
|
|
),
|
|
True,
|
|
)
|
|
eq_(
|
|
sa_typing.includes_none(
|
|
typing.Union[int, "typing.Union[int, str]"]
|
|
),
|
|
False,
|
|
)
|
|
|
|
# there are not supported. should return True
|
|
eq_(
|
|
sa_typing.includes_none(typing.Union[bool, "TA_null_union"]), False
|
|
)
|
|
eq_(
|
|
sa_typing.includes_none(typing.Union[bool, "TAext_null_union"]),
|
|
False,
|
|
)
|
|
eq_(sa_typing.includes_none(typing.Union[bool, "NT_null"]), False)
|
|
|
|
def test_is_union(self):
|
|
eq_(sa_typing.is_union(str), False)
|
|
for t in union_types() + null_union_types():
|
|
eq_(sa_typing.is_union(t), True)
|
|
for t in type_aliases() + new_types() + annotated_l():
|
|
eq_(sa_typing.is_union(t), False)
|
|
|
|
def test_TypingInstances(self):
|
|
is_(sa_typing._type_tuples, sa_typing._type_instances)
|
|
is_(
|
|
isinstance(sa_typing._type_instances, sa_typing._TypingInstances),
|
|
True,
|
|
)
|
|
|
|
# cached
|
|
is_(
|
|
sa_typing._type_instances.Literal,
|
|
sa_typing._type_instances.Literal,
|
|
)
|
|
|
|
for k in ["Literal", "Annotated", "TypeAliasType"]:
|
|
types = set()
|
|
ti = getattr(sa_typing._type_instances, k)
|
|
for lib in [typing, typing_extensions]:
|
|
lt = getattr(lib, k, None)
|
|
if lt is not None:
|
|
types.add(lt)
|
|
is_(lt in ti, True)
|
|
eq_(len(ti), len(types), k)
|