Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 0 additions & 1 deletion .github/workflows/dist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ jobs:
- "macos-15" # arm64
- "windows-2025"
python_version:
- '3.11'
- '3.12'
- '3.13'
- '3.14'
Expand Down
4 changes: 1 addition & 3 deletions devtools/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

import subprocess
import sys
import typing as T

import click
from packaging.requirements import Requirement
from packaging.version import Version

from .ctx import Context
Expand Down Expand Up @@ -105,7 +103,7 @@ def build_other_wheels(ctx: Context, no_test: bool):
@click.option("--buildtype", help="meson build type (debug, release, etc)")
@click.pass_obj
def build_meson_wheels(
ctx: Context, no_test: bool, cross: T.Optional[str], buildtype: T.Optional[str]
ctx: Context, no_test: bool, cross: str | None, buildtype: str | None
):
"""
Builds wheels that use meson, runs tests.
Expand Down
14 changes: 7 additions & 7 deletions devtools/ci_check_wpistructs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def _normalize_cpp_type(type_name: str) -> str:
return " ".join(type_name.split())


def _find_struct_specializations(text: str) -> T.List[str]:
def _find_struct_specializations(text: str) -> list[str]:
"""Find concrete wpi::util::Struct<T> specializations in C++ text."""
types = []
for match in _STRUCT_SPECIALIZATION_RE.finditer(text):
Expand All @@ -43,7 +43,7 @@ def _find_struct_specializations(text: str) -> T.List[str]:

def _struct_header_to_owner_header(
header: pathlib.Path, include_root: pathlib.Path
) -> T.Optional[str]:
) -> str | None:
"""Map wpi/foo/struct/BarStruct.hpp to wpi/foo/Bar.hpp."""
rel_parts = header.relative_to(include_root).parts
if len(rel_parts) < 2 or rel_parts[-2] != "struct":
Expand All @@ -65,7 +65,7 @@ def _has_setup_wpistruct(yaml_path: pathlib.Path, type_name: str) -> bool:
return f"SetupWPyStruct<{compact_type}>" in compact


def _native_include_roots(project) -> T.List[pathlib.Path]:
def _native_include_roots(project) -> list[pathlib.Path]:
native_root = project.path / "src" / "native"
if not native_root.exists():
return []
Expand All @@ -83,9 +83,9 @@ def _iter_native_headers(include_root: pathlib.Path) -> T.Iterator[pathlib.Path]

def _collect_wpistruct_checks(
ctx: Context,
) -> T.List[T.Tuple[str, pathlib.Path, str, pathlib.Path, bool]]:
checks: T.List[T.Tuple[str, pathlib.Path, str, pathlib.Path, bool]] = []
seen: T.Set[T.Tuple[str, pathlib.Path, str, pathlib.Path]] = set()
) -> list[tuple[str, pathlib.Path, str, pathlib.Path, bool]]:
checks: list[tuple[str, pathlib.Path, str, pathlib.Path, bool]] = []
seen: set[tuple[str, pathlib.Path, str, pathlib.Path]] = set()

for project in ctx.subprojects.values():
if not getattr(project, "is_semiwrap_project", lambda: False)():
Expand Down Expand Up @@ -152,7 +152,7 @@ def _collect_wpistruct_checks(

def _collect_missing_wpistructs(
ctx: Context,
) -> T.List[T.Tuple[str, pathlib.Path, str, pathlib.Path]]:
) -> list[tuple[str, pathlib.Path, str, pathlib.Path]]:
return [
(project_name, yaml_path, type_name, struct_header)
for project_name, yaml_path, type_name, struct_header, found in _collect_wpistruct_checks(
Expand Down
17 changes: 8 additions & 9 deletions devtools/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import dataclasses
import tomlkit
import typing as T

from .util import parse_input

Expand All @@ -26,29 +25,29 @@ class Parameters:

mrclib_bin_version: str
mrclib_bin_url: str
mrclib_artifacts: T.Set[str]
mrclib_artifacts: set[str]

#: semiwrap name_transform known_words shared by all wrapper projects
known_words: T.List[str]
known_words: list[str]

#: renames [project.entry-points.KEY*] to [project.entry-points.VALUE]
entrypoints: T.Dict[str, str]
entrypoints: dict[str, str]

exclude_artifacts: T.Set[str]
exclude_artifacts: set[str]

requirements: T.Dict[str, str]
requirements: dict[str, str]

robot_wheel_platform: str


@dataclasses.dataclass
class UpdateConfig:
py_versions: T.Dict[str, str]
py_versions: dict[str, str]
params: Parameters
subprojects: T.Dict[str, SubprojectConfig]
subprojects: dict[str, SubprojectConfig]


def load(fname) -> T.Tuple[UpdateConfig, tomlkit.TOMLDocument]:
def load(fname) -> tuple[UpdateConfig, tomlkit.TOMLDocument]:
with open(fname) as fp:
cfgdata = tomlkit.parse(fp.read())

Expand Down
3 changes: 1 addition & 2 deletions devtools/ctx.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import subprocess
import sys
import sysconfig
import typing as T

import toposort

Expand All @@ -30,7 +29,7 @@ def __init__(self, verbose: bool) -> None:
self.wheel_path = self.root_path / "dist"
self.other_wheel_path = self.root_path / "dist-other"

subprojects: T.List[Subproject] = []
subprojects: list[Subproject] = []
for project, cfg in self.cfg.subprojects.items():
# Skip projects that aren't compatible with the robot
if self.is_robot and not cfg.robot:
Expand Down
4 changes: 2 additions & 2 deletions devtools/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def _validate_example_list(root: pathlib.Path, expected_dirs: T.Sequence[str]) -

@dataclasses.dataclass
class ExamplesTests:
base: T.List[str]
ignored: T.List[str]
base: list[str]
ignored: list[str]


@dataclasses.dataclass
Expand Down
4 changes: 2 additions & 2 deletions devtools/pyproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ def _render(self, name: str) -> RenderedProject:
text = tomlkit.dumps(data)
return RenderedProject(path, path.parent / "pyproject.toml", data, text)

def render_all(self) -> T.Dict[str, RenderedProject]:
def render_all(self) -> dict[str, RenderedProject]:
return {name: self._render(name) for name in self.cfg.subprojects}

def validate_templates(self) -> T.List[str]:
def validate_templates(self) -> list[str]:
errors = []

def check(path, field, actual, expected):
Expand Down
6 changes: 3 additions & 3 deletions devtools/subproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def is_native_project(self) -> bool:
# Tasks
#

def _config_settings(self, config_settings: T.List[str]) -> T.List[str]:
def _config_settings(self, config_settings: list[str]) -> list[str]:
if sys.platform == "win32" and self.is_meson_project():
config_settings = config_settings + [
"setup-args=-Dcpp_std=none",
Expand All @@ -68,7 +68,7 @@ def _config_settings(self, config_settings: T.List[str]) -> T.List[str]:

return config_settings

def develop(self, buildtype: str, jobs: T.Optional[int] = None):
def develop(self, buildtype: str, jobs: int | None = None):

config_settings = [f"setup-args=-Dbuildtype={buildtype}"]
if jobs is not None:
Expand Down Expand Up @@ -154,7 +154,7 @@ def build_wheel(
wheel_path: pathlib.Path,
other_wheel_path: pathlib.Path,
install: bool,
config_settings: T.List[str],
config_settings: list[str],
):
wheel_path.mkdir(parents=True, exist_ok=True)

Expand Down
3 changes: 1 addition & 2 deletions devtools/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import shlex
import subprocess
import sys
import typing

from validobj import errors
Expand Down Expand Up @@ -37,7 +36,7 @@ def _convert_validation_error(fname, ve: errors.ValidationError) -> ValidationEr
return ValidationError(vmsg)


def parse_input(value: typing.Any, spec: typing.Type[T], fname) -> T:
def parse_input(value: typing.Any, spec: type[T], fname) -> T:
try:
return validobj.validation.parse_input(value, spec)
except errors.ValidationError as ve:
Expand Down
2 changes: 1 addition & 1 deletion examples/check_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


def check_file_content(file_path):
with open(file_path, "r") as file:
with open(file_path) as file:
lines = file.readlines()

if file.name.endswith("robot.py"):
Expand Down
3 changes: 3 additions & 0 deletions examples/robot/ArcadeDrive/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# the WPILib BSD license file in the root directory of this project.
#

from typing import override

import wpilib
import wpilib_drivers

Expand All @@ -29,6 +31,7 @@ def __init__(self):
# gearbox is constructed, you might have to invert the left side instead.
right_motor.set_inverted(True)

@override
def teleop_periodic(self):
# Drive with arcade drive.
# That means that the Y axis drives forward
Expand Down
3 changes: 3 additions & 0 deletions examples/robot/ArcadeDriveXboxController/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# the WPILib BSD license file in the root directory of this project.
#

from typing import override

import wpilib
import wpilib_drivers

Expand All @@ -29,6 +31,7 @@ def __init__(self):
# gearbox is constructed, you might have to invert the left side instead.
right_motor.set_inverted(True)

@override
def teleop_periodic(self):
# Drive with split arcade style
# That means that the Y axis of the left stick moves forward
Expand Down
6 changes: 6 additions & 0 deletions examples/robot/ArmSimulation/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# the WPILib BSD license file in the root directory of this project.
#

from typing import override

import wpilib

from constants import Constants
Expand All @@ -19,12 +21,15 @@ def __init__(self) -> None:
self.arm = Arm()
self.joystick = wpilib.Joystick(Constants.JOYSTICK_PORT)

@override
def simulation_periodic(self) -> None:
self.arm.simulation_periodic()

@override
def teleop_init(self) -> None:
self.arm.load_preferences()

@override
def teleop_periodic(self) -> None:
if self.joystick.get_trigger():
# Here, we run PID control like normal.
Expand All @@ -33,6 +38,7 @@ def teleop_periodic(self) -> None:
# Otherwise, we disable the motor.
self.arm.stop()

@override
def disabled_init(self) -> None:
# This just makes sure that our simulation code knows that the motor's off.
self.arm.stop()
14 changes: 11 additions & 3 deletions examples/robot/DSGamepadChooser/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
# the WPILib BSD license file in the root directory of this project.
#

from hal import RobotMode
from typing import override

import wpilib
from hal import RobotMode
from wpilib.opmodes import OpModeRobot


Expand All @@ -28,15 +30,18 @@ def __init__(self) -> None:
self.delay = 0
self.speed = 0.25

def disabledPeriodic(self) -> None:
@override
def disabled_periodic(self) -> None:
self.chooser.update()
wpilib.DriverStationDisplay.update_lines()

@override
def start(self) -> None:
self.target = self.chooser.get_selected("Target")
self.delay = self.chooser.get_selected_integer("Delay")
self.speed = self.chooser.get_selected_double("Speed")

@override
def periodic(self) -> None:
wpilib.DriverStationDisplay.add_data("Selected Auto", "Score")
wpilib.DriverStationDisplay.add_data("Target", self.target)
Expand All @@ -59,15 +64,18 @@ def __init__(self) -> None:
self.attempts = 1
self.turnScale = 0.5

def disabledPeriodic(self) -> None:
@override
def disabled_periodic(self) -> None:
self.chooser.update()
wpilib.DriverStationDisplay.update_lines()

@override
def start(self) -> None:
self.approach = self.chooser.get_selected("Approach")
self.attempts = self.chooser.get_selected_integer("Attempts")
self.turnScale = self.chooser.get_selected_double("Turn Scale")

@override
def periodic(self) -> None:
wpilib.DriverStationDisplay.add_data("Selected Auto", "Balance")
wpilib.DriverStationDisplay.add_data("Approach", self.approach)
Expand Down
4 changes: 4 additions & 0 deletions examples/robot/DifferentialDriveBot/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# the WPILib BSD license file in the root directory of this project.
#

from typing import override

import wpimath
import wpilib

Expand All @@ -22,10 +24,12 @@ def __init__(self) -> None:
self.velocity_limiter = wpimath.SlewRateLimiter(3)
self.rot_limiter = wpimath.SlewRateLimiter(3)

@override
def autonomous_periodic(self) -> None:
self.teleop_periodic()
self.drive.update_odometry()

@override
def teleop_periodic(self) -> None:
# Get the x velocity. We are inverting this because Xbox controllers return
# negative values when we push forward.
Expand Down
6 changes: 6 additions & 0 deletions examples/robot/DifferentialDrivePoseEstimator/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# the WPILib BSD license file in the root directory of this project.
#

from typing import override

import ntcore
import wpilib
import wpimath
Expand All @@ -26,16 +28,20 @@ def __init__(self) -> None:
self.velocity_limiter = wpimath.SlewRateLimiter(3)
self.rot_limiter = wpimath.SlewRateLimiter(3)

@override
def autonomous_periodic(self) -> None:
self.teleop_periodic()
self.drive.update_odometry()

@override
def simulation_periodic(self) -> None:
self.drive.simulation_periodic()

@override
def robot_periodic(self) -> None:
self.drive.periodic()

@override
def teleop_periodic(self) -> None:
# Get the x velocity. We are inverting this because Xbox controllers return
# negative values when we push forward.
Expand Down
2 changes: 0 additions & 2 deletions examples/robot/DriveDistanceOffboard/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
changes.
"""

import math


class DriveConstants:
DT = 0.02
Expand Down
Loading
Loading