Skip to content

Commit a412738

Browse files
authored
Improve getting started docs (#13875)
- Show complete code examples for dynamic typing - Make clearer that the insides of dynamically typed functions will not be checked - Remove emphasis on function signatures. The cheat sheet does a better job than this document. Try to keep this more on a concept level. (I plan on making similar changes to the other parts of this doc) - Emphasise the presence of --strict, since it's 2022.
1 parent 6f80fe0 commit a412738

File tree

2 files changed

+47
-77
lines changed

2 files changed

+47
-77
lines changed

docs/source/existing_code.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ fraction of production network requests. This clearly requires more
168168
care, as type collection could impact the reliability or the
169169
performance of your service.
170170

171+
.. _getting-to-strict:
172+
171173
Introduce stricter options
172174
--------------------------
173175

@@ -181,7 +183,7 @@ An excellent goal to aim for is to have your codebase pass when run against ``my
181183
This basically ensures that you will never have a type related error without an explicit
182184
circumvention somewhere (such as a ``# type: ignore`` comment).
183185

184-
The following config is equivalent to ``--strict``:
186+
The following config is equivalent to ``--strict`` (as of mypy 0.990):
185187

186188
.. code-block:: text
187189

docs/source/getting_started.rst

Lines changed: 44 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ easy to adopt mypy incrementally.
4444
In order to get useful diagnostics from mypy, you must add *type annotations*
4545
to your code. See the section below for details.
4646

47-
Function signatures and dynamic vs static typing
48-
************************************************
47+
Dynamic vs static typing
48+
************************
4949

5050
A function without type annotations is considered to be *dynamically typed* by mypy:
5151

@@ -57,22 +57,32 @@ A function without type annotations is considered to be *dynamically typed* by m
5757
By default, mypy will **not** type check dynamically typed functions. This means
5858
that with a few exceptions, mypy will not report any errors with regular unannotated Python.
5959

60-
This is the case even if you misuse the function: for example, mypy would currently
61-
not report any errors if you tried running ``greeting(3)`` or ``greeting(b"Alice")``
62-
even though those function calls would result in errors at runtime.
60+
This is the case even if you misuse the function!
61+
62+
.. code-block:: python
63+
64+
def greeting(name):
65+
return 'Hello ' + name
66+
67+
# These calls will fail when the program run, but mypy does not report an error
68+
# because "greeting" does not have type annotations.
69+
greeting(123)
70+
greeting(b"Alice")
6371
64-
You can teach mypy to detect these kinds of bugs by adding *type annotations* (also
65-
known as *type hints*). For example, you can teach mypy that ``greeting`` both accepts
72+
We can get mypy to detect these kinds of bugs by adding *type annotations* (also
73+
known as *type hints*). For example, you can tell mypy that ``greeting`` both accepts
6674
and returns a string like so:
6775

6876
.. code-block:: python
6977
78+
# The "name: str" annotation says that the "name" argument should be a string
79+
# The "-> str" annotation says that "greeting" will return a string
7080
def greeting(name: str) -> str:
7181
return 'Hello ' + name
7282
73-
This function is now *statically typed*: mypy can use the provided type hints to detect
74-
incorrect usages of the ``greeting`` function. For example, it will reject the following
75-
calls since the arguments have invalid types:
83+
This function is now *statically typed*: mypy will use the provided type hints
84+
to detect incorrect use of the ``greeting`` function and incorrect use of
85+
variables within the ``greeting`` function. For example:
7686

7787
.. code-block:: python
7888
@@ -81,6 +91,10 @@ calls since the arguments have invalid types:
8191
8292
greeting(3) # Argument 1 to "greeting" has incompatible type "int"; expected "str"
8393
greeting(b'Alice') # Argument 1 to "greeting" has incompatible type "bytes"; expected "str"
94+
greeting("World!") # No error
95+
96+
def bad_greeting(name: str) -> str:
97+
return 'Hello ' * name # Unsupported operand types for * ("str" and "str")
8498
8599
Being able to pick whether you want a function to be dynamically or statically
86100
typed can be very helpful. For example, if you are migrating an existing
@@ -91,56 +105,32 @@ the code using dynamic typing and only add type hints later once the code is mor
91105

92106
Once you are finished migrating or prototyping your code, you can make mypy warn you
93107
if you add a dynamic function by mistake by using the :option:`--disallow-untyped-defs <mypy --disallow-untyped-defs>`
94-
flag. See :ref:`command-line` for more information on configuring mypy.
95-
96-
More function signatures
97-
************************
98-
99-
Here are a few more examples of adding type hints to function signatures.
100-
101-
If a function does not explicitly return a value, give it a return
102-
type of ``None``. Using a ``None`` result in a statically typed
103-
context results in a type check error:
104-
105-
.. code-block:: python
108+
flag. You can also get mypy to provide some limited checking of dynamically typed
109+
functions by using the :option:`--check-untyped-defs <mypy --check-untyped-defs>` flag.
110+
See :ref:`command-line` for more information on configuring mypy.
106111

107-
def p() -> None:
108-
print('hello')
112+
Strict mode and configuration
113+
*****************************
109114

110-
a = p() # Error: "p" does not return a value
115+
Mypy has a *strict mode* that enables a number of additional checks,
116+
like :option:`--disallow-untyped-defs <mypy --disallow-untyped-defs>`.
111117

112-
Make sure to remember to include ``None``: if you don't, the function
113-
will be dynamically typed. For example:
118+
If you run mypy with the :option:`--strict <mypy --strict>` flag, you
119+
will basically never get a type related error at runtime without a corresponding
120+
mypy error, unless you explicitly circumvent mypy somehow.
114121

115-
.. code-block:: python
116-
117-
def f():
118-
1 + 'x' # No static type error (dynamically typed)
119-
120-
def g() -> None:
121-
1 + 'x' # Type check error (statically typed)
122-
123-
Arguments with default values can be annotated like so:
124-
125-
.. code-block:: python
126-
127-
def greeting(name: str, excited: bool = False) -> str:
128-
message = f'Hello, {name}'
129-
if excited:
130-
message += '!!!'
131-
return message
122+
However, this flag will probably be too aggressive if you are trying
123+
to add static types to a large, existing codebase. See :ref:`existing-code`
124+
for suggestions on how to handle that case.
132125

133-
``*args`` and ``**kwargs`` arguments can be annotated like so:
126+
Mypy is very configurable, so you can start with using ``--strict``
127+
and toggle off individual checks. For instance, if you use many third
128+
party libraries that do not have types,
129+
:option:`--ignore-missing-imports <mypy --ignore-missing-imports>`
130+
may be useful. See :ref:`getting-to-strict` for how to build up to ``--strict``.
134131

135-
.. code-block:: python
136-
137-
def stars(*args: int, **kwargs: float) -> None:
138-
# 'args' has type 'tuple[int, ...]' (a tuple of ints)
139-
# 'kwargs' has type 'dict[str, float]' (a dict of strs to floats)
140-
for arg in args:
141-
print(arg)
142-
for key, value in kwargs.items():
143-
print(key, value)
132+
See :ref:`command-line` and :ref:`config-file` for a complete reference on
133+
configuration options.
144134

145135
Additional types, and the typing module
146136
***************************************
@@ -440,28 +430,6 @@ You can also :ref:`create
440430
stubs <stub-files>` easily. We discuss strategies for handling errors
441431
about missing stubs in :ref:`ignore-missing-imports`.
442432

443-
Configuring mypy
444-
****************
445-
446-
Mypy supports many command line options that you can use to tweak how
447-
mypy behaves: see :ref:`command-line` for more details.
448-
449-
For example, suppose you want to make sure *all* functions within your
450-
codebase are using static typing and make mypy report an error if you
451-
add a dynamically-typed function by mistake. You can make mypy do this
452-
by running mypy with the :option:`--disallow-untyped-defs <mypy --disallow-untyped-defs>` flag.
453-
454-
Another potentially useful flag is :option:`--strict <mypy --strict>`, which enables many
455-
(though not all) of the available strictness options -- including
456-
:option:`--disallow-untyped-defs <mypy --disallow-untyped-defs>`.
457-
458-
This flag is mostly useful if you're starting a new project from scratch
459-
and want to maintain a high degree of type safety from day one. However,
460-
this flag will probably be too aggressive if you either plan on using
461-
many untyped third party libraries or are trying to add static types to
462-
a large, existing codebase. See :ref:`existing-code` for more suggestions
463-
on how to handle the latter case.
464-
465433
Next steps
466434
**********
467435

0 commit comments

Comments
 (0)