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
209 changes: 196 additions & 13 deletions docs/spec/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 == <string literal>``
* ``sys.platform != <string literal>``
* ``sys.platform.startswith(<string literal>)``
* ``sys.platform in <tuple of string literals>``
* ``sys.platform in <set of string literals>``
* ``sys.platform in <list of string literals>``
* ``sys.platform not in <tuple of string literals>``
* ``sys.platform not in <set of string literals>``
* ``sys.platform not in <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 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
Comment thread
Josverl marked this conversation as resolved.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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 in <set of string literals>``
* ``sys.implementation.name in <list of string literals>``
* ``sys.implementation.name not in <tuple of string literals>``
* ``sys.implementation.name not in <set of string literals>``
* ``sys.implementation.name not in <list of string literals>``

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
Comment thread
Josverl marked this conversation as resolved.


sys.implementation.version checks

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same as above, I think we should probably be explicit here that when a type checker has no "implementation" information, it should assume "CPython, and implementation version matches sys.version_info".

It's less clear to me what should happen if a type-checker is told that the implementation is not CPython, but is not given any specific version information. I guess this could be an error? Otherwise I'm not sure how type-checkers should guess at the implementation version.

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.

fair point. there should be no guessing involved, And defaulting to CPyton would be the most logical thing to do.

As an example a device that happens to be connected:

MicroPython v1.28.0 on 2026-04-06; Wio Terminal D51R with SAMD51P19A
Type "help()" for more information.
>>> import sys
>>> sys.version
'3.4.0; MicroPython v1.28.0 on 2026-04-06'
>>> sys.implementation
(name='micropython', version=(1, 28, 0, ''), _machine='Wio Terminal D51R with SAMD51P19A', _mpy=7942, _build='SEEED_WIO_TERMINAL')

If I want to typecheck an app for this device and firmware I would need to supply the typechecker with:

  • sys.implementation.name="micropython"
  • sys.implementation.version=(1,28)
  • sys.version = (3,9) *

using the relevant configuration options for that checker

  • MicroPython uses a subset of features from 3.5-3.11, generally 3.9/3.10 make a good base fit.
    BUt that is just one implementation.

If not provided explicit information through: typechecker config, environment or switches, or detected python runtime sys.implementation.version should fall-back to sys.version.

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.

Added a table in the config section to add clarity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is defaulting to sys.version_info really the right call here? On MicroPython that's apparently meaningless, since the version is 1.x instead of 3.x.

@Josverl Josverl Sep 6, 2026

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 can not think of anything other than a cross implementation lookup table, that would come with its own maintenance and distribution chalenges, to solve this for all or even most Python implementations.
The proposed default is intened to make things simpler to understand for humans on CPython,
on other platforms I think is is acceptable to require this to be specified in a .toml or .json

And as I mentioned before - it is quite similar to type checking for Windows+ Python 3.10 from 3.14 venv on Linux

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Commented on the table below, but I agree with @JelleZijlstra that "fallback to sys.version_info" is only acceptable if the implementation is CPython. If a non-CPython implementation is specified, and no implementation version is specified or inferable from the runtime environment, that must be a configuration error. (I don't love specifying type checker configuration errors, but we cannot specify that type checkers must fall back to a known-wrong sys.implementation.version in this scenario.

@Josverl Josverl Sep 21, 2026

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 think there might be a misunderstanding;
IIRC I never mentioned a cross platform fallback to CPython, and I can't find the word fallback in the prose either
nonetheless I have updated the table entry for sys.implementation.version to :

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.

I hope that sufficiently clarifies this , if not; I would welcome a text suggestion to improve.

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

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:
Comment thread
Josverl marked this conversation as resolved.

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

Expand Down
Loading