Skip to content

Allow ThingServer to accept ThingServerConfig instances directly#320

Open
rwb27 wants to merge 9 commits intomainfrom
tidy-server-initialisation
Open

Allow ThingServer to accept ThingServerConfig instances directly#320
rwb27 wants to merge 9 commits intomainfrom
tidy-server-initialisation

Conversation

@rwb27
Copy link
Copy Markdown
Collaborator

@rwb27 rwb27 commented Apr 29, 2026

Currently, ThingServer is initialised by supplying a dictionary of Thing subclasses and other parameters. This means the constructor of ThingServer duplicates all the arguments to the constructor of ThingServerConfig, which causes a few wrinkles.

I propose we allow ThingServer to accept a config model directly. This avoids some argument duplication and avoids revalidation of the config model.

It is, however, the case that it's more convenient in test or example code to use ThingServer in the current way, i.e. to supply the dictionary of Thing subclasses as the first argument, and other config parameters as subsequent arguments. It is also desirable to be backwards-compatible, which requires keeping this signature as an option.

I propose we allow ThingServer to accept a config model, providing backwards compatibility with the existing way of doing things. This can be done unambiguously if we make things a reserved name, i.e. it's not allowed to have a Thing on your server with the name things. In the future, we might split this out of the initialiser, such that you can either initialise a server with:

server = lt.ThingServer(config_model_or_dictionary)

or

server = lt.ThingServer.from_things(
    {"name": ThingSubclass}, settings_folder="./my_settings"
)

Avoiding revalidation should allow easier subclassing of the config model, which ought to come in handy when customising the server downstream.

I've also added:

  • a property for debug to allow downstream code to see it.
  • single-sourced settings_folder from the config model
  • a serve method to run the server with uvicorn.run
  • a test_client method to supply a test client.

I've removed the dry_run argument from serve_from_cli (in favour of testing it properly using mocker) and changed it to use the new serve method of the server. This also meant I could improve a couple of the tests by checking it produced a server in the correct state, and not just that they logged the right thing.

It is unfortunate that the number of touched files is so large. Mostly this is a result of a couple of search-and-replace operations to change ThingServer(things) to ThingServer.from_things(things) and get rid of ThingServer.from_config.

Closes #295
Closes #298
Closes #311

This avoids some argument duplication and avoids revalidation of the config model.

This should allow subclassing of the config model, which ought to come in handy when customising the server downstream.

I've also added a property for `debug` to allow downstream code to see it.
@barecheck
Copy link
Copy Markdown

barecheck Bot commented Apr 29, 2026

Barecheck - Code coverage report

Total: 96.68%

Your code coverage diff: 0.04% ▴

Uncovered files and lines
FileLines
src/labthings_fastapi/outputs/mjpeg_stream.py195, 197, 200, 203, 255-257, 266-268, 295, 299-300, 334, 362, 438, 474
src/labthings_fastapi/server/__init__.py290, 304-307
src/labthings_fastapi/server/cli.py102, 163

…erver`.

These methods don't do anything new, but might tidy up downstream code slightly.
Comment thread src/labthings_fastapi/server/__init__.py Outdated
rwb27 added 5 commits April 29, 2026 16:00
This makes the initialiser of `ThingServer` much simpler, and
makes it clearer what should go where.

It's technically a breaking change, but I think it's easy enough to fix that Julian and I are comfortable it's the right call here.
Passing a dictionary of things is common in test/example code, and
needs to be updated to use the new form. This commit is more or less
a search and replace to do that.

`ThingServer({}, **kwargs)` becomes `ThingServer.from_things({}, **kwargs)`

`ThingServer.from_config(config)` becomes `ThingServer(config)`
This seems tidier than `TestClient(server.app)`.
This:
* replaces the call to `uvicorn.run` with a call to `ThingServer.serve` in `serve_from_cli`.
* removes the `dry_run` argument in favour of using a mock for `uvicorn.run`
* always either returns a server or fails to return in `serve_from_cli`
* tests the server's debug flag directly in the debug-related tests.
@rwb27 rwb27 requested a review from julianstirling April 29, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Debug not held in state Consider adding server.serve_with_uvicorn() or similar Allow ThingServer.__init__ to accept a config model instance

2 participants