Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 214 additions & 13 deletions docs/spec/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,23 +154,224 @@ 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.

Required support is limited to comparisons against literal two-element tuples.
Type checkers may choose to also support comparisons against three-element tuple
literals: ``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 == <string literal>``
* ``sys.platform != <string literal>``
* ``sys.platform.startswith(<string literal>)``
* ``sys.platform in <literal tuple of string literals>``
* ``sys.platform in <literal set of string literals>``
* ``sys.platform in <literal list of string literals>``
* ``sys.platform not in <literal tuple of string literals>``
* ``sys.platform not in <literal set of string literals>``
* ``sys.platform not in <literal list of string literals>``

Common values: ``"linux"``, ``"darwin"``, ``"win32"``, ``"emscripten"``,
``"wasi"``

The membership checks ``in`` and ``not in`` only support simple containment
testing with a literal tuple, literal set, or literal 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
Comment thread
Josverl marked this conversation as resolved.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers should support these comparison patterns with
``sys.implementation.name``:

* ``sys.implementation.name == <string literal>``
* ``sys.implementation.name != <string literal>``
* ``sys.implementation.name in <literal tuple of string literals>``
* ``sys.implementation.name in <literal set of string literals>``
* ``sys.implementation.name in <literal list of string literals>``
* ``sys.implementation.name not in <literal tuple of string literals>``
* ``sys.implementation.name not in <literal set of string literals>``
* ``sys.implementation.name not in <literal list of string literals>``

Default value: ``"cpython"``, unless configured otherwise.

Common values: ``"cpython"``, ``"pypy"``, ``"micropython"``, ``"graalpy"``,
``"android"``, ``"ios"``, ``"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
Comment thread
Josverl marked this conversation as resolved.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The value of ``sys.implementation.version`` is a tuple, in a similar 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
be specified in the type checker configuration or discovered at runtime.

Type checkers should support the following comparison patterns:
Comment thread
Josverl marked this conversation as resolved.

* ``sys.implementation.version >= <2-tuple>``
* ``sys.implementation.version < <2-tuple>``

Required support is limited to comparisons against literal two-element tuples.
Type checkers may choose to also support comparisons against three-element tuple
literals of ``sys.implementation.version``.
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


os.name checks
^^^^^^^^^^^^^^

Type checkers may optionally support comparisons of ``os.name`` with string
literals.

* ``os.name == <string literal>``
* ``os.name != <string literal>``

.. code-block:: python
:caption: Example of an ``os.name`` check
:emphasize-lines: 3

import os

if os.name == "posix":
# POSIX-specific code

Required forms and optional extensions
Comment thread
jorenham marked this conversation as resolved.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers must support the forms specified above as required. Support for additional

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consistency nit

Suggested change
Type checkers must support the forms specified above as required. Support for additional
Type checkers should support the forms specified above as required. Support for additional

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that "should" can be combined with "required" in this sentence.
That would degrade the meaning of the "required" statements in the prior paragraphs, which I think is incorrect.

comparison patterns and syntax forms is optional. 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 should be able to retrieve the information from the Python
implementation's runtime environment, or provide configuration or CLI options
to specify target ``sys.version_info``, ``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_info``. On other
implementations, the value should be
provided in configuration or
otherwise inferred.
============================== ======================== ============= =====================================

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`:

Expand Down
Loading