17db96d56Sopenharmony_ci.. _annotations-howto:
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci**************************
47db96d56Sopenharmony_ciAnnotations Best Practices
57db96d56Sopenharmony_ci**************************
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci:author: Larry Hastings
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci.. topic:: Abstract
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ci  This document is designed to encapsulate the best practices
127db96d56Sopenharmony_ci  for working with annotations dicts.  If you write Python code
137db96d56Sopenharmony_ci  that examines ``__annotations__`` on Python objects, we
147db96d56Sopenharmony_ci  encourage you to follow the guidelines described below.
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci  The document is organized into four sections:
177db96d56Sopenharmony_ci  best practices for accessing the annotations of an object
187db96d56Sopenharmony_ci  in Python versions 3.10 and newer,
197db96d56Sopenharmony_ci  best practices for accessing the annotations of an object
207db96d56Sopenharmony_ci  in Python versions 3.9 and older,
217db96d56Sopenharmony_ci  other best practices
227db96d56Sopenharmony_ci  for ``__annotations__`` that apply to any Python version,
237db96d56Sopenharmony_ci  and
247db96d56Sopenharmony_ci  quirks of ``__annotations__``.
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci  Note that this document is specifically about working with
277db96d56Sopenharmony_ci  ``__annotations__``, not uses *for* annotations.
287db96d56Sopenharmony_ci  If you're looking for information on how to use "type hints"
297db96d56Sopenharmony_ci  in your code, please see the :mod:`typing` module.
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ciAccessing The Annotations Dict Of An Object In Python 3.10 And Newer
337db96d56Sopenharmony_ci====================================================================
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci  Python 3.10 adds a new function to the standard library:
367db96d56Sopenharmony_ci  :func:`inspect.get_annotations`.  In Python versions 3.10
377db96d56Sopenharmony_ci  and newer, calling this function is the best practice for
387db96d56Sopenharmony_ci  accessing the annotations dict of any object that supports
397db96d56Sopenharmony_ci  annotations.  This function can also "un-stringize"
407db96d56Sopenharmony_ci  stringized annotations for you.
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci  If for some reason :func:`inspect.get_annotations` isn't
437db96d56Sopenharmony_ci  viable for your use case, you may access the
447db96d56Sopenharmony_ci  ``__annotations__`` data member manually.  Best practice
457db96d56Sopenharmony_ci  for this changed in Python 3.10 as well: as of Python 3.10,
467db96d56Sopenharmony_ci  ``o.__annotations__`` is guaranteed to *always* work
477db96d56Sopenharmony_ci  on Python functions, classes, and modules.  If you're
487db96d56Sopenharmony_ci  certain the object you're examining is one of these three
497db96d56Sopenharmony_ci  *specific* objects, you may simply use ``o.__annotations__``
507db96d56Sopenharmony_ci  to get at the object's annotations dict.
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci  However, other types of callables--for example,
537db96d56Sopenharmony_ci  callables created by :func:`functools.partial`--may
547db96d56Sopenharmony_ci  not have an ``__annotations__`` attribute defined.  When
557db96d56Sopenharmony_ci  accessing the ``__annotations__`` of a possibly unknown
567db96d56Sopenharmony_ci  object,  best practice in Python versions 3.10 and
577db96d56Sopenharmony_ci  newer is to call :func:`getattr` with three arguments,
587db96d56Sopenharmony_ci  for example ``getattr(o, '__annotations__', None)``.
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci  Before Python 3.10, accessing ``__annotations__`` on a class that
617db96d56Sopenharmony_ci  defines no annotations but that has a parent class with
627db96d56Sopenharmony_ci  annotations would return the parent's ``__annotations__``.
637db96d56Sopenharmony_ci  In Python 3.10 and newer, the child class's annotations
647db96d56Sopenharmony_ci  will be an empty dict instead.
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ciAccessing The Annotations Dict Of An Object In Python 3.9 And Older
687db96d56Sopenharmony_ci===================================================================
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci  In Python 3.9 and older, accessing the annotations dict
717db96d56Sopenharmony_ci  of an object is much more complicated than in newer versions.
727db96d56Sopenharmony_ci  The problem is a design flaw in these older versions of Python,
737db96d56Sopenharmony_ci  specifically to do with class annotations.
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci  Best practice for accessing the annotations dict of other
767db96d56Sopenharmony_ci  objects--functions, other callables, and modules--is the same
777db96d56Sopenharmony_ci  as best practice for 3.10, assuming you aren't calling
787db96d56Sopenharmony_ci  :func:`inspect.get_annotations`: you should use three-argument
797db96d56Sopenharmony_ci  :func:`getattr` to access the object's ``__annotations__``
807db96d56Sopenharmony_ci  attribute.
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci  Unfortunately, this isn't best practice for classes.  The problem
837db96d56Sopenharmony_ci  is that, since ``__annotations__`` is optional on classes, and
847db96d56Sopenharmony_ci  because classes can inherit attributes from their base classes,
857db96d56Sopenharmony_ci  accessing the ``__annotations__`` attribute of a class may
867db96d56Sopenharmony_ci  inadvertently return the annotations dict of a *base class.*
877db96d56Sopenharmony_ci  As an example::
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci      class Base:
907db96d56Sopenharmony_ci          a: int = 3
917db96d56Sopenharmony_ci          b: str = 'abc'
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci      class Derived(Base):
947db96d56Sopenharmony_ci          pass
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci      print(Derived.__annotations__)
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci  This will print the annotations dict from ``Base``, not
997db96d56Sopenharmony_ci  ``Derived``.
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci  Your code will have to have a separate code path if the object
1027db96d56Sopenharmony_ci  you're examining is a class (``isinstance(o, type)``).
1037db96d56Sopenharmony_ci  In that case, best practice relies on an implementation detail
1047db96d56Sopenharmony_ci  of Python 3.9 and before: if a class has annotations defined,
1057db96d56Sopenharmony_ci  they are stored in the class's ``__dict__`` dictionary.  Since
1067db96d56Sopenharmony_ci  the class may or may not have annotations defined, best practice
1077db96d56Sopenharmony_ci  is to call the ``get`` method on the class dict.
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci  To put it all together, here is some sample code that safely
1107db96d56Sopenharmony_ci  accesses the ``__annotations__`` attribute on an arbitrary
1117db96d56Sopenharmony_ci  object in Python 3.9 and before::
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci      if isinstance(o, type):
1147db96d56Sopenharmony_ci          ann = o.__dict__.get('__annotations__', None)
1157db96d56Sopenharmony_ci      else:
1167db96d56Sopenharmony_ci          ann = getattr(o, '__annotations__', None)
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci  After running this code, ``ann`` should be either a
1197db96d56Sopenharmony_ci  dictionary or ``None``.  You're encouraged to double-check
1207db96d56Sopenharmony_ci  the type of ``ann`` using :func:`isinstance` before further
1217db96d56Sopenharmony_ci  examination.
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ci  Note that some exotic or malformed type objects may not have
1247db96d56Sopenharmony_ci  a ``__dict__`` attribute, so for extra safety you may also wish
1257db96d56Sopenharmony_ci  to use :func:`getattr` to access ``__dict__``.
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ciManually Un-Stringizing Stringized Annotations
1297db96d56Sopenharmony_ci==============================================
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci  In situations where some annotations may be "stringized",
1327db96d56Sopenharmony_ci  and you wish to evaluate those strings to produce the
1337db96d56Sopenharmony_ci  Python values they represent, it really is best to
1347db96d56Sopenharmony_ci  call :func:`inspect.get_annotations` to do this work
1357db96d56Sopenharmony_ci  for you.
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci  If you're using Python 3.9 or older, or if for some reason
1387db96d56Sopenharmony_ci  you can't use :func:`inspect.get_annotations`, you'll need
1397db96d56Sopenharmony_ci  to duplicate its logic.  You're encouraged to examine the
1407db96d56Sopenharmony_ci  implementation of :func:`inspect.get_annotations` in the
1417db96d56Sopenharmony_ci  current Python version and follow a similar approach.
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci  In a nutshell, if you wish to evaluate a stringized annotation
1447db96d56Sopenharmony_ci  on an arbitrary object ``o``:
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci  * If ``o`` is a module, use ``o.__dict__`` as the
1477db96d56Sopenharmony_ci    ``globals`` when calling :func:`eval`.
1487db96d56Sopenharmony_ci  * If ``o`` is a class, use ``sys.modules[o.__module__].__dict__``
1497db96d56Sopenharmony_ci    as the ``globals``, and ``dict(vars(o))`` as the ``locals``,
1507db96d56Sopenharmony_ci    when calling :func:`eval`.
1517db96d56Sopenharmony_ci  * If ``o`` is a wrapped callable using :func:`functools.update_wrapper`,
1527db96d56Sopenharmony_ci    :func:`functools.wraps`, or :func:`functools.partial`, iteratively
1537db96d56Sopenharmony_ci    unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as
1547db96d56Sopenharmony_ci    appropriate, until you have found the root unwrapped function.
1557db96d56Sopenharmony_ci  * If ``o`` is a callable (but not a class), use
1567db96d56Sopenharmony_ci    ``o.__globals__`` as the globals when calling :func:`eval`.
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci  However, not all string values used as annotations can
1597db96d56Sopenharmony_ci  be successfully turned into Python values by :func:`eval`.
1607db96d56Sopenharmony_ci  String values could theoretically contain any valid string,
1617db96d56Sopenharmony_ci  and in practice there are valid use cases for type hints that
1627db96d56Sopenharmony_ci  require annotating with string values that specifically
1637db96d56Sopenharmony_ci  *can't* be evaluated.  For example:
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_ci  * :pep:`604` union types using ``|``, before support for this
1667db96d56Sopenharmony_ci    was added to Python 3.10.
1677db96d56Sopenharmony_ci  * Definitions that aren't needed at runtime, only imported
1687db96d56Sopenharmony_ci    when :const:`typing.TYPE_CHECKING` is true.
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci  If :func:`eval` attempts to evaluate such values, it will
1717db96d56Sopenharmony_ci  fail and raise an exception.  So, when designing a library
1727db96d56Sopenharmony_ci  API that works with annotations, it's recommended to only
1737db96d56Sopenharmony_ci  attempt to evaluate string values when explicitly requested
1747db96d56Sopenharmony_ci  to by the caller.
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ciBest Practices For ``__annotations__`` In Any Python Version
1787db96d56Sopenharmony_ci============================================================
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci  * You should avoid assigning to the ``__annotations__`` member
1817db96d56Sopenharmony_ci    of objects directly.  Let Python manage setting ``__annotations__``.
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci  * If you do assign directly to the ``__annotations__`` member
1847db96d56Sopenharmony_ci    of an object, you should always set it to a ``dict`` object.
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci  * If you directly access the ``__annotations__`` member
1877db96d56Sopenharmony_ci    of an object, you should ensure that it's a
1887db96d56Sopenharmony_ci    dictionary before attempting to examine its contents.
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci  * You should avoid modifying ``__annotations__`` dicts.
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_ci  * You should avoid deleting the ``__annotations__`` attribute
1937db96d56Sopenharmony_ci    of an object.
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci``__annotations__`` Quirks
1977db96d56Sopenharmony_ci==========================
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci  In all versions of Python 3, function
2007db96d56Sopenharmony_ci  objects lazy-create an annotations dict if no annotations
2017db96d56Sopenharmony_ci  are defined on that object.  You can delete the ``__annotations__``
2027db96d56Sopenharmony_ci  attribute using ``del fn.__annotations__``, but if you then
2037db96d56Sopenharmony_ci  access ``fn.__annotations__`` the object will create a new empty dict
2047db96d56Sopenharmony_ci  that it will store and return as its annotations.  Deleting the
2057db96d56Sopenharmony_ci  annotations on a function before it has lazily created its annotations
2067db96d56Sopenharmony_ci  dict will throw an ``AttributeError``; using ``del fn.__annotations__``
2077db96d56Sopenharmony_ci  twice in a row is guaranteed to always throw an ``AttributeError``.
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci  Everything in the above paragraph also applies to class and module
2107db96d56Sopenharmony_ci  objects in Python 3.10 and newer.
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci  In all versions of Python 3, you can set ``__annotations__``
2137db96d56Sopenharmony_ci  on a function object to ``None``.  However, subsequently
2147db96d56Sopenharmony_ci  accessing the annotations on that object using ``fn.__annotations__``
2157db96d56Sopenharmony_ci  will lazy-create an empty dictionary as per the first paragraph of
2167db96d56Sopenharmony_ci  this section.  This is *not* true of modules and classes, in any Python
2177db96d56Sopenharmony_ci  version; those objects permit setting ``__annotations__`` to any
2187db96d56Sopenharmony_ci  Python value, and will retain whatever value is set.
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci  If Python stringizes your annotations for you
2217db96d56Sopenharmony_ci  (using ``from __future__ import annotations``), and you
2227db96d56Sopenharmony_ci  specify a string as an annotation, the string will
2237db96d56Sopenharmony_ci  itself be quoted.  In effect the annotation is quoted
2247db96d56Sopenharmony_ci  *twice.*  For example::
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci       from __future__ import annotations
2277db96d56Sopenharmony_ci       def foo(a: "str"): pass
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci       print(foo.__annotations__)
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci  This prints ``{'a': "'str'"}``.  This shouldn't really be considered
2327db96d56Sopenharmony_ci  a "quirk"; it's mentioned here simply because it might be surprising.
233