From 79eb6fcade1c883cf27867bc2c24a3de859087e9 Mon Sep 17 00:00:00 2001 From: Matt Land Date: Mon, 24 Apr 2023 15:43:13 -0600 Subject: [PATCH 1/3] initial typing support, mypy passes add missing copyright statements to .pre-commit-config.yaml, gitignore --- .gitignore | 3 + .pre-commit-config.yaml | 14 +++ adafruit_rgb_display/hx8353.py | 20 ++++- adafruit_rgb_display/hx8357.py | 30 ++++--- adafruit_rgb_display/ili9341.py | 34 +++++--- adafruit_rgb_display/rgb.py | 148 ++++++++++++++++++++------------ adafruit_rgb_display/s6d02a1.py | 31 ++++++- adafruit_rgb_display/ssd1331.py | 36 +++++--- adafruit_rgb_display/ssd1351.py | 38 ++++---- adafruit_rgb_display/st7735.py | 98 +++++++++++---------- adafruit_rgb_display/st7789.py | 39 +++++---- mypy.ini | 22 +++++ optional_requirements.txt | 5 ++ 13 files changed, 346 insertions(+), 172 deletions(-) create mode 100644 mypy.ini diff --git a/.gitignore b/.gitignore index 871d9a7..7d6346a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -47,3 +48,5 @@ _build .idea .vscode *~ + +.mypy_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6996f9c..5cedefc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: Unlicense @@ -40,3 +41,16 @@ repos: files: "^tests/" args: - --disable=missing-docstring,consider-using-f-string,duplicate-code + - repo: local + hooks: + - id: mypy + name: mypy (library code) + entry: "mypy adafruit_rgb_display" + language: python + additional_dependencies: ["mypy==1.2.0"] + types: [python] + exclude: "^(docs/|examples/|tests/|setup.py$)" + # use require_serial so that script + # is only called once per commit + require_serial: true + pass_filenames: false diff --git a/adafruit_rgb_display/hx8353.py b/adafruit_rgb_display/hx8353.py index 69819a8..2aaf712 100644 --- a/adafruit_rgb_display/hx8353.py +++ b/adafruit_rgb_display/hx8353.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,11 +9,17 @@ A simple driver for the HX8353-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional + import digitalio + import busio +except ImportError: + pass __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -59,5 +66,14 @@ class HX8353(DisplaySPI): _ENCODE_POS = ">HH" # pylint: disable-msg=useless-super-delegation, too-many-arguments - def __init__(self, spi, dc, cs, rst=None, width=128, height=128, rotation=0): + def __init__( + self, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 128, + height: int = 128, + rotation: int = 0, + ) -> None: super().__init__(spi, dc, cs, rst, width, height, rotation) diff --git a/adafruit_rgb_display/hx8357.py b/adafruit_rgb_display/hx8357.py index 556f107..dfb9e2f 100755 --- a/adafruit_rgb_display/hx8357.py +++ b/adafruit_rgb_display/hx8357.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,11 +9,18 @@ A simple driver for the HX8357-based displays. -* Author(s): Melissa LeBlanc-Williams +* Author(s): Melissa LeBlanc-Williams, Matt Land """ from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -94,16 +102,16 @@ class HX8357(DisplaySPI): # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=480, - height=320, - baudrate=16000000, - polarity=0, - phase=0, - rotation=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 480, + height: int = 320, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, + rotation: int = 0, ): super().__init__( spi, diff --git a/adafruit_rgb_display/ili9341.py b/adafruit_rgb_display/ili9341.py index a01c38b..bb90093 100644 --- a/adafruit_rgb_display/ili9341.py +++ b/adafruit_rgb_display/ili9341.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,12 +9,19 @@ A simple driver for the ILI9341/ILI9340-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ import struct from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -74,16 +82,16 @@ class ILI9341(DisplaySPI): # pylint: disable-msg=too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=240, - height=320, - baudrate=16000000, - polarity=0, - phase=0, - rotation=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 240, + height: int = 320, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, + rotation: int = 0, ): super().__init__( spi, @@ -101,7 +109,9 @@ def __init__( # pylint: enable-msg=too-many-arguments - def scroll(self, dy=None): # pylint: disable-msg=invalid-name + def scroll( + self, dy: Optional[int] = None # pylint: disable-msg=invalid-name + ) -> Optional[int]: """Scroll the display by delta y""" if dy is None: return self._scroll diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 1486203..c9b3233 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,12 +9,21 @@ Base class for all RGB Display devices -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ import struct import time +try: + from typing import Optional, Union, Tuple, List, Any, ByteString + import digitalio + import busio + + Image = Any # from PIL import Image +except ImportError: + pass + try: import numpy except ImportError: @@ -36,18 +46,22 @@ pass -def color565(r, g=0, b=0): +def color565( + r: Union[int, Tuple[int, int, int], List[int]], + g: int = 0, + b: int = 0, +) -> int: """Convert red, green and blue values (0-255) into a 16-bit 565 encoding. As a convenience this is also available in the parent adafruit_rgb_display package namespace.""" - try: - r, g, b = r # see if the first var is a tuple/list - except TypeError: - pass - return (r & 0xF8) << 8 | (g & 0xFC) << 3 | b >> 3 + if not isinstance(r, int): # see if the first var is a tuple/list + red, g, b = r + else: + red = r + return (red & 0xF8) << 8 | (g & 0xFC) << 3 | b >> 3 -def image_to_data(image): +def image_to_data(image: Image) -> Any: """Generator function to convert a PIL image to 16-bit 565 RGB bytes.""" # NumPy is much faster at doing this. NumPy code provided by: # Keith (https://www.blogger.com/profile/02555547344016007163) @@ -63,37 +77,39 @@ def image_to_data(image): class DummyPin: """Can be used in place of a ``DigitalInOut()`` when you don't want to skip it.""" - def deinit(self): + def deinit(self) -> None: """Dummy DigitalInOut deinit""" - def switch_to_output(self, *args, **kwargs): + def switch_to_output( + self, *, value: bool = False, drive_mode: Optional[digitalio.DriveMode] = None + ) -> None: """Dummy switch_to_output method""" - def switch_to_input(self, *args, **kwargs): + def switch_to_input(self, *, pull: Optional[digitalio.Pull] = None) -> None: """Dummy switch_to_input method""" @property - def value(self): + def value(self) -> digitalio.DigitalInOut: """Dummy value DigitalInOut property""" @value.setter - def value(self, val): + def value(self, val: digitalio.DigitalInOut) -> None: pass @property - def direction(self): + def direction(self) -> digitalio.Direction: """Dummy direction DigitalInOut property""" @direction.setter - def direction(self, val): + def direction(self, val: digitalio.Direction) -> None: pass @property - def pull(self): + def pull(self) -> digitalio.Pull: """Dummy pull DigitalInOut property""" @pull.setter - def pull(self, val): + def pull(self, val: digitalio.Pull) -> None: pass @@ -103,18 +119,18 @@ class Display: # pylint: disable-msg=no-member :param height: number of pixels high """ - _PAGE_SET = None - _COLUMN_SET = None - _RAM_WRITE = None - _RAM_READ = None + _PAGE_SET: Optional[int] = None + _COLUMN_SET: Optional[int] = None + _RAM_WRITE: Optional[int] = None + _RAM_READ: Optional[int] = None _X_START = 0 # pylint: disable=invalid-name _Y_START = 0 # pylint: disable=invalid-name - _INIT = () + _INIT: Tuple[Tuple[int, Union[ByteString, None]], ...] = () _ENCODE_PIXEL = ">H" _ENCODE_POS = ">HH" _DECODE_PIXEL = ">BBB" - def __init__(self, width, height, rotation): + def __init__(self, width: int, height: int, rotation: int) -> None: self.width = width self.height = height if rotation not in (0, 90, 180, 270): @@ -122,13 +138,25 @@ def __init__(self, width, height, rotation): self._rotation = rotation self.init() - def init(self): + def write( + self, command: Optional[int] = None, data: Optional[ByteString] = None + ) -> None: + """Abstract method""" + raise NotImplementedError() + + def read(self, command: Optional[int] = None, count: int = 0) -> ByteString: + """Abstract method""" + raise NotImplementedError() + + def init(self) -> None: """Run the initialization commands.""" for command, data in self._INIT: self.write(command, data) # pylint: disable-msg=invalid-name,too-many-arguments - def _block(self, x0, y0, x1, y1, data=None): + def _block( + self, x0: int, y0: int, x1: int, y1: int, data: Optional[ByteString] = None + ) -> Optional[ByteString]: """Read or write a block of data.""" self.write( self._COLUMN_SET, self._encode_pos(x0 + self._X_START, x1 + self._X_START) @@ -144,28 +172,34 @@ def _block(self, x0, y0, x1, y1, data=None): # pylint: enable-msg=invalid-name,too-many-arguments - def _encode_pos(self, x, y): - """Encode a postion into bytes.""" + def _encode_pos(self, x: int, y: int) -> bytes: + """Encode a position into bytes.""" return struct.pack(self._ENCODE_POS, x, y) - def _encode_pixel(self, color): + def _encode_pixel(self, color: Any) -> bytes: """Encode a pixel color into bytes.""" return struct.pack(self._ENCODE_PIXEL, color) - def _decode_pixel(self, data): + def _decode_pixel(self, data: Union[bytes, Union[bytearray, memoryview]]) -> int: """Decode bytes into a pixel color.""" return color565(*struct.unpack(self._DECODE_PIXEL, data)) - def pixel(self, x, y, color=None): + def pixel(self, x: int, y: int, color: Optional[Any] = None) -> Optional[int]: """Read or write a pixel at a given position.""" if color is None: - return self._decode_pixel(self._block(x, y, x, y)) + return self._decode_pixel(self._block(x, y, x, y)) # type: ignore[arg-type] if 0 <= x < self.width and 0 <= y < self.height: self._block(x, y, x, y, self._encode_pixel(color)) return None - def image(self, img, rotation=None, x=0, y=0): + def image( + self, + img: Image, + rotation: Optional[int] = None, + x: int = 0, + y: int = 0, + ) -> None: """Set buffer to value of Python Imaging Library image. The image should be in 1 bit mode and a size not exceeding the display size when drawn at the supplied origin.""" @@ -197,7 +231,9 @@ def image(self, img, rotation=None, x=0, y=0): self._block(x, y, x + imwidth - 1, y + imheight - 1, pixels) # pylint: disable-msg=too-many-arguments - def fill_rectangle(self, x, y, width, height, color): + def fill_rectangle( + self, x: int, y: int, width: int, height: int, color: Any + ) -> None: """Draw a rectangle at specified position with specified width and height, and fill it with the specified color.""" x = min(self.width - 1, max(0, x)) @@ -215,25 +251,25 @@ def fill_rectangle(self, x, y, width, height, color): # pylint: enable-msg=too-many-arguments - def fill(self, color=0): + def fill(self, color: Any = 0) -> None: """Fill the whole display with the specified color.""" self.fill_rectangle(0, 0, self.width, self.height, color) - def hline(self, x, y, width, color): + def hline(self, x: int, y: int, width: int, color: Any) -> None: """Draw a horizontal line.""" self.fill_rectangle(x, y, width, 1, color) - def vline(self, x, y, height, color): + def vline(self, x: int, y: int, height: int, color: Any) -> None: """Draw a vertical line.""" self.fill_rectangle(x, y, 1, height, color) @property - def rotation(self): + def rotation(self) -> int: """Set the default rotation""" return self._rotation @rotation.setter - def rotation(self, val): + def rotation(self, val: int) -> None: if val not in (0, 90, 180, 270): raise ValueError("Rotation must be 0/90/180/270") self._rotation = val @@ -245,19 +281,19 @@ class DisplaySPI(Display): # pylint: disable-msg=too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=1, - height=1, - baudrate=12000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 1, + height: int = 1, + baudrate: int = 12000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=0, - y_offset=0, - rotation=0 + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0 ): self.spi_device = spi_device.SPIDevice( spi, cs, baudrate=baudrate, polarity=polarity, phase=phase @@ -274,15 +310,19 @@ def __init__( # pylint: enable-msg=too-many-arguments - def reset(self): + def reset(self) -> None: """Reset the device""" + if not self.rst: + raise RuntimeError("a reset pin was not provided") self.rst.value = 0 time.sleep(0.050) # 50 milliseconds self.rst.value = 1 time.sleep(0.050) # 50 milliseconds # pylint: disable=no-member - def write(self, command=None, data=None): + def write( + self, command: Optional[int] = None, data: Optional[ByteString] = None + ) -> None: """SPI write to the device: commands and data""" if command is not None: self.dc_pin.value = 0 @@ -293,13 +333,13 @@ def write(self, command=None, data=None): with self.spi_device as spi: spi.write(data) - def read(self, command=None, count=0): + def read(self, command: Optional[int] = None, count: int = 0) -> ByteString: """SPI read from device with optional command""" data = bytearray(count) self.dc_pin.value = 0 with self.spi_device as spi: if command is not None: - spi.write(bytearray([command])) + spi.write(bytearray([command])) # change to self.write() if count: spi.readinto(data) return data diff --git a/adafruit_rgb_display/s6d02a1.py b/adafruit_rgb_display/s6d02a1.py index 92cd2d1..568cdec 100644 --- a/adafruit_rgb_display/s6d02a1.py +++ b/adafruit_rgb_display/s6d02a1.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,12 +9,19 @@ A simple driver for the S6D02A1-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -59,5 +67,22 @@ class S6D02A1(DisplaySPI): _ENCODE_POS = ">HH" # pylint: disable-msg=useless-super-delegation, too-many-arguments - def __init__(self, spi, dc, cs, rst=None, width=128, height=160, rotation=0): - super().__init__(spi, dc, cs, rst, width, height, rotation) + def __init__( + self, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 128, + height: int = 160, + rotation: int = 0, + ): + super().__init__( + spi=spi, + dc=dc, + cs=cs, + rst=rst, + width=width, + height=height, + rotation=rotation, + ) diff --git a/adafruit_rgb_display/ssd1331.py b/adafruit_rgb_display/ssd1331.py index 6fd0e90..167afe1 100644 --- a/adafruit_rgb_display/ssd1331.py +++ b/adafruit_rgb_display/ssd1331.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,12 +9,19 @@ A simple driver for the SSD1331-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional, ByteString + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -107,18 +115,18 @@ class SSD1331(DisplaySPI): # super required to allow override of default values def __init__( self, - spi, - dc, - cs, - rst=None, - width=96, - height=64, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 96, + height: int = 64, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - rotation=0 - ): + rotation: int = 0 + ) -> None: super().__init__( spi, dc, @@ -133,7 +141,9 @@ def __init__( ) # pylint: disable=no-member - def write(self, command=None, data=None): + def write( + self, command: Optional[int] = None, data: Optional[ByteString] = None + ) -> None: """write procedure specific to SSD1331""" self.dc_pin.value = command is None with self.spi_device as spi: diff --git a/adafruit_rgb_display/ssd1351.py b/adafruit_rgb_display/ssd1351.py index cc5e5b8..03e58ab 100644 --- a/adafruit_rgb_display/ssd1351.py +++ b/adafruit_rgb_display/ssd1351.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,11 +9,18 @@ A simple driver for the SSD1351-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -99,22 +107,20 @@ class SSD1351(DisplaySPI): # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=128, - height=128, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 128, + height: int = 128, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=0, - y_offset=0, - rotation=0 + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0 ): - baudrate = min(baudrate, 16000000) # Limit to Display Max Baudrate - super().__init__( spi, dc, @@ -122,7 +128,7 @@ def __init__( rst, width, height, - baudrate=baudrate, + baudrate=min(baudrate, 16000000), # Limit to Display Max Baudrate polarity=polarity, phase=phase, x_offset=x_offset, diff --git a/adafruit_rgb_display/st7735.py b/adafruit_rgb_display/st7735.py index ca86edc..daa5020 100644 --- a/adafruit_rgb_display/st7735.py +++ b/adafruit_rgb_display/st7735.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Radomir Dopieralski for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,13 +9,20 @@ A simple driver for the ST7735-based displays. -* Author(s): Radomir Dopieralski, Michael McWethy +* Author(s): Radomir Dopieralski, Michael McWethy, Matt Land """ import struct from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional, Tuple, ByteString, Union + import digitalio + import busio +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -113,27 +121,27 @@ class ST7735(DisplaySPI): (_RASET, b"\x00\x02\x00\x81"), # XSTART = 2, XEND = 129 (_NORON, None), (_DISPON, None), - ) + ) # type: Tuple[Tuple[int, Union[ByteString, None]], ...] _ENCODE_PIXEL = ">H" _ENCODE_POS = ">HH" # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=128, - height=128, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 128, + height: int = 128, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=0, - y_offset=0, - rotation=0, - ): + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0, + ) -> None: super().__init__( spi, dc, @@ -182,22 +190,22 @@ class ST7735R(ST7735): # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=128, - height=160, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio] = None, + width: int = 128, + height: int = 160, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=0, - y_offset=0, - rotation=0, - bgr=False, - invert=False, - ): + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0, + bgr: bool = False, + invert: bool = False, + ) -> None: self._bgr = bgr self._invert = invert super().__init__( @@ -215,7 +223,7 @@ def __init__( rotation=rotation, ) - def init(self): + def init(self) -> None: super().init() cols = struct.pack(">HH", 0, self.width - 1) rows = struct.pack(">HH", 0, self.height - 1) @@ -271,21 +279,21 @@ class ST7735S(ST7735): # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - bl, - rst=None, - width=128, - height=160, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + bl: digitalio.DigitalInOut, # Backlight + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 128, + height: int = 160, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=2, - y_offset=1, - rotation=0, - ): + x_offset: int = 2, + y_offset: int = 1, + rotation: int = 0, + ) -> None: self._bl = bl # Turn on backlight self._bl.switch_to_output(value=1) diff --git a/adafruit_rgb_display/st7789.py b/adafruit_rgb_display/st7789.py index af57686..3fcfc43 100644 --- a/adafruit_rgb_display/st7789.py +++ b/adafruit_rgb_display/st7789.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: MIT @@ -8,14 +9,21 @@ A simple driver for the ST7789-based displays. -* Author(s): Melissa LeBlanc-Williams +* Author(s): Melissa LeBlanc-Williams, Matt Land """ import struct +import busio +import digitalio from micropython import const from adafruit_rgb_display.rgb import DisplaySPI +try: + from typing import Optional +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" @@ -96,20 +104,20 @@ class ST7789(DisplaySPI): # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, - spi, - dc, - cs, - rst=None, - width=240, - height=320, - baudrate=16000000, - polarity=0, - phase=0, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 240, + height: int = 320, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, *, - x_offset=0, - y_offset=0, - rotation=0 - ): + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0 + ) -> None: super().__init__( spi, dc, @@ -125,8 +133,7 @@ def __init__( rotation=rotation, ) - def init(self): - + def init(self) -> None: super().init() cols = struct.pack(">HH", self._X_START, self.width + self._X_START) rows = struct.pack(">HH", self._Y_START, self.height + self._Y_START) diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..8bf7236 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2023 Matt Land +# +# SPDX-License-Identifier: Unlicense +[mypy] +python_version = 3.7 +disallow_untyped_defs = True +exclude = (examples|tests|setup.py|docs) + +[mypy-digitalio] +ignore_missing_imports = True + +[mypy-busio] +ignore_missing_imports = True + +[mypy-numpy] +ignore_missing_imports = True + +[mypy-adafruit_bus_device] +ignore_missing_imports = True + +[mypy-micropython] +ignore_missing_imports = True diff --git a/optional_requirements.txt b/optional_requirements.txt index d4e27c4..595a870 100644 --- a/optional_requirements.txt +++ b/optional_requirements.txt @@ -1,3 +1,8 @@ # SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: Unlicense + +#adafruit_bus_device +#numpy +#PIL From 5aa898f3e0e0f5674346c81324150128a0493871 Mon Sep 17 00:00:00 2001 From: Matt Land Date: Mon, 24 Apr 2023 17:25:13 -0600 Subject: [PATCH 2/3] Add Color Type, change Image type, remove mypy pre-commit hook, remove comment --- .pre-commit-config.yaml | 14 -------------- adafruit_rgb_display/rgb.py | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5cedefc..6996f9c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,4 @@ # SPDX-FileCopyrightText: 2020 Diego Elio Pettenò -# SPDX-FileCopyrightText: 2023 Matt Land # # SPDX-License-Identifier: Unlicense @@ -41,16 +40,3 @@ repos: files: "^tests/" args: - --disable=missing-docstring,consider-using-f-string,duplicate-code - - repo: local - hooks: - - id: mypy - name: mypy (library code) - entry: "mypy adafruit_rgb_display" - language: python - additional_dependencies: ["mypy==1.2.0"] - types: [python] - exclude: "^(docs/|examples/|tests/|setup.py$)" - # use require_serial so that script - # is only called once per commit - require_serial: true - pass_filenames: false diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index c9b3233..48710e5 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -20,7 +20,7 @@ import digitalio import busio - Image = Any # from PIL import Image + from circuitpython_typing.pil import Image except ImportError: pass @@ -176,7 +176,7 @@ def _encode_pos(self, x: int, y: int) -> bytes: """Encode a position into bytes.""" return struct.pack(self._ENCODE_POS, x, y) - def _encode_pixel(self, color: Any) -> bytes: + def _encode_pixel(self, color: Union[int, Tuple]) -> bytes: """Encode a pixel color into bytes.""" return struct.pack(self._ENCODE_PIXEL, color) @@ -184,7 +184,9 @@ def _decode_pixel(self, data: Union[bytes, Union[bytearray, memoryview]]) -> int """Decode bytes into a pixel color.""" return color565(*struct.unpack(self._DECODE_PIXEL, data)) - def pixel(self, x: int, y: int, color: Optional[Any] = None) -> Optional[int]: + def pixel( + self, x: int, y: int, color: Optional[Union[int, Tuple]] = None + ) -> Optional[int]: """Read or write a pixel at a given position.""" if color is None: return self._decode_pixel(self._block(x, y, x, y)) # type: ignore[arg-type] @@ -232,7 +234,7 @@ def image( # pylint: disable-msg=too-many-arguments def fill_rectangle( - self, x: int, y: int, width: int, height: int, color: Any + self, x: int, y: int, width: int, height: int, color: Union[int, Tuple] ) -> None: """Draw a rectangle at specified position with specified width and height, and fill it with the specified color.""" @@ -251,15 +253,15 @@ def fill_rectangle( # pylint: enable-msg=too-many-arguments - def fill(self, color: Any = 0) -> None: + def fill(self, color: Union[int, Tuple] = 0) -> None: """Fill the whole display with the specified color.""" self.fill_rectangle(0, 0, self.width, self.height, color) - def hline(self, x: int, y: int, width: int, color: Any) -> None: + def hline(self, x: int, y: int, width: int, color: Union[int, Tuple]) -> None: """Draw a horizontal line.""" self.fill_rectangle(x, y, width, 1, color) - def vline(self, x: int, y: int, height: int, color: Any) -> None: + def vline(self, x: int, y: int, height: int, color: Union[int, Tuple]) -> None: """Draw a vertical line.""" self.fill_rectangle(x, y, 1, height, color) @@ -339,7 +341,7 @@ def read(self, command: Optional[int] = None, count: int = 0) -> ByteString: self.dc_pin.value = 0 with self.spi_device as spi: if command is not None: - spi.write(bytearray([command])) # change to self.write() + spi.write(bytearray([command])) if count: spi.readinto(data) return data From 2c7e95d1dd53944ff458a6246cb681e4c8f36fbb Mon Sep 17 00:00:00 2001 From: Matt Land Date: Tue, 25 Apr 2023 08:13:04 -0600 Subject: [PATCH 3/3] requested changes, fix DummyPin::value return --- adafruit_rgb_display/rgb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 48710e5..5c906f7 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -89,7 +89,7 @@ def switch_to_input(self, *, pull: Optional[digitalio.Pull] = None) -> None: """Dummy switch_to_input method""" @property - def value(self) -> digitalio.DigitalInOut: + def value(self) -> bool: """Dummy value DigitalInOut property""" @value.setter