Skip to content

Commit 236cdad

Browse files
[3.12] gh-107432 Fix incorrect indentation in annotations HOWTO (GH-107445) (#107654)
gh-107432 Fix incorrect indentation in annotations HOWTO (GH-107445) gh-107432 Fix incorrect indentation in annotations document Body text in https://docs.python.org/3/howto/annotations.html was indented throughout, and was being rendered in blockquote elements. (cherry picked from commit 5e2746d) Co-authored-by: Daniele Procida <[email protected]>
1 parent 6e4eec7 commit 236cdad

File tree

1 file changed

+163
-163
lines changed

1 file changed

+163
-163
lines changed

Doc/howto/annotations.rst

Lines changed: 163 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -32,201 +32,201 @@ Annotations Best Practices
3232
Accessing The Annotations Dict Of An Object In Python 3.10 And Newer
3333
====================================================================
3434

35-
Python 3.10 adds a new function to the standard library:
36-
:func:`inspect.get_annotations`. In Python versions 3.10
37-
and newer, calling this function is the best practice for
38-
accessing the annotations dict of any object that supports
39-
annotations. This function can also "un-stringize"
40-
stringized annotations for you.
41-
42-
If for some reason :func:`inspect.get_annotations` isn't
43-
viable for your use case, you may access the
44-
``__annotations__`` data member manually. Best practice
45-
for this changed in Python 3.10 as well: as of Python 3.10,
46-
``o.__annotations__`` is guaranteed to *always* work
47-
on Python functions, classes, and modules. If you're
48-
certain the object you're examining is one of these three
49-
*specific* objects, you may simply use ``o.__annotations__``
50-
to get at the object's annotations dict.
51-
52-
However, other types of callables--for example,
53-
callables created by :func:`functools.partial`--may
54-
not have an ``__annotations__`` attribute defined. When
55-
accessing the ``__annotations__`` of a possibly unknown
56-
object, best practice in Python versions 3.10 and
57-
newer is to call :func:`getattr` with three arguments,
58-
for example ``getattr(o, '__annotations__', None)``.
59-
60-
Before Python 3.10, accessing ``__annotations__`` on a class that
61-
defines no annotations but that has a parent class with
62-
annotations would return the parent's ``__annotations__``.
63-
In Python 3.10 and newer, the child class's annotations
64-
will be an empty dict instead.
35+
Python 3.10 adds a new function to the standard library:
36+
:func:`inspect.get_annotations`. In Python versions 3.10
37+
and newer, calling this function is the best practice for
38+
accessing the annotations dict of any object that supports
39+
annotations. This function can also "un-stringize"
40+
stringized annotations for you.
41+
42+
If for some reason :func:`inspect.get_annotations` isn't
43+
viable for your use case, you may access the
44+
``__annotations__`` data member manually. Best practice
45+
for this changed in Python 3.10 as well: as of Python 3.10,
46+
``o.__annotations__`` is guaranteed to *always* work
47+
on Python functions, classes, and modules. If you're
48+
certain the object you're examining is one of these three
49+
*specific* objects, you may simply use ``o.__annotations__``
50+
to get at the object's annotations dict.
51+
52+
However, other types of callables--for example,
53+
callables created by :func:`functools.partial`--may
54+
not have an ``__annotations__`` attribute defined. When
55+
accessing the ``__annotations__`` of a possibly unknown
56+
object, best practice in Python versions 3.10 and
57+
newer is to call :func:`getattr` with three arguments,
58+
for example ``getattr(o, '__annotations__', None)``.
59+
60+
Before Python 3.10, accessing ``__annotations__`` on a class that
61+
defines no annotations but that has a parent class with
62+
annotations would return the parent's ``__annotations__``.
63+
In Python 3.10 and newer, the child class's annotations
64+
will be an empty dict instead.
6565

6666

6767
Accessing The Annotations Dict Of An Object In Python 3.9 And Older
6868
===================================================================
6969

70-
In Python 3.9 and older, accessing the annotations dict
71-
of an object is much more complicated than in newer versions.
72-
The problem is a design flaw in these older versions of Python,
73-
specifically to do with class annotations.
70+
In Python 3.9 and older, accessing the annotations dict
71+
of an object is much more complicated than in newer versions.
72+
The problem is a design flaw in these older versions of Python,
73+
specifically to do with class annotations.
7474

75-
Best practice for accessing the annotations dict of other
76-
objects--functions, other callables, and modules--is the same
77-
as best practice for 3.10, assuming you aren't calling
78-
:func:`inspect.get_annotations`: you should use three-argument
79-
:func:`getattr` to access the object's ``__annotations__``
80-
attribute.
75+
Best practice for accessing the annotations dict of other
76+
objects--functions, other callables, and modules--is the same
77+
as best practice for 3.10, assuming you aren't calling
78+
:func:`inspect.get_annotations`: you should use three-argument
79+
:func:`getattr` to access the object's ``__annotations__``
80+
attribute.
8181

82-
Unfortunately, this isn't best practice for classes. The problem
83-
is that, since ``__annotations__`` is optional on classes, and
84-
because classes can inherit attributes from their base classes,
85-
accessing the ``__annotations__`` attribute of a class may
86-
inadvertently return the annotations dict of a *base class.*
87-
As an example::
82+
Unfortunately, this isn't best practice for classes. The problem
83+
is that, since ``__annotations__`` is optional on classes, and
84+
because classes can inherit attributes from their base classes,
85+
accessing the ``__annotations__`` attribute of a class may
86+
inadvertently return the annotations dict of a *base class.*
87+
As an example::
8888

89-
class Base:
90-
a: int = 3
91-
b: str = 'abc'
89+
class Base:
90+
a: int = 3
91+
b: str = 'abc'
9292

93-
class Derived(Base):
94-
pass
93+
class Derived(Base):
94+
pass
9595

96-
print(Derived.__annotations__)
96+
print(Derived.__annotations__)
9797

98-
This will print the annotations dict from ``Base``, not
99-
``Derived``.
98+
This will print the annotations dict from ``Base``, not
99+
``Derived``.
100100

101-
Your code will have to have a separate code path if the object
102-
you're examining is a class (``isinstance(o, type)``).
103-
In that case, best practice relies on an implementation detail
104-
of Python 3.9 and before: if a class has annotations defined,
105-
they are stored in the class's ``__dict__`` dictionary. Since
106-
the class may or may not have annotations defined, best practice
107-
is to call the ``get`` method on the class dict.
101+
Your code will have to have a separate code path if the object
102+
you're examining is a class (``isinstance(o, type)``).
103+
In that case, best practice relies on an implementation detail
104+
of Python 3.9 and before: if a class has annotations defined,
105+
they are stored in the class's ``__dict__`` dictionary. Since
106+
the class may or may not have annotations defined, best practice
107+
is to call the ``get`` method on the class dict.
108108

109-
To put it all together, here is some sample code that safely
110-
accesses the ``__annotations__`` attribute on an arbitrary
111-
object in Python 3.9 and before::
109+
To put it all together, here is some sample code that safely
110+
accesses the ``__annotations__`` attribute on an arbitrary
111+
object in Python 3.9 and before::
112112

113-
if isinstance(o, type):
114-
ann = o.__dict__.get('__annotations__', None)
115-
else:
116-
ann = getattr(o, '__annotations__', None)
113+
if isinstance(o, type):
114+
ann = o.__dict__.get('__annotations__', None)
115+
else:
116+
ann = getattr(o, '__annotations__', None)
117117

118-
After running this code, ``ann`` should be either a
119-
dictionary or ``None``. You're encouraged to double-check
120-
the type of ``ann`` using :func:`isinstance` before further
121-
examination.
118+
After running this code, ``ann`` should be either a
119+
dictionary or ``None``. You're encouraged to double-check
120+
the type of ``ann`` using :func:`isinstance` before further
121+
examination.
122122

123-
Note that some exotic or malformed type objects may not have
124-
a ``__dict__`` attribute, so for extra safety you may also wish
125-
to use :func:`getattr` to access ``__dict__``.
123+
Note that some exotic or malformed type objects may not have
124+
a ``__dict__`` attribute, so for extra safety you may also wish
125+
to use :func:`getattr` to access ``__dict__``.
126126

127127

128128
Manually Un-Stringizing Stringized Annotations
129129
==============================================
130130

131-
In situations where some annotations may be "stringized",
132-
and you wish to evaluate those strings to produce the
133-
Python values they represent, it really is best to
134-
call :func:`inspect.get_annotations` to do this work
135-
for you.
136-
137-
If you're using Python 3.9 or older, or if for some reason
138-
you can't use :func:`inspect.get_annotations`, you'll need
139-
to duplicate its logic. You're encouraged to examine the
140-
implementation of :func:`inspect.get_annotations` in the
141-
current Python version and follow a similar approach.
142-
143-
In a nutshell, if you wish to evaluate a stringized annotation
144-
on an arbitrary object ``o``:
145-
146-
* If ``o`` is a module, use ``o.__dict__`` as the
147-
``globals`` when calling :func:`eval`.
148-
* If ``o`` is a class, use ``sys.modules[o.__module__].__dict__``
149-
as the ``globals``, and ``dict(vars(o))`` as the ``locals``,
150-
when calling :func:`eval`.
151-
* If ``o`` is a wrapped callable using :func:`functools.update_wrapper`,
152-
:func:`functools.wraps`, or :func:`functools.partial`, iteratively
153-
unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as
154-
appropriate, until you have found the root unwrapped function.
155-
* If ``o`` is a callable (but not a class), use
156-
``o.__globals__`` as the globals when calling :func:`eval`.
157-
158-
However, not all string values used as annotations can
159-
be successfully turned into Python values by :func:`eval`.
160-
String values could theoretically contain any valid string,
161-
and in practice there are valid use cases for type hints that
162-
require annotating with string values that specifically
163-
*can't* be evaluated. For example:
164-
165-
* :pep:`604` union types using ``|``, before support for this
166-
was added to Python 3.10.
167-
* Definitions that aren't needed at runtime, only imported
168-
when :const:`typing.TYPE_CHECKING` is true.
169-
170-
If :func:`eval` attempts to evaluate such values, it will
171-
fail and raise an exception. So, when designing a library
172-
API that works with annotations, it's recommended to only
173-
attempt to evaluate string values when explicitly requested
174-
to by the caller.
131+
In situations where some annotations may be "stringized",
132+
and you wish to evaluate those strings to produce the
133+
Python values they represent, it really is best to
134+
call :func:`inspect.get_annotations` to do this work
135+
for you.
136+
137+
If you're using Python 3.9 or older, or if for some reason
138+
you can't use :func:`inspect.get_annotations`, you'll need
139+
to duplicate its logic. You're encouraged to examine the
140+
implementation of :func:`inspect.get_annotations` in the
141+
current Python version and follow a similar approach.
142+
143+
In a nutshell, if you wish to evaluate a stringized annotation
144+
on an arbitrary object ``o``:
145+
146+
* If ``o`` is a module, use ``o.__dict__`` as the
147+
``globals`` when calling :func:`eval`.
148+
* If ``o`` is a class, use ``sys.modules[o.__module__].__dict__``
149+
as the ``globals``, and ``dict(vars(o))`` as the ``locals``,
150+
when calling :func:`eval`.
151+
* If ``o`` is a wrapped callable using :func:`functools.update_wrapper`,
152+
:func:`functools.wraps`, or :func:`functools.partial`, iteratively
153+
unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as
154+
appropriate, until you have found the root unwrapped function.
155+
* If ``o`` is a callable (but not a class), use
156+
``o.__globals__`` as the globals when calling :func:`eval`.
157+
158+
However, not all string values used as annotations can
159+
be successfully turned into Python values by :func:`eval`.
160+
String values could theoretically contain any valid string,
161+
and in practice there are valid use cases for type hints that
162+
require annotating with string values that specifically
163+
*can't* be evaluated. For example:
164+
165+
* :pep:`604` union types using ``|``, before support for this
166+
was added to Python 3.10.
167+
* Definitions that aren't needed at runtime, only imported
168+
when :const:`typing.TYPE_CHECKING` is true.
169+
170+
If :func:`eval` attempts to evaluate such values, it will
171+
fail and raise an exception. So, when designing a library
172+
API that works with annotations, it's recommended to only
173+
attempt to evaluate string values when explicitly requested
174+
to by the caller.
175175

176176

177177
Best Practices For ``__annotations__`` In Any Python Version
178178
============================================================
179179

180-
* You should avoid assigning to the ``__annotations__`` member
181-
of objects directly. Let Python manage setting ``__annotations__``.
180+
* You should avoid assigning to the ``__annotations__`` member
181+
of objects directly. Let Python manage setting ``__annotations__``.
182182

183-
* If you do assign directly to the ``__annotations__`` member
184-
of an object, you should always set it to a ``dict`` object.
183+
* If you do assign directly to the ``__annotations__`` member
184+
of an object, you should always set it to a ``dict`` object.
185185

186-
* If you directly access the ``__annotations__`` member
187-
of an object, you should ensure that it's a
188-
dictionary before attempting to examine its contents.
186+
* If you directly access the ``__annotations__`` member
187+
of an object, you should ensure that it's a
188+
dictionary before attempting to examine its contents.
189189

190-
* You should avoid modifying ``__annotations__`` dicts.
190+
* You should avoid modifying ``__annotations__`` dicts.
191191

192-
* You should avoid deleting the ``__annotations__`` attribute
193-
of an object.
192+
* You should avoid deleting the ``__annotations__`` attribute
193+
of an object.
194194

195195

196196
``__annotations__`` Quirks
197197
==========================
198198

199-
In all versions of Python 3, function
200-
objects lazy-create an annotations dict if no annotations
201-
are defined on that object. You can delete the ``__annotations__``
202-
attribute using ``del fn.__annotations__``, but if you then
203-
access ``fn.__annotations__`` the object will create a new empty dict
204-
that it will store and return as its annotations. Deleting the
205-
annotations on a function before it has lazily created its annotations
206-
dict will throw an ``AttributeError``; using ``del fn.__annotations__``
207-
twice in a row is guaranteed to always throw an ``AttributeError``.
208-
209-
Everything in the above paragraph also applies to class and module
210-
objects in Python 3.10 and newer.
211-
212-
In all versions of Python 3, you can set ``__annotations__``
213-
on a function object to ``None``. However, subsequently
214-
accessing the annotations on that object using ``fn.__annotations__``
215-
will lazy-create an empty dictionary as per the first paragraph of
216-
this section. This is *not* true of modules and classes, in any Python
217-
version; those objects permit setting ``__annotations__`` to any
218-
Python value, and will retain whatever value is set.
219-
220-
If Python stringizes your annotations for you
221-
(using ``from __future__ import annotations``), and you
222-
specify a string as an annotation, the string will
223-
itself be quoted. In effect the annotation is quoted
224-
*twice.* For example::
225-
226-
from __future__ import annotations
227-
def foo(a: "str"): pass
228-
229-
print(foo.__annotations__)
230-
231-
This prints ``{'a': "'str'"}``. This shouldn't really be considered
232-
a "quirk"; it's mentioned here simply because it might be surprising.
199+
In all versions of Python 3, function
200+
objects lazy-create an annotations dict if no annotations
201+
are defined on that object. You can delete the ``__annotations__``
202+
attribute using ``del fn.__annotations__``, but if you then
203+
access ``fn.__annotations__`` the object will create a new empty dict
204+
that it will store and return as its annotations. Deleting the
205+
annotations on a function before it has lazily created its annotations
206+
dict will throw an ``AttributeError``; using ``del fn.__annotations__``
207+
twice in a row is guaranteed to always throw an ``AttributeError``.
208+
209+
Everything in the above paragraph also applies to class and module
210+
objects in Python 3.10 and newer.
211+
212+
In all versions of Python 3, you can set ``__annotations__``
213+
on a function object to ``None``. However, subsequently
214+
accessing the annotations on that object using ``fn.__annotations__``
215+
will lazy-create an empty dictionary as per the first paragraph of
216+
this section. This is *not* true of modules and classes, in any Python
217+
version; those objects permit setting ``__annotations__`` to any
218+
Python value, and will retain whatever value is set.
219+
220+
If Python stringizes your annotations for you
221+
(using ``from __future__ import annotations``), and you
222+
specify a string as an annotation, the string will
223+
itself be quoted. In effect the annotation is quoted
224+
*twice.* For example::
225+
226+
from __future__ import annotations
227+
def foo(a: "str"): pass
228+
229+
print(foo.__annotations__)
230+
231+
This prints ``{'a': "'str'"}``. This shouldn't really be considered
232+
a "quirk"; it's mentioned here simply because it might be surprising.

0 commit comments

Comments
 (0)