Skip to content

Commit d67b5b0

Browse files
author
Joel Collins
committed
Removed default task pool
1 parent 53ea2bf commit d67b5b0

File tree

10 files changed

+84
-120
lines changed

10 files changed

+84
-120
lines changed

src/labthings/find.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
from flask import current_app, url_for
33
import weakref
44

5+
from werkzeug.local import LocalProxy
6+
57
from .names import EXTENSION_NAME
68

79
__all__ = [
810
"current_app",
911
"url_for",
1012
"current_labthing",
13+
"current_thing",
1114
"registered_extensions",
1215
"registered_components",
1316
"find_component",
@@ -23,11 +26,10 @@ def current_labthing(app=None):
2326
# We use _get_current_object so that Task threads can still
2427
# reach the Flask app object. Just using current_app returns
2528
# a wrapper, which breaks it's use in Task threads
26-
if not app:
27-
try:
28-
app = current_app._get_current_object() # skipcq: PYL-W0212
29-
except RuntimeError:
30-
return None
29+
try:
30+
app = current_app._get_current_object() # skipcq: PYL-W0212
31+
except RuntimeError:
32+
return None
3133
ext = app.extensions.get(EXTENSION_NAME, None)
3234
if isinstance(ext, weakref.ref):
3335
return ext()
@@ -107,3 +109,6 @@ def find_extension(extension_name, labthing_instance=None):
107109
return labthing_instance.extensions[extension_name]
108110
else:
109111
return None
112+
113+
114+
current_thing = LocalProxy(current_labthing)

src/labthings/labthing.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
from .httperrorhandler import SerializedExceptionHandler
1717
from .logging import LabThingLogger
1818
from .json.encoder import LabThingsJSONEncoder
19+
from .representations import DEFAULT_REPRESENTATIONS
1920
from .apispec import MarshmallowPlugin, rule_to_apispec_path
2021
from .td import ThingDescription
2122
from .sockets import Sockets
2223
from .event import Event
2324

24-
from .tasks import Pool, change_default_pool
25+
from .tasks import Pool
2526

2627
from .view.builder import property_of, action_from
2728

@@ -61,7 +62,6 @@ def __init__(
6162
self.extensions = {}
6263

6364
self.actions = Pool() # Pool of greenlets for Actions
64-
change_default_pool(self.actions)
6565

6666
self.events = {}
6767

@@ -94,6 +94,9 @@ def __init__(
9494
self.log_handler = LabThingLogger()
9595
logging.getLogger().addHandler(self.log_handler)
9696

97+
# Representation formatter map
98+
self.representations = DEFAULT_REPRESENTATIONS
99+
97100
# API Spec
98101
self.spec = APISpec(
99102
title=self.title,

src/labthings/representations.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from flask import make_response, current_app
2+
from collections import OrderedDict
23

34
from .json.encoder import LabThingsJSONEncoder, encode_json
45
from .utilities import PY3
@@ -24,6 +25,4 @@ def output_json(data, code, headers=None):
2425
return resp
2526

2627

27-
DEFAULT_REPRESENTATIONS = [
28-
("application/json", output_json),
29-
]
28+
DEFAULT_REPRESENTATIONS = OrderedDict({"application/json": output_json,})

src/labthings/tasks/__init__.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,19 @@
11
__all__ = [
22
"Pool",
3-
"taskify",
4-
"tasks",
5-
"to_dict",
6-
"states",
73
"current_task",
84
"update_task_progress",
9-
"cleanup",
10-
"discard_id",
115
"update_task_data",
12-
"default_pool",
13-
"change_default_pool",
6+
"TaskKillException",
147
"ThreadTerminationError",
158
]
169

1710
from .pool import (
1811
Pool,
19-
tasks,
20-
to_dict,
21-
states,
2212
current_task,
2313
update_task_progress,
24-
cleanup,
25-
discard_id,
2614
update_task_data,
27-
taskify,
28-
default_pool,
29-
change_default_pool,
3015
)
31-
from .thread import ThreadTerminationError
16+
from .thread import TaskKillException
17+
18+
# Legacy alias
19+
ThreadTerminationError = TaskKillException

src/labthings/tasks/pool.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -112,43 +112,3 @@ def update_task_data(data: dict):
112112
current_task().update_data(data)
113113
else:
114114
logging.info("Cannot update task data of __main__ thread. Skipping.")
115-
116-
117-
# Main "taskify" functions
118-
119-
120-
def taskify(f):
121-
"""
122-
A decorator that wraps the passed in function
123-
and surpresses exceptions should one occur
124-
"""
125-
global default_pool
126-
127-
@wraps(f)
128-
def wrapped(*args, **kwargs):
129-
task = default_pool.spawn(
130-
f, *args, **kwargs
131-
) # Append to parent object's task list
132-
return task
133-
134-
return wrapped
135-
136-
137-
# Create our default, protected, module-level task pool
138-
default_pool = Pool()
139-
140-
tasks = default_pool.tasks
141-
to_dict = default_pool.to_dict
142-
states = default_pool.states
143-
cleanup = default_pool.cleanup
144-
discard_id = default_pool.discard_id
145-
146-
147-
def change_default_pool(new_default_pool: Pool):
148-
global default_pool, tasks, to_dict, states, cleanup, discard_id
149-
default_pool = new_default_pool
150-
tasks = new_default_pool.tasks
151-
to_dict = new_default_pool.to_dict
152-
states = new_default_pool.states
153-
cleanup = new_default_pool.cleanup
154-
discard_id = new_default_pool.discard_id

src/labthings/tasks/thread.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
_LOG = logging.getLogger(__name__)
1111

1212

13-
class ThreadTerminationError(SystemExit):
14-
"""Sibling of SystemExit, but specific to thread termination."""
15-
16-
1713
class TaskKillException(Exception):
1814
"""Sibling of SystemExit, but specific to thread termination."""
1915

src/labthings/view/__init__.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@
33
from werkzeug.wrappers import Response as ResponseBase
44
from werkzeug.exceptions import BadRequest
55

6-
from collections import OrderedDict
7-
86
from .args import use_args
97
from .marshalling import marshal_with
108

119
from ..utilities import unpack, get_docstring, get_summary, merge
1210
from ..representations import DEFAULT_REPRESENTATIONS
13-
from ..find import current_labthing
11+
from ..find import current_labthing, current_thing
1412
from ..event import PropertyStatusEvent
1513
from ..schema import Schema, ActionSchema, build_action_schema
16-
from ..tasks import default_pool
14+
from ..tasks import Pool
1715
from ..deque import Deque, resize_deque
1816
from ..json.schemas import schema_to_json
1917
from .. import fields
@@ -46,8 +44,9 @@ def __init__(self, *args, **kwargs):
4644
MethodView.__init__(self, *args, **kwargs)
4745

4846
# Set the default representations
49-
# TODO: Inherit from parent LabThing. See original flask_restful implementation
50-
self.representations = OrderedDict(DEFAULT_REPRESENTATIONS)
47+
self.representations = (
48+
current_thing.representations if current_thing else DEFAULT_REPRESENTATIONS
49+
)
5150

5251
@classmethod
5352
def get_apispec(cls):
@@ -152,6 +151,7 @@ class ActionView(View):
152151
# Internal
153152
_cls_tags = {"actions"}
154153
_deque = Deque() # Action queue
154+
_emergency_pool = Pool()
155155

156156
def get(self):
157157
queue_schema = build_action_schema(self.schema, self.args)(many=True)
@@ -247,8 +247,9 @@ def dispatch_request(self, *args, **kwargs):
247247
if self.schema:
248248
meth = marshal_with(self.schema)(meth)
249249

250+
# Try to find a pool on the current LabThing, but fall back to Views emergency pool
251+
pool = current_thing.actions if current_thing else self._emergency_pool
250252
# Make a task out of the views `post` method
251-
pool = current_labthing().actions if current_labthing else default_pool
252253
task = pool.spawn(meth, *args, **kwargs)
253254

254255
# Keep a copy of the raw, unmarshalled JSON input in the task
@@ -380,8 +381,8 @@ def dispatch_request(self, *args, **kwargs):
380381
self, "__name__", "unknown"
381382
)
382383

383-
if current_labthing():
384-
current_labthing().message(
384+
if current_thing:
385+
current_thing.message(
385386
PropertyStatusEvent(property_name), property_value,
386387
)
387388

tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from apispec.ext.marshmallow import MarshmallowPlugin
99
from labthings.server.labthing import LabThing
1010
from labthings.server.view import View
11+
from labthings.tasks import Pool
1112

1213
from werkzeug.test import EnvironBuilder
1314
from flask.testing import FlaskClient
@@ -309,3 +310,12 @@ def _foo(*args, **kwargs):
309310
return FakeWebsocket(*args, **kwargs)
310311

311312
return _foo
313+
314+
315+
@pytest.fixture
316+
def task_pool():
317+
"""
318+
Return a task pool
319+
"""
320+
321+
return Pool()

tests/test_default_views.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from labthings import tasks
1+
from labthings.find import current_labthing
22

33
import gevent
44

@@ -18,56 +18,55 @@ def test_extensions(thing_client):
1818
assert c.get("/extensions").json == []
1919

2020

21-
def test_tasks_list(thing_client):
21+
def test_actions_list(thing_client):
2222
def task_func():
2323
pass
2424

25-
task_obj = tasks.taskify(task_func)()
25+
task_obj = current_labthing().actions.spawn(task_func)
2626

2727
with thing_client as c:
28-
response = c.get("/tasks").json
28+
response = c.get("/actions").json
2929
ids = [task.get("id") for task in response]
3030
assert str(task_obj.id) in ids
3131

3232

33-
def test_task_representation(thing_client):
33+
def test_action_representation(thing_client):
3434
def task_func():
3535
pass
3636

37-
task_obj = tasks.taskify(task_func)()
37+
task_obj = current_labthing().actions.spawn(task_func)
3838
task_id = str(task_obj.id)
3939

4040
with thing_client as c:
41-
response = c.get(f"/tasks/{task_id}").json
41+
response = c.get(f"/actions/{task_id}").json
4242
assert response
4343

4444

45-
def test_task_representation_missing(thing_client):
45+
def test_action_representation_missing(thing_client):
4646
with thing_client as c:
47-
assert c.get("/tasks/missing_id").status_code == 404
47+
assert c.get("/actions/missing_id").status_code == 404
4848

4949

50-
def test_task_kill(thing_client):
50+
def test_action_kill(thing_client):
5151
def task_func():
5252
while True:
5353
gevent.sleep(0)
5454

55-
task_obj = tasks.taskify(task_func)()
55+
task_obj = current_labthing().actions.spawn(task_func)
5656
task_id = str(task_obj.id)
5757

5858
# Wait for task to start
5959
task_obj.started_event.wait()
60-
assert task_id in tasks.to_dict()
60+
assert task_id in current_labthing().actions.to_dict()
6161

6262
# Send a DELETE request to terminate the task
6363
with thing_client as c:
64-
response = c.delete(f"/tasks/{task_id}")
65-
print(response.json)
64+
response = c.delete(f"/actions/{task_id}")
6665
assert response.status_code == 200
6766
# Test task was terminated
6867
assert task_obj._status == "terminated"
6968

7069

71-
def test_task_kill_missing(thing_client):
70+
def test_action_kill_missing(thing_client):
7271
with thing_client as c:
73-
assert c.delete("/tasks/missing_id").status_code == 404
72+
assert c.delete("/actions/missing_id").status_code == 404

0 commit comments

Comments
 (0)