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
144 changes: 131 additions & 13 deletions docs/spec/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,141 @@ 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 support narrowing based on:
* ``sys.version_info``
* ``sys.platform``
* ``sys.implementation.version``
* ``sys.implementation.name``

import sys
Type checkers should support combining these checks with:
* A ``not`` unary operator
* An ``and`` or ``or`` binary operator

if sys.version_info >= (3, 12):
# Python 3.12+
else:
# Python 3.11 and lower
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.

if sys.platform == 'win32':
# Windows specific definitions
else:
# Posix specific definitions
The comparison patterns for these variables are described in more detail in the following paragraphs.

Don't expect a checker to understand obfuscations like
``"".join(reversed(sys.platform)) == "xunil"``.
sys.version_info checks
^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers should support the following comparison patterns:
* ``sys.version_info >= <2-tuple>``
* ``sys.version_info < <2-tuple>``

Comparisons checks are only supported against the first two elements of the version tuple.
Use of named attributes is not supported.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Use of named attributes is not supported.
Use of named attributes is not mandated.

Copy link
Author

@Josverl Josverl Feb 22, 2026

Choose a reason for hiding this comment

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

IIRC @carljm requested that addition.
Agree that not mandated is clearer for the metadata.

< Same on line 238>

Copy link
Member

Choose a reason for hiding this comment

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

I think "not mandated" is clearer that type checkers are permitted to support something additionally if they wish to, but that they are not required to do so. So in general I prefer "not mandated".

The one exception for me might be comparisons against length-3-or-greater tuples for sys.version_info or sys.implementation.version. I think it's usually actually incorrect for a type checker to support those unless the type checker actually either infers the micro version of the Python install the user has locally or offers a configuration knob for the micro version to be specified. To my knowledge, no type checker currently does. So for comparisons between sys.version_info or sys.implementation.version and tuples of >=3 length, I think the stronger language of "not supported" (or maybe even stronger than that) is probably still appropriate


.. code-block:: python
:caption: Example `sys.version_info`
:emphasize-lines: 2

import sys
if sys.version_info >= (3, 12):
# Python 3.12+
else:
# Python 3.11 and lower

sys.platform checks
^^^^^^^^^^^^^^^^^^^

Type checkers should support the following comparison patterns:
* ``sys.platform == <string literal>``
* ``sys.platform != <string literal>``
* ``sys.platform in <tuple of string literals>``
* ``sys.platform not in <tuple of string literals>``

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

The membership checks ``in`` and ``not in``, only support simple containment testing to a tuple of literal strings.

.. code-block:: python
:caption: Example `sys.platform`
:emphasize-lines: 2,4

import sys
if sys.platform == 'win32':
# Windows specific definitions
if sys.platform in ("linux", "darwin"):
# Platform-specific stubs for Linux and macOS
...


sys.implementation.name checks
Copy link
Member

Choose a reason for hiding this comment

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

I think adding this has does have significant ecosystem costs (as outlined by @erictraut in https://discuss.python.org/t/proposal-to-improve-support-for-other-python-platforms-in-the-typing-specification/91877/3 ).

In the end I think it is probably worth it, because without it, type-checking for alternative implementations of Python seems quite difficult. The cost to type checkers themselves seems relatively low: one new config option, defaulting to "cpython".

Copy link
Author

Choose a reason for hiding this comment

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

The ecosystem is larger than just one implementation.
But I know I can't properly assess the effort needed to update and maintain the tooling I hope to influence.
So I'll leave the weighing up to those who can.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers should support comparison patterns:
* ``sys.implementation.name == <string literal>``
* ``sys.implementation.name != <string literal>``
* ``sys.implementation.name in <tuple of string literals>``
* ``sys.implementation.name not in <tuple of string literals>``

Common values: ``"cpython"``, ``"pypy"``, ``"micropython"``, ``"graalpy"``, ``"jython"``, ``"ironpython"``

.. code-block:: python
:caption: Example `sys.implementation.name`
: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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers should support the following comparison patterns:
* ``sys.implementation.version >= <2-tuple>``
* ``sys.implementation.version < <2-tuple>``

Comparisons checks are only supported against the first two elements of the implementation version tuple.
Use of named attributes is not supported.

.. code-block:: python
:caption: Example `sys.implementation.version`
:emphasize-lines: 2,4

import sys
if sys.implementation.name == "pypy" and sys.implementation.version >= (7, 3):
# PyPy version 7.3 and above
if sys.implementation.name == "micropython" and sys.implementation.version >= (1, 24):
# MicroPython version 1.24 and above

.. note::

``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 this is the same as `sys.version_info`.


No support for complex expressions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Type checkers are only required to support the above patterns, and are not required to evaluate complex expressions involving these variables.
For example, the pattern ``sys.platform == "linux"`` is supported but other syntax variants such as ``platform == "linux"`` and ``"win" not in sys.platform`` are not supported.
Copy link
Author

@Josverl Josverl Feb 22, 2026

Choose a reason for hiding this comment

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

@erictraut , @AlexWaygood

Alex proposed elsewhere to change not supported to not mandated

as this section also uses that, I wanted to check if there is a need to change the wording here as well.

Also on the light of Jelle's functionality scan


Therefore checkers are **not required** to understand obfuscations such as:

.. code-block:: python
:caption: Examples of unsupported or overly complex version/platform checks
:emphasize-lines: 3,5,7

import sys
from sys import platform
if "".join(reversed(sys.platform)) == "xunil":
# Linux specific code
if platform == "linux":
# Linux specific code
if "win" not in sys.platform:
# Non-Windows specific code


Configuration
^^^^^^^^^^^^^

Type checkers should provide configuration or CLI options to specify target sys.version, sys.platform, sys.implementation.name and sys.implementation.version.
The exact mechanism for this is implementation-defined by the type checker.

.. _`deprecated`:

Expand Down