Skip to content

Add typechecking #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ jobs:
- name: Lint
run: |
make fmt
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Typecheck
run: |
make typecheck
archive:
runs-on: ubuntu-latest
steps:
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ sync-time: uv ## Syncs th time from your computer to the PROVES Kit board
fmt: pre-commit-install ## Lint and format files
$(UVX) pre-commit run --all-files

typecheck: .venv ## Run type check
@$(UV) run -m pyright .

BOARD_MOUNT_POINT ?= ""
VERSION ?= $(shell git tag --points-at HEAD --sort=-creatordate < /dev/null | head -n 1)

Expand Down
9 changes: 4 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import digitalio
import microcontroller
from busio import SPI

try:
from board_definitions import proveskit_rp2040_v4 as board
Expand Down Expand Up @@ -42,7 +43,7 @@
rtc = MicrocontrollerManager()

logger: Logger = Logger(
error_counter=Counter(index=register.ERRORCNT, datastore=microcontroller.nvm),
error_counter=Counter(index=register.ERRORCNT),
colorized=False,
)

Expand All @@ -66,7 +67,7 @@
config: Config = Config("config.json")

# TODO(nateinaction): fix spi init
spi0 = _spi_init(
spi0: SPI = _spi_init(
logger,
board.SPI0_SCK,
board.SPI0_MOSI,
Expand All @@ -76,7 +77,7 @@
radio = RFM9xManager(
logger,
config.radio,
Flag(index=register.FLAG, bit_index=7, datastore=microcontroller.nvm),
Flag(index=register.FLAG, bit_index=7),
spi0,
initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True),
initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True),
Expand Down Expand Up @@ -153,9 +154,7 @@ def main():

f.listen_loiter()

f.all_face_data()
watchdog.pet()
f.send_face()

f.listen_loiter()

Expand Down
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies = [
"circuitpython-stubs==9.2.5",
"coverage==7.6.10",
"pre-commit==4.0.1",
"pyright[nodejs]==1.1.399",
"pytest==8.3.2",
]

Expand Down Expand Up @@ -49,3 +50,16 @@ directory = ".coverage-reports/html"

[tool.coverage.xml]
output = ".coverage-reports/coverage.xml"

[tool.pyright]
include = ["main.py", "boot.py", "repl.py", "safemode.py"]
exclude = [
"**/__pycache__",
".venv",
".git",
"artifacts",
"lib",
"typings",
]
stubPath = "./typings"
reportMissingModuleSource = false
4 changes: 1 addition & 3 deletions repl.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import microcontroller

import lib.pysquared.nvm.register as register
from lib.pysquared.config.config import Config
from lib.pysquared.logger import Logger
from lib.pysquared.nvm.counter import Counter
from lib.pysquared.satellite import Satellite

logger: Logger = Logger(
error_counter=Counter(index=register.ERRORCNT, datastore=microcontroller.nvm),
error_counter=Counter(index=register.ERRORCNT),
colorized=False,
)
config: Config = Config("config.json")
Expand Down
71 changes: 71 additions & 0 deletions typings/board.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# SPDX-FileCopyrightText: 2024 Justin Myers
#
# SPDX-License-Identifier: MIT
"""
Board stub for PROVES Kit v4
- port: raspberrypi
- board_id: proveskit_rp2040_v4
- NVM size: 4096
- Included modules: _asyncio, _bleio, _pixelmap, adafruit_bus_device, adafruit_pixelbuf, aesio, alarm, analogbufio, analogio, array, atexit, audiobusio, audiocore, audiomixer, audiomp3, audiopwmio, binascii, bitbangio, bitmapfilter, bitmaptools, bitops, board, builtins, builtins.pow3, busdisplay, busio, busio.SPI, busio.UART, codeop, collections, countio, digitalio, displayio, epaperdisplay, errno, floppyio, fontio, fourwire, framebufferio, getpass, gifio, hashlib, i2cdisplaybus, i2ctarget, imagecapture, io, jpegio, json, keypad, keypad.KeyMatrix, keypad.Keys, keypad.ShiftRegisterKeys, keypad_demux, keypad_demux.DemuxKeyMatrix, locale, math, memorymap, microcontroller, msgpack, neopixel_write, nvm, onewireio, os, os.getenv, paralleldisplaybus, pulseio, pwmio, qrio, rainbowio, random, re, rgbmatrix, rotaryio, rp2pio, rtc, sdcardio, select, sharpdisplay, storage, struct, supervisor, synthio, sys, terminalio, tilepalettemapper, time, touchio, traceback, ulab, usb, usb_cdc, usb_hid, usb_host, usb_midi, usb_video, vectorio, warnings, watchdog, zlib
- Frozen libraries:
---
proveskit: Borrowed from circuitpython-stubs https://pypi.org/project/circuitpython-stubs/#files board definitions
"""

# Imports
import busio
import microcontroller

# Board Info:
board_id: str

# Pins:
SPI0_CS1: microcontroller.Pin # GPIO26
NEO_PWR: microcontroller.Pin # GPIO27
SPI0_CS2: microcontroller.Pin # GPIO28
D0: microcontroller.Pin # GPIO29
D8: microcontroller.Pin # GPIO18
D9: microcontroller.Pin # GPIO19
D6: microcontroller.Pin # GPIO16
TX: microcontroller.Pin # GPIO0
RX: microcontroller.Pin # GPIO1
I2C1_SDA: microcontroller.Pin # GPIO2
I2C1_SCL: microcontroller.Pin # GPIO3
I2C0_SDA: microcontroller.Pin # GPIO4
I2C0_SCL: microcontroller.Pin # GPIO5
PC: microcontroller.Pin # GPIO6
VS: microcontroller.Pin # GPIO7
SPI0_MISO: microcontroller.Pin # GPIO8
SPI0_CS0: microcontroller.Pin # GPIO9
SPI0_SCK: microcontroller.Pin # GPIO10
SPI0_MOSI: microcontroller.Pin # GPIO11
D2: microcontroller.Pin # GPIO12
D3: microcontroller.Pin # GPIO13
D4: microcontroller.Pin # GPIO14
D5: microcontroller.Pin # GPIO15
RF1_RST: microcontroller.Pin # GPIO20
WDT_WDI: microcontroller.Pin # GPIO21
RF1_IO4: microcontroller.Pin # GPIO22
RF1_IO0: microcontroller.Pin # GPIO23
NEOPIX: microcontroller.Pin # GPIO24
HS: microcontroller.Pin # GPIO25
D7: microcontroller.Pin # GPIO17

# Members:
def I2C() -> busio.I2C:
"""Returns the `busio.I2C` object for the board's designated I2C bus(es).
The object created is a singleton, and uses the default parameter values for `busio.I2C`.
"""

def SPI() -> busio.SPI:
"""Returns the `busio.SPI` object for the board's designated SPI bus(es).
The object created is a singleton, and uses the default parameter values for `busio.SPI`.
"""

def UART() -> busio.UART:
"""Returns the `busio.UART` object for the board's designated UART bus(es).
The object created is a singleton, and uses the default parameter values for `busio.UART`.
"""

# Unmapped:
# none
116 changes: 116 additions & 0 deletions typings/gc.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
Control the garbage collector.

MicroPython module: https://docs.micropython.org/en/v1.25.0/library/gc.html

CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html .

---
Module: 'gc' on micropython-v1.25.0-rp2-RPI_PICO
---
proveskit: Borrowed from https://github.com/Josverl/micropython-stubs
https://pypi.org/project/micropython-rp2-stubs/#files
"""

# MCU: {'build': '', 'ver': '1.25.0', 'version': '1.25.0', 'port': 'rp2', 'board': 'RPI_PICO', 'mpy': 'v6.3', 'family': 'micropython', 'cpu': 'RP2040', 'arch': 'armv6m'}
# Stubber: v1.24.0
from __future__ import annotations

from typing import overload

from _typeshed import Incomplete

def mem_alloc() -> int:
"""
Return the number of bytes of heap RAM that are allocated by Python code.

Admonition:Difference to CPython
:class: attention

This function is MicroPython extension.
"""
...

def isenabled(*args, **kwargs) -> Incomplete: ...
def mem_free() -> int:
"""
Return the number of bytes of heap RAM that is available for Python
code to allocate, or -1 if this amount is not known.

Admonition:Difference to CPython
:class: attention

This function is MicroPython extension.
"""
...

@overload
def threshold() -> int:
"""
Set or query the additional GC allocation threshold. Normally, a collection
is triggered only when a new allocation cannot be satisfied, i.e. on an
out-of-memory (OOM) condition. If this function is called, in addition to
OOM, a collection will be triggered each time after *amount* bytes have been
allocated (in total, since the previous time such an amount of bytes
have been allocated). *amount* is usually specified as less than the
full heap size, with the intention to trigger a collection earlier than when the
heap becomes exhausted, and in the hope that an early collection will prevent
excessive memory fragmentation. This is a heuristic measure, the effect
of which will vary from application to application, as well as
the optimal value of the *amount* parameter.

Calling the function without argument will return the current value of
the threshold. A value of -1 means a disabled allocation threshold.

Admonition:Difference to CPython
:class: attention

This function is a MicroPython extension. CPython has a similar
function - ``set_threshold()``, but due to different GC
implementations, its signature and semantics are different.
"""

@overload
def threshold(amount: int) -> None:
"""
Set or query the additional GC allocation threshold. Normally, a collection
is triggered only when a new allocation cannot be satisfied, i.e. on an
out-of-memory (OOM) condition. If this function is called, in addition to
OOM, a collection will be triggered each time after *amount* bytes have been
allocated (in total, since the previous time such an amount of bytes
have been allocated). *amount* is usually specified as less than the
full heap size, with the intention to trigger a collection earlier than when the
heap becomes exhausted, and in the hope that an early collection will prevent
excessive memory fragmentation. This is a heuristic measure, the effect
of which will vary from application to application, as well as
the optimal value of the *amount* parameter.

Calling the function without argument will return the current value of
the threshold. A value of -1 means a disabled allocation threshold.

Admonition:Difference to CPython
:class: attention

This function is a MicroPython extension. CPython has a similar
function - ``set_threshold()``, but due to different GC
implementations, its signature and semantics are different.
"""

def collect() -> None:
"""
Run a garbage collection.
"""
...

def enable() -> None:
"""
Enable automatic garbage collection.
"""
...

def disable() -> None:
"""
Disable automatic garbage collection. Heap memory can still be allocated,
and garbage collection can still be initiated manually using :meth:`gc.collect`.
"""
...
36 changes: 36 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading