Skip to content

Commit f96446c

Browse files
authored
Various small documentation updates (#11817)
Improve consistency, grammar, formatting and clarity in the documentation. Also some minor content fixes.
1 parent 9d5ef72 commit f96446c

10 files changed

+227
-184
lines changed

docs/source/class_basics.rst

+14-8
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ Slots
320320
*****
321321

322322
When a class has explicitly defined
323-
`__slots__ <https://docs.python.org/3/reference/datamodel.html#slots>`_
324-
mypy will check that all attributes assigned to are members of `__slots__`.
323+
`__slots__ <https://docs.python.org/3/reference/datamodel.html#slots>`_,
324+
mypy will check that all attributes assigned to are members of ``__slots__``:
325325

326326
.. code-block:: python
327327
@@ -331,13 +331,19 @@ mypy will check that all attributes assigned to are members of `__slots__`.
331331
def __init__(self, name: str, year: int) -> None:
332332
self.name = name
333333
self.year = year
334-
self.released = True # E: Trying to assign name "released" that is not in "__slots__" of type "Album"
334+
# Error: Trying to assign name "released" that is not in "__slots__" of type "Album"
335+
self.released = True
335336
336337
my_album = Album('Songs about Python', 2021)
337338
338-
Mypy will only check attribute assignments against `__slots__` when the following conditions hold:
339+
Mypy will only check attribute assignments against ``__slots__`` when
340+
the following conditions hold:
339341

340-
1. All base classes (except builtin ones) must have explicit ``__slots__`` defined (mirrors CPython's behaviour)
341-
2. ``__slots__`` does not include ``__dict__``, since if ``__slots__`` includes ``__dict__``
342-
it allows setting any attribute, similar to when ``__slots__`` is not defined (mirrors CPython's behaviour)
343-
3. All values in ``__slots__`` must be statically known. For example, no variables: only string literals.
342+
1. All base classes (except builtin ones) must have explicit
343+
``__slots__`` defined (this mirrors Python semantics).
344+
345+
2. ``__slots__`` does not include ``__dict__``. If ``__slots__``
346+
includes ``__dict__``, arbitrary attributes can be set, similar to
347+
when ``__slots__`` is not defined (this mirrors Python semantics).
348+
349+
3. All values in ``__slots__`` must be string literals.

docs/source/command_line.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ The following options are available:
312312
.. option:: --disallow-any-generics
313313

314314
This flag disallows usage of generic types that do not specify explicit
315-
type parameters. For example you can't use a bare ``x: list``, you must say
316-
``x: list[int]``.
315+
type parameters. For example, you can't use a bare ``x: list``. Instead, you
316+
must always write something like ``x: list[int]``.
317317

318318
.. option:: --disallow-subclassing-any
319319

docs/source/common_issues.rst

+107-97
Original file line numberDiff line numberDiff line change
@@ -26,102 +26,102 @@ No errors reported for obviously wrong code
2626
There are several common reasons why obviously wrong code is not
2727
flagged as an error.
2828

29-
- **The function containing the error is not annotated.** Functions that
30-
do not have any annotations (neither for any argument nor for the
31-
return type) are not type-checked, and even the most blatant type
32-
errors (e.g. ``2 + 'a'``) pass silently. The solution is to add
33-
annotations. Where that isn't possible, functions without annotations
34-
can be checked using :option:`--check-untyped-defs <mypy --check-untyped-defs>`.
29+
**The function containing the error is not annotated.** Functions that
30+
do not have any annotations (neither for any argument nor for the
31+
return type) are not type-checked, and even the most blatant type
32+
errors (e.g. ``2 + 'a'``) pass silently. The solution is to add
33+
annotations. Where that isn't possible, functions without annotations
34+
can be checked using :option:`--check-untyped-defs <mypy --check-untyped-defs>`.
3535

36-
Example:
36+
Example:
3737

38-
.. code-block:: python
38+
.. code-block:: python
3939
40-
def foo(a):
41-
return '(' + a.split() + ')' # No error!
40+
def foo(a):
41+
return '(' + a.split() + ')' # No error!
4242
43-
This gives no error even though ``a.split()`` is "obviously" a list
44-
(the author probably meant ``a.strip()``). The error is reported
45-
once you add annotations:
43+
This gives no error even though ``a.split()`` is "obviously" a list
44+
(the author probably meant ``a.strip()``). The error is reported
45+
once you add annotations:
4646

47-
.. code-block:: python
47+
.. code-block:: python
4848
49-
def foo(a: str) -> str:
50-
return '(' + a.split() + ')'
51-
# error: Unsupported operand types for + ("str" and List[str])
49+
def foo(a: str) -> str:
50+
return '(' + a.split() + ')'
51+
# error: Unsupported operand types for + ("str" and List[str])
5252
53-
If you don't know what types to add, you can use ``Any``, but beware:
53+
If you don't know what types to add, you can use ``Any``, but beware:
5454

55-
- **One of the values involved has type 'Any'.** Extending the above
56-
example, if we were to leave out the annotation for ``a``, we'd get
57-
no error:
55+
**One of the values involved has type 'Any'.** Extending the above
56+
example, if we were to leave out the annotation for ``a``, we'd get
57+
no error:
5858

59-
.. code-block:: python
59+
.. code-block:: python
6060
61-
def foo(a) -> str:
62-
return '(' + a.split() + ')' # No error!
61+
def foo(a) -> str:
62+
return '(' + a.split() + ')' # No error!
6363
64-
The reason is that if the type of ``a`` is unknown, the type of
65-
``a.split()`` is also unknown, so it is inferred as having type
66-
``Any``, and it is no error to add a string to an ``Any``.
64+
The reason is that if the type of ``a`` is unknown, the type of
65+
``a.split()`` is also unknown, so it is inferred as having type
66+
``Any``, and it is no error to add a string to an ``Any``.
6767

68-
If you're having trouble debugging such situations,
69-
:ref:`reveal_type() <reveal-type>` might come in handy.
68+
If you're having trouble debugging such situations,
69+
:ref:`reveal_type() <reveal-type>` might come in handy.
7070

71-
Note that sometimes library stubs have imprecise type information,
72-
e.g. the :py:func:`pow` builtin returns ``Any`` (see `typeshed issue 285
73-
<https://github.com/python/typeshed/issues/285>`_ for the reason).
71+
Note that sometimes library stubs have imprecise type information,
72+
e.g. the :py:func:`pow` builtin returns ``Any`` (see `typeshed issue 285
73+
<https://github.com/python/typeshed/issues/285>`_ for the reason).
7474

75-
- :py:meth:`__init__ <object.__init__>` **method has no annotated
76-
arguments or return type annotation.** :py:meth:`__init__ <object.__init__>`
77-
is considered fully-annotated **if at least one argument is annotated**,
78-
while mypy will infer the return type as ``None``.
79-
The implication is that, for a :py:meth:`__init__ <object.__init__>` method
80-
that has no argument, you'll have to explicitly annotate the return type
81-
as ``None`` to type-check this :py:meth:`__init__ <object.__init__>` method:
75+
:py:meth:`__init__ <object.__init__>` **method has no annotated
76+
arguments or return type annotation.** :py:meth:`__init__ <object.__init__>`
77+
is considered fully-annotated **if at least one argument is annotated**,
78+
while mypy will infer the return type as ``None``.
79+
The implication is that, for a :py:meth:`__init__ <object.__init__>` method
80+
that has no argument, you'll have to explicitly annotate the return type
81+
as ``None`` to type-check this :py:meth:`__init__ <object.__init__>` method:
8282

83-
.. code-block:: python
83+
.. code-block:: python
8484
85-
def foo(s: str) -> str:
86-
return s
87-
88-
class A():
89-
def __init__(self, value: str): # Return type inferred as None, considered as typed method
90-
self.value = value
91-
foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
92-
93-
class B():
94-
def __init__(self): # No argument is annotated, considered as untyped method
95-
foo(1) # No error!
96-
97-
class C():
98-
def __init__(self) -> None: # Must specify return type to type-check
99-
foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
100-
101-
- **Some imports may be silently ignored**. Another source of
102-
unexpected ``Any`` values are the :option:`--ignore-missing-imports
103-
<mypy --ignore-missing-imports>` and :option:`--follow-imports=skip
104-
<mypy --follow-imports>` flags. When you use :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`,
105-
any imported module that cannot be found is silently replaced with
106-
``Any``. When using :option:`--follow-imports=skip <mypy --follow-imports>` the same is true for
107-
modules for which a ``.py`` file is found but that are not specified
108-
on the command line. (If a ``.pyi`` stub is found it is always
109-
processed normally, regardless of the value of
110-
:option:`--follow-imports <mypy --follow-imports>`.) To help debug the former situation (no
111-
module found at all) leave out :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`; to get
112-
clarity about the latter use :option:`--follow-imports=error <mypy --follow-imports>`. You can
113-
read up about these and other useful flags in :ref:`command-line`.
114-
115-
- **A function annotated as returning a non-optional type returns 'None'
116-
and mypy doesn't complain**.
85+
def foo(s: str) -> str:
86+
return s
87+
88+
class A():
89+
def __init__(self, value: str): # Return type inferred as None, considered as typed method
90+
self.value = value
91+
foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
92+
93+
class B():
94+
def __init__(self): # No argument is annotated, considered as untyped method
95+
foo(1) # No error!
96+
97+
class C():
98+
def __init__(self) -> None: # Must specify return type to type-check
99+
foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
100+
101+
**Some imports may be silently ignored**. Another source of
102+
unexpected ``Any`` values are the :option:`--ignore-missing-imports
103+
<mypy --ignore-missing-imports>` and :option:`--follow-imports=skip
104+
<mypy --follow-imports>` flags. When you use :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`,
105+
any imported module that cannot be found is silently replaced with
106+
``Any``. When using :option:`--follow-imports=skip <mypy --follow-imports>` the same is true for
107+
modules for which a ``.py`` file is found but that are not specified
108+
on the command line. (If a ``.pyi`` stub is found it is always
109+
processed normally, regardless of the value of
110+
:option:`--follow-imports <mypy --follow-imports>`.) To help debug the former situation (no
111+
module found at all) leave out :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`; to get
112+
clarity about the latter use :option:`--follow-imports=error <mypy --follow-imports>`. You can
113+
read up about these and other useful flags in :ref:`command-line`.
114+
115+
**A function annotated as returning a non-optional type returns 'None'
116+
and mypy doesn't complain**.
117117

118-
.. code-block:: python
118+
.. code-block:: python
119119
120-
def foo() -> str:
121-
return None # No error!
120+
def foo() -> str:
121+
return None # No error!
122122
123-
You may have disabled strict optional checking (see
124-
:ref:`no_strict_optional` for more).
123+
You may have disabled strict optional checking (see
124+
:ref:`no_strict_optional` for more).
125125

126126
.. _silencing_checker:
127127

@@ -383,10 +383,10 @@ explicit type cast:
383383
if index < 0:
384384
raise ValueError('No str found')
385385
386-
found = a[index] # Has `object` type, despite the fact that we know it is `str`
387-
return cast(str, found) # So, we need an explicit cast to make mypy happy
386+
found = a[index] # Has type "object", despite the fact that we know it is "str"
387+
return cast(str, found) # We need an explicit cast to make mypy happy
388388
389-
Alternatively, you can use ``assert`` statement together with some
389+
Alternatively, you can use an ``assert`` statement together with some
390390
of the supported type inference techniques:
391391

392392
.. code-block:: python
@@ -396,9 +396,9 @@ of the supported type inference techniques:
396396
if index < 0:
397397
raise ValueError('No str found')
398398
399-
found = a[index] # Has `object` type, despite the fact that we know it is `str`
400-
assert isinstance(found, str) # Now, `found` will be narrowed to `str` subtype
401-
return found # No need for the explicit `cast()` anymore
399+
found = a[index] # Has type "object", despite the fact that we know it is "str"
400+
assert isinstance(found, str) # Now, "found" will be narrowed to "str"
401+
return found # No need for the explicit "cast()" anymore
402402
403403
.. note::
404404

@@ -411,7 +411,7 @@ of the supported type inference techniques:
411411

412412
.. note::
413413

414-
You can read more about type narrowing techniques here.
414+
You can read more about type narrowing techniques :ref:`here <type-narrowing>`.
415415

416416
Type inference in Mypy is designed to work well in common cases, to be
417417
predictable and to let the type checker give useful error
@@ -634,32 +634,41 @@ You can install the latest development version of mypy from source. Clone the
634634
Variables vs type aliases
635635
-------------------------
636636

637-
Mypy has both type aliases and variables with types like ``Type[...]`` and it is important to know their difference.
637+
Mypy has both *type aliases* and variables with types like ``Type[...]``. These are
638+
subtly different, and it's important to understand how they differ to avoid pitfalls.
638639

639-
1. Variables with type ``Type[...]`` should be created by assignments with an explicit type annotations:
640+
1. A variable with type ``Type[...]`` is defined using an assignment with an
641+
explicit type annotation:
640642

641643
.. code-block:: python
642644
643645
class A: ...
644646
tp: Type[A] = A
645647
646-
2. Aliases are created by assignments without an explicit type.
648+
2. You can define a type alias using an assignment without an explicit type annotation
649+
at the top level of a module:
647650

648651
.. code-block:: python
649652
650653
class A: ...
651654
Alias = A
652655
653-
Or you can also use :pep:`613` and explicit type aliases:
656+
You can also use ``TypeAlias`` (:pep:`613`) to define an *explicit type alias*:
654657

655658
.. code-block:: python
656-
657-
from typing import TypeAlias # or `from typing_extensions` before `python3.10`
658-
659+
660+
from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier
661+
659662
class A: ...
660663
Alias: TypeAlias = A
661664
662-
3. The difference is that aliases are completely known statically and can be used in type context (annotations):
665+
You should always use ``TypeAlias`` to define a type alias in a class body or
666+
inside a function.
667+
668+
The main difference is that the target of an alias is precisely known statically, and this
669+
means that they can be used in type annotations and other *type contexts*. Type aliases
670+
can't be defined conditionally (unless using
671+
:ref:`supported Python version and platform checks <version_and_platform_checks>`):
663672

664673
.. code-block:: python
665674
@@ -669,17 +678,18 @@ Mypy has both type aliases and variables with types like ``Type[...]`` and it is
669678
if random() > 0.5:
670679
Alias = A
671680
else:
672-
Alias = B # error: Cannot assign multiple types to name "Alias" without an explicit "Type[...]" annotation \
673-
# error: Incompatible types in assignment (expression has type "Type[B]", variable has type "Type[A]")
681+
# error: Cannot assign multiple types to name "Alias" without an
682+
# explicit "Type[...]" annotation
683+
Alias = B
674684
675-
tp: Type[object] # tp is a type variable
685+
tp: Type[object] # "tp" is a variable with a type object value
676686
if random() > 0.5:
677687
tp = A
678688
else:
679689
tp = B # This is OK
680690
681-
def fun1(x: Alias) -> None: ... # This is OK
682-
def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type
691+
def fun1(x: Alias) -> None: ... # OK
692+
def fun2(x: tp) -> None: ... # Error: "tp" is not valid as a type
683693
684694
Incompatible overrides
685695
----------------------

0 commit comments

Comments
 (0)