Skip to content
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 10 commits into from Feb 17, 2021
4 changes: 2 additions & 2 deletions pydantic/fields.py
Expand Up @@ -343,7 +343,7 @@ def _get_field_info(
field_info_from_config = config.get_field_info(field_name)

field_info = None
if get_origin(annotation) is Annotated:
if Annotated and get_origin(annotation) is Annotated:
field_infos = [arg for arg in get_args(annotation)[1:] if isinstance(arg, FieldInfo)]
if len(field_infos) > 1:
raise ValueError(f'cannot specify multiple `Annotated` `Field`s for {field_name!r}')
Expand Down Expand Up @@ -497,7 +497,7 @@ def _type_analysis(self) -> None: # noqa: C901 (ignore complexity)
if isinstance(self.type_, type) and isinstance(None, self.type_):
self.allow_none = True
return
if origin is Annotated:
if Annotated and origin is Annotated:
self.type_ = get_args(self.type_)[0]
self._type_analysis()
return
Expand Down
2 changes: 1 addition & 1 deletion pydantic/schema.py
Expand Up @@ -944,7 +944,7 @@ def go(type_: Any) -> Type[Any]:
# forward refs cause infinite recursion below
return type_

if origin is Annotated:
if Annotated and origin is Annotated:
return go(args[0])
if origin is Union:
return Union[tuple(go(a) for a in args)] # type: ignore
Expand Down
16 changes: 1 addition & 15 deletions pydantic/typing.py
Expand Up @@ -90,21 +90,7 @@ def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
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 = None


# Annotated[...] is implemented by returning an instance of one of these classes, depending on
Expand Down
6 changes: 2 additions & 4 deletions tests/test_annotated.py
Expand Up @@ -7,8 +7,9 @@
from pydantic.fields import Undefined
from pydantic.typing import Annotated

pytestmark = pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



@pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
@pytest.mark.parametrize(
['hint_fn', 'value'],
[
Expand Down Expand Up @@ -55,7 +56,6 @@ class M(BaseModel):
assert get_type_hints(M)['x'] == hint


@pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
@pytest.mark.parametrize(
['hint_fn', 'value', 'subclass_ctx'],
[
Expand Down Expand Up @@ -93,7 +93,6 @@ class M(BaseModel):
x: hint = value


@pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
@pytest.mark.parametrize(
['hint_fn', 'value', 'empty_init_ctx'],
[
Expand Down Expand Up @@ -121,7 +120,6 @@ class M(BaseModel):
assert M().x == 5


@pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
def test_field_reuse():
field = Field(description='Long description')

Expand Down