-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix coverage and make typing-extensions a required dependency #2368
Merged
Merged
Changes from 8 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
50a6915
fixing coverage by simplifying Annotated import logic, fix #2367
samuelcolvin bc17abc
avoid checking against annotated if it's None
samuelcolvin 281450b
make typing-extensions required WIP
samuelcolvin 18a570a
more making typing-extensions required
samuelcolvin 3ef4ea7
fix docs and get_origin for python 3.6
samuelcolvin ee34a3f
fix mypy test
samuelcolvin 7e60be4
fix docs
samuelcolvin 2eb0ff9
update docs, cleanup and add change
samuelcolvin f500367
clean docs/examples/schema_annotated.py
samuelcolvin 6b2bcfc
move AnnotatedTypeNames
samuelcolvin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Making `typing-extensions` a required dependency. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,8 @@ | |
cast, | ||
) | ||
|
||
from typing_extensions import Annotated, Literal | ||
|
||
try: | ||
from typing import _TypingBase as typing_base # type: ignore | ||
except ImportError: | ||
|
@@ -81,87 +83,16 @@ def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: | |
NoArgAnyCallable = TypingCallable[[], Any] | ||
|
||
|
||
if sys.version_info >= (3, 9): | ||
from typing import Annotated | ||
else: | ||
if TYPE_CHECKING: | ||
from typing_extensions import Annotated | ||
else: # due to different mypy warnings raised during CI for python 3.7 and 3.8 | ||
try: | ||
from typing_extensions import Annotated | ||
except ImportError: | ||
# Create mock Annotated values distinct from `None`, which is a valid `get_origin` | ||
# return value. | ||
class _FalseMeta(type): | ||
# Allow short circuiting with "Annotated[...] if Annotated else None". | ||
def __bool__(cls): | ||
return False | ||
|
||
# Give a nice suggestion for unguarded use | ||
def __getitem__(cls, key): | ||
raise RuntimeError( | ||
'Annotated is not supported in this python version, please `pip install typing-extensions`.' | ||
) | ||
|
||
class Annotated(metaclass=_FalseMeta): | ||
pass | ||
|
||
|
||
# Annotated[...] is implemented by returning an instance of one of these classes, depending on | ||
# python/typing_extensions version. | ||
AnnotatedTypeNames = ('AnnotatedMeta', '_AnnotatedAlias') | ||
|
||
|
||
if sys.version_info < (3, 8): # noqa: C901 | ||
if TYPE_CHECKING: | ||
from typing_extensions import Literal | ||
else: # due to different mypy warnings raised during CI for python 3.7 and 3.8 | ||
try: | ||
from typing_extensions import Literal | ||
except ImportError: | ||
Literal = None | ||
|
||
if sys.version_info < (3, 7): | ||
|
||
def get_args(t: Type[Any]) -> Tuple[Any, ...]: | ||
"""Simplest get_args compatibility layer possible. | ||
|
||
The Python 3.6 typing module does not have `_GenericAlias` so | ||
this won't work for everything. In particular this will not | ||
support the `generics` module (we don't support generic models in | ||
python 3.6). | ||
|
||
""" | ||
if Annotated and type(t).__name__ in AnnotatedTypeNames: | ||
return t.__args__ + t.__metadata__ | ||
return getattr(t, '__args__', ()) | ||
|
||
else: | ||
from typing import _GenericAlias | ||
|
||
def get_args(t: Type[Any]) -> Tuple[Any, ...]: | ||
"""Compatibility version of get_args for python 3.7. | ||
|
||
Mostly compatible with the python 3.8 `typing` module version | ||
and able to handle almost all use cases. | ||
""" | ||
if Annotated and type(t).__name__ in AnnotatedTypeNames: | ||
return t.__args__ + t.__metadata__ | ||
if isinstance(t, _GenericAlias): | ||
res = t.__args__ | ||
if t.__origin__ is Callable and res and res[0] is not Ellipsis: | ||
res = (list(res[:-1]), res[-1]) | ||
return res | ||
return getattr(t, '__args__', ()) | ||
if sys.version_info < (3, 8): | ||
|
||
def get_origin(t: Type[Any]) -> Optional[Type[Any]]: | ||
if Annotated and type(t).__name__ in AnnotatedTypeNames: | ||
if type(t).__name__ in AnnotatedTypeNames: | ||
return cast(Type[Any], Annotated) # mypy complains about _SpecialForm in py3.6 | ||
return getattr(t, '__origin__', None) | ||
|
||
|
||
else: | ||
from typing import Literal, get_args as typing_get_args, get_origin as typing_get_origin | ||
from typing import get_origin as _typing_get_origin | ||
|
||
def get_origin(tp: Type[Any]) -> Type[Any]: | ||
""" | ||
|
@@ -170,11 +101,55 @@ def get_origin(tp: Type[Any]) -> Type[Any]: | |
It should be useless once https://github.com/cython/cython/issues/3537 is | ||
solved and https://github.com/samuelcolvin/pydantic/pull/1753 is merged. | ||
""" | ||
if Annotated and type(tp).__name__ in AnnotatedTypeNames: | ||
if type(tp).__name__ in AnnotatedTypeNames: | ||
return cast(Type[Any], Annotated) # mypy complains about _SpecialForm | ||
return typing_get_origin(tp) or getattr(tp, '__origin__', None) | ||
return _typing_get_origin(tp) or getattr(tp, '__origin__', None) | ||
|
||
|
||
# Annotated[...] is implemented by returning an instance of one of these classes, depending on | ||
# python/typing_extensions version. | ||
AnnotatedTypeNames = {'AnnotatedMeta', '_AnnotatedAlias'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be moved up since it's referenced in the branches above? |
||
|
||
|
||
if sys.version_info < (3, 7): # noqa: C901 (ignore complexity) | ||
|
||
def get_args(t: Type[Any]) -> Tuple[Any, ...]: | ||
"""Simplest get_args compatibility layer possible. | ||
|
||
The Python 3.6 typing module does not have `_GenericAlias` so | ||
this won't work for everything. In particular this will not | ||
support the `generics` module (we don't support generic models in | ||
python 3.6). | ||
|
||
""" | ||
if type(t).__name__ in AnnotatedTypeNames: | ||
return t.__args__ + t.__metadata__ | ||
return getattr(t, '__args__', ()) | ||
|
||
|
||
elif sys.version_info < (3, 8): # noqa: C901 | ||
from typing import _GenericAlias | ||
|
||
def get_args(t: Type[Any]) -> Tuple[Any, ...]: | ||
"""Compatibility version of get_args for python 3.7. | ||
|
||
Mostly compatible with the python 3.8 `typing` module version | ||
and able to handle almost all use cases. | ||
""" | ||
if type(t).__name__ in AnnotatedTypeNames: | ||
return t.__args__ + t.__metadata__ | ||
if isinstance(t, _GenericAlias): | ||
res = t.__args__ | ||
if t.__origin__ is Callable and res and res[0] is not Ellipsis: | ||
res = (list(res[:-1]), res[-1]) | ||
return res | ||
return getattr(t, '__args__', ()) | ||
|
||
|
||
else: | ||
from typing import get_args as _typing_get_args | ||
|
||
def generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]: | ||
def _generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]: | ||
""" | ||
In python 3.9, `typing.Dict`, `typing.List`, ... | ||
do have an empty `__args__` by default (instead of the generic ~T for example). | ||
|
@@ -196,10 +171,10 @@ def get_args(tp: Type[Any]) -> Tuple[Any, ...]: | |
get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) | ||
get_args(Callable[[], T][int]) == ([], int) | ||
""" | ||
if Annotated and type(tp).__name__ in AnnotatedTypeNames: | ||
if type(tp).__name__ in AnnotatedTypeNames: | ||
return tp.__args__ + tp.__metadata__ | ||
# the fallback is needed for the same reasons as `get_origin` (see above) | ||
return typing_get_args(tp) or getattr(tp, '__args__', ()) or generic_get_args(tp) | ||
return _typing_get_args(tp) or getattr(tp, '__args__', ()) or _generic_get_args(tp) | ||
|
||
|
||
if TYPE_CHECKING: | ||
|
@@ -220,7 +195,6 @@ def get_args(tp: Type[Any]) -> Tuple[Any, ...]: | |
__all__ = ( | ||
'ForwardRef', | ||
'Callable', | ||
'Annotated', | ||
'AnyCallable', | ||
'NoArgAnyCallable', | ||
'NoneType', | ||
|
@@ -230,7 +204,6 @@ def get_args(tp: Type[Any]) -> Tuple[Any, ...]: | |
'is_callable_type', | ||
'is_literal_type', | ||
'literal_values', | ||
'Literal', | ||
'is_namedtuple', | ||
'is_typeddict', | ||
'is_new_type', | ||
|
@@ -255,9 +228,7 @@ def get_args(tp: Type[Any]) -> Tuple[Any, ...]: | |
|
||
|
||
NoneType = None.__class__ | ||
NONE_TYPES: Set[Any] = {None, NoneType} | ||
if Literal: | ||
NONE_TYPES.add(Literal[None]) | ||
NONE_TYPES: Set[Any] = {None, NoneType, Literal[None]} | ||
|
||
|
||
def display_as_type(v: Type[Any]) -> str: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change should probably be explicitly noted as a breaking change in the changelog, just in case there are people ignoring the warning.
I can also think of scenarios where people are using another libraries TypedDict, but I'm not sure if that's common or not (I've never done this before).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need it's in the same new version v1.8 ;)