Skip to content

Commit f5653ce

Browse files
committed
Lint RST in docstrings
sphinx-autodoc2 gives difficult-to-follow errors that don't easily show where in the source they come from. I've set up flake8 to lint the docstrings, and fixed the errors. I've also fixed my links, which used incorrect syntax for `:ref:` links. I may try out sphinx.ext.autodoc instead - this imports the module, but might be more reliable.
1 parent 81e8b0c commit f5653ce

36 files changed

+319
-190
lines changed

NOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ switched to using `pydoclint` directly, and configured it in `pyproject.toml`. I
6060
- Example code in the descriptor may want a doctest in due course.
6161
- Could do with example code showing how it works in a simple camera?
6262
* `server`: could do with some more specific exceptions.
63+
- `__init__:80` does this need to be a global? I think it might work without, and flake8 complains.
64+
I've silenced it at the import and also the global line.
6365
* `server.cli`: need a model for config.
6466
* `thing_description`:
6567
- Custom exception for `recursion_limit`

dev-requirements.txt

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# This file was autogenerated by uv via the following command:
22
# uv pip compile --extra dev pyproject.toml --output-file dev-requirements.txt
3+
alabaster==0.7.16
4+
# via sphinx
35
annotated-types==0.7.0
46
# via pydantic
57
anyio==4.8.0
@@ -12,10 +14,15 @@ attrs==25.1.0
1214
# via
1315
# jsonschema
1416
# referencing
17+
babel==2.17.0
18+
# via sphinx
1519
certifi==2025.1.31
1620
# via
1721
# httpcore
1822
# httpx
23+
# requests
24+
charset-normalizer==3.4.2
25+
# via requests
1926
click==8.1.8
2027
# via
2128
# pydoclint
@@ -26,19 +33,40 @@ colorama==0.4.6
2633
# via
2734
# click
2835
# pytest
36+
# sphinx
2937
# uvicorn
3038
coverage==7.6.12
3139
# via pytest-cov
3240
dnspython==2.7.0
3341
# via email-validator
3442
docstring-parser-fork==0.0.12
3543
# via pydoclint
44+
docutils==0.20.1
45+
# via
46+
# restructuredtext-lint
47+
# sphinx
48+
# sphinx-rtd-theme
3649
email-validator==2.2.0
3750
# via fastapi
3851
fastapi==0.115.11
3952
# via labthings-fastapi (pyproject.toml)
4053
fastapi-cli==0.0.7
4154
# via fastapi
55+
flake8==7.3.0
56+
# via
57+
# labthings-fastapi (pyproject.toml)
58+
# flake8-docstrings
59+
# flake8-pyproject
60+
# flake8-rst
61+
# flake8-rst-docstrings
62+
flake8-docstrings==1.7.0
63+
# via labthings-fastapi (pyproject.toml)
64+
flake8-pyproject==1.2.3
65+
# via labthings-fastapi (pyproject.toml)
66+
flake8-rst==0.8.0
67+
# via labthings-fastapi (pyproject.toml)
68+
flake8-rst-docstrings==0.3.1
69+
# via labthings-fastapi (pyproject.toml)
4270
h11==0.14.0
4371
# via
4472
# httpcore
@@ -56,14 +84,19 @@ idna==3.10
5684
# anyio
5785
# email-validator
5886
# httpx
87+
# requests
5988
ifaddr==0.2.0
6089
# via zeroconf
90+
imagesize==1.4.1
91+
# via sphinx
6192
iniconfig==2.0.0
6293
# via pytest
6394
itsdangerous==2.2.0
6495
# via fastapi
6596
jinja2==3.1.6
66-
# via fastapi
97+
# via
98+
# fastapi
99+
# sphinx
67100
jsonschema==4.23.0
68101
# via labthings-fastapi (pyproject.toml)
69102
jsonschema-specifications==2024.10.1
@@ -72,6 +105,8 @@ markdown-it-py==3.0.0
72105
# via rich
73106
markupsafe==3.0.2
74107
# via jinja2
108+
mccabe==0.7.0
109+
# via flake8
75110
mdurl==0.1.2
76111
# via markdown-it-py
77112
mypy==1.15.0
@@ -83,11 +118,15 @@ numpy==2.2.3
83118
orjson==3.10.15
84119
# via fastapi
85120
packaging==24.2
86-
# via pytest
121+
# via
122+
# pytest
123+
# sphinx
87124
pillow==11.3.0
88125
# via labthings-fastapi (pyproject.toml)
89126
pluggy==1.5.0
90127
# via pytest
128+
pycodestyle==2.14.0
129+
# via flake8
91130
pydantic==2.10.6
92131
# via
93132
# labthings-fastapi (pyproject.toml)
@@ -102,8 +141,15 @@ pydantic-settings==2.8.1
102141
# via fastapi
103142
pydoclint==0.6.6
104143
# via labthings-fastapi (pyproject.toml)
144+
pydocstyle==6.3.0
145+
# via flake8-docstrings
146+
pyflakes==3.4.0
147+
# via flake8
105148
pygments==2.19.1
106-
# via rich
149+
# via
150+
# flake8-rst-docstrings
151+
# rich
152+
# sphinx
107153
pytest==7.4.4
108154
# via
109155
# labthings-fastapi (pyproject.toml)
@@ -125,6 +171,10 @@ referencing==0.36.2
125171
# jsonschema
126172
# jsonschema-specifications
127173
# types-jsonschema
174+
requests==2.32.4
175+
# via sphinx
176+
restructuredtext-lint==1.4.0
177+
# via flake8-rst-docstrings
128178
rich==13.9.4
129179
# via
130180
# rich-toolkit
@@ -141,6 +191,31 @@ shellingham==1.5.4
141191
# via typer
142192
sniffio==1.3.1
143193
# via anyio
194+
snowballstemmer==3.0.1
195+
# via
196+
# pydocstyle
197+
# sphinx
198+
sphinx==7.4.7
199+
# via
200+
# labthings-fastapi (pyproject.toml)
201+
# sphinx-rtd-theme
202+
# sphinxcontrib-jquery
203+
sphinx-rtd-theme==2.0.0
204+
# via labthings-fastapi (pyproject.toml)
205+
sphinxcontrib-applehelp==2.0.0
206+
# via sphinx
207+
sphinxcontrib-devhelp==2.0.0
208+
# via sphinx
209+
sphinxcontrib-htmlhelp==2.1.0
210+
# via sphinx
211+
sphinxcontrib-jquery==4.1
212+
# via sphinx-rtd-theme
213+
sphinxcontrib-jsmath==1.0.1
214+
# via sphinx
215+
sphinxcontrib-qthelp==2.0.0
216+
# via sphinx
217+
sphinxcontrib-serializinghtml==2.0.0
218+
# via sphinx
144219
starlette==0.46.0
145220
# via fastapi
146221
typer==0.15.2
@@ -161,6 +236,8 @@ typing-extensions==4.12.2
161236
# typer
162237
ujson==5.10.0
163238
# via fastapi
239+
urllib3==2.5.0
240+
# via requests
164241
uvicorn==0.34.0
165242
# via
166243
# fastapi

docs/source/actions.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ terms, any method of a `.Thing` that we want to be able to call over HTTP
88
should be decorated as an Action, using :deco:`.thing_action`.
99

1010
This page gives an overview of how actions are implemented in LabThings-FastAPI.
11-
wot_cc_ includes a section on wot_actions_ that introduces the general concept.
11+
:ref:`wot_cc` includes a section on wot_:ref:`actions` that introduces the general concept.
1212

1313
Running actions via HTTP
1414
------------------------
@@ -54,6 +54,6 @@ the Thing Description, so it is important to use them consistently.
5454
There are some function arguments that are not considered input parameters.
5555
The first is ``self`` (the first positional argument), which is always the
5656
`.Thing` on which the argument is defined. The other special arguments are
57-
dependencies_, which use annotated type hints to tell LabThings to
57+
:ref:`dependencies`, which use annotated type hints to tell LabThings to
5858
supply resources needed by the action. Most often, this is a way of accessing
5959
other `.Things` on the same server.

docs/source/lt_core_concepts.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The server API is accessed over an HTTP requests, allowing client code (see belo
1515
Everything is a Thing
1616
---------------------
1717

18-
As described in wot_cc_, a Thing represents a piece of hardware or software. LabThings-FastAPI automatically generates a wot_td_ to describe each Thing. Each function offered by the Thing is either a Property or Action (LabThings-FastAPI does not yet support Events). These are termed "interaction affordances" in WoT_ terminology.
18+
As described in :ref:`wot_cc`, a Thing represents a piece of hardware or software. LabThings-FastAPI automatically generates a :ref:`wot_td` to describe each Thing. Each function offered by the Thing is either a Property or Action (LabThings-FastAPI does not yet support Events). These are termed "interaction affordances" in WoT_ terminology.
1919

2020
Code on the LabThings FastAPI Server is composed of Things, however these can call generic Python functions/classes. The entire HTTP API served by the server is defined by `.Thing` objects. As such the full API is composed of the actions and properties (and perhaps eventually events) defined in each Thing.
2121

docs/source/using_things.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ One goal of LabThings-FastAPI is to make code portable between a client (e.g. a
2828

2929
A `.DirectThingClient` class will call actions and properties of other `.Thing` subclasses using the same interface that would be used by a remote client, which means code for an action may be developed as an HTTP client, for example in a Jupyter notebook, and then moved to the server with minimal changes. Currently, there are a few differences in behaviour between working locally or remotely, most notably the return types (which are usually Pydantic models on the server, and currently dictionaries on the client). This should be improved in the future.
3030

31-
It is also possible for a `.Thing` to access other `.Thing` instances directly. This gives access to functionality that is only available in Python, i.e. not available through a `.ThingClient` over HTTP. However, the `.Thing` must then be supplied manually with any dependencies_ required by its actions, and the public API as defined by the wot_td_ is no longer enforced.
31+
It is also possible for a `.Thing` to access other `.Thing` instances directly. This gives access to functionality that is only available in Python, i.e. not available through a `.ThingClient` over HTTP. However, the `.Thing` must then be supplied manually with any :ref:`dependencies` required by its actions, and the public API as defined by the :ref:`wot_td` is no longer enforced.
3232

33-
Actions that make use of other `.Thing` objects on the same server should access them using dependencies_.
33+
Actions that make use of other `.Thing` objects on the same server should access them using :ref:`dependencies`.
3434

3535
Planned future development: static code generation
3636
--------------------------------------------------

pyproject.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ dev = [
3131
"ruff>=0.1.3",
3232
"types-jsonschema",
3333
"Pillow",
34+
"flake8",
35+
"flake8-pyproject",
36+
"flake8-docstrings",
37+
"flake8-rst",
38+
"flake8-rst-docstrings",
3439
"pydoclint",
40+
"sphinx-rtd-theme",
41+
"sphinx>=7.2",
3542
]
3643

3744
[project.urls]
@@ -92,5 +99,19 @@ check-yield-types = false # use type annotations instead
9299
[tool.mypy]
93100
plugins = ["pydantic.mypy", "numpy.typing.mypy_plugin"]
94101

102+
[tool.flake8]
103+
extend-ignore = ["DOC301"]
104+
max-line-length = 88
105+
rst-roles = [
106+
"class",
107+
"func",
108+
"ref",
109+
"deco",
110+
"doc",
111+
]
112+
rst-directives = [
113+
"todo",
114+
]
115+
95116
[project.scripts]
96117
labthings-server = "labthings_fastapi.server.cli:serve_from_cli"

src/labthings_fastapi/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
r"""LabThings-FastAPI.
22
33
This is the top level module for LabThings-FastAPI, a library for building
4-
wot_cc_ devices using Python. There is documentation on readthedocs_,
4+
:ref:`wot_cc` devices using Python. There is documentation on readthedocs_,
55
and the recommended place to start is :doc:`index`\ .
66
7+
.. _readthedocs: https://labthings-fastapi.readthedocs.io/
8+
79
This module contains a number of convenience
810
imports and is intended to be imported using:
911

src/labthings_fastapi/actions/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
:ref:`wot_actions` are represented by methods, decorated with the `.thing_action`
44
decorator.
55
6-
See the actions_ documentation for a top-level overview of actions in LabThings-FastAPI.
6+
See the :ref:`actions` documentation for a top-level overview of actions in
7+
LabThings-FastAPI.
78
89
Developer notes
910
---------------

src/labthings_fastapi/client/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ObjectHasNoLinksError(KeyError):
3333
def _get_link(obj: dict, rel: str) -> Mapping:
3434
"""Retrieve a link from an object's ``links`` list, by its ``rel`` attribute.
3535
36-
Various places in the wot_td_ feature a list of links. This is represented
36+
Various places in the :ref:`wot_td` feature a list of links. This is represented
3737
in JSON as a property called ``links`` which is a list of objects that have
3838
``href`` and ``rel`` properties.
3939
@@ -160,7 +160,7 @@ def set_property(self, path: str, value: Any):
160160
r.raise_for_status()
161161

162162
def invoke_action(self, path: str, **kwargs):
163-
"""Invoke an action on the Thing.
163+
r"""Invoke an action on the Thing.
164164
165165
This method will make the initial POST request to invoke an action,
166166
then poll the resulting invocation until it completes. If successful,
@@ -171,7 +171,7 @@ def invoke_action(self, path: str, **kwargs):
171171
172172
:param path: the URI of the ``invokeaction`` endpoint, relative to the
173173
``base_url``
174-
:param **kwargs: Additional arguments will be combined into the JSON
174+
:param \**kwargs: Additional arguments will be combined into the JSON
175175
body of the ``POST`` request and sent as input to the action.
176176
These will be validated on the server.
177177
@@ -244,7 +244,7 @@ def subclass_from_td(cls, thing_description: dict) -> type[Self]:
244244
Dynamically subclass `.ThingClient` to add properties and
245245
methods for each property and action in the Thing Description.
246246
247-
:param thing_description: A wot_td_ as a dictionary, which will
247+
:param thing_description: A :ref:`wot_td` as a dictionary, which will
248248
be used to construct the class.
249249
250250
:return: a `.ThingClient` subclass with the right properties and
@@ -345,7 +345,7 @@ def add_action(cls: type[ThingClient], action_name: str, action: dict) -> None:
345345
action.
346346
:param action_name: is both the name we assign the method to, and
347347
the name of the action in the Thing Description.
348-
:param action: a dictionary representing the action, in wot_td_
348+
:param action: a dictionary representing the action, in :ref:`wot_td`
349349
format.
350350
"""
351351

@@ -371,7 +371,7 @@ def add_property(cls: type[ThingClient], property_name: str, property: dict):
371371
property.
372372
:param property_name: is both the name we assign the descriptor to, and
373373
the name of the property in the Thing Description.
374-
:param property: a dictionary representing the property, in wot_td_
374+
:param property: a dictionary representing the property, in :ref:`wot_td`
375375
format.
376376
"""
377377
setattr(

src/labthings_fastapi/client/in_server.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use an interface that is identical to the `.ThingClient` used to access
55
the same `.Thing` remotely. This means that code can run either on the
66
server or on a client, e.g. in a Jupyter notebook where it is much
7-
easier to debug. See things_from_things_ for more detail.
7+
easier to debug. See :ref:`things_from_things` for more detail.
88
99
Currently `.DirectThingClient` is not a subclass of `.ThingClient`,
1010
that may need to change. It's a good idea to create a
@@ -55,15 +55,15 @@ class DirectThingClient:
5555
"""The path to the Thing on the server. Relative to the server's base URL."""
5656

5757
def __init__(self, request: Request, **dependencies: Mapping[str, Any]):
58-
"""Wrap a `.Thing` so it works like a `.ThingClient`.
58+
r"""Wrap a `.Thing` so it works like a `.ThingClient`.
5959
6060
This class is designed to be used as a FastAPI dependency, and will
6161
retrieve a `.Thing` based on its ``thing_path`` attribute.
6262
Finding the Thing by class may also be an option in the future.
6363
6464
:param request: This is a FastAPI dependency to access the
6565
`fastapi.Request` object, allowing access to various resources.
66-
:param **dependencies: Further arguments will be added
66+
:param \**dependencies: Further arguments will be added
6767
dynamically by subclasses, by duplicating this method and
6868
manipulating its signature. Adding arguments with annotated
6969
type hints instructs FastAPI to inject dependency arguments,
@@ -139,7 +139,7 @@ class DependencyNameClashError(KeyError):
139139
"""A dependency argument name is used inconsistently.
140140
141141
A current limitation of `.DirectThingClient` is that the dependency
142-
arguments (see dependencies_) are collected together in a single
142+
arguments (see :ref:`dependencies`) are collected together in a single
143143
dictionary. This makes the assumption that, if a name is reused, it is
144144
reused for the same dependency.
145145
@@ -247,7 +247,7 @@ def direct_thing_client_class(
247247
thing_path: str,
248248
actions: Optional[list[str]] = None,
249249
) -> type[DirectThingClient]:
250-
"""Create a DirectThingClient from a Thing class and a path.
250+
r"""Create a DirectThingClient from a Thing class and a path.
251251
252252
This is a class, not an instance: it's designed to be a FastAPI dependency.
253253
@@ -258,11 +258,11 @@ def direct_thing_client_class(
258258
dependencies we need.
259259
260260
:return: a subclass of `DirectThingClient` with attributes that match the
261-
properties and actions of ``thing_class``. The ``__init__` method
261+
properties and actions of ``thing_class``. The ``__init__`` method
262262
will have annotations that instruct FastAPI to supply all the
263263
dependencies needed by its actions.
264264
265-
This class may be used as a FastAPI dependency: see things_from_things_.
265+
This class may be used as a FastAPI dependency: see :ref:`things_from_things`.
266266
"""
267267

268268
def init_proxy(self, request: Request, **dependencies: Mapping[str, Any]):

0 commit comments

Comments
 (0)