Add flake8 bugbear checks

This commit is contained in:
Julian Stirling 2025-08-12 13:09:43 +01:00
parent 7ea92ad55f
commit 6142a267db
11 changed files with 40 additions and 30 deletions

View file

@ -105,7 +105,7 @@ def test_exposure_time_on_start_and_stop_stream():
time.sleep(0.5)
# Take a couple of images to make sure that the exposure is adjusted to
# a hardware compatible value.
for i in range(2):
for _i in range(2):
client.capture_jpeg(resolution="full")
# Save this time.
set_time = client.exposure_time
@ -135,7 +135,7 @@ def _load_camera_and_return_exposure(tmpdir: str) -> int:
time.sleep(0.5)
# Take a couple of images to make sure that the exposure is adjusted to
# a hardware compatible value.
for i in range(2):
for _i in range(2):
client.capture_jpeg(resolution="full")
# Save this time.
return client.exposure_time

View file

@ -109,7 +109,7 @@ select = [
"W", #pycodestyle warnings
"F", # PyFlakes
# "PL", # Pylint (a subset of, catches far less than pylint does)
# "B", # Flake8 bugbear
"B", # Flake8 bugbear
"A", # Flake8 builtins checker
"C", # Flake8 comprehensions
# "FIX", #TODO/FIXME's in code. These should be added during development for ongoing tasks.
@ -136,6 +136,12 @@ ignore = [
# The checkers below should be turned on as they complain about missing docstrings.
]
[tool.ruff.lint.per-file-ignores]
# Tests are currently not fully docstring-ed, we'll ignore this for now.
"tests/*" = [
"B018", # Complaining about useless attribute access in tests, but we need them to check errors are raised
]
[tool.ruff.lint.pydocstyle]
# This lets the D401 checker understand that decorated thing properties and thing
# settings act like properties so should be documented as such.

View file

@ -346,8 +346,8 @@ class StreamingPiCamera2(BaseCamera):
sensor_modes property, and then starts the streams.
"""
self._initialise_picamera()
# populate sensor modes by reading the property
self.sensor_modes
# Sensor modes is a cached property read it once after initialising the camera
_modes = self.sensor_modes
self.start_streaming()
return self

View file

@ -98,7 +98,9 @@ class BaseStage(lt.Thing):
if isinstance(position, (list, tuple)):
return [
-int(pos) if inverted else int(pos)
for pos, inverted in zip(position, self.axis_inverted.values())
for pos, inverted in zip(
position, self.axis_inverted.values(), strict=True
)
]
if isinstance(position, Mapping):
try:

View file

@ -65,7 +65,7 @@ class DummyStage(BaseStage):
fraction_complete = (time.time() - start_time) / (dt * max_displacement)
self.instantaneous_position = {
ax: self._hardware_position[ax] + int(fraction_complete * disp)
for ax, disp in zip(self.axis_names, displacement)
for ax, disp in zip(self.axis_names, displacement, strict=True)
}
fraction_complete = 1.0
except lt.exceptions.InvocationCancelledError as e:
@ -77,7 +77,7 @@ class DummyStage(BaseStage):
self.moving = False
self._hardware_position = {
ax: self._hardware_position[ax] + int(fraction_complete * disp)
for ax, disp in zip(self.axis_names, displacement)
for ax, disp in zip(self.axis_names, displacement, strict=True)
}
self.instantaneous_position = self._hardware_position

View file

@ -77,7 +77,9 @@ class SangaboardThing(BaseStage):
def update_position(self) -> None:
"""Read position from the stage and set the corresponding property."""
with self.sangaboard() as sb:
self._hardware_position = dict(zip(self.axis_names, sb.position))
self._hardware_position = dict(
zip(self.axis_names, sb.position, strict=True)
)
def _hardware_move_relative(
self,
@ -164,7 +166,7 @@ class SangaboardThing(BaseStage):
"Brightness control is not yet implemented. Desired brightness: "
f"{intended_brightness}. Set brightness: {on_brightness}"
)
for i in range(number_of_flashes):
for _i in range(number_of_flashes):
sb.query(f"{led_command} 0")
time.sleep(dt)
sb.query(f"{led_command} {on_brightness}")

View file

@ -147,13 +147,13 @@ def test_buffer_size_respected():
images = []
buffer_ids = []
for i in range(10):
for _i in range(10):
image = random_image()
buffer_id = mem_buf.add_image(image, buffer_max=5)
images.append(image)
buffer_ids.append(buffer_id)
for i, (image, buffer_id) in enumerate(zip(images, buffer_ids)):
for i, (image, buffer_id) in enumerate(zip(images, buffer_ids, strict=True)):
if i < 5:
with pytest.raises(NoImageInMemoryError):
mem_buf.get_image(buffer_id)
@ -168,7 +168,7 @@ def test_clear_buffer():
images = []
buffer_ids = []
for i in range(10):
for _i in range(10):
image = random_image()
buffer_id = mem_buf.add_image(image, buffer_max=10)
images.append(image)
@ -178,7 +178,7 @@ def test_clear_buffer():
mem_buf.clear()
# They are now gone
for i, (image, buffer_id) in enumerate(zip(images, buffer_ids)):
for _i, (_image, buffer_id) in enumerate(zip(images, buffer_ids, strict=True)):
with pytest.raises(NoImageInMemoryError):
mem_buf.get_image(buffer_id)
@ -190,7 +190,7 @@ def test_get_metadata_too():
images = []
metadatas = []
buffer_ids = []
for i in range(10):
for _i in range(10):
image = random_image()
metadata = random_metadata()
buffer_id = mem_buf.add_image(image, metadata, buffer_max=10)
@ -199,10 +199,10 @@ def test_get_metadata_too():
buffer_ids.append(buffer_id)
# Preallocate zipped data, to avoid long confusing lines
zipped = zip(images, metadatas, buffer_ids)
zipped = zip(images, metadatas, buffer_ids, strict=True)
# Check both image and metadata
for i, (image, metadata, buffer_id) in enumerate(zipped):
for _i, (image, metadata, buffer_id) in enumerate(zipped):
returned_image, returned_metadata = mem_buf.get_image(buffer_id)
assert image is returned_image
assert metadata is returned_metadata

View file

@ -97,11 +97,11 @@ def test_stage(client):
move = {"x": 1, "y": 2, "z": 3}
stage.move_relative(**move)
pos = stage.position
for s, m, p in zip(start.values(), move.values(), pos.values()):
for s, m, p in zip(start.values(), move.values(), pos.values(), strict=True):
assert s + m == p
stage.move_relative(**{k: -v for k, v in move.items()})
pos = stage.position
for s, p in zip(start.values(), pos.values()):
for s, p in zip(start.values(), pos.values(), strict=True):
assert s == p

View file

@ -245,7 +245,7 @@ def test_scan_info():
scan_dir_manager = ScanDirectoryManager(BASE_SCAN_DIR)
scan_dir = scan_dir_manager.new_scan_dir("fake_scan")
for i in range(17):
for _i in range(17):
_add_fake_image(scan_dir)
info = scan_dir.scan_info()
now = time.time()
@ -273,7 +273,7 @@ def test_get_final_stitch():
scan_dir = scan_dir_manager.new_scan_dir("fake_scan")
# Create some scan images files
for i in range(17):
for _i in range(17):
_add_fake_image(scan_dir)
# No scans, so None should be returned, from both manager and scan dir
@ -365,7 +365,7 @@ def test_zipping_scan_data():
scan_dir = scan_dir_manager.new_scan_dir("fake_scan")
# Create 21 fake scan images, a fake stitch, and a fake zip
for i in range(21):
for _i in range(21):
_add_fake_image(scan_dir)
_add_fake_file(scan_dir, "fake_scan_0001_stitched.jpg", in_im_dir=True)
_add_fake_file(scan_dir, "zipfile.zip")
@ -502,7 +502,7 @@ def test_extracting_files():
assert scan_dir._extract_dzi_files(scan_files) == []
# Add a number of images
for i in range(2321):
for _i in range(2321):
_add_fake_image(scan_dir)
scan_files = scan_dir.get_scan_files()

View file

@ -212,7 +212,7 @@ def _test_move_relative(dummy_stage, axis_inverted, path):
dummy_stage.move_relative(
cancel=cancel, x=movement[0], y=movement[1], z=movement[2]
)
position = [pos + move for pos, move in zip(position, movement)]
position = [pos + move for pos, move in zip(position, movement, strict=True)]
stage_pos = dummy_stage.get_xyz_position()
hw_pos = dummy_stage._hardware_position
assert position[0] == stage_pos[0] == hw_pos["x"] * x_dir
@ -244,7 +244,7 @@ def test_move_relative(stage_client, dummy_stage, path):
axis_names = stage_client.axis_names
# Create every combination of True/False for x,y,z.
inversion_combinations = [
dict(zip(axis_names, inverted))
dict(zip(axis_names, inverted, strict=True))
for inverted in itertools.product([True, False], repeat=len(axis_names))
]
print(path)
@ -305,7 +305,7 @@ def test_move_absolute(stage_client, dummy_stage, path):
axis_names = stage_client.axis_names
# Create every combination of True/False for x,y,z.
inversion_combinations = [
dict(zip(axis_names, inverted))
dict(zip(axis_names, inverted, strict=True))
for inverted in itertools.product([True, False], repeat=len(axis_names))
]
for axis_inverted in inversion_combinations:

View file

@ -60,8 +60,8 @@ def visualise_scan(sample: FakeSample, planner: scan_planners.ScanPlanner) -> Fi
"""For a given sample and scanner object return a matplotlib figure of the scan."""
fig, ax = plt.subplots(figsize=(8, 8))
ax.add_artist(sample.patch)
xh, yh = zip(*planner._path_history)
xi, yi, _ = zip(*planner._imaged_locations)
xh, yh = zip(*planner._path_history, strict=True)
xi, yi, _ = zip(*planner._imaged_locations, strict=True)
# convert history to numpy array so can calculate quiver arrows
xh = np.array(xh)
@ -91,7 +91,7 @@ def interp_closed_path(xy_points: list[tuple[int, int]], n_points: int) -> MatPa
https://stackoverflow.com/questions/33962717/interpolating-a-closed-curve-using-scipy
"""
# Use zip to separate x and y points into tuples
x, y = zip(*xy_points)
x, y = zip(*xy_points, strict=True)
# Append first point and convert to array
x = np.array(x + (x[0],))
@ -105,7 +105,7 @@ def interp_closed_path(xy_points: list[tuple[int, int]], n_points: int) -> MatPa
xi, yi = interpolate.splev(np.linspace(0, 1, n_points), spline_data)
# Convert to a matplotlib closed path
path_points = [[xp, yp] for xp, yp in (zip(xi, yi))]
path_points = [[xp, yp] for xp, yp in (zip(xi, yi, strict=True))]
return MatPath(path_points, closed=True)