-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat: support PEP604 syntax str | None
#168
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #168 +/- ##
==========================================
- Coverage 89.02% 88.99% -0.04%
==========================================
Files 17 17
Lines 2005 2017 +12
Branches 437 439 +2
==========================================
+ Hits 1785 1795 +10
- Misses 144 145 +1
- Partials 76 77 +1 ☔ View full report in Codecov by Sentry. |
I don't think I know enough to review this well, so will rely on @msto. |
@msto bump |
"""Returns true if type_ is optional""" | ||
return typing.get_origin(type_) is Union and type(None) in typing.get_args(type_) | ||
# NB: since `_GenericAlias` is a private attribute of the `typing` module, mypy doesn't find it | ||
TypeAnnotation: TypeAlias = Union[type, typing._GenericAlias, UnionType] # type: ignore[name-defined] |
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.
issue GenericAlias
should be included as a valid type annotation type. Also add from types import GenericAlias
above
TypeAnnotation: TypeAlias = Union[type, typing._GenericAlias, UnionType] # type: ignore[name-defined] | |
TypeAnnotation: TypeAlias = Union[type, typing._GenericAlias, UnionType, | |
types.GenericAlias] # type: ignore[name-defined] |
"""Check if a type is `Optional`. | ||
An optional type may be declared using three syntaxes: `Optional[T]`, `Union[T, None]`, or `T | | ||
None`. All of these syntaxes is supported by this function. | ||
Args: | ||
dtype: A type. | ||
Returns: | ||
True if the type is a union type with exactly two elements, one of which is `None`. | ||
False otherwise. | ||
Raises: | ||
TypeError: If the input is not a valid `TypeAnnotation` type (see above). | ||
""" |
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.
"""Check if a type is `Optional`. | |
An optional type may be declared using three syntaxes: `Optional[T]`, `Union[T, None]`, or `T | | |
None`. All of these syntaxes is supported by this function. | |
Args: | |
dtype: A type. | |
Returns: | |
True if the type is a union type with exactly two elements, one of which is `None`. | |
False otherwise. | |
Raises: | |
TypeError: If the input is not a valid `TypeAnnotation` type (see above). | |
""" | |
""" | |
Check if a type is `Optional`. | |
An optional type may be declared using three syntaxes: `Optional[T]`, `Union[T, None]`, or `T | | |
None`. All of these syntaxes are supported by this function. | |
Args: | |
dtype: A type. | |
Returns: | |
True if the type is a union type with exactly two elements, one of which is `None`. | |
False otherwise. | |
Raises: | |
TypeError: If the input is not a valid `TypeAnnotation` type. | |
Type annotations may be any of `type`, `types.UnionType`, `types.GenericAlias`, or `typing._GenericAlias`. | |
""" |
# TODO When dropping support for Python 3.9, deprecate this in favor of performing instance checks | ||
# directly on the `TypeAnnotation` union type. | ||
# NB: since `_GenericAlias` is a private attribute of the `typing` module, mypy doesn't find it | ||
TYPE_ANNOTATION_TYPES = (type, typing._GenericAlias, UnionType) # type: ignore[attr-defined] |
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.
issue as above, we should include types.GenericAlias
TYPE_ANNOTATION_TYPES = (type, typing._GenericAlias, UnionType) # type: ignore[attr-defined] | |
TYPE_ANNOTATION_TYPES = (type, typing._GenericAlias, UnionType, GenericAlias) # type: ignore[attr-defined] |
origin = typing.get_origin(dtype) | ||
args = typing.get_args(dtype) |
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.
nit I think it's more in line with our convention to import these functions instead of referencing them as module attributes
origin = typing.get_origin(dtype) | |
args = typing.get_args(dtype) | |
origin = get_origin(dtype) | |
args = get_args(dtype) |
assert not types._is_optional(str) | ||
|
||
|
||
if sys.version_info >= (3, 10): | ||
|
||
def test_is_optional_python_310() -> None: | ||
assert types._is_optional(str | None) |
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.
suggestion Save a couple lines?
assert not types._is_optional(str) | |
if sys.version_info >= (3, 10): | |
def test_is_optional_python_310() -> None: | |
assert types._is_optional(str | None) | |
assert not types._is_optional(str) | |
if sys.version_info >= (3, 10): | |
assert types._is_optional(str | None) |
assert types._is_optional(Optional[str]) | ||
assert not types._is_optional(str) |
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.
suggestion Test a couple union types that don't meet our criteria
assert types._is_optional(Optional[str]) | |
assert not types._is_optional(str) | |
assert types._is_optional(Optional[str]) | |
assert not types._is_optional(Union[str, int]) | |
assert not types._is_optional(Union[str, int, None]) | |
assert not types._is_optional(str) |
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.
NB: for brevity (and to catch multiple failures in a single pytest
invocation), you could use pytest.mark.parameterize
over the tested types
Fixes #89