fix: enforce strict ruff lint (17 rule sets) across entire repo
- Expand ruff config from E/F to 17 rule sets (B, RUF, SIM, PIE, T20, ARG, ERA, A, BLE, RET, ISC, TCH, UP, C4, PERF) - Fix 907 lint errors across all Python files (GUI, FPGA cosim, schematics scripts, simulations, utilities, tools) - Replace all blind except-Exception with specific exception types - Remove commented-out dead code (ERA001) from cosim/simulation files - Modernize typing: deprecated typing.List/Dict/Tuple to builtins - Fix unused args/loop vars, ambiguous unicode, perf anti-patterns - Delete legacy GUI files V1-V4 - Add V7 test suite, requirements files - All CI jobs pass: ruff (0 errors), py_compile, pytest (92/92), MCU tests (20/20), FPGA regression (25/25)
This commit is contained in:
@@ -36,9 +36,9 @@ except ImportError:
|
||||
USB_AVAILABLE = False
|
||||
logging.warning("pyusb not available. USB CDC functionality will be disabled.")
|
||||
|
||||
try:
|
||||
from pyftdi.ftdi import Ftdi
|
||||
from pyftdi.usbtools import UsbTools
|
||||
try:
|
||||
from pyftdi.ftdi import Ftdi, FtdiError
|
||||
from pyftdi.usbtools import UsbTools
|
||||
|
||||
FTDI_AVAILABLE = True
|
||||
except ImportError:
|
||||
@@ -108,8 +108,7 @@ class RadarProcessor:
|
||||
|
||||
def dual_cpi_fusion(self, range_profiles_1, range_profiles_2):
|
||||
"""Dual-CPI fusion for better detection"""
|
||||
fused_profile = np.mean(range_profiles_1, axis=0) + np.mean(range_profiles_2, axis=0)
|
||||
return fused_profile
|
||||
return np.mean(range_profiles_1, axis=0) + np.mean(range_profiles_2, axis=0)
|
||||
|
||||
def multi_prf_unwrap(self, doppler_measurements, prf1, prf2):
|
||||
"""Multi-PRF velocity unwrapping"""
|
||||
@@ -156,7 +155,7 @@ class RadarProcessor:
|
||||
|
||||
return clusters
|
||||
|
||||
def association(self, detections, clusters):
|
||||
def association(self, detections, _clusters):
|
||||
"""Association of detections to tracks"""
|
||||
associated_detections = []
|
||||
|
||||
@@ -250,7 +249,7 @@ class USBPacketParser:
|
||||
if len(data) >= 30 and data[0:4] == b"GPSB":
|
||||
return self._parse_binary_gps_with_pitch(data)
|
||||
|
||||
except Exception as e:
|
||||
except (ValueError, struct.error) as e:
|
||||
logging.error(f"Error parsing GPS data: {e}")
|
||||
|
||||
return None
|
||||
@@ -302,7 +301,7 @@ class USBPacketParser:
|
||||
timestamp=time.time(),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
except (ValueError, struct.error) as e:
|
||||
logging.error(f"Error parsing binary GPS with pitch: {e}")
|
||||
return None
|
||||
|
||||
@@ -344,13 +343,12 @@ class RadarPacketParser:
|
||||
|
||||
if packet_type == 0x01:
|
||||
return self.parse_range_packet(payload)
|
||||
elif packet_type == 0x02:
|
||||
if packet_type == 0x02:
|
||||
return self.parse_doppler_packet(payload)
|
||||
elif packet_type == 0x03:
|
||||
if packet_type == 0x03:
|
||||
return self.parse_detection_packet(payload)
|
||||
else:
|
||||
logging.warning(f"Unknown packet type: {packet_type:02X}")
|
||||
return None
|
||||
logging.warning(f"Unknown packet type: {packet_type:02X}")
|
||||
return None
|
||||
|
||||
def calculate_crc(self, data):
|
||||
return self.crc16_func(data)
|
||||
@@ -373,7 +371,7 @@ class RadarPacketParser:
|
||||
"chirp": chirp_counter,
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
except Exception as e:
|
||||
except (ValueError, struct.error) as e:
|
||||
logging.error(f"Error parsing range packet: {e}")
|
||||
return None
|
||||
|
||||
@@ -397,7 +395,7 @@ class RadarPacketParser:
|
||||
"chirp": chirp_counter,
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
except Exception as e:
|
||||
except (ValueError, struct.error) as e:
|
||||
logging.error(f"Error parsing Doppler packet: {e}")
|
||||
return None
|
||||
|
||||
@@ -419,7 +417,7 @@ class RadarPacketParser:
|
||||
"chirp": chirp_counter,
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
except Exception as e:
|
||||
except (ValueError, struct.error) as e:
|
||||
logging.error(f"Error parsing detection packet: {e}")
|
||||
return None
|
||||
|
||||
@@ -687,23 +685,22 @@ class MapGenerator:
|
||||
# Calculate coverage radius in km
|
||||
coverage_radius_km = coverage_radius / 1000.0
|
||||
|
||||
# Generate HTML content
|
||||
map_html = self.map_html_template.replace("{lat}", str(gps_data.latitude))
|
||||
map_html = map_html.replace("{lon}", str(gps_data.longitude))
|
||||
map_html = map_html.replace("{alt:.1f}", f"{gps_data.altitude:.1f}")
|
||||
map_html = map_html.replace("{pitch:+.1f}", f"{gps_data.pitch:+.1f}")
|
||||
map_html = map_html.replace("{coverage_radius}", str(coverage_radius))
|
||||
map_html = map_html.replace("{coverage_radius_km:.1f}", f"{coverage_radius_km:.1f}")
|
||||
map_html = map_html.replace("{target_count}", str(len(map_targets)))
|
||||
|
||||
# Inject initial targets as JavaScript variable
|
||||
targets_json = json.dumps(map_targets)
|
||||
map_html = map_html.replace(
|
||||
"// Display initial targets if any",
|
||||
f"window.initialTargets = {targets_json};\n // Display initial targets if any",
|
||||
)
|
||||
|
||||
return map_html
|
||||
# Generate HTML content
|
||||
targets_json = json.dumps(map_targets)
|
||||
return (
|
||||
self.map_html_template.replace("{lat}", str(gps_data.latitude))
|
||||
.replace("{lon}", str(gps_data.longitude))
|
||||
.replace("{alt:.1f}", f"{gps_data.altitude:.1f}")
|
||||
.replace("{pitch:+.1f}", f"{gps_data.pitch:+.1f}")
|
||||
.replace("{coverage_radius}", str(coverage_radius))
|
||||
.replace("{coverage_radius_km:.1f}", f"{coverage_radius_km:.1f}")
|
||||
.replace("{target_count}", str(len(map_targets)))
|
||||
.replace(
|
||||
"// Display initial targets if any",
|
||||
"window.initialTargets = "
|
||||
f"{targets_json};\n // Display initial targets if any",
|
||||
)
|
||||
)
|
||||
|
||||
def polar_to_geographic(self, radar_lat, radar_lon, range_m, azimuth_deg):
|
||||
"""
|
||||
@@ -775,7 +772,7 @@ class STM32USBInterface:
|
||||
"device": dev,
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
except (usb.core.USBError, ValueError):
|
||||
devices.append(
|
||||
{
|
||||
"description": f"STM32 CDC (VID:{vid:04X}, PID:{pid:04X})",
|
||||
@@ -786,7 +783,7 @@ class STM32USBInterface:
|
||||
)
|
||||
|
||||
return devices
|
||||
except Exception as e:
|
||||
except usb.core.USBError as e:
|
||||
logging.error(f"Error listing USB devices: {e}")
|
||||
# Return mock devices for testing
|
||||
return [
|
||||
@@ -836,7 +833,7 @@ class STM32USBInterface:
|
||||
logging.info(f"STM32 USB device opened: {device_info['description']}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
except usb.core.USBError as e:
|
||||
logging.error(f"Error opening USB device: {e}")
|
||||
return False
|
||||
|
||||
@@ -852,7 +849,7 @@ class STM32USBInterface:
|
||||
packet = self._create_settings_packet(settings)
|
||||
logging.info("Sending radar settings to STM32 via USB...")
|
||||
return self._send_data(packet)
|
||||
except Exception as e:
|
||||
except (usb.core.USBError, struct.error) as e:
|
||||
logging.error(f"Error sending settings via USB: {e}")
|
||||
return False
|
||||
|
||||
@@ -869,9 +866,6 @@ class STM32USBInterface:
|
||||
return None
|
||||
logging.error(f"USB read error: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error(f"Error reading from USB: {e}")
|
||||
return None
|
||||
|
||||
def _send_data(self, data):
|
||||
"""Send data to STM32 via USB"""
|
||||
@@ -889,7 +883,7 @@ class STM32USBInterface:
|
||||
self.ep_out.write(chunk)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
except usb.core.USBError as e:
|
||||
logging.error(f"Error sending data via USB: {e}")
|
||||
return False
|
||||
|
||||
@@ -915,7 +909,7 @@ class STM32USBInterface:
|
||||
try:
|
||||
usb.util.dispose_resources(self.device)
|
||||
self.is_open = False
|
||||
except Exception as e:
|
||||
except usb.core.USBError as e:
|
||||
logging.error(f"Error closing USB device: {e}")
|
||||
|
||||
|
||||
@@ -930,16 +924,14 @@ class FTDIInterface:
|
||||
logging.warning("FTDI not available - please install pyftdi")
|
||||
return []
|
||||
|
||||
try:
|
||||
devices = []
|
||||
# Get list of all FTDI devices
|
||||
for device in UsbTools.find_all([(0x0403, 0x6010)]): # FT2232H vendor/product ID
|
||||
devices.append(
|
||||
{"description": f"FTDI Device {device}", "url": f"ftdi://{device}/1"}
|
||||
)
|
||||
return devices
|
||||
except Exception as e:
|
||||
logging.error(f"Error listing FTDI devices: {e}")
|
||||
try:
|
||||
# Get list of all FTDI devices
|
||||
return [
|
||||
{"description": f"FTDI Device {device}", "url": f"ftdi://{device}/1"}
|
||||
for device in UsbTools.find_all([(0x0403, 0x6010)])
|
||||
] # FT2232H vendor/product ID
|
||||
except usb.core.USBError as e:
|
||||
logging.error(f"Error listing FTDI devices: {e}")
|
||||
# Return mock devices for testing
|
||||
return [{"description": "FT2232H Device A", "url": "ftdi://device/1"}]
|
||||
|
||||
@@ -966,7 +958,7 @@ class FTDIInterface:
|
||||
logging.info(f"FTDI device opened: {device_url}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
except FtdiError as e:
|
||||
logging.error(f"Error opening FTDI device: {e}")
|
||||
return False
|
||||
|
||||
@@ -980,7 +972,7 @@ class FTDIInterface:
|
||||
if data:
|
||||
return bytes(data)
|
||||
return None
|
||||
except Exception as e:
|
||||
except FtdiError as e:
|
||||
logging.error(f"Error reading from FTDI: {e}")
|
||||
return None
|
||||
|
||||
@@ -1242,7 +1234,7 @@ class RadarGUI:
|
||||
"""
|
||||
self.browser.load_html(placeholder_html)
|
||||
|
||||
except Exception as e:
|
||||
except (tk.TclError, RuntimeError) as e:
|
||||
logging.error(f"Failed to create embedded browser: {e}")
|
||||
self.create_browser_fallback()
|
||||
else:
|
||||
@@ -1340,7 +1332,7 @@ Map HTML will appear here when generated.
|
||||
self.fallback_text.configure(state="disabled")
|
||||
self.fallback_text.see("1.0") # Scroll to top
|
||||
logging.info("Fallback text widget updated with map HTML")
|
||||
except Exception as e:
|
||||
except (tk.TclError, RuntimeError) as e:
|
||||
logging.error(f"Error updating embedded browser: {e}")
|
||||
|
||||
def generate_map(self):
|
||||
@@ -1386,7 +1378,7 @@ Map HTML will appear here when generated.
|
||||
|
||||
logging.info(f"Map generated with {len(targets)} targets")
|
||||
|
||||
except Exception as e:
|
||||
except (OSError, ValueError) as e:
|
||||
logging.error(f"Error generating map: {e}")
|
||||
self.map_status_label.config(text=f"Map: Error - {str(e)[:50]}")
|
||||
|
||||
@@ -1400,19 +1392,19 @@ Map HTML will appear here when generated.
|
||||
# Create temporary HTML file
|
||||
import tempfile
|
||||
|
||||
temp_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".html", delete=False, encoding="utf-8"
|
||||
)
|
||||
temp_file.write(self.current_map_html)
|
||||
temp_file.close()
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".html", delete=False, encoding="utf-8"
|
||||
) as temp_file:
|
||||
temp_file.write(self.current_map_html)
|
||||
temp_file_path = temp_file.name
|
||||
|
||||
# Open in default browser
|
||||
webbrowser.open("file://" + os.path.abspath(temp_file.name))
|
||||
logging.info(f"Map opened in external browser: {temp_file.name}")
|
||||
webbrowser.open("file://" + os.path.abspath(temp_file_path))
|
||||
logging.info(f"Map opened in external browser: {temp_file_path}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error opening external browser: {e}")
|
||||
messagebox.showerror("Error", f"Failed to open browser: {e}")
|
||||
except (OSError, ValueError) as e:
|
||||
logging.error(f"Error opening external browser: {e}")
|
||||
messagebox.showerror("Error", f"Failed to open browser: {e}")
|
||||
|
||||
# ... [Rest of the methods remain the same - demo mode, radar processing, etc.] ...
|
||||
|
||||
@@ -1427,7 +1419,7 @@ def main():
|
||||
root = tk.Tk()
|
||||
_app = RadarGUI(root)
|
||||
root.mainloop()
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001
|
||||
logging.error(f"Application error: {e}")
|
||||
messagebox.showerror("Fatal Error", f"Application failed to start: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user