Skip to content

Commit 168b903

Browse files
authored
Merge pull request #172 from labthings/enable-bugbear
Enable bugbear rules
2 parents ba43627 + acb1e30 commit 168b903

20 files changed

Lines changed: 122 additions & 60 deletions

docs/source/quickstart/counter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def increment_counter(self) -> None:
1818
@lt.thing_action
1919
def slowly_increase_counter(self) -> None:
2020
"""Increment the counter slowly over a minute"""
21-
for i in range(60):
21+
for _i in range(60):
2222
time.sleep(1)
2323
self.increment_counter()
2424

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,17 @@ docstring-code-format = true
7676

7777
[tool.ruff.lint]
7878
external = ["DOC401", "F824", "DOC101", "DOC103"] # used via flake8/pydoclint
79-
select = ["E4", "E7", "E9", "F", "D", "DOC"]
79+
select = ["B", "E4", "E7", "E9", "F", "D", "DOC"]
8080
ignore = [
8181
"D203", # incompatible with D204
8282
"D213", # incompatible with D212
8383
"DOC402", # doesn't work with sphinx-style docstrings, use flake8/pydoclint
8484
"DOC201", # doesn't work with sphinx-style docstrings, use flake8/pydoclint
8585
"DOC501", # doesn't work with sphinx-style docstrings, use flake8/pydoclint
8686
"DOC502", # doesn't work with sphinx-style docstrings, use flake8/pydoclint
87+
"B008", # This disallows function calls in default values.
88+
# FastAPI Depends() breaks this rule, and FastAPI's response is "disable it".
89+
# see https://github.com/fastapi/fastapi/issues/1522
8790
]
8891
preview = true
8992

src/labthings_fastapi/actions/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,11 @@ def action_invocation(
491491
try:
492492
with self._invocations_lock:
493493
return self._invocations[id].response(request=request)
494-
except KeyError:
494+
except KeyError as e:
495495
raise HTTPException(
496496
status_code=404,
497497
detail="No action invocation found with ID {id}",
498-
)
498+
) from e
499499

500500
@app.get(
501501
ACTION_INVOCATIONS_PATH + "/{id}/output",
@@ -530,11 +530,11 @@ def action_invocation_output(id: uuid.UUID, _blob_manager: BlobIOContextDep):
530530
with self._invocations_lock:
531531
try:
532532
invocation: Any = self._invocations[id]
533-
except KeyError:
533+
except KeyError as e:
534534
raise HTTPException(
535535
status_code=404,
536536
detail="No action invocation found with ID {id}",
537-
)
537+
) from e
538538
if not invocation.output:
539539
raise HTTPException(
540540
status_code=503,
@@ -569,11 +569,11 @@ def delete_invocation(id: uuid.UUID) -> None:
569569
with self._invocations_lock:
570570
try:
571571
invocation: Any = self._invocations[id]
572-
except KeyError:
572+
except KeyError as e:
573573
raise HTTPException(
574574
status_code=404,
575575
detail="No action invocation found with ID {id}",
576-
)
576+
) from e
577577
if invocation.status not in [
578578
InvocationStatus.RUNNING,
579579
InvocationStatus.PENDING,

src/labthings_fastapi/client/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ def _get_link(obj: dict, rel: str) -> Mapping:
5757
raise ObjectHasNoLinksError(f"Can't find any links on {obj}.")
5858
try:
5959
return next(link for link in obj["links"] if link["rel"] == rel)
60-
except StopIteration:
61-
raise KeyError(f"No link was found with rel='{rel}' on {obj}.")
60+
except StopIteration as e:
61+
raise KeyError(f"No link was found with rel='{rel}' on {obj}.") from e
6262

6363

6464
def invocation_href(invocation: dict) -> str:

src/labthings_fastapi/client/in_server.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,24 @@ def direct_thing_client_class(
265265
This class may be used as a FastAPI dependency: see :ref:`things_from_things`.
266266
"""
267267

268-
def init_proxy(self, request: Request, **dependencies: Mapping[str, Any]):
269-
f"""A client for {thing_class} at {thing_path}"""
268+
def init_proxy(
269+
self: DirectThingClient, request: Request, **dependencies: Mapping[str, Any]
270+
):
271+
r"""Initialise a DirectThingClient (this docstring will be replaced).
272+
273+
:param self: The DirectThingClient instance we're initialising.
274+
:param request: a FastAPI Request option (will be supplied by FastAPI).
275+
:param \**dependencies: Other keyword arguments will be saved as
276+
dependencies. FastAPI will look at the signature (which we will
277+
manipulate below) to determine these.
278+
"""
270279
# NB this definition isimportant, as we must modify its signature.
271280
# Inheriting __init__ means we'll accidentally modify the signature
272281
# of `DirectThingClient` with bad results.
273282
DirectThingClient.__init__(self, request, **dependencies)
274283

284+
init_proxy.__doc__ = f"""Initialise a client for {thing_class} at {thing_path}"""
285+
275286
# Using a class definition gets confused by the scope of the function
276287
# arguments - this is equivalent to a class definition but all the
277288
# arguments are evaluated in the right scope.

src/labthings_fastapi/example_things/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def slowly_increase_counter(self, increments: int = 60, delay: float = 1):
9090
:param increments: how many times to increment.
9191
:param delay: the wait time between increments.
9292
"""
93-
for i in range(increments):
93+
for _i in range(increments):
9494
time.sleep(delay)
9595
self.increment_counter()
9696

src/labthings_fastapi/outputs/blob.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,11 @@ def retrieve_data(self) -> Self:
364364
url_to_blobdata = url_to_blobdata_ctx.get()
365365
self._data = url_to_blobdata(self.href)
366366
self.href = "blob://local"
367-
except LookupError:
367+
except LookupError as e:
368368
raise LookupError(
369369
"Blobs may only be created from URLs passed in over HTTP."
370370
f"The URL in question was {self.href}."
371-
)
371+
) from e
372372
return self
373373

374374
@model_serializer(mode="plain", when_used="always")
@@ -398,11 +398,11 @@ def to_dict(self) -> Mapping[str, str]:
398398
blobdata_to_url = blobdata_to_url_ctx.get()
399399
# MyPy seems to miss that `self.data` is a property, hence the ignore
400400
href = blobdata_to_url(self.data) # type: ignore[arg-type]
401-
except LookupError:
401+
except LookupError as e:
402402
raise LookupError(
403403
"Blobs may only be serialised inside the "
404404
"context created by BlobIOContextDep."
405-
)
405+
) from e
406406
else:
407407
href = self.href
408408
return {

src/labthings_fastapi/server/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ async def lifespan(self, app: FastAPI) -> AsyncGenerator[None]:
210210
for thing in self.things.values():
211211
await stack.enter_async_context(thing)
212212
yield
213-
for name, thing in self.things.items():
213+
for _name, thing in self.things.items():
214214
# Remove the blocking portal - the event loop is about to stop.
215215
thing._labthings_blocking_portal = None
216216

@@ -284,9 +284,8 @@ def server_from_config(config: dict) -> ThingServer:
284284
except ImportError as e:
285285
raise ImportError(
286286
f"Could not import {thing['class']}, which was "
287-
f"specified as the class for {path}. The error is "
288-
f"printed below:\n\n{e}"
289-
)
287+
f"specified as the class for {path}."
288+
) from e
290289
instance = cls(*thing.get("args", {}), **thing.get("kwargs", {}))
291290
assert isinstance(instance, Thing), f"{thing['class']} is not a Thing"
292291
server.add_thing(instance, path)

src/labthings_fastapi/server/cli.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ def config_from_args(args: Namespace) -> dict:
9696
try:
9797
with open(args.config) as f:
9898
config = json.load(f)
99-
except FileNotFoundError:
100-
raise FileNotFoundError(f"Could not find configuration file {args.config}")
99+
except FileNotFoundError as e:
100+
raise FileNotFoundError(
101+
f"Could not find configuration file {args.config}"
102+
) from e
101103
else:
102104
config = {}
103105
if args.json:

src/labthings_fastapi/thing_description/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,8 @@ def look_up_reference(reference: str, d: JSONSchema) -> JSONSchema:
7575
return resolved
7676
except KeyError as ke:
7777
raise KeyError(
78-
f"The JSON reference {reference} was not found in the schema "
79-
f"(original error {ke})."
80-
)
78+
f"The JSON reference {reference} was not found in the schema."
79+
) from ke
8180

8281

8382
def is_an_object(d: JSONSchema) -> bool:

0 commit comments

Comments
 (0)