From 58a5cbd7f86144ec776fc0f3cb710fd3d74b47c2 Mon Sep 17 00:00:00 2001 From: KotlinIsland <65446343+kotlinisland@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:09:05 +1000 Subject: [PATCH] `In`/`Out` --- basedtyping/__init__.py | 45 +++++++++++++++++++++++++++++++++++++++++ tests/test_in_out.py | 1 + 2 files changed, 46 insertions(+) create mode 100644 tests/test_in_out.py diff --git a/basedtyping/__init__.py b/basedtyping/__init__.py index 1ec8a0a..a5d8431 100644 --- a/basedtyping/__init__.py +++ b/basedtyping/__init__.py @@ -51,6 +51,8 @@ "Untyped", "Intersection", "TypeForm", + "In", + "Out", ) if TYPE_CHECKING: @@ -556,3 +558,46 @@ def f[T](t: TypeForm[T]) -> T: ... reveal_type(f(int | str)) # int | str """) + + +class _InForm(_BasedSpecialForm, _root=True): # type: ignore[misc] + def __init__(self, doc: str): + self._name = "In" + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters: object | tuple[object]) -> _BasedGenericAlias: + if not isinstance(parameters, tuple): + parameters = (parameters,) + + return _BasedGenericAlias(self, parameters) # type: ignore[arg-type] + + +In = _InForm(doc="""\ + A type that can be used to represent a contravariant form of a type. + For example: + + list_of_objects: list[object] + list_of_ints: list[In[int]] = list_of_objects # valid + """) + + +class _OutForm(_BasedSpecialForm, _root=True): # type: ignore[misc] + def __init__(self, doc: str): + self._name = "Out" + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters: object | tuple[object]) -> _BasedGenericAlias: + if not isinstance(parameters, tuple): + parameters = (parameters,) + + return _BasedGenericAlias(self, parameters) # type: ignore[arg-type] + + +Out = _OutForm(doc="""\ + An annotation that can be used to represent a covariant form of a type. + For example: + + list_of_ints: list[int] + list_of_objects: list[Out[object]] = a # valid + """) + diff --git a/tests/test_in_out.py b/tests/test_in_out.py new file mode 100644 index 0000000..a623ce9 --- /dev/null +++ b/tests/test_in_out.py @@ -0,0 +1 @@ +raise NotImplementedError \ No newline at end of file