diff --git a/docs/spec/directives.rst b/docs/spec/directives.rst index 488d71a2..eae15d29 100644 --- a/docs/spec/directives.rst +++ b/docs/spec/directives.rst @@ -154,23 +154,157 @@ 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: + * ``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>`` + +Comparison checks are only supported against the first two elements of the version tuple. +It should be noted that 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: Example `sys.version_info` + :emphasize-lines: 2 + + import sys + if sys.version_info >= (3, 12): + # Python 3.12+ + elif sys.version_info >= (3, 11): + # Python 3.11 + else: + # Python 3.10 and lower + +sys.platform checks +^^^^^^^^^^^^^^^^^^^ + +Type checkers should support the following comparison patterns: + * ``sys.platform == `` + * ``sys.platform != `` + * ``sys.platform.startswith()`` + * ``sys.platform 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 set 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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Type checkers should support comparison patterns: + * ``sys.implementation.name == `` + * ``sys.implementation.name != `` + * ``sys.implementation.name in `` + * ``sys.implementation.name not in `` + + Default value: ``"cpython"``, unless configured otherwise. + 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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``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`. + +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: 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 + + +No support for complex expressions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Type checkers are required to support the above patterns, and are not required to evaluate other comparisons or other syntax variants. + +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: 4,6,8 + + import sys + from sys import platform + + if "".join(reversed(sys.platform)) == "xunil": + # Typecheckers will not be required to understand this obfuscated check + if platform == "linux": + # Typecheckers will not be required to understand this import alias for sys.platform + if "win" not in sys.platform: + # Typecheckers will not be required to understand this reversed membership check + + +Configuration +^^^^^^^^^^^^^ + +Type checkers must 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`` 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"`` The value used for ``sys.version`` unless configured otherwise. +================================ ========================== ============== =========================================================================== + +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 name for these configuration options is implementation-specific, and defined by each type checker. .. _`deprecated`: