diff --git a/docs/spec/directives.rst b/docs/spec/directives.rst index 488d71a26..0582ccfa9 100644 --- a/docs/spec/directives.rst +++ b/docs/spec/directives.rst @@ -154,23 +154,206 @@ left undefined by the typing spec at this time. Version and platform checking ----------------------------- -Type checkers are expected to understand simple version and platform -checks, e.g.:: +Type checkers should understand code paths as definitely reachable or not reachable +due to comparison tests against these symbols: - import sys +* ``sys.version_info`` +* ``sys.platform`` +* ``sys.implementation.version`` +* ``sys.implementation.name`` - if sys.version_info >= (3, 12): - # Python 3.12+ - else: - # Python 3.11 and lower +Type checkers should support combining these checks with: - if sys.platform == 'win32': - # Windows specific definitions - else: - # Posix specific definitions +* A ``not`` unary operator +* An ``and`` or ``or`` binary operator -Don't expect a checker to understand obfuscations like -``"".join(reversed(sys.platform)) == "xunil"``. +Type checkers are only required to support the fully-qualified form +(e.g., ``sys.platform``). Support for aliases or import variants +(e.g., ``from sys import platform``) is not required, though type checkers may +choose to support them. + +The comparison patterns for these variables are described in more detail in the +following paragraphs. + +sys.version_info checks +^^^^^^^^^^^^^^^^^^^^^^^^ + +Type checkers should support the following comparison patterns: + +* ``sys.version_info >= <2-tuple>`` +* ``sys.version_info < <2-tuple>`` + +where ``<2-tuple>`` is a literal tuple of two literal integers. + +Comparison checks are only supported against the first two elements of the version +tuple. Type checkers may choose to also support the 3-tuple +``sys.version_info >= <3-tuple>``. Type checkers are not expected to support +comparisons with named attributes of ``sys.version_info``. + +.. code-block:: python + :caption: Examples of ``sys.version_info`` checks + :emphasize-lines: 2,4 + + import sys + if sys.version_info >= (3, 13): + # Python 3.13+ + elif sys.version_info < (3, 11): + # Python 3.10 and lower + else: + # Python 3.11, 3.12 + +sys.platform checks +^^^^^^^^^^^^^^^^^^^ + +Type checkers should support the following comparison patterns: + +* ``sys.platform == `` +* ``sys.platform != `` +* ``sys.platform.startswith()`` +* ``sys.platform in `` +* ``sys.platform in `` +* ``sys.platform in `` +* ``sys.platform not in `` +* ``sys.platform not in `` +* ``sys.platform not in `` + +Common values: ``"linux"``, ``"darwin"``, ``"win32"``, ``"emscripten"``, +``"wasi"`` + +The membership checks ``in`` and ``not in`` only support simple containment +testing with a tuple, set, or list of literal strings. + +.. code-block:: python + :caption: Examples of ``sys.platform`` checks + :emphasize-lines: 2,4,6,8 + + import sys + if sys.platform == "win32": + # Windows-specific definitions + elif sys.platform in ("linux", "darwin"): + # Platform-specific stubs for Linux and macOS + elif sys.platform.startswith("freebsd"): + # FreeBSD-specific stubs, including versions such as "freebsd8" + if sys.platform not in ["wasi", "emscripten"]: + # Stubs for platforms other than WASI and Emscripten + + +sys.implementation.name checks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Type checkers should support comparison patterns: + +* ``sys.implementation.name == `` +* ``sys.implementation.name != `` +* ``sys.implementation.name in `` +* ``sys.implementation.name in `` +* ``sys.implementation.name in `` +* ``sys.implementation.name not in `` +* ``sys.implementation.name not in `` +* ``sys.implementation.name not in `` + +Default value: ``"cpython"``, unless configured otherwise. + +Common values: ``"cpython"``, ``"pypy"``, ``"micropython"``, ``"graalpy"``, +``"jython"``, ``"ironpython"`` + +.. code-block:: python + :caption: Examples of ``sys.implementation.name`` checks + :emphasize-lines: 2,4 + + import sys + if sys.implementation.name == "cpython": + # CPython-specific stub + if sys.implementation.name == "micropython": + # MicroPython-specific stub + + +sys.implementation.version checks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The value of ``sys.implementation.version`` is a tuple, in the same format as +``sys.version_info``. However, it represents the version of the +*Python implementation* rather than the version of the *Python language*. This has +a distinct meaning from the specific version of the Python language to which the +currently running interpreter conforms. + +For CPython (``sys.implementation.name == "cpython"``) this is the same as +``sys.version_info``. +For other Python implementations the value of ``sys.implementation.version`` may +differ and must be specified according to the type checkers' +configuration options. If it is not specified, type checkers should issue a warning +or error if it is used in a type-checking context. + +Type checkers should support the following comparison patterns: + +* ``sys.implementation.version >= <2-tuple>`` +* ``sys.implementation.version < <2-tuple>`` + +Comparison checks are only supported against the first two elements of the +implementation version tuple. Type checkers are not required to support comparisons +against named attributes of ``sys.implementation.version``. + +.. code-block:: python + :caption: Examples of ``sys.implementation.version`` checks + :emphasize-lines: 2,4 + + import sys + if sys.implementation.name == "pypy" and sys.implementation.version >= (7, 3): + # PyPy version 7.3 and above + elif sys.implementation.name == "micropython" and sys.implementation.version >= (1, 24): + # MicroPython version 1.24 and above + + +Required forms and optional extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Type checkers must support the forms described above. They may support additional +comparisons and syntax forms, but are not required to recognize them. For example, +type checkers are not required to support the following forms: + +.. code-block:: python + :caption: Examples of forms that type checkers are not required to support + :emphasize-lines: 4,6,8 + + import sys + from sys import platform + + if "".join(reversed(sys.platform)) == "xunil": + # Comparison using a computed value + if platform == "linux": + # Comparison using an imported alias + if "win" not in sys.platform: + # Substring membership test against sys.platform + + +Configuration +^^^^^^^^^^^^^ + +Type checkers must be able to retrieve the information from the Python +implementation's runtime environment, or provide configuration or CLI options +to specify target ``sys.version``, ``sys.platform``, +``sys.implementation.name`` and ``sys.implementation.version``. + +============================== ======================== ============= ===================================== +Symbol Suggested Format Example Suggested Default +============================== ======================== ============= ===================================== +``sys.version_info`` string ``"major.minor"`` ``"3.11"`` The version of the Python interpreter + used to run the type checker. +``sys.platform`` lowercase string ``"linux"`` The platform of the Python interpreter + used to run the type checker. +``sys.implementation.name`` lowercase string ``"cpython"`` ``"cpython"`` unless configured + otherwise. +``sys.implementation.version`` string ``"major.minor"`` ``"3.14"`` On CPython, default to the value used + for ``sys.version``. On other + implementations, the value must be + provided according to the type + checker's configuration options. +============================== ======================== ============= ===================================== + +The configuration options should allow users to specify the target values for these +symbols, so that type checkers can evaluate the version and platform checks +correctly. The exact mechanism and names for these configuration options are +implementation-specific and defined by each type checker. .. _`deprecated`: