Update specification for directives for sys.implementation and sys.platform checks.#2173
Update specification for directives for sys.implementation and sys.platform checks.#2173Josverl wants to merge 1 commit intopython:mainfrom
Conversation
docs/spec/directives.rst
Outdated
| * Tuple slicing: ``sys.version_info[:2] >= (3, 10)`` | ||
| * Element access: ``sys.version_info[0] >= 3`` |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Thanks, I think that is a useful restriction.
Patch level should mean no API level changes, thus no changes in typing.
| * Membership: ``sys.platform in ("linux", "darwin")`` | ||
| * Negative membership: ``sys.platform not in ("win32", "cygwin")`` | ||
|
|
||
| sys.implementation.name checks |
There was a problem hiding this comment.
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".
There was a problem hiding this comment.
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.
docs/spec/directives.rst
Outdated
|
|
||
| **Supported patterns:** | ||
|
|
||
| * Equality: ``sys.version_info == (3, 10)`` |
There was a problem hiding this comment.
I agree with Carl. Equality and inequality checks don't make sense. In think the only operators that make sense are < and >=.
docs/spec/directives.rst
Outdated
|
|
||
| * 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.
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.
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.
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.
docs/spec/directives.rst
Outdated
|
|
||
| * Equality: ``sys.implementation.name == "cpython"`` | ||
| * Inequality: ``sys.implementation.name != "cpython"`` | ||
| * Membership: ``sys.implementation.name in ("pypy", "graalpy")`` |
There was a problem hiding this comment.
Here again, I don't think there's good justification for supporting a containment operator.
There was a problem hiding this comment.
I addedd this for consistency, but I'm OK to remove sys.implementation.name in ("pypy", "graalpy") from the spec to simplify the implementation.
4151e84 to
d7fbb9e
Compare
docs/spec/directives.rst
Outdated
|
|
||
| Supported patterns: | ||
| * ``sys.platform <comparison> <string literal>`` | ||
| * ``sys.platform in <tuple of string literals>`` |
There was a problem hiding this comment.
the not / and / or are described further down to avoid neededing to repeat then for every possible clause, although != is repeated.
I could move that section to the top if that is clearer.
Multiple comparisons can be combined with:
* A not unary operator
* An and or or binary operator
There was a problem hiding this comment.
That's different, it would allow not (sys.platform in ("a", "b")), not sys.platform not in ("a", "b").
There was a problem hiding this comment.
I see your point, then I think it is clearer to just enumerate all option directly,
Supported patterns:
* ``sys.platform == <string literal>``
* ``sys.platform != <string literal>``
* ``sys.platform in <tuple of string literals>``
* ``sys.platform not in <tuple of string literals>``
d7fbb9e to
62d90dc
Compare
|
I have updated the text to better clarify the exact comparisons for each of the supported attributes, |
…atform checks. Signed-off-by: Jos Verlinde <Jos.Verlinde@Microsoft.com>
62d90dc to
ff338e3
Compare
| * ``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 supported. |
There was a problem hiding this comment.
| Use of named attributes is not supported. | |
| Use of named attributes is not mandated. |
There was a problem hiding this comment.
IIRC @carljm requested that addition.
Agree that not mandated is clearer for the metadata.
< Same on line 238>
There was a problem hiding this comment.
I think "not mandated" is clearer that type checkers are permitted to support something additionally if they wish to, but that they are not required to do so. So in general I prefer "not mandated".
The one exception for me might be comparisons against length-3-or-greater tuples for sys.version_info or sys.implementation.version. I think it's usually actually incorrect for a type checker to support those unless the type checker actually either infers the micro version of the Python install the user has locally or offers a configuration knob for the micro version to be specified. To my knowledge, no type checker currently does. So for comparisons between sys.version_info or sys.implementation.version and tuples of >=3 length, I think the stronger language of "not supported" (or maybe even stronger than that) is probably still appropriate
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| Type checkers are only required to support the above patterns, and are not required to evaluate complex expressions involving these variables. | ||
| 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 supported. |
There was a problem hiding this comment.
Alex proposed elsewhere to change not supported to not mandated
as this section also uses that, I wanted to check if there is a need to change the wording here as well.
Also on the light of Jelle's functionality scan
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 :
sys.implementation.nameReferences :