Skip to content

Commit

Permalink
Small changes + added docs
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p committed Nov 2, 2020
1 parent ba75620 commit f471865
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 7 deletions.
90 changes: 90 additions & 0 deletions docs/source/kinds_of_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,96 @@ more specific type:
since the caller may have to use :py:func:`isinstance` before doing anything
interesting with the value.

.. _alternative_union_syntax:

Alternative union syntax
------------------------

`PEP 604 <https://www.python.org/dev/peps/pep-0604/>`_ introduced an alternative way
for writing union types. Starting with **Python 3.10** it is possible to write
``Union[int, str]`` as ``int | str``. Any of the following options is possible

.. code-block:: python
from typing import List
# Use as Union
t1: int | str # equivalent to Union[int, str]
# Use as Optional
t2: int | None # equivalent to Optional[int]
# Use in generics
t3: List[int | str] # equivalent to List[Union[int, str]]
# Use in type aliases
T4 = int | None
x: T4
# Quoted variable annotations
t5: "int | str"
# Quoted function annotations
def f(t6: "int | str") -> None: ...
# Type comments
t6 = 42 # type: int | str
It is possible to use most of these even for earlier versions. However there are some
limitations to be aware of.

.. _alternative_union_syntax_stub_files:

Stub files
""""""""""

All options are supported, regardless of the Python version the project uses.

.. _alternative_union_syntax_37:

Python 3.7 - 3.9
""""""""""""""""

It is necessary to add ``from __future__ import annotations`` to delay the evaluation
of type annotations. Not using it would result in a ``TypeError``.
This does not apply for **type comments**, **quoted function** and **quoted variable** annotations,
as those also work for earlier versions, see :ref:`below <alternative_union_syntax_older_version>`.

.. warning::

Type aliases are **NOT** supported! Those result in a ``TypeError`` regardless
if the evaluation of type annotations is delayed.

Dynamic evaluation of annotations is **NOT** possible (e.g. ``typing.get_type_hints`` and ``eval``).
See `note PEP 604 <https://www.python.org/dev/peps/pep-0604/#change-only-pep-484-type-hints-to-accept-the-syntax-type1-type2>`_.
Use ``typing.Union`` or **Python 3.10** instead if you need those!

.. code-block:: python
from __future__ import annotations
t1: int | None
# Type aliases
T2 = int | None # TypeError!
.. _alternative_union_syntax_older_version:

Older versions
""""""""""""""

+------------------------------------------+-----------+-----------+-----------+
| Python Version | 3.6 | 3.0 - 3.5 | 2.7 |
+==========================================+===========+===========+===========+
| Type comments | yes | yes | yes |
+------------------------------------------+-----------+-----------+-----------+
| Quoted function annotations | yes | yes | |
+------------------------------------------+-----------+-----------+-----------+
| Quoted variable annotations | yes | | |
+------------------------------------------+-----------+-----------+-----------+
| Everything else | | | |
+------------------------------------------+-----------+-----------+-----------+

.. _strict_optional:

Optional types and the None type
Expand Down
8 changes: 4 additions & 4 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def parse_type_comment(type_comment: str,
line=line,
override_column=column,
assume_str_is_unicode=assume_str_is_unicode,
is_type_comment=True).visit(typ.body)
is_evaluated=False).visit(typ.body)
return ignored, converted


Expand Down Expand Up @@ -1279,14 +1279,14 @@ def __init__(self,
line: int = -1,
override_column: int = -1,
assume_str_is_unicode: bool = True,
is_type_comment: bool = False,
is_evaluated: bool = True,
) -> None:
self.errors = errors
self.line = line
self.override_column = override_column
self.node_stack = [] # type: List[AST]
self.assume_str_is_unicode = assume_str_is_unicode
self.is_type_comment = is_type_comment
self.is_evaluated = is_evaluated

def convert_column(self, column: int) -> int:
"""Apply column override if defined; otherwise return column.
Expand Down Expand Up @@ -1436,7 +1436,7 @@ def visit_BinOp(self, n: ast3.BinOp) -> Type:
return UnionType([left, right],
line=self.line,
column=self.convert_column(n.col_offset),
is_evaluated=(not self.is_type_comment),
is_evaluated=self.is_evaluated,
uses_pep604_syntax=True)

def visit_NameConstant(self, n: NameConstant) -> Type:
Expand Down
26 changes: 23 additions & 3 deletions test-data/unit/check-union-or-syntax.test
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,41 @@ reveal_type(x) # N: Revealed type is 'builtins.list[Union[builtins.int, builtin
[builtins fixtures/list.pyi]


[case testUnionOrSyntaxWithQuotedTypes]
# flags: --python-version 3.10
[case testUnionOrSyntaxWithQuotedFunctionTypes]
# flags: --python-version 3.4
from typing import Union
def f(x: 'Union[int, str, None]') -> 'Union[int, None]':
reveal_type(x) # N: Revealed type is 'Union[builtins.int, builtins.str, None]'
return 42
reveal_type(f) # N: Revealed type is 'def (x: Union[builtins.int, builtins.str, None]) -> Union[builtins.int, None]'

# flags: --python-version 3.10
def g(x: "int | str | None") -> "int | None":
reveal_type(x) # N: Revealed type is 'Union[builtins.int, builtins.str, None]'
return 42
reveal_type(g) # N: Revealed type is 'def (x: Union[builtins.int, builtins.str, None]) -> Union[builtins.int, None]'


[case testUnionOrSyntaxWithQuotedVariableTypes]
# flags: --python-version 3.6
y: "int | str" = 42
reveal_type(y) # N: Revealed type is 'Union[builtins.int, builtins.str]'


[case testUnionOrSyntaxWithTypeAliasWorking]
# flags: --python-version 3.10
from typing import Union
T = Union[int, str]
x: T
reveal_type(x) # N: Revealed type is 'Union[builtins.int, builtins.str]'


[case testUnionOrSyntaxWithTypeAliasNotAllowed]
# flags: --python-version 3.9
from __future__ import annotations
T = int | str # E: Unsupported left operand type for | ("Type[int]")
[builtins fixtures/tuple.pyi]


[case testUnionOrSyntaxInComment]
# flags: --python-version 3.6
x = 1 # type: int | str
Expand Down

0 comments on commit f471865

Please sign in to comment.