vsergeev / python-periphery

A pure Python 2/3 library for peripheral I/O (GPIO, LED, PWM, SPI, I2C, MMIO, Serial) in Linux.
MIT License
519 stars 139 forks source link

Add typing files #47

Closed CrazyIvan359 closed 1 year ago

CrazyIvan359 commented 3 years ago

So I'm switching over to pylance in a project I'm working on that uses periphery and I've made a pyi file for the gpio file. I figured I'd share it here for anyone interested in making them for the rest of this library. If I have time I may come back around and do them, but I'm not sure when that would be.

I had to change the file extension in order to upload it: gpio.txt 12/12/2020 updated EdgeEvent properties

vsergeev commented 3 years ago

This would be nice to have. It should probably follow https://mypy.readthedocs.io/en/stable/installed_packages.html#making-pep-561-compatible-packages

CrazyIvan359 commented 3 years ago

Which option do you prefer:

I don't currently have time to go through the whole library and type it, but I can submit a PR with the GPIO file done in the format you want as a starting point.

vsergeev commented 3 years ago

I'm a little suspicious of inline typing given the Python 2 support. There are a few union types throughout the library that would probably requiring the typing module. So I think stubs distributed with periphery would probably be a good starting point.

No worries about not doing the whole library. I can add to it over time.

CrazyIvan359 commented 3 years ago

I'm using it without issue in Jython 2.7.2 like this:

try:
    import typing as t
except:
    pass

my_var = None  # type: t.Union[str, None]

The import gets skipped over if it's missing and to a language unaware of type hints the comments are just comments.

vsergeev commented 3 years ago

I'm using it without issue in Jython 2.7.2 like this:

try:
    import typing as t
except:
    pass

my_var = None  # type: t.Union[str, None]

The import gets skipped over if it's missing and to a language unaware of type hints the comments are just comments.

Does that work with arguments in methods though? e.g. def poll(self, timeout: Union[int, float, None] = ...) -> bool: in your stub file.

CrazyIvan359 commented 3 years ago

Methods you have 2 options

For shorter methods:

def poll(self, timeout):
    # type: (t.Optional[int, float] = ...) -> bool

For methods with more arguments or complex typings:

def poll(
    self,
    timeout,  # type: t.Optional[int, float]
):
    # type: (...) -> bool

I'll get a PR done this morning for GPIO so you can see and I'll look up the documents I learned all this from and get you links

CrazyIvan359 commented 3 years ago
CrazyIvan359 commented 3 years ago

In the event that there are things that could only be done in a stub file, would you rather have everything in the stub or only what has to be and the rest inlined?

So far I think that just EdgeEvent and this method need to go in the stub in order to do this:

class GPIO(object):
    @t.overload
    def __new__(cls, line: int, direction: str) -> 'SysfsGPIO': ...
    @t.overload
    def __new__(
        path: str,
        line: t.Union[int, str],
        direction: str,
        edge: str = ...,
        bias: str = ...,
        drive: str = ...,
        inverted: bool = ...,
        label: t.Optional[str] = ...
    ) -> 'CdevGPIO': ...

Because the best we can do inline is this and it is woefully ambiguous...

class GPIO(object):
    def __new__(cls, *args, **kwargs):
        # type: (...) -> t.Union[SysfsGPIO, CdevGPIO]
CrazyIvan359 commented 3 years ago

Well it's a bit of a moot point (my above example on the __new__ method) because Pylance doesn't see the specified return types and just says you get an instance of GPIO back when calling GPIO(...)