diff --git a/openpilot/cereal/messaging/tests/test_pub_sub_master.py b/openpilot/cereal/messaging/tests/test_pub_sub_master.py index 02f944b69f..20ff855fda 100644 --- a/openpilot/cereal/messaging/tests/test_pub_sub_master.py +++ b/openpilot/cereal/messaging/tests/test_pub_sub_master.py @@ -92,6 +92,7 @@ class TestSubMaster: for service, (max_freq, min_freq) in checks.items(): if max_freq is not None: + assert min_freq is not None assert sm._check_avg_freq(service) assert sm.freq_tracker[service].max_freq == max_freq*1.2 assert sm.freq_tracker[service].min_freq == min_freq*0.8 diff --git a/openpilot/common/swaglog.py b/openpilot/common/swaglog.py index ac64230eed..8b629b3fba 100644 --- a/openpilot/common/swaglog.py +++ b/openpilot/common/swaglog.py @@ -27,7 +27,7 @@ class SwaglogRotatingFileHandler(BaseRotatingHandler): self.log_files = self.get_existing_logfiles() log_indexes = [f.split(".")[-1] for f in self.log_files] self.last_file_idx = max([int(i) for i in log_indexes if i.isdigit()] or [-1]) - self.last_rollover = None + self.last_rollover = 0.0 self.doRollover() def _open(self): diff --git a/openpilot/selfdrive/car/tests/test_models.py b/openpilot/selfdrive/car/tests/test_models.py index 436de261e6..cda94b3158 100644 --- a/openpilot/selfdrive/car/tests/test_models.py +++ b/openpilot/selfdrive/car/tests/test_models.py @@ -250,7 +250,7 @@ class TestCarModelBase(unittest.TestCase): # Don't check relay malfunction on disabled routes (relay closed), # or before fingerprinting is done (elm327 and noOutput) - if self.openpilot_enabled and t / 1e4 > self.car_safety_mode_frame: + if self.car_safety_mode_frame is not None and t / 1e4 > self.car_safety_mode_frame: self.assertFalse(self.safety.get_relay_malfunction()) else: self.safety.set_relay_malfunction(False) diff --git a/openpilot/selfdrive/locationd/test/test_locationd_scenarios.py b/openpilot/selfdrive/locationd/test/test_locationd_scenarios.py index 69f2ca2821..04d2d6b55b 100644 --- a/openpilot/selfdrive/locationd/test/test_locationd_scenarios.py +++ b/openpilot/selfdrive/locationd/test/test_locationd_scenarios.py @@ -37,9 +37,9 @@ def get_select_fields_data(logs): def sig_smooth(signal): return masked_symmetric_moving_average(signal, np.ones_like(signal), 5, 1.0) def get_nested_keys(msg, keys): - val = None + val = msg for key in keys: - val = getattr(msg if val is None else val, key) if isinstance(key, str) else val[key] + val = getattr(val, key) if isinstance(key, str) else val[key] return val lp = [x.livePose for x in logs if x.which() == 'livePose'] data = defaultdict(list) diff --git a/openpilot/selfdrive/ui/mici/layouts/offroad_alerts.py b/openpilot/selfdrive/ui/mici/layouts/offroad_alerts.py index 47a2ddde95..c27e05f752 100644 --- a/openpilot/selfdrive/ui/mici/layouts/offroad_alerts.py +++ b/openpilot/selfdrive/ui/mici/layouts/offroad_alerts.py @@ -250,12 +250,12 @@ class MiciOffroadAlerts(Scroller): {alert_data.key: self.params.get(alert_data.key) for alert_data in self.sorted_alerts}) time.sleep(REFRESH_INTERVAL) - def _refresh(self) -> int: + def _refresh(self, pending_params: dict) -> int: """Refresh alerts from params and return active count.""" active_count = 0 # Handle UpdateAvailable alert specially - update_available = self._pending_params["UpdateAvailable"] + update_available = pending_params["UpdateAvailable"] update_alert_data = next((alert_data for alert_data in self.sorted_alerts if alert_data.key == "UpdateAvailable"), None) if update_alert_data: @@ -263,7 +263,7 @@ class MiciOffroadAlerts(Scroller): version_string = "" # Get new version description and parse version and date - new_desc = self._pending_params["UpdaterNewDescription"] or "" + new_desc = pending_params["UpdaterNewDescription"] or "" if new_desc: # format: "version / branch / commit / date" parts = new_desc.split(" / ") @@ -284,7 +284,7 @@ class MiciOffroadAlerts(Scroller): continue # Skip, already handled above text = "" - alert_json = self._pending_params[alert_data.key] + alert_json = pending_params[alert_data.key] if alert_json: text = alert_json.get("text", "").replace("%1", alert_json.get("extra", "")) @@ -311,8 +311,9 @@ class MiciOffroadAlerts(Scroller): def _update_state(self): """Periodically refresh alerts.""" # Refresh alerts when thread updates params - if self._pending_params is not None: - self._refresh() + pending_params = self._pending_params + if pending_params is not None: + self._refresh(pending_params) self._pending_params = None def _render(self, rect: rl.Rectangle): diff --git a/openpilot/selfdrive/ui/mici/widgets/button.py b/openpilot/selfdrive/ui/mici/widgets/button.py index 1dceb79691..3dd7ad9a8a 100644 --- a/openpilot/selfdrive/ui/mici/widgets/button.py +++ b/openpilot/selfdrive/ui/mici/widgets/button.py @@ -375,6 +375,7 @@ class GreyBigButton(BigButton): class BigMultiParamToggle(BigMultiToggle): def __init__(self, text: str, param: str, options: list[str], toggle_callback: Callable | None = None, select_callback: Callable | None = None): + assert Params is not None super().__init__(text, options, toggle_callback, select_callback) self._param = param @@ -392,6 +393,7 @@ class BigMultiParamToggle(BigMultiToggle): class BigParamControl(BigToggle): def __init__(self, text: str, param: str, toggle_callback: Callable | None = None): + assert Params is not None super().__init__(text, "", toggle_callback=toggle_callback) self.param = param self.params = Params() @@ -409,6 +411,7 @@ class BigParamControl(BigToggle): class BigCircleParamControl(BigCircleToggle): def __init__(self, icon: rl.Texture, param: str, toggle_callback: Callable | None = None, icon_offset: tuple[int, int] = (0, 0)): + assert Params is not None super().__init__(icon, toggle_callback, icon_offset=icon_offset) self._param = param self.params = Params() diff --git a/openpilot/selfdrive/ui/translations/update_translations.py b/openpilot/selfdrive/ui/translations/update_translations.py index 6ff3667d8a..9b0d63ee12 100755 --- a/openpilot/selfdrive/ui/translations/update_translations.py +++ b/openpilot/selfdrive/ui/translations/update_translations.py @@ -12,9 +12,9 @@ POT_FILE = os.path.join(str(TRANSLATIONS_DIR), "app.pot") def update_translations(): files = [] for root, _, filenames in chain(os.walk(SYSTEM_UI_DIR), - os.walk(os.path.join(UI_DIR, "widgets")), - os.walk(os.path.join(UI_DIR, "layouts")), - os.walk(os.path.join(UI_DIR, "onroad"))): + os.walk(os.path.join(str(UI_DIR), "widgets")), + os.walk(os.path.join(str(UI_DIR), "layouts")), + os.walk(os.path.join(str(UI_DIR), "onroad"))): for filename in filenames: if filename.endswith(".py"): files.append(os.path.relpath(os.path.join(root, filename), BASEDIR)) @@ -25,7 +25,7 @@ def update_translations(): # Generate/update translation files for each language for name in multilang.languages.values(): - po_file = os.path.join(TRANSLATIONS_DIR, f"app_{name}.po") + po_file = os.path.join(str(TRANSLATIONS_DIR), f"app_{name}.po") if os.path.exists(po_file): merge_po(po_file, POT_FILE) else: diff --git a/openpilot/system/loggerd/tests/test_loggerd.py b/openpilot/system/loggerd/tests/test_loggerd.py index 5d8f635d96..666b56dc03 100644 --- a/openpilot/system/loggerd/tests/test_loggerd.py +++ b/openpilot/system/loggerd/tests/test_loggerd.py @@ -277,7 +277,9 @@ class TestLoggerd: assert recv_cnt == 0, f"got {recv_cnt} {s} msgs in qlog" else: # check logged message count matches decimation - expected_cnt = (len(msgs) - 1) // SERVICE_LIST[s].decimation + 1 + decimation = SERVICE_LIST[s].decimation + assert decimation is not None + expected_cnt = (len(msgs) - 1) // decimation + 1 assert recv_cnt == expected_cnt, f"expected {expected_cnt} msgs for {s}, got {recv_cnt}" def test_rlog(self): diff --git a/openpilot/system/qcomgpsd/nmeaport.py b/openpilot/system/qcomgpsd/nmeaport.py index 0e695b65e5..ba7cf117b1 100644 --- a/openpilot/system/qcomgpsd/nmeaport.py +++ b/openpilot/system/qcomgpsd/nmeaport.py @@ -3,7 +3,7 @@ import sys from dataclasses import dataclass, fields from subprocess import check_output, CalledProcessError from time import sleep -from typing import NoReturn +from typing import NoReturn, cast DEBUG = int(os.environ.get("DEBUG", "0")) @@ -30,7 +30,8 @@ class GnssClockNmeaPort: def __post_init__(self): for field in fields(self): val = getattr(self, field.name) - setattr(self, field.name, field.type(val) if val else None) + field_type = cast(type, field.type) + setattr(self, field.name, field_type(val) if val else None) @dataclass class GnssMeasNmeaPort: @@ -73,7 +74,8 @@ class GnssMeasNmeaPort: def __post_init__(self): for field in fields(self): val = getattr(self, field.name) - setattr(self, field.name, field.type(val) if val else None) + field_type = cast(type, field.type) + setattr(self, field.name, field_type(val) if val else None) def nmea_checksum_ok(s): checksum = 0 diff --git a/openpilot/system/ui/lib/application.py b/openpilot/system/ui/lib/application.py index bd2c9dfcd3..3fa47ebd20 100644 --- a/openpilot/system/ui/lib/application.py +++ b/openpilot/system/ui/lib/application.py @@ -823,6 +823,7 @@ class GuiApplication: import pstats self._render_profiler.disable() + assert self._render_profile_start_time is not None elapsed_ms = (time.monotonic() - self._render_profile_start_time) * 1e3 avg_frame_time = elapsed_ms / self._frame if self._frame > 0 else 0 diff --git a/openpilot/system/ui/widgets/network.py b/openpilot/system/ui/widgets/network.py index f104ba6add..710202c54f 100644 --- a/openpilot/system/ui/widgets/network.py +++ b/openpilot/system/ui/widgets/network.py @@ -105,6 +105,7 @@ class NetworkUI(Widget): class AdvancedNetworkSettings(Widget): def __init__(self, wifi_manager: WifiManager): + assert Params is not None super().__init__() self._wifi_manager = wifi_manager self._wifi_manager.add_callbacks(networks_updated=self._on_network_updated) diff --git a/openpilot/tools/clip/run.py b/openpilot/tools/clip/run.py index fa4b203862..594383f7fd 100755 --- a/openpilot/tools/clip/run.py +++ b/openpilot/tools/clip/run.py @@ -11,6 +11,7 @@ import itertools import numpy as np import tqdm from argparse import ArgumentParser +from collections.abc import Callable from pathlib import Path from concurrent.futures import ThreadPoolExecutor, as_completed @@ -138,7 +139,7 @@ def iter_segment_frames(camera_paths, start_time, end_time, fps=20, use_qcam=Fal frames_per_seg = fps * 60 start_frame, end_frame = int(start_time * fps), int(end_time * fps) current_seg: int = -1 - seg_frames: FrameReader | np.ndarray | None = None + get_frame: Callable[[int], np.ndarray] | None = None for global_idx in range(start_frame, end_frame): seg_idx, local_idx = global_idx // frames_per_seg, global_idx % frames_per_seg @@ -157,12 +158,12 @@ def iter_segment_frames(camera_paths, start_time, end_time, fps=20, use_qcam=Fal if result.returncode != 0: raise RuntimeError(f"ffmpeg failed: {result.stderr.decode()}") seg_frames = np.frombuffer(result.stdout, dtype=np.uint8).reshape(-1, w * h * 3 // 2) + get_frame = seg_frames.__getitem__ else: - seg_frames = FrameReader(path, pix_fmt="nv12") + get_frame = FrameReader(path, pix_fmt="nv12").get - assert seg_frames is not None - frame = seg_frames[local_idx] if use_qcam else seg_frames.get(local_idx) - yield global_idx, frame + assert get_frame is not None + yield global_idx, get_frame(local_idx) class FrameQueue: diff --git a/openpilot/tools/lib/comma_car_segments.py b/openpilot/tools/lib/comma_car_segments.py index cd19356d66..b27887ed29 100644 --- a/openpilot/tools/lib/comma_car_segments.py +++ b/openpilot/tools/lib/comma_car_segments.py @@ -74,7 +74,7 @@ def get_repo_url(path): response = requests.head(get_repo_raw_url(path)) - if "text/plain" in response.headers.get("content-type"): + if "text/plain" in response.headers.get("content-type", ""): # This is an LFS pointer, so download the raw data from lfs response = requests.get(get_repo_raw_url(path)) assert response.status_code == 200 diff --git a/openpilot/tools/sim/bridge/metadrive/metadrive_world.py b/openpilot/tools/sim/bridge/metadrive/metadrive_world.py index c5111289d0..54b461a46c 100644 --- a/openpilot/tools/sim/bridge/metadrive/metadrive_world.py +++ b/openpilot/tools/sim/bridge/metadrive/metadrive_world.py @@ -97,7 +97,7 @@ class MetaDriveWorld(World): self.op_engaged.set() # check moving 5 seconds after engaged, doesn't move right away - after_engaged_check = is_engaged and time.monotonic() - self.first_engage >= 5 and self.test_run + after_engaged_check = is_engaged and self.first_engage is not None and time.monotonic() - self.first_engage >= 5 and self.test_run x_dist = abs(curr_pos[0] - self.vehicle_last_pos[0]) y_dist = abs(curr_pos[1] - self.vehicle_last_pos[1]) diff --git a/pyproject.toml b/pyproject.toml index da04c77f1e..5c9f16d33a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -189,11 +189,7 @@ unresolved-attribute = "ignore" # many from capnp and Cython modules invalid-method-override = "ignore" # signature variance issues possibly-missing-attribute = "ignore" # too many false positives invalid-assignment = "ignore" # often intentional monkey-patching -no-matching-overload = "ignore" # numpy/ctypes overload matching issues invalid-argument-type = "ignore" # many false positives from raylib, ctypes, numpy -call-non-callable = "ignore" # false positives from dynamic types -unsupported-operator = "ignore" # false positives from dynamic types -not-subscriptable = "ignore" # false positives from dynamic types [tool.uv] python-preference = "only-managed"