Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ All changes to the codebase should go via pull requests, and should only be merg

Dependencies are defined in `pyproject.toml` and can be compiled to `dev-requirements.txt` with:
```
uv pip compile --extra dev pyproject.toml --output-file dev-requirements.txt
uv pip compile dev-requirements.in -o dev-requirements.txt
```
If you're not using `uv`, just regular `pip-compile` from `pip-tools` should do the same thing.

Expand Down
1 change: 1 addition & 0 deletions dev-requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .[dev]
102 changes: 52 additions & 50 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --extra dev pyproject.toml --output-file dev-requirements.txt
# uv pip compile dev-requirements.in -o dev-requirements.txt
-e .
# via -r dev-requirements.in
alabaster==1.0.0
# via sphinx
annotated-doc==0.0.4
Expand All @@ -8,10 +10,10 @@ annotated-doc==0.0.4
# typer
annotated-types==0.7.0
# via pydantic
anyio==4.13.0
anyio==4.14.0
# via
# labthings-fastapi (pyproject.toml)
# httpx
# labthings-fastapi
# starlette
# watchfiles
apeye==1.4.1
Expand All @@ -29,11 +31,11 @@ autodocsumm==0.2.15
# via sphinx-toolbox
babel==2.18.0
# via sphinx
beautifulsoup4==4.14.3
beautifulsoup4==4.15.0
# via sphinx-toolbox
cachecontrol==0.14.4
# via sphinx-toolbox
certifi==2026.5.20
certifi==2026.6.17
# via
# httpcore
# httpx
Expand All @@ -49,8 +51,8 @@ click==8.4.1
# rich-toolkit
# uvicorn
codespell==2.4.2
# via labthings-fastapi (pyproject.toml)
coverage==7.14.1
# via labthings-fastapi
coverage==7.14.3
# via pytest-cov
detect-installer==0.1.0
# via fastapi-cloud-cli
Expand Down Expand Up @@ -83,30 +85,30 @@ exceptiongroup==1.3.1
# anyio
# pytest
fastapi==0.135.4
# via labthings-fastapi (pyproject.toml)
fastapi-cli==0.0.24
# via labthings-fastapi
fastapi-cli==0.0.27
# via fastapi
fastapi-cloud-cli==0.18.0
fastapi-cloud-cli==0.20.0
# via fastapi-cli
fastar==0.11.0
# via fastapi-cloud-cli
filelock==3.29.0
filelock==3.29.4
# via
# cachecontrol
# sphinx-toolbox
flake8==7.3.0
# via
# labthings-fastapi (pyproject.toml)
# flake8-pyproject
# flake8-rst
# flake8-rst-docstrings
# labthings-fastapi
# pydoclint
flake8-pyproject==1.2.4
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
flake8-rst==0.8.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
flake8-rst-docstrings==0.4.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
h11==0.16.0
# via
# httpcore
Expand All @@ -119,10 +121,10 @@ httptools==0.8.0
# via uvicorn
httpx==0.28.1
# via
# labthings-fastapi (pyproject.toml)
# fastapi
# fastapi-cloud-cli
idna==3.16
# labthings-fastapi
idna==3.18
# via
# anyio
# apeye-core
Expand All @@ -146,7 +148,7 @@ jinja2==3.1.6
# sphinx-jinja2-compat
jsonschema==4.26.0
# via
# labthings-fastapi (pyproject.toml)
# labthings-fastapi
# sphobjinv
jsonschema-specifications==2025.9.1
# via jsonschema
Expand All @@ -162,25 +164,25 @@ mccabe==0.7.0
# via flake8
mdurl==0.1.2
# via markdown-it-py
msgpack==1.1.2
msgpack==1.2.1
# via cachecontrol
mypy==1.20.2
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
mypy-extensions==1.1.0
# via mypy
natsort==8.4.0
# via domdf-python-tools
numpy==2.2.6
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
packaging==26.2
# via
# pytest
# sphinx
pathspec==1.1.1
# via mypy
pillow==12.2.0
# via labthings-fastapi (pyproject.toml)
platformdirs==4.9.6
# via labthings-fastapi
platformdirs==4.10.0
# via apeye
pluggy==1.6.0
# via
Expand All @@ -190,19 +192,19 @@ pycodestyle==2.14.0
# via flake8
pydantic==2.13.4
# via
# labthings-fastapi (pyproject.toml)
# fastapi
# fastapi-cloud-cli
# labthings-fastapi
# pydantic-extra-types
# pydantic-settings
pydantic-core==2.46.4
# via pydantic
pydantic-extra-types==2.11.1
# via fastapi
pydantic-settings==2.14.1
pydantic-settings==2.14.2
# via fastapi
pydoclint==0.8.4
# via labthings-fastapi (pyproject.toml)
pydoclint==0.8.7
# via labthings-fastapi
pyflakes==3.4.0
# via flake8
pygments==2.20.0
Expand All @@ -213,20 +215,20 @@ pygments==2.20.0
# sphinx
# sphinx-prompt
# sphinx-tabs
pytest==9.0.3
pytest==9.1.1
# via
# labthings-fastapi (pyproject.toml)
# labthings-fastapi
# pytest-cov
# pytest-mock
pytest-cov==7.1.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
pytest-mock==3.15.1
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
python-dotenv==1.2.2
# via
# pydantic-settings
# uvicorn
python-multipart==0.0.29
python-multipart==0.0.32
# via fastapi
pyyaml==6.0.3
# via
Expand All @@ -249,7 +251,7 @@ rich==15.0.0
# via
# rich-toolkit
# typer
rich-toolkit==0.19.10
rich-toolkit==0.20.1
# via
# fastapi-cli
# fastapi-cloud-cli
Expand All @@ -263,22 +265,22 @@ rpds-py==0.30.0
# referencing
ruamel-yaml==0.19.1
# via sphinx-toolbox
ruff==0.15.14
# via labthings-fastapi (pyproject.toml)
sentry-sdk==2.60.0
ruff==0.15.18
# via labthings-fastapi
sentry-sdk==2.63.0
# via fastapi-cloud-cli
shellingham==1.5.4
# via typer
six==1.17.0
# via html5lib
snowballstemmer==3.1.0
snowballstemmer==3.1.1
# via sphinx
soupsieve==2.8.4
# via beautifulsoup4
sphinx==8.1.3
# via
# labthings-fastapi (pyproject.toml)
# autodocsumm
# labthings-fastapi
# sphinx-autoapi
# sphinx-autodoc-typehints
# sphinx-prompt
Expand All @@ -287,19 +289,19 @@ sphinx==8.1.3
# sphinx-toolbox
# sphinxcontrib-jquery
sphinx-autoapi==3.8.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
sphinx-autodoc-typehints==3.0.1
# via sphinx-toolbox
sphinx-jinja2-compat==0.4.1
# via sphinx-toolbox
sphinx-prompt==1.9.0
# via sphinx-toolbox
sphinx-rtd-theme==3.1.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
sphinx-tabs==3.5.0
# via sphinx-toolbox
sphinx-toolbox==4.2.0
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
sphinxcontrib-applehelp==2.0.0
# via sphinx
sphinxcontrib-devhelp==2.0.0
Expand All @@ -315,38 +317,38 @@ sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
# via sphinx
sphobjinv==2.4
# via labthings-fastapi (pyproject.toml)
starlette==1.1.0
# via labthings-fastapi
starlette==1.3.1
# via fastapi
tabulate==0.10.0
# via sphinx-toolbox
tinycss2==1.5.1
# via dict2css
tomli==2.4.1
# via
# labthings-fastapi (pyproject.toml)
# coverage
# fastapi-cli
# flake8-pyproject
# labthings-fastapi
# mypy
# pydoclint
# pytest
# sphinx
typer==0.26.1
typer==0.26.7
# via
# fastapi-cli
# fastapi-cloud-cli
types-jsonschema==4.26.0.20260518
# via labthings-fastapi (pyproject.toml)
# via labthings-fastapi
typing-extensions==4.15.0
# via
# labthings-fastapi (pyproject.toml)
# anyio
# astroid
# beautifulsoup4
# domdf-python-tools
# exceptiongroup
# fastapi
# labthings-fastapi
# mypy
# pydantic
# pydantic-core
Expand All @@ -367,7 +369,7 @@ urllib3==2.7.0
# requests
# sentry-sdk
# sphinx-prompt
uvicorn==0.48.0
uvicorn==0.49.0
# via
# fastapi
# fastapi-cli
Expand All @@ -382,5 +384,5 @@ webencodings==0.5.1
# tinycss2
websockets==16.0
# via uvicorn
zeroconf==0.149.16
# via labthings-fastapi (pyproject.toml)
zeroconf==0.150.0
# via labthings-fastapi
4 changes: 2 additions & 2 deletions src/labthings_fastapi/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@

@property
def output(self) -> Any:
"""Return value of the Action. If the Action is still running, returns None."""
"""The Action's output (return value) or `None` if it's still running."""
with self._status_lock:
return RootModelWrapper.unwrap(self._output_model_instance)

@property
def output_model_instance(self) -> BaseModel | None:
"""Return value of the Action, as a model, or None."""
"""The Action's output (return value), as a model, or None."""
with self._status_lock:
return self._output_model_instance

Expand Down Expand Up @@ -568,8 +568,8 @@
with self._invocations_lock:
try:
invocation: Any = self._invocations[id]
except KeyError as e:
raise HTTPException(

Check warning on line 572 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

571-572 lines are not covered with tests
status_code=404,
detail="No action invocation found with ID {id}",
) from e
Expand All @@ -582,7 +582,7 @@
invocation.output.response
):
# TODO: honour "accept" header
return invocation.output.response()

Check warning on line 585 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

585 line is not covered with tests
try:
return serialise_from_user_code(
model_instance=invocation.output_model_instance,
Expand Down Expand Up @@ -618,8 +618,8 @@
with self._invocations_lock:
try:
invocation: Any = self._invocations[id]
except KeyError as e:
raise HTTPException(

Check warning on line 622 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

621-622 lines are not covered with tests
status_code=404,
detail="No action invocation found with ID {id}",
) from e
Expand Down Expand Up @@ -814,7 +814,7 @@
"""
super().__set_name__(owner, name)
if self.name != self.func.__name__:
raise ValueError(

Check warning on line 817 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

817 line is not covered with tests
f"Action name '{self.name}' does not match function name "
f"'{self.func.__name__}'",
)
Expand Down Expand Up @@ -925,9 +925,9 @@
status_code=201,
code=self.func,
)
except InvalidReturnValueError as e:
thing.logger.error(e)
raise HTTPException(status_code=500, detail=str(e)) from e

Check warning on line 930 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

928-930 lines are not covered with tests

if issubclass(self.input_model, EmptyInput):
annotation = Body(default_factory=StrictEmptyInput)
Expand Down Expand Up @@ -958,14 +958,14 @@
try:
responses[200]["model"] = self.output_model
pass
except AttributeError:
print(f"Failed to generate response model for action {self.name}")

Check warning on line 962 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

961-962 lines are not covered with tests
# Add an additional media type if we may return a file
if hasattr(self.output_model, "media_type"):
responses[200]["content"][self.output_model.media_type] = {}

Check warning on line 965 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

965 line is not covered with tests
# Now we can add the endpoint to the app.
if thing.path is None:
raise NotConnectedToServerError(

Check warning on line 968 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

968 line is not covered with tests
"Can't add the endpoint without thing.path!"
)
app.post(
Expand Down Expand Up @@ -1013,7 +1013,7 @@
"""
path = path or thing.path
if path is None:
raise NotConnectedToServerError("Can't generate forms without a path!")

Check warning on line 1016 in src/labthings_fastapi/actions.py

View workflow job for this annotation

GitHub Actions / coverage

1016 line is not covered with tests
forms = [
Form[ActionOp](href=path + self.name, op=[ActionOp.invokeaction]),
]
Expand Down
4 changes: 2 additions & 2 deletions src/labthings_fastapi/base_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@

@property
def owning_class(self) -> type[Owner]:
"""Retrieve the class this info object is describing."""
"""The class this info object is describing."""
return self._descriptor_cls

@property
def owning_object(self) -> Owner | None:
"""Retrieve the object to which this info object is bound, if present."""
"""The object to which this info object is bound, if present."""
return self._bound_to_obj

@property
Expand Down Expand Up @@ -181,7 +181,7 @@
self._descriptor_ref = ref(descriptor)
if cls is None:
if obj is None:
raise ValueError("Either `obj` or `cls` must be supplied.")

Check warning on line 184 in src/labthings_fastapi/base_descriptor.py

View workflow job for this annotation

GitHub Actions / coverage

184 line is not covered with tests
cls = obj.__class__
self._descriptor_cls = cls
self._bound_to_obj = obj
Expand Down
2 changes: 1 addition & 1 deletion src/labthings_fastapi/outputs/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ def data(self) -> BlobData:

@property
def content(self) -> bytes:
"""Return the the output as a `bytes` object.
"""The blob's content as a `bytes` object in memory.

This property may return the `bytes` object, or if we have a file it
will read the file and return the contents. Client objects may use
Expand Down
Loading
Loading