| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Sorry, something went wrong.
|
|
||
| * Equality: ``sys.platform == "linux"`` | ||
| * Inequality: ``sys.platform != "win32"`` | ||
| * Membership: ``sys.platform in ("linux", "darwin")`` |
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
I fully agree with Eric here FWIW. Adding support for this will add significant complexity to type checkers, and this is the first time I've seen it requested. If we want to ask type checkers to add support for in/not in comparisons with sys.platform and sys.implementation.name, I think it should be a wholly separate proposal to the proposal that asks type checkers to add initial support for comparisons against sys.implementation.version and sys.implementation.name in the same way that they already do for sys.version_info and sys.platform.
Sorry, something went wrong.
|
I have updated the text to better clarify the exact comparisons for each of the supported attributes, |
Sorry, something went wrong.
|
Dear TC, If so kindly let me know how to proceed. |
Sorry, something went wrong.
There was a problem hiding this comment.
I'm generally supportive but I think this change needs some more editing, and I'd like support in at least some type checkers (at least an open PR) before we start mandating this pattern.
Sorry, something went wrong.
|
Dear typing council, However now it appears that this PR is in a Catch-22 situation; Lacking response I plan close this in a few weeks |
Sorry, something went wrong.
| * ``sys.platform in <tuple of string literals>`` | ||
| * ``sys.platform not in <tuple of string literals>`` |
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
In the wild I've seen things like sys.platform.startswith("freebsd") a couple of times, because in this case there's also a version number in the platform string (e.g. "freebsd8"). So how about we also allow sys.platform.startswith(<string literal>)?
Sorry, something went wrong.
There was a problem hiding this comment.
ty already supports sys.platform.startswith; I don't have any objection there.
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 sys.version_info comparisons, but it is awkward if this rule is generally being applied in a codebase and has to be specifically ignored for sys.version_info checks.
Sorry, something went wrong.
There was a problem hiding this comment.
change to set and added sys.platform.startswith(<string literal>)
Sorry, something went wrong.
There was a problem hiding this comment.
To be clear, I think that both tuple and set literals should be specified as supported -- it would be surprising IMO if sets work and tuples don't.
This is perhaps an argument against supporting sets -- it opens a bit of a slippery slope: why not lists? etc
Sorry, something went wrong.
There was a problem hiding this comment.
my original proposal was tuples, as that is one of the core building blocks of Python.
I don't think that for this scale sets have a real benefit over tuples.
I'd like it to be straight and narrow though ,
requiring tuple + set = is still ok , though I notice that ruff mentions 'This rule is unstable and in preview.'
adding lists would start to 🛝
Pausing edits until there is consensus
Sorry, something went wrong.
| * ``sys.version_info >= <2-tuple>`` | ||
| * ``sys.version_info < <2-tuple>`` | ||
|
|
||
| Comparisons checks are only supported against the first two elements of the version tuple. |
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
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 pyproject.toml etc) typically do not specify micro versions, and I don't think we want to require users to always start requiring them. (Whereas I think in practice all type checkers already do require users to always provide major/minor version in some way, explicitly or implicitly.) So what is the expected behavior if micro Python version is not available to the type checker?
For example, ty currently "supports" if sys.version_info >= (3, 14, 1) (when Python version is configured to 3.14) in the "sound" way, by treating it as "unknown truthiness" and considering that either path may be taken (since actual Python version could be 3.14.0 or 3.14.1+). Would that behavior be considered to meet the bar required of type checkers here, or not? In some sense that behavior is a "regression" from writing if sys.version_info >= (3, 14), where ty would always infer a definite truthiness.
("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.)
Sorry, something went wrong.
There was a problem hiding this comment.
My instinct in case of sys.version_info >= (x, y, z) and sys.version_info < (x, y, z) when statically only x and y are known is to use the latest available z, because that's what I expect to be most common in practice. I'm sure there will be edge-cases that this could be problematic for, but on the macro I this this'll solve more problems that it'll cause.
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?
Sorry, something went wrong.
There was a problem hiding this comment.
use the latest available z
Type checkers don't really have a way to know the latest available z at any point in time, either, so I think this rule would have to be something more like "assume z is ∞", or something like that. Which will lead to weird behavior in some edge cases (imagine a new feature is introduced in 3.15 beta and someone introduces an if sys.version_info <= (3, 14) in typeshed when it is introduced, and immediately type checkers all start assuming every user is running 3.15 beta or later). But you may be right that in practice it does the right thing most of the time.
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?
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.
Sorry, something went wrong.
There was a problem hiding this comment.
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.
In theory, yes. But there have been many time where type-checker maintainers weren't willing to implement a certain feature, purely because it wasn't in the typing spec. So that's why I suggested adding this as explicitly optional.
Sorry, something went wrong.
This is not the case at all. It is very typical for type checkers to implement features even if they are not in the spec. It is very helpful to have feedback from type checker authors to be able to understand potential problems with spec changes. I think this has worked quite well in the past.and if a feature is useful enough there is usually a type checker that will implement it. |
Sorry, something went wrong.
There was a problem hiding this comment.
Thanks for your patience, @Josverl. I'm not sure we've fully reached consensus yet on what should be supported here, but I also generally support making this clearly specified. I also think this still needs some editing to give a clear and unambiguous presentation of the requirements.
Sorry, something went wrong.
| * ``sys.version_info >= <2-tuple>`` | ||
| * ``sys.version_info < <2-tuple>`` | ||
|
|
||
| Comparisons checks are only supported against the first two elements of the version tuple. |
There was a problem hiding this comment.
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 pyproject.toml etc) typically do not specify micro versions, and I don't think we want to require users to always start requiring them. (Whereas I think in practice all type checkers already do require users to always provide major/minor version in some way, explicitly or implicitly.) So what is the expected behavior if micro Python version is not available to the type checker?
For example, ty currently "supports" if sys.version_info >= (3, 14, 1) (when Python version is configured to 3.14) in the "sound" way, by treating it as "unknown truthiness" and considering that either path may be taken (since actual Python version could be 3.14.0 or 3.14.1+). Would that behavior be considered to meet the bar required of type checkers here, or not? In some sense that behavior is a "regression" from writing if sys.version_info >= (3, 14), where ty would always infer a definite truthiness.
("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.)
Sorry, something went wrong.
| * ``sys.version_info >= <2-tuple>`` | ||
| * ``sys.version_info < <2-tuple>`` | ||
|
|
||
| Comparisons checks are only supported against the first two elements of the version tuple. |
There was a problem hiding this comment.
| Comparisons checks are only supported against the first two elements of the version tuple. | |
| Comparison checks are only supported against the first two elements of the version tuple. |
Sorry, something went wrong.
| * ``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 mandated. |
There was a problem hiding this comment.
| Use of named attributes is not mandated. | |
| Type checkers are not expected to support comparisons with named attributes of `sys.version_info`. |
Sorry, something went wrong.
| * ``sys.platform in <tuple of string literals>`` | ||
| * ``sys.platform not in <tuple of string literals>`` |
There was a problem hiding this comment.
ty already supports sys.platform.startswith; I don't have any objection there.
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 sys.version_info comparisons, but it is awkward if this rule is generally being applied in a codebase and has to be specifically ignored for sys.version_info checks.
Sorry, something went wrong.
| * ``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. |
There was a problem hiding this comment.
| Comparisons checks are only supported against the first two elements of the implementation version tuple. | |
| Comparison checks are only supported against the first two elements of the implementation version tuple. |
Sorry, something went wrong.
|
Thanks all for the renewed attention and comments.
|
Sorry, something went wrong.
…atform checks. Signed-off-by: Jos Verlinde <Jos.Verlinde@Microsoft.com>
Formatting improvements. Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
…sion comparisons. Signed-off-by: Jos Verlinde <Jos_Verlinde@hotmail.com>
Signed-off-by: Jos Verlinde <Jos_Verlinde@hotmail.com>
|
Again thanks for the feedback and suggestions to improve the spec. I processed the comments and suggestion - and commented or marked them as resolved to keep track. Open topics. 1. 2-Tuple or 3-Tuple version comparisons.
2. Should in / not in membership checks use tuple, set or list. * ``sys.platform in <tuple/set/list of string literals>`` * ``sys.platform not in <tuple/set/list of string literals>`` * ``sys.implementation.name in <tuple/set/listof string literals>`` * ``sys.implementation.name not in <tuple/set/list of string literals>`` 3. Scope I think the commits should be squashed when merging - I've kept them separate for now. |
Sorry, something went wrong.
|
We could eliminate open-question (2) and at least partially address (3) by just considering containment checks as out of scope to specify for now. Considering they don't add any new capability, just allow writing more concise code, they aren't really necessary. We could leave this out of the spec / conformance suite for now and up to individual type checkers. Similarly maybe for startswith. Leaving it out doesn't prevent type checkers from supporting it. And including it in the spec / conformance suite doesn't guarantee type-checker support, either, so it's unclear how soon some of these difficult-to-support patterns will be usable in practice anyway, even if they are included here. |
Sorry, something went wrong.
+1
Unlike containment checks, startswith can't always be expressed using equality checks. For example sys.platform on FreeBSD on Python<3.14 includes the version number (docs) , so it can be "freebsd7", "freebsd8", ...., "freebsd15". This list will grow each two (?) years too. So if you want to check if you're on FreeBSD, you'll have to spell out each previous version + a bunch of future versions. So at least until Python 3.13 is EOL, I think that we should keep startswith. |
Sorry, something went wrong.
That would be disappointing, especially as one of the first responses in May'25 in DPO included :
But reality is that there different opinions based on different considerations, and .startwith() was added based on review comments. More than happy to remove that to simplify matters. |
Sorry, something went wrong.
|
Not closed in anger - just a typo |
Sorry, something went wrong.
Is there any type checker that support this currently? |
Sorry, something went wrong.
ty |
Sorry, something went wrong.
|
At least for ty, startswith support is trivial (already there!), don't know how difficult for other type checkers. Point taken that (unlike containment checks) it really does introduce a new (and sometimes needed capability). Regarding containment checks, for ty tuples are trivial (also already supported!) but mutable types are not. ty handles this quite differently from other type checkers: we use full type inference, not special-cased AST-matching. This makes some thing a lot easier, and some things harder. For mutable container types, we would normally not infer e.g. ["foo", "bar"] as list[Literal["foo", "bar"]] but as list[str] (same for set), so we normally would lose the literal precision. It should be doable, just not straightforward and I'm not sure how quickly we'd prioritize it. (But once we did support it, we would support it for all containment checks of a literal type against a literal list/set of literal types, not just for sys.platform and friends specifically.) I suspect that for type checkers that do AST matching, containment checks for tuple/list/set should all be equally straightforward. |
Sorry, something went wrong.
Would frozenset help? |
Sorry, something went wrong.
Not much. It would require that we implement astral-sh/ty#2280, which probably mostly requires the same machinery. (The problem here is that frozenset doesn't have a literal syntax, so first you have to build a literal container of some other kind, and then pass it to the frozenset constructor, so we still end up promoting literals in that process.) To be clear, I don't want you to weight this ty implementation issue too much -- I'd rather first hear from other typing council members what they think a good scope is here. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
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 :
References :