Skip to content

Commit 5086596

Browse files
committed
Move MyThing to example_things submodule
I've improved test coverage by adding explicit tests of MyThing.
1 parent 4ca711d commit 5086596

File tree

4 files changed

+77
-94
lines changed

4 files changed

+77
-94
lines changed

src/labthings_fastapi/example_things/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ def increment_counter(self):
6767
self.counter += 1
6868

6969
@thing_action
70-
def slowly_increase_counter(self):
70+
def slowly_increase_counter(self, increments=60, delay=1):
7171
"""Increment the counter slowly over a minute"""
72-
for i in range(60):
73-
time.sleep(1)
72+
for i in range(increments):
73+
time.sleep(delay)
7474
self.increment_counter()
7575

7676
counter = PropertyDescriptor(
@@ -83,6 +83,16 @@ def slowly_increase_counter(self):
8383
description="A pointless string for demo purposes.",
8484
)
8585

86+
@thing_action
87+
def action_without_arguments(self) -> None:
88+
"""An action that takes no arguments"""
89+
pass
90+
91+
@thing_action
92+
def action_with_only_kwargs(self, **kwargs) -> None:
93+
"""An action that takes **kwargs"""
94+
pass
95+
8696

8797
class ThingWithBrokenAffordances(Thing):
8898
"""A Thing that raises exceptions in actions/properites"""

tests/test_actions.py

Lines changed: 3 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,97 +2,10 @@
22
import pytest
33
from labthings_fastapi.server import ThingServer
44
from temp_client import poll_task, get_link
5-
import time
6-
from typing import Optional, Annotated
7-
from labthings_fastapi.thing import Thing
85
from labthings_fastapi.decorators import thing_action
9-
from labthings_fastapi.descriptors import PropertyDescriptor
10-
from pydantic import Field
11-
12-
13-
class TestThing(Thing):
14-
@thing_action
15-
def anaction(
16-
self,
17-
repeats: Annotated[
18-
int, Field(description="The number of times to try the action")
19-
], # no default = required parameter
20-
undocumented: int,
21-
title: Annotated[
22-
str, Field(description="the title of the invocation")
23-
] = "Untitled",
24-
attempts: Annotated[
25-
Optional[list[str]],
26-
Field(
27-
description="Names for each attempt - I suggest final, Final, FINAL."
28-
),
29-
] = None,
30-
) -> dict[str, str]:
31-
"""Quite a complicated action
32-
33-
This action has lots of parameters and is designed to confuse my schema
34-
generator. I hope it doesn't!
35-
36-
I might even use some Markdown here:
37-
38-
* If this renders, it supports lists
39-
* With at east two items.
40-
"""
41-
# We should be able to call actions as normal Python functions
42-
self.increment_counter()
43-
return {"end_result": "finished!!"}
44-
45-
@thing_action
46-
def make_a_dict(
47-
self,
48-
extra_key: Optional[str] = None,
49-
extra_value: Optional[str] = None,
50-
) -> dict[str, str]:
51-
"""An action that returns a dict"""
52-
out = {"key": "value"}
53-
if extra_key is not None:
54-
out[extra_key] = extra_value
55-
return out
56-
57-
@thing_action
58-
def increment_counter(self):
59-
"""Increment the counter property
60-
61-
This action doesn't do very much - all it does, in fact,
62-
is increment the counter (which may be read using the
63-
`counter` property).
64-
"""
65-
self.counter += 1
66-
67-
@thing_action
68-
def slowly_increase_counter(self):
69-
"""Increment the counter slowly over a minute"""
70-
for i in range(60):
71-
time.sleep(1)
72-
self.increment_counter()
73-
74-
counter = PropertyDescriptor(
75-
model=int, initial_value=0, readonly=True, description="A pointless counter"
76-
)
77-
78-
foo = PropertyDescriptor(
79-
model=str,
80-
initial_value="Example",
81-
description="A pointless string for demo purposes.",
82-
)
83-
84-
@thing_action
85-
def action_without_arguments(self) -> None:
86-
"""An action that takes no arguments"""
87-
pass
88-
89-
@thing_action
90-
def action_with_only_kwargs(self, **kwargs) -> None:
91-
"""An action that takes **kwargs"""
92-
pass
93-
94-
95-
thing = TestThing()
6+
from labthings_fastapi.example_things import MyThing
7+
8+
thing = MyThing()
969
server = ThingServer()
9710
server.add_thing(thing, "/thing")
9811

tests/test_example_thing.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from labthings_fastapi.example_things import (
2+
MyThing,
3+
ThingWithBrokenAffordances,
4+
ThingThatCantInstantiate,
5+
ThingThatCantStart,
6+
)
7+
import pytest
8+
9+
10+
class DummyBlockingPortal:
11+
"""A dummy blocking portal for testing
12+
13+
This is a blocking portal that doesn't actually do anything.
14+
In the future, we should improve LabThings so this is not required.
15+
"""
16+
def start_task_soon(self, func, *args, **kwargs):
17+
pass
18+
19+
20+
def test_mything():
21+
thing = MyThing()
22+
thing._labthings_blocking_portal = DummyBlockingPortal()
23+
assert isinstance(thing, MyThing)
24+
assert thing.counter == 0
25+
ret = thing.anaction(3, 1, title="MyTitle", attempts=["a", "b", "c"])
26+
assert ret == {"end_result": "finished!!"}
27+
ret = thing.make_a_dict("key2", "value2")
28+
assert ret == {"key": "value", "key2": "value2"}
29+
before = thing.counter
30+
thing.increment_counter()
31+
assert thing.counter == before + 1
32+
thing.slowly_increase_counter(3, 0)
33+
assert thing.counter == before + 4
34+
assert thing.foo == "Example"
35+
thing.foo = "New Value"
36+
assert thing.foo == "New Value"
37+
thing.action_without_arguments()
38+
thing.action_with_only_kwargs(foo="bar")
39+
40+
41+
def test_thing_with_broken_affordances():
42+
thing = ThingWithBrokenAffordances()
43+
assert isinstance(thing, ThingWithBrokenAffordances)
44+
with pytest.raises(RuntimeError):
45+
thing.broken_action()
46+
with pytest.raises(RuntimeError):
47+
thing.broken_property()
48+
49+
50+
def test_thing_that_cant_instantiate():
51+
with pytest.raises(Exception):
52+
ThingThatCantInstantiate()
53+
54+
55+
def test_thing_that_cant_start():
56+
thing = ThingThatCantStart()
57+
assert isinstance(thing, ThingThatCantStart)
58+
with pytest.raises(Exception):
59+
with thing:
60+
pass

tests/test_websocket.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from fastapi.testclient import TestClient
22
from labthings_fastapi.server import ThingServer
3-
from test_thing import MyThing
3+
from labthings_fastapi.example_things import MyThing
44

55
my_thing = MyThing()
66
server = ThingServer()

0 commit comments

Comments
 (0)