Closed ANogin closed 8 hours ago
Can you add some more detail on the type checker you are using, the python version on your host and the stubs package and version you are using?
If I test your sample in Pyright's playground it also shows an error ( but a different one )
Code sample in pyright playground
from typing import TypeVar, Generic, List, Tuple
T = TypeVar('T')
class Foo(Generic[T]):
...
# Something does not exist
class Baz(Foo[Something]):
...
# Something needs to exist
Something = List[Tuple]
class Bar(Foo[Something]):
...
And a quick test does seem not show an obvious error.
from typing import Dict, Generic, TypeVar
from typing_extensions import reveal_type
T = TypeVar("T")
from machine import Pin, Signal
class Registry(Generic[T]):
def __init__(self) -> None:
self._store: Dict[str, T] = {}
def set_item(self, k: str, v: T) -> None:
self._store[k] = v
def get_item(self, k: str) -> T:
return self._store[k]
inputs = Registry[Pin]()
inputs.set_item("button", Pin(4, Pin.IN))
inputs.set_item("X", Pin(18, Pin.IN))
inputs.set_item("Y", Pin(19, Pin.IN))
outputs = Registry[Signal]()
outputs.set_item("Player-A", Signal(Pin(5, Pin.OUT)))
outputs.set_item("Player-B", Signal(Pin(6, Pin.OUT)))
outputs.set_item("Game over", Signal(Pin(8, Pin.OUT), invert=True))
b = inputs.get_item("button")
reveal_type(b) # Expected `Pin`, got `Pin`
x = inputs.get_item("X")
reveal_type(x) # Expected `Pin`, got `Pin`
game_over = outputs.get_item("Game over")
reveal_type(game_over) # Expected `Signal`, got `Signal`
Couple of things, sorry for not being sufficiently clear:
Something
as a placeholder for something complicated I have defined in my actual case.Then it may be that you need to add the round brackets , that I tend to forget as well
So rather than inputs = Registry[Pin]
use inputs = Registry[Pin]()
Or in your sample foo = Foo[Something]()
@js
Then it may be that you need to add the round brackets , that I tend to forget as well So rather than
inputs = Registry[Pin]
useinputs = Registry[Pin]()
Or in your sample
foo = Foo[Something]()
Note that I do not have any foo
- I have a subclass definition. Again, note that this works correctly with mypy and the syntax is correct. The issue is that the hack you use to define Generic
causes subclasses to fail in micropython.
E.g.
% cat test.py
from typing import TypeVar, Generic, Any
T = TypeVar('T')
class Foo(Generic[T]):
pass
class Bar(Foo[Any]):
pass
% mypy test.py Success: no issues found in 1 source file % python3 test.py % wget https://github.com/Josverl/micropython-stubs/raw/main/mip/typing.mpy --2024-05-28 21:12:05-- https://github.com/Josverl/micropython-stubs/raw/main/mip/typing.mpy Resolving github.com (github.com)... 140.82.116.3 Connecting to github.com (github.com)|140.82.116.3|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/Josverl/micropython-stubs/main/mip/typing.mpy [following] --2024-05-28 21:12:06-- https://raw.githubusercontent.com/Josverl/micropython-stubs/main/mip/typing.mpy Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 1669 (1.6K) [application/octet-stream] Saving to: ‘typing.mpy’
typing.mpy 100%[=================================================>] 1.63K --.-KB/s in 0s
2024-05-28 21:12:06 (15.9 MB/s) - ‘typing.mpy’ saved [1669/1669]
% micropython
MicroPython v1.22.2 on 2024-02-20; darwin [GCC 4.2.1] version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> import test
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 8, in <module>
TypeError: '_AnyCall' object isn't subscriptable
Thanks , now I know what to look for .
Likely _AnyCall
needs a __getitem__
method
Ah, Generic is subscriptable, but doing so returns AnyCall which isn't. Maybe subscriptable should inherit from AnyCall, but return a new subscriptable so it can be used recursively like this.
@ANogin ,
I think I can solve your problem based on Andrew`s suggestion. But the only testing in this thusfar has been on your code snippet so please let me know if this works for you.
typings.py
class _AnyCall:
def __init__(*args, **kwargs):
pass
def __call__(*args, **kwargs):
pass
def __getitem__(self, arg): # <--
return _anyCall
_anyCall = _AnyCall()
class _SubscriptableType:
def __getitem__(self, arg):
return _anyCall
I have merged the updated typings.py/.mpy and added a number of test cases. See: https://github.com/Josverl/micropython-stubs/tree/main/tests/quality_tests/feat_typing
I have
And micropython complains:
for the
Foo[Something]
...