Start adding ANN ruff rules

This commit is contained in:
Julian Stirling 2025-08-27 13:21:34 +01:00
parent 154f063ab3
commit 24233412af
19 changed files with 123 additions and 46 deletions

View file

@ -12,7 +12,7 @@ from gitlab.exceptions import GitlabGetError
PROJECT_ID = 9238334 PROJECT_ID = 9238334
def main(tag, branch: str = "v3"): def main(tag: str, branch: str = "v3"):
"""Create a list of the MRs into a given branch after a tag. """Create a list of the MRs into a given branch after a tag.
:param tag: The tag the mrs should be since. :param tag: The tag the mrs should be since.

View file

@ -124,8 +124,9 @@ select = [
"C90", # McCabe complexity! "C90", # McCabe complexity!
"NPY", # Numpy linting "NPY", # Numpy linting
"N", # PEP8 naming "N", # PEP8 naming
"D", # Docstring checks these may need to be added gradually "D", # Docstring checks
"ERA001", # Commented out code! "ERA001", # Commented out code!
"ANN001",
] ]
ignore = [ ignore = [
@ -140,6 +141,11 @@ ignore = [
# Tests are currently not fully docstring-ed, we'll ignore this for now. # Tests are currently not fully docstring-ed, we'll ignore this for now.
"tests/*" = [ "tests/*" = [
"B018", # Complaining about useless attribute access in tests, but we need them to check errors are raised "B018", # Complaining about useless attribute access in tests, but we need them to check errors are raised
"ANN", # Tests are not typehinted for fixtures etc
]
"hardware-specific-tests/*" = [
"B018", # Complaining about useless attribute access in tests, but we need them to check errors are raised
"ANN", # Tests are not typehinted for fixtures etc
] ]
[tool.ruff.lint.pydocstyle] [tool.ruff.lint.pydocstyle]

View file

@ -21,7 +21,7 @@ from fastapi import HTTPException
OFM_LOG_FILE = None OFM_LOG_FILE = None
def configure_logging(log_folder): def configure_logging(log_folder: str):
"""Configure logging for the server while it is running. """Configure logging for the server while it is running.
This modifies the root logger to have a rotating file handler and This modifies the root logger to have a rotating file handler and
@ -120,7 +120,7 @@ class OFMLogFileFormatter(logging.Formatter):
class OFMHandler(logging.Handler): class OFMHandler(logging.Handler):
"""A logging.Handler that stores the most recent logs for access by the server.""" """A logging.Handler that stores the most recent logs for access by the server."""
def __init__(self, level=logging.INFO, max_logs=250): def __init__(self, level: int = logging.INFO, max_logs: int = 250):
"""Initialise the handler with a set logging level and message buffer size. """Initialise the handler with a set logging level and message buffer size.
:param level: The level of logs captured. As standard logs of INFO and above :param level: The level of logs captured. As standard logs of INFO and above

View file

@ -551,7 +551,7 @@ class ScanDirectory:
return zip_fname return zip_fname
def get_files_in_zip(zip_path): def get_files_in_zip(zip_path: str):
"""List the relative paths of all files and folders in the zip folder specified.""" """List the relative paths of all files and folders in the zip folder specified."""
scan_zip = zipfile.ZipFile(zip_path) scan_zip = zipfile.ZipFile(zip_path)
return [os.path.normpath(i) for i in scan_zip.namelist()] return [os.path.normpath(i) for i in scan_zip.namelist()]

View file

@ -332,7 +332,7 @@ class SmartSpiral(ScanPlanner):
"""Sort the remaining positions based on the current location.""" """Sort the remaining positions based on the current location."""
# Defined rather than use a lambda for readability # Defined rather than use a lambda for readability
def sort_key(pos): def sort_key(pos: XYPos):
return ( return (
self.moves_between(current_pos, pos), self.moves_between(current_pos, pos),
self.moves_between(self._initial_position, pos), self.moves_between(self._initial_position, pos),

View file

@ -185,7 +185,7 @@ class FinalStitcher(BaseStitcher):
def __init__( def __init__(
self, self,
images_dir, images_dir: str,
*, *,
logger: lt.deps.InvocationLogger, logger: lt.deps.InvocationLogger,
overlap: Optional[float] = None, overlap: Optional[float] = None,

View file

@ -127,7 +127,7 @@ class StackParams:
""" """
return self.min_images_to_test + 15 return self.min_images_to_test + 15
def slice_to_save(self, sharpest_index): def slice_to_save(self, sharpest_index: int):
"""Return the slice of images to save given the index of the sharpest image.""" """Return the slice of images to save given the index of the sharpest image."""
images_each_side = (self.images_to_save - 1) // 2 images_each_side = (self.images_to_save - 1) // 2
return slice( return slice(
@ -401,7 +401,7 @@ class AutofocusThing(lt.Thing):
self, self,
stage: Stage, stage: Stage,
sharpness_monitor: SharpnessMonitorDep, sharpness_monitor: SharpnessMonitorDep,
dz=2000, dz: int = 2000,
start: Literal["centre", "base"] = "centre", start: Literal["centre", "base"] = "centre",
): ):
"""Repeatedly autofocus the stage until it looks focused. """Repeatedly autofocus the stage until it looks focused.

View file

@ -8,6 +8,7 @@ See repository root for licensing information.
from __future__ import annotations from __future__ import annotations
from typing import Literal, Optional, Tuple, Any from typing import Literal, Optional, Tuple, Any
from types import TracebackType
import json import json
import io import io
import time import time
@ -185,7 +186,12 @@ class BaseCamera(lt.Thing):
"""Open hardware connection when the Thing context manager is opened.""" """Open hardware connection when the Thing context manager is opened."""
raise NotImplementedError("CameraThings must define their own __enter__ method") raise NotImplementedError("CameraThings must define their own __enter__ method")
def __exit__(self, _exc_type, _exc_value, _traceback) -> None: def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
) -> None:
"""Close hardware connection when the Thing context manager is closed.""" """Close hardware connection when the Thing context manager is closed."""
raise NotImplementedError("CameraThings must define their own __exit__ method") raise NotImplementedError("CameraThings must define their own __exit__ method")
@ -575,7 +581,7 @@ class BaseCamera(lt.Thing):
return self.active_detector.status return self.active_detector.status
@lt.thing_action @lt.thing_action
def update_detector_settings(self, data) -> None: def update_detector_settings(self, data: dict[str, Any]) -> None:
"""Update the settings of the current detector. """Update the settings of the current detector.
This is an action not a setting/property as the data model depends on the This is an action not a setting/property as the data model depends on the

View file

@ -10,6 +10,7 @@ from __future__ import annotations
import logging import logging
from typing import Literal, Optional from typing import Literal, Optional
from types import TracebackType
from threading import Thread from threading import Thread
import cv2 import cv2
@ -42,7 +43,12 @@ class OpenCVCamera(BaseCamera):
self._capture_thread.start() self._capture_thread.start()
return self return self
def __exit__(self, _exc_type, _exc_value, _traceback): def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
):
"""Release the camera when the Thing context manager is closed. """Release the camera when the Thing context manager is closed.
Before releasing the camera the capture thread is closed. Before releasing the camera the capture thread is closed.

View file

@ -15,7 +15,8 @@ https://datasheets.raspberrypi.com/camera/raspberry-pi-camera-guide.pdf
""" """
from __future__ import annotations from __future__ import annotations
from typing import Annotated, Iterator, Literal, Mapping, Optional, overload from typing import Annotated, Iterator, Literal, Mapping, Optional, overload, Any
from types import TracebackType
import json import json
import logging import logging
import os import os
@ -65,7 +66,12 @@ class PicameraStreamOutput(Output):
self.portal = portal self.portal = portal
def outputframe( def outputframe(
self, frame, _keyframe=True, _timestamp=None, _packet=None, _audio=False self,
frame: bytes,
_keyframe: Optional[bool] = True,
_timestamp: Optional[int] = None,
_packet: Any = None,
_audio: bool = False,
): ):
"""Add a frame to the stream's ringbuffer.""" """Add a frame to the stream's ringbuffer."""
self.stream.add_frame(frame, self.portal) self.stream.add_frame(frame, self.portal)
@ -396,7 +402,7 @@ class StreamingPiCamera2(BaseCamera):
return self._picamera is not None and self._picamera.started return self._picamera is not None and self._picamera.started
@contextmanager @contextmanager
def _streaming_picamera(self, pause_stream=False) -> Iterator[Picamera2]: def _streaming_picamera(self, pause_stream: bool = False) -> Iterator[Picamera2]:
"""Lock access to picamera and return the underlying ``Picamera2`` instance. """Lock access to picamera and return the underlying ``Picamera2`` instance.
Optionally the stream can be paused to allow updating the camera settings. Optionally the stream can be paused to allow updating the camera settings.
@ -419,7 +425,12 @@ class StreamingPiCamera2(BaseCamera):
if pause_stream and already_streaming: if pause_stream and already_streaming:
self.start_streaming() self.start_streaming()
def __exit__(self, exc_type, exc_value, traceback): def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
):
"""Close the picamera connection when the Thing context manager is closed.""" """Close the picamera connection when the Thing context manager is closed."""
self.stop_streaming() self.stop_streaming()
with self._streaming_picamera() as cam: with self._streaming_picamera() as cam:
@ -725,7 +736,10 @@ class StreamingPiCamera2(BaseCamera):
return tuple(recalibrate_utils.get_static_ccm(self.tuning)[0]["ccm"]) return tuple(recalibrate_utils.get_static_ccm(self.tuning)[0]["ccm"])
@colour_correction_matrix.setter # type: ignore @colour_correction_matrix.setter # type: ignore
def colour_correction_matrix(self, value) -> None: def colour_correction_matrix(
self,
value: tuple[float, float, float, float, float, float, float, float, float],
) -> None:
recalibrate_utils.set_static_ccm(self.tuning, value) recalibrate_utils.set_static_ccm(self.tuning, value)
if self._picamera is not None: if self._picamera is not None:

View file

@ -353,7 +353,9 @@ def upsample_channels(grids: np.ndarray, shape: tuple[int]) -> np.ndarray:
return zoom(grids, zoom_factors, order=1)[:, : shape[0], : shape[1]] return zoom(grids, zoom_factors, order=1)[:, : shape[0], : shape[1]]
def downsampled_channels(channels: np.ndarray, blacklevel=64) -> list[np.ndarray]: def downsampled_channels(
channels: np.ndarray, blacklevel: int = 64
) -> list[np.ndarray]:
"""Generate a downsampled, un-normalised image from which to calculate the LST. """Generate a downsampled, un-normalised image from which to calculate the LST.
TODO: blacklevel probably ought to be determined from the camera... TODO: blacklevel probably ought to be determined from the camera...

View file

@ -9,6 +9,7 @@ See repository root for licensing information.
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Literal, Optional from typing import Literal, Optional
from types import TracebackType
from threading import Thread from threading import Thread
import time import time
@ -212,7 +213,12 @@ class SimulatedCamera(BaseCamera):
self.start_streaming() self.start_streaming()
return self return self
def __exit__(self, _exc_type, _exc_value, _traceback): def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
):
"""Close the capture thread when the Thing context manager is closed.""" """Close the capture thread when the Thing context manager is closed."""
if self.stream_active: if self.stream_active:
self._capture_enabled = False self._capture_enabled = False

View file

@ -7,7 +7,7 @@ It also controls external processes for live stitching composite images, and
the creation of the final stitched images. the creation of the final stitched images.
""" """
from typing import Optional from typing import Optional, Self, TypeVar, ParamSpec, Callable, Concatenate
import threading import threading
import os import os
import time import time
@ -30,6 +30,9 @@ from .camera_stage_mapping import CameraStageMapper
from .camera import CameraDependency as CameraClient from .camera import CameraDependency as CameraClient
from .stage import StageDependency as StageDep from .stage import StageDependency as StageDep
T = TypeVar("T")
P = ParamSpec("P")
CSMDep = lt.deps.direct_thing_client_dependency( CSMDep = lt.deps.direct_thing_client_dependency(
CameraStageMapper, "/camera_stage_mapping/" CameraStageMapper, "/camera_stage_mapping/"
) )
@ -43,7 +46,9 @@ class ScanNotRunningError(RuntimeError):
"""Exception called when scan not running that requires a scan to be running.""" """Exception called when scan not running that requires a scan to be running."""
def _scan_running(method): def _scan_running(
method: Callable[Concatenate[Self, P], T],
) -> Callable[Concatenate[Self, P], T]:
"""Decorate a method so that it will error if a scan is not running. """Decorate a method so that it will error if a scan is not running.
This decorator is used by all methods in SmartScanThing that are using This decorator is used by all methods in SmartScanThing that are using
@ -52,7 +57,7 @@ def _scan_running(method):
the same time and released with the lock the same time and released with the lock
""" """
def scan_running_wrapper(self, *args, **kwargs): def scan_running_wrapper(self: Self, *args: P.args, **kwargs: P.kwargs) -> T:
# Only start the method is the scan logger is set # Only start the method is the scan logger is set
if self._scan_logger is not None: if self._scan_logger is not None:
return method(self, *args, **kwargs) return method(self, *args, **kwargs)
@ -623,7 +628,7 @@ class SmartScanThing(lt.Thing):
if scan_info.number_of_images == 0: if scan_info.number_of_images == 0:
self._delete_scan(scan_info.name, logger) self._delete_scan(scan_info.name, logger)
def _delete_scan(self, scan_name, logger: lt.deps.InvocationLogger) -> bool: def _delete_scan(self, scan_name: str, logger: lt.deps.InvocationLogger) -> bool:
"""Delete a scan. """Delete a scan.
This is a wrapper around scan manager's delete_scan that logs to the This is a wrapper around scan manager's delete_scan that logs to the

View file

@ -142,7 +142,7 @@ class BaseStage(lt.Thing):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make a relative move. Keyword arguments should be axis names.""" """Make a relative move. Keyword arguments should be axis names."""
self._hardware_move_relative( self._hardware_move_relative(
@ -155,7 +155,7 @@ class BaseStage(lt.Thing):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make a relative move in the coordinate system used by the physical hardware. """Make a relative move in the coordinate system used by the physical hardware.
@ -170,7 +170,7 @@ class BaseStage(lt.Thing):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make an absolute move. Keyword arguments should be axis names.""" """Make an absolute move. Keyword arguments should be axis names."""
self._hardware_move_absolute( self._hardware_move_absolute(
@ -183,7 +183,7 @@ class BaseStage(lt.Thing):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make a absolute move in the coordinate system used by the physical hardware. """Make a absolute move in the coordinate system used by the physical hardware.

View file

@ -2,6 +2,8 @@
from __future__ import annotations from __future__ import annotations
from typing import Optional
from types import TracebackType
from collections.abc import Mapping from collections.abc import Mapping
import time import time
@ -33,7 +35,12 @@ class DummyStage(BaseStage):
"""Register the stage position when the Thing context manager is opened.""" """Register the stage position when the Thing context manager is opened."""
self.instantaneous_position = self._hardware_position self.instantaneous_position = self._hardware_position
def __exit__(self, _exc_type, _exc_value, _traceback): def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
):
"""Nothing to do when the Thing context manager is closed.""" """Nothing to do when the Thing context manager is closed."""
axis_inverted = lt.ThingSetting( axis_inverted = lt.ThingSetting(
@ -47,7 +54,7 @@ class DummyStage(BaseStage):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make a relative move. Keyword arguments should be axis names.""" """Make a relative move. Keyword arguments should be axis names."""
displacement = [kwargs.get(k, 0) for k in self.axis_names] displacement = [kwargs.get(k, 0) for k in self.axis_names]
@ -85,7 +92,7 @@ class DummyStage(BaseStage):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
"""Make an absolute move. Keyword arguments should be axis names.""" """Make an absolute move. Keyword arguments should be axis names."""
displacement = { displacement = {

View file

@ -5,7 +5,8 @@ import logging
import threading import threading
import time import time
from copy import copy from copy import copy
from typing import Iterator, Literal from typing import Iterator, Literal, Optional
from types import TracebackType
from contextlib import contextmanager from contextlib import contextmanager
from collections.abc import Mapping from collections.abc import Mapping
@ -53,7 +54,12 @@ class SangaboardThing(BaseStage):
sb.query("blocking_moves false") sb.query("blocking_moves false")
self.update_position() self.update_position()
def __exit__(self, _exc_type, _exc_value, _traceback): def __exit__(
self,
_exc_type: type[BaseException],
_exc_value: Optional[BaseException],
_traceback: Optional[TracebackType],
):
"""Close the sangaboard connection when the Thing context manager is closed.""" """Close the sangaboard connection when the Thing context manager is closed."""
with self.sangaboard() as sb: with self.sangaboard() as sb:
sb.close() sb.close()
@ -85,7 +91,7 @@ class SangaboardThing(BaseStage):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
) -> None: ) -> None:
"""Make a relative move in the coordinate system used by the sangaboard.""" """Make a relative move in the coordinate system used by the sangaboard."""
displacement = [kwargs.get(axis, 0) for axis in self.axis_names] displacement = [kwargs.get(axis, 0) for axis in self.axis_names]
@ -112,7 +118,7 @@ class SangaboardThing(BaseStage):
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
) -> None: ) -> None:
"""Make a absolute move in the coordinate system used by the sangaboard.""" """Make a absolute move in the coordinate system used by the sangaboard."""
with self.sangaboard(): with self.sangaboard():

View file

@ -1,7 +1,11 @@
"""Functionality for communicating the required user interface for a thing.""" """Functionality for communicating the required user interface for a thing."""
from typing import Callable, Any
from pydantic import BaseModel from pydantic import BaseModel
import labthings_fastapi as lt
class ActionButton(BaseModel): class ActionButton(BaseModel):
"""The data required for creating an actionButton in Vue. """The data required for creating an actionButton in Vue.
@ -43,7 +47,7 @@ class ActionButton(BaseModel):
"""The message to show on successful completion.""" """The message to show on successful completion."""
def action_button_for(action, **kwargs) -> ActionButton: def action_button_for(action: Callable[..., Any], **kwargs: Any) -> ActionButton:
"""Create a ActionButton data for the specified Thing Action. """Create a ActionButton data for the specified Thing Action.
:param action: The thing action to create a button for. :param action: The thing action to create a button for.
@ -80,7 +84,9 @@ class PropertyControl(BaseModel):
"""The delay in ms before reading back the property.""" """The delay in ms before reading back the property."""
def property_control_for(thing, property_name, **kwargs) -> PropertyControl: def property_control_for(
thing: lt.Thing, property_name: str, **kwargs: Any
) -> PropertyControl:
"""Create an PropertyControl data for the specified Thing Property. """Create an PropertyControl data for the specified Thing Property.
:param thing: The instance of the thing that has the property to be controlled. :param thing: The instance of the thing that has the property to be controlled.

View file

@ -1,6 +1,6 @@
"""Utility functions and classes.""" """Utility functions and classes."""
from typing import TypeVar, Callable, ParamSpec from typing import TypeVar, Callable, ParamSpec, Optional, Any, Concatenate, Self
import os import os
import re import re
import sys import sys
@ -24,7 +24,7 @@ COMMIT_REGEX = re.compile(r"[0-9a-f]{40}")
REF_REGEX = re.compile(r"^ref:\s(.*)$") REF_REGEX = re.compile(r"^ref:\s(.*)$")
def _is_lock_like(obj): def _is_lock_like(obj: Any) -> bool:
"""Check if an object is a lock. """Check if an object is a lock.
Cannot use ``isinstance(obj, threading.RLock)``, may be possible to use Cannot use ``isinstance(obj, threading.RLock)``, may be possible to use
@ -34,14 +34,16 @@ def _is_lock_like(obj):
return hasattr(obj, "acquire") and hasattr(obj, "release") return hasattr(obj, "acquire") and hasattr(obj, "release")
def requires_lock(method: Callable[P, T]) -> Callable[P, T]: def requires_lock(
method: Callable[Concatenate[Self, P], T],
) -> Callable[Concatenate[Self, P], T]:
"""Decorate a class method so that it requires the class lock to run. """Decorate a class method so that it requires the class lock to run.
The class should have a reentrant lock with the name ``self._lock``. The class should have a reentrant lock with the name ``self._lock``.
""" """
@wraps(method) @wraps(method)
def wrapper(self, *args: P.args, **kwargs: P.kwargs) -> T: def wrapper(self: Self, *args: P.args, **kwargs: P.kwargs) -> T:
# Confirm the object the method is attached to has a self._lock property # Confirm the object the method is attached to has a self._lock property
if not hasattr(self, "_lock"): if not hasattr(self, "_lock"):
raise AttributeError(f"{self.__class__.__name__} has no '_lock' attribute") raise AttributeError(f"{self.__class__.__name__} has no '_lock' attribute")
@ -67,7 +69,16 @@ class ErrorCapturingThread(Thread):
join is run. join is run.
""" """
def __init__(self, group=None, target=None, args=None, kwargs=None, daemon=None): def __init__(
self,
group: Optional[Any] = None,
target: Optional[Callable[..., Any]] = None,
name: Optional[str] = None,
args: tuple[Any, ...] = (),
kwargs: Optional[dict[str, Any]] = None,
*,
daemon: Optional[bool] = None,
):
"""Initialise with the same arguments as Thread.""" """Initialise with the same arguments as Thread."""
# As all inputs are keywords we need to set the default values for args and kwargs: # As all inputs are keywords we need to set the default values for args and kwargs:
if args is None: if args is None:
@ -88,12 +99,13 @@ class ErrorCapturingThread(Thread):
super().__init__( super().__init__(
group=group, group=group,
target=_wrap_and_catch_errors, target=_wrap_and_catch_errors,
name=name,
args=args, args=args,
kwargs=kwargs, kwargs=kwargs,
daemon=daemon, daemon=daemon,
) )
def join(self, timeout=None): def join(self, timeout: Optional[float] = None):
"""Join when the thread is complete. """Join when the thread is complete.
If the thread ended due to an unhandled exception, the exception will be raised If the thread ended due to an unhandled exception, the exception will be raised
@ -107,7 +119,9 @@ class ErrorCapturingThread(Thread):
raise err raise err
def _wrap_and_catch_errors(target, error_buffer, *args, **kwargs): def _wrap_and_catch_errors(
target: Callable[..., Any], error_buffer: list, *args, **kwargs
):
"""Run target function in a try-except block. """Run target function in a try-except block.
This function is designed only to be used by ErrorCapturingThread. This function is designed only to be used by ErrorCapturingThread.

View file

@ -1,6 +1,5 @@
"""Test the stage without creating a full HTTP server and socket connection.""" """Test the stage without creating a full HTTP server and socket connection."""
from collections.abc import Mapping
import tempfile import tempfile
import itertools import itertools
@ -69,7 +68,7 @@ def test_override_base_movement():
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
pass pass
@ -82,7 +81,7 @@ def test_override_base_movement():
self, self,
cancel: lt.deps.CancelHook, cancel: lt.deps.CancelHook,
block_cancellation: bool = False, block_cancellation: bool = False,
**kwargs: Mapping[str, int], **kwargs: int,
): ):
pass pass