-
Notifications
You must be signed in to change notification settings - Fork 304
Update specification for directives for sys.implementation and sys.platform checks. #2173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5d84766
8116891
c951b00
b3b76c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -154,23 +154,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. | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I mentioned a while back in https://discuss.python.org/t/proposal-to-improve-support-for-other-python-platforms-in-the-typing-specification/91877/13, there are genuine use cases for also comparing against the patch version, e.g. in typeshed: https://github.com/python/typeshed/blob/4f84ac178fb23541475f9038840c5b149834374f/stdlib/heapq.pyi#L9-L11 So I propose we loosen this restriction to also allow for 3-tuples.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As also discussed in that thread, I think mandating support for 3-tuple comparisons opens up a can of worms regarding what "support" for 3-tuple comparisons even means. We cannot require type checkers to always precisely support such comparisons, because type checkers may not have access to precise micro Python versions: type checker configurations (and For example, ty currently "supports" ("Get the micro version from the runtime Python environment" is not a reliable fallback. It requires running the Python executable, which is avoided by at least ty since it can ~double the overall runtime of checking a small project using a fast type checker. And type checking -- e.g. for a small project without dependencies -- doesn't even necessarily require a Python runtime environment to begin with.)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My instinct in case of But having just written this, I now see how the complexity of this solution might indeed not be worth it for a problem as niche as rare as this one. So how about we don't require type-checkers to support 3-tuples, but explicitly state that type-checkers may choose to also support 3-tuples?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Type checkers don't really have a way to know the latest available
I think in general the assumption of this entire PR should be that type checkers can always choose to support more than what is required here, and the wording in all sections should be such as to leave that possibility open. If this is the route we take, I don't know that we need to specially emphasize it for 3-tuples, but we can.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| Use of named attributes is not mandated. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| .. 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 | ||||||||||||||
|
Comment on lines
+189
to
+190
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be good to include
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| 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>`` | ||||||||||||||
|
Comment on lines
+198
to
+199
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ruff (PLR6201) will report an error for this tuple membership check, and I tend to agree with ruff that a set literal would be more idiomatic here.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the wild I've seen things like
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ty already supports Supporting set literals will be a little tricky in ty, but should be doable, and I'm not opposed to requiring support for it. I don't think the performance motivation of PLR6201 typically applies much to |
||||||||||||||
|
|
||||||||||||||
| Common values: ``"linux"``, ``"darwin"``, ``"win32"``, ``"emscripten"``, ``"wasi"`` | ||||||||||||||
|
|
||||||||||||||
| The membership checks ``in`` and ``not in`` only support simple containment testing with 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 | ||||||||||||||
|
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 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 | ||||||||||||||
|
Comment on lines
+220
to
+236
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This raises similar questions as the three-tuple I think for
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess an alternative behavior to specify here would be that Python type checkers should not assume any particular implemention -- that is, should not treat these checks in any special way -- unless a particular known implementation has been configured. |
||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| sys.implementation.version checks | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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. |
||||||||||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||||||||||||
|
|
||||||||||||||
| 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. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| Use of named attributes is not mandated. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| .. 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`. | ||||||||||||||
|
Comment on lines
+261
to
+262
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like it belongs more as introductory text in this section, rather than as a note. |
||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| 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. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the expectation is that |
||||||||||||||
| 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 mandated. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure why we need to give exactly the same examples both in prose and then below in a code snippet. |
||||||||||||||
|
|
||||||||||||||
| Therefore checkers are **not required** to understand obfuscations such as: | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "reversed" example is an obfuscation, but Let's avoid value judgments and just give a clear presentation of the forms that are supported, and some example forms that type checkers are not required to support. |
||||||||||||||
|
|
||||||||||||||
| .. 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. | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| The exact mechanism for this is implementation-defined by the type checker. | ||||||||||||||
|
|
||||||||||||||
| .. _`deprecated`: | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think "narrowing" is the right term here.