Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Update specification for directives for sys.implementation and sys.platform checks.#2173

Open
Josverl wants to merge 1 commit intopython:main from
Josverl:specs/sys.implementation.name
Open

Update specification for directives for sys.implementation and sys.platform checks. #2173
Josverl wants to merge 1 commit intopython:main from
Josverl:specs/sys.implementation.name

Conversation

@Josverl
Copy link

@Josverl Josverl commented Feb 12, 2026
edited
Loading

This PR adds additional detail to the specification for Version and Platform checking.
Specificially it aims to add support for typechers to add support for :

  • checks on sys.implementation.name
  • membership checks (in tuple)
  • negative membership checks ( not in tuple)

References :

...atform checks.
Signed-off-by: Jos Verlinde <Jos.Verlinde@Microsoft.com>
Copy link

python-cla-bot bot commented Feb 12, 2026
edited
Loading

All commit authors signed the Contributor License Agreement.

CLA signed


**Supported patterns:**

* Equality: ``sys.version_info == (3, 10)``
Copy link
Member

Choose a reason for hiding this comment

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

This example doesn't make much sense, since it would never be true at runtime on any actual Python version.

A realistic example that might actually return True would need to look like sys.version_info == (3, 13, 1, "final", 0) -- but how useful is that in practice?

I would suggest not specifying that equality checks should be supported at all; I don't think they are usable for any realistic scenario.

JelleZijlstra and hauntsaninja reacted with thumbs up emoji
Copy link
Author

Choose a reason for hiding this comment

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

I agree that the specific version should be adjusted, but I don't think that testing for equality should be dismissed, or truncated to an arbitrary number of nodes.

Copy link
Member

@carljm carljm Feb 12, 2026
edited
Loading

Choose a reason for hiding this comment

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

I don't understand what the possible use case is here. Can you elaborate?

To be clear, at runtime equality checks with sys.version_info will never return True unless you provide all five elements of the sys.version_info tuple. Every other equality check will always return False. So this is only usable if you check all five elements, and making that useful requires that type checkers allow specifying the Python version down to "releaselevel" and "serial" level in their configurations.

From a type checker implementer perspective, I feel pretty strongly that we would never implement support for this, because it is a bunch of work and it is not useful in any realistic case. I see this as a blocker for this proposal.

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for the clear feedback,
Do I understand correctly that Major.Minor would be acceptable for comparison?

Copy link
Member

@carljm carljm Feb 12, 2026
edited
Loading

Choose a reason for hiding this comment

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

Yes, I think that all sys.version_info checks should only handle major/minor. That implies that support for inequality/equality checks against all of sys.version_info must be removed from the proposal, because there is no way to perform a useful equality/inequality check against all of sys.version_info (as shown in this example) that only considers major/minor.

I'm fine with supporting sys.version_info[:2] == (3, 14)! So if we are explicit that equality/inequality checks are supported against only the first two elements, but not against the entire tuple, that resolves my objection.

Copy link
Author

Choose a reason for hiding this comment

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

If all sys.version_info comparisons are only supported on the first two elements of the version tuple, the I think that therer is no need to support the explicit form sys.version_info[:2] either.
I have removed that option.

**Supported patterns:**

* Equality: ``sys.version_info == (3, 10)``
* Inequality: ``sys.version_info != (3, 9)``
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 inequality checks should also not be supported, for the same reason discussed above for equality checks.

Copy link
Author

@Josverl Josverl Feb 14, 2026
edited
Loading

Choose a reason for hiding this comment

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

I see your point; removed

Comment on lines +168 to +169
* Tuple slicing: ``sys.version_info[:2] >= (3, 10)``
* Element access: ``sys.version_info[0] >= 3``
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 for these cases (and even for the basic comparison case) it's also important to specify which elements of the tuple are supported. For example, are type checkers expected to support sys.version_info[2] == 1 (where sys.version_info[2] is the micro version). What about the fourth and fifth elements ("releaselevel" and "serial")?

I think we should be explicit that type checkers should only be expected to have special handling for the first two tuple elements (major and minor version); anything more than that adds a lot of complexity to type checker configuration for little to no gain.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, I think that is a useful restriction.
Patch level should mean no API level changes, thus no changes in typing.

Comment on lines +168 to +169
* Tuple slicing: ``sys.version_info[:2] >= (3, 10)``
* Element access: ``sys.version_info[0] >= 3``
Copy link
Member

Choose a reason for hiding this comment

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

What about the named attributes? Should type checkers support e.g. sys.version_info.major >= 3?

(I don't think this is useful enough to require, but maybe we should be explicit that support for it is not expected.)

Copy link
Author

Choose a reason for hiding this comment

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

From a MicroPyton perspective I concur, as it does not support named attributes for this, but I don't necessarily want to force that on other implementations.

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

Type checkers should provide configuration to specify target version, platform, and implementation. The exact mechanism is implementation-defined.
Copy link
Member

Choose a reason for hiding this comment

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

Target version to what granularity?

Copy link
Author

Choose a reason for hiding this comment

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

Fair point, I think; as you suggested; Major.Minor

* Membership: ``sys.platform in ("linux", "darwin")``
* Negative membership: ``sys.platform not in ("win32", "cygwin")``

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 are expected to understand simple version and platform
checks, e.g.::

Type checkers should support narrowing based on ``sys.version_info``, ``sys.platform``, and ``sys.implementation.name`` checks.
Copy link
Collaborator

@erictraut erictraut Feb 14, 2026

Choose a reason for hiding this comment

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

I think it's important for the language to be very specific about the exact syntactical forms that are supported. Type checkers need to evaluate these expressions early in the analysis process, prior to type evaluation. That means they need to do exact tree matching of the AST. That means it's important to reduce the variations that are supported. For example, sys.version_info <= (3, 10) is fine, but version_info <= (3, 10) is not, nor is (3, 10) > version_info.

Copy link
Member

@AlexWaygood AlexWaygood Feb 16, 2026

Choose a reason for hiding this comment

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

Type checkers need to evaluate these expressions early in the analysis process, prior to type evaluation. That means they need to do exact tree matching of the AST. That means it's important to reduce the variations that are supported. For example, sys.version_info <= (3, 10) is fine, but version_info <= (3, 10) is not, nor is (3, 10) > version_info.

(None of this is true for how ty implements sys.version_info or sys.platform branches, FWIW)

Copy link
Member

Choose a reason for hiding this comment

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

I don't think that changes anything about what should be supported in the spec though, since it's true for all other type checkers.


**Supported patterns:**

* Equality: ``sys.version_info == (3, 10)``
Copy link
Collaborator

@erictraut erictraut Feb 14, 2026

Choose a reason for hiding this comment

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

I agree with Carl. Equality and inequality checks don't make sense. In think the only operators that make sense are < and >=.

Copy link
Author

Choose a reason for hiding this comment

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

adjusted accordingly.


* Equality: ``sys.platform == "linux"``
* Inequality: ``sys.platform != "win32"``
* Membership: ``sys.platform in ("linux", "darwin")``
Copy link
Collaborator

@erictraut erictraut Feb 14, 2026

Choose a reason for hiding this comment

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

I'm not convinced that containment should be supported here. There's already a way to express this in a way that all tools today support. I understand the argument that this is less verbose, but it's not that common for checks to include more than one platform, so I don't think there's a compelling argument to force all tools to support this additional form.

Copy link
Member

@JelleZijlstra JelleZijlstra Feb 14, 2026

Choose a reason for hiding this comment

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

For deciding on issues like this it would be helpful to have a little summary of what type checkers currently support (like what I did in https://discuss.python.org/t/spec-change-clarify-that-tuple-should-not-be-prohibited-as-an-argument-to-type/105590/7). I'll gather a few variants and summarize it.

I think part of this change will be codifying what is already supported universally, and another part will be adding support for more features. The first group should be uncontroversial, and in the second group we should only force work on type checker authors if there's a clear use case.

carljm and Josverl reacted with thumbs up emoji
Copy link
Author

Choose a reason for hiding this comment

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

If possible this would really help with creating readable and maintainable type stubs for MicroPython.
even with the proposed sys.implementation.name check we still see significant API differences due the underlying MCU vendor SDKs being significantly different.
Though MicroPython tries to abstract much of these differences away that is not entirly possible as the underlying SDK or hardware is simply different. This is a common source of errors when code is ported from one MCU architecture to another.
For instance Timers are available on all platforms, but with many different default values.

While the below would work

# machine.pyi 
class Timer():
 """"Timer object"""
 if sys.implementation.name == "micropython" and (sys.platform == "esp32" or sys.platform == "mimxrt" or sys.platform == "rp2" or sys.platform == "samd" or sys.platform == "stm32" or sys.platform == "alif" or sys.platform == "webassembly"): 
 @overload
 def __init__(
 self,
 id: int,
 /,
 *,
 mode: int = PERIODIC,
 period: int | None = None,
 callback: Callable[[Timer], None] | None = None,
 hard: bool | None = None,
 ):...
 elif sys.implementation.name == "micropython" and (sys.platform == "esp8266" or sys.platform == "unix" or sys.platform == "windows" or sys.platform == "zephyr"): 
 @overload
 def __init__(
 self,
 id: int = -1,
 /,
 *,
 mode: int = PERIODIC,
 period: int | None = None,
 callback: Callable[[Timer], None] | None = None,
 ):...

the below is much simpler to understand and maintain.

class Timer():
 """"Timer object"""
 if sys.implementation.name == "micropython" and (sys.platform in ("esp32", "mimxrt", "rp2", "samd", "stm32", "alif", "webassembly")): 
 @overload
 def __init__(
 self,
 id: int,
 /,
 *,
 mode: int = PERIODIC,
 period: int | None = None,
 callback: Callable[[Timer], None] | None = None,
 hard: bool | None = None,
 ):...
 elif sys.implementation.name == "micropython" and (sys.platform in ("esp8266", "unix", "windows", "zephyr")): 
 @overload
 def __init__(
 self,
 id: int = -1,
 /,
 *,
 mode: int = PERIODIC,
 period: int | None = None,
 callback: Callable[[Timer], None] | None = None,
 ):...

I think it would be reasonable to explicitly restrict this to "a tuple of literal strings",assuming that simplies the implementation.
Negative membership option could also be omitted , I think that would still be sufficient.


**Supported patterns:**

* Equality: ``sys.platform == "linux"``
Copy link
Collaborator

@erictraut erictraut Feb 14, 2026

Choose a reason for hiding this comment

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

Here also, I think it would be useful for the spec to be specific that sys.platform == "linux" is supported but other variants like platform == "linux" and "linux" == sys.platform are not.

Copy link
Author

Choose a reason for hiding this comment

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

makes sense.
I added a note to explicitly clarify that.


* Equality: ``sys.implementation.name == "cpython"``
* Inequality: ``sys.implementation.name != "cpython"``
* Membership: ``sys.implementation.name in ("pypy", "graalpy")``
Copy link
Collaborator

@erictraut erictraut Feb 14, 2026

Choose a reason for hiding this comment

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

Here again, I don't think there's good justification for supporting a containment operator.

Copy link
Author

Choose a reason for hiding this comment

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

I addedd this for consistency, but I'm OK to remove sys.implementation.name in ("pypy", "graalpy") from the spec to simplify the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@carljm carljm carljm requested changes

@JelleZijlstra JelleZijlstra JelleZijlstra left review comments

@AlexWaygood AlexWaygood AlexWaygood left review comments

@erictraut erictraut erictraut requested changes

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /