Skip to content

Commit 3104d86

Browse files
author
Joel Collins
committed
Added a bunch of type definitions
1 parent 69370c0 commit 3104d86

File tree

21 files changed

+310
-238
lines changed

21 files changed

+310
-238
lines changed

poetry.lock

Lines changed: 33 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pylint = "^2.6.0"
3131
sphinx = "^3.2.1"
3232
sphinx-autoapi = "^1.4.0"
3333
sphinx-rtd-theme = "^0.5.0"
34+
mypy = "^0.790"
3435

3536
[tool.black]
3637
exclude = '(\.eggs|\.git|\.venv)'

src/labthings/actions/pool.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import threading
3-
from functools import wraps
3+
4+
from typing import Dict
45

56
from ..deque import Deque
67
from .thread import ActionThread
@@ -41,7 +42,7 @@ def spawn(self, action: str, function, *args, **kwargs):
4142
self.start(thread)
4243
return thread
4344

44-
def kill(self, timeout=5):
45+
def kill(self, timeout: int = 5):
4546
"""
4647
4748
:param timeout: (Default value = 5)
@@ -73,7 +74,7 @@ def states(self):
7374
"""
7475
return {str(t.id): t.state for t in self.threads}
7576

76-
def to_dict(self):
77+
def to_dict(self) -> Dict[str, ActionThread]:
7778
"""
7879
7980
@@ -84,8 +85,8 @@ def to_dict(self):
8485
"""
8586
return {str(t.id): t for t in self.threads}
8687

87-
def get(self, task_id):
88-
return self.to_dict.get(task_id, None)
88+
def get(self, task_id: str):
89+
return self.to_dict().get(task_id, None)
8990

9091
def discard_id(self, task_id):
9192
"""

src/labthings/actions/thread.py

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from flask import copy_current_request_context, has_request_context, request
99
from werkzeug.exceptions import BadRequest
1010

11+
from typing import Optional, Iterable, Dict, Any, Callable
12+
1113
from ..deque import LockableDeque
1214
from ..utilities import TimeoutTracker
1315

@@ -25,12 +27,12 @@ class ActionThread(threading.Thread):
2527

2628
def __init__(
2729
self,
28-
action,
29-
target=None,
30-
name=None,
31-
args=None,
32-
kwargs=None,
33-
daemon=True,
30+
action: str,
31+
target: Optional[Callable] = None,
32+
name: Optional[str] = None,
33+
args: Optional[Iterable[Any]] = None,
34+
kwargs: Optional[Dict[str, Any]] = None,
35+
daemon: bool = True,
3436
default_stop_timeout: int = 5,
3537
log_len: int = 100,
3638
):
@@ -39,34 +41,32 @@ def __init__(
3941
group=None,
4042
target=target,
4143
name=name,
42-
args=args,
43-
kwargs=kwargs,
44+
args=args or (),
45+
kwargs=kwargs or {},
4446
daemon=daemon,
4547
)
4648

47-
# Safely populate missing arguments
48-
args = args or ()
49-
kwargs = kwargs or {}
50-
5149
# Action resource corresponding to this action object
5250
self.action = action
5351

5452
# A UUID for the ActionThread (not the same as the threading.Thread ident)
5553
self._ID = uuid.uuid4() # Task ID
5654

5755
# Event to track if the task has started
58-
self.started = threading.Event()
56+
self.started: threading.Event = threading.Event()
5957
# Event to track if the user has requested stop
60-
self.stopping = threading.Event()
61-
self.default_stop_timeout = default_stop_timeout
58+
self.stopping: threading.Event = threading.Event()
59+
self.default_stop_timeout: int = default_stop_timeout
6260

6361
# Make _target, _args, and _kwargs available to the subclass
64-
self._target = target
65-
self._args = args
66-
self._kwargs = kwargs
62+
self._target: Optional[Callable] = target
63+
self._args: Iterable[Any] = args or ()
64+
self._kwargs: Dict[str, Any] = kwargs or {}
6765

6866
# Nice string representation of target function
69-
self.target_string = f"{self._target}(args={self._args}, kwargs={self._kwargs})"
67+
self.target_string: str = (
68+
f"{self._target}(args={self._args}, kwargs={self._kwargs})"
69+
)
7070

7171
# copy_current_request_context allows threads to access flask current_app
7272
if has_request_context():
@@ -82,14 +82,14 @@ def __init__(
8282

8383
# Private state properties
8484
self._status: str = "pending" # Task status
85-
self._return_value = None # Return value
86-
self._request_time = datetime.datetime.now()
87-
self._start_time = None # Task start time
88-
self._end_time = None # Task end time
85+
self._return_value: Optional[Any] = None # Return value
86+
self._request_time: datetime.datetime = datetime.datetime.now()
87+
self._start_time: Optional[datetime.datetime] = None # Task start time
88+
self._end_time: Optional[datetime.datetime] = None # Task end time
8989

9090
# Public state properties
91-
self.progress: int = None # Percent progress of the task
92-
self.data = {} # Dictionary of custom data added during the task
91+
self.progress: Optional[int] = None # Percent progress of the task
92+
self.data: dict = {} # Dictionary of custom data added during the task
9393
self._log = LockableDeque(
9494
None, log_len
9595
) # The log will hold dictionary objects with log information
@@ -100,14 +100,14 @@ def __init__(
100100
) # Lock obtained while self._target is running
101101

102102
@property
103-
def id(self):
103+
def id(self) -> uuid.UUID:
104104
"""
105105
UUID for the thread. Note this not the same as the native thread ident.
106106
"""
107107
return self._ID
108108

109109
@property
110-
def output(self):
110+
def output(self) -> Any:
111111
"""
112112
Return value of the Action function. If the Action is still running, returns None.
113113
"""
@@ -119,7 +119,7 @@ def log(self):
119119
return list(logdeque)
120120

121121
@property
122-
def status(self):
122+
def status(self) -> str:
123123
"""
124124
Current running status of the thread.
125125
@@ -136,19 +136,19 @@ def status(self):
136136
return self._status
137137

138138
@property
139-
def dead(self):
139+
def dead(self) -> bool:
140140
"""
141141
Has the thread finished, by any means (return, exception, termination).
142142
"""
143143
return not self.is_alive()
144144

145145
@property
146-
def stopped(self):
146+
def stopped(self) -> bool:
147147
"""Has the thread been cancelled"""
148148
return self.stopping.is_set()
149149

150150
@property
151-
def cancelled(self):
151+
def cancelled(self) -> bool:
152152
"""Alias of `stopped`"""
153153
return self.stopped
154154

@@ -162,7 +162,7 @@ def update_progress(self, progress: int):
162162
# Update progress of the task
163163
self.progress = progress
164164

165-
def update_data(self, data: dict):
165+
def update_data(self, data: Dict[Any, Any]):
166166
"""
167167
168168
:param data: dict:
@@ -183,7 +183,7 @@ def run(self):
183183
# an argument that has a member that points to the thread.
184184
del self._target, self._args, self._kwargs
185185

186-
def _thread_proc(self, f):
186+
def _thread_proc(self, f: Callable):
187187
"""Wraps the target function to handle recording `status` and `return` to `state`.
188188
Happens inside the task thread.
189189
@@ -228,7 +228,7 @@ def wrapped(*args, **kwargs):
228228

229229
return wrapped
230230

231-
def get(self, block=True, timeout=None):
231+
def get(self, block: bool = True, timeout: Optional[int] = None):
232232
"""Start waiting for the task to finish before returning
233233
234234
:param block: (Default value = True)
@@ -275,7 +275,7 @@ def _async_raise(self, exc_type):
275275
% (exc_type, self.name, self.ident, result)
276276
)
277277

278-
def _is_thread_proc_running(self):
278+
def _is_thread_proc_running(self) -> bool:
279279
"""Test if thread funtion (_thread_proc) is running,
280280
by attemtping to acquire the lock _thread_proc acquires at runtime.
281281
@@ -285,13 +285,13 @@ def _is_thread_proc_running(self):
285285
:rtype: bool
286286
287287
"""
288-
could_acquire = self._running_lock.acquire(0)
288+
could_acquire = self._running_lock.acquire(False)
289289
if could_acquire:
290290
self._running_lock.release()
291291
return False
292292
return True
293293

294-
def terminate(self, exception=ActionKilledException):
294+
def terminate(self, exception=ActionKilledException) -> bool:
295295
"""
296296
297297
:param exception: (Default value = ActionKilledException)
@@ -314,7 +314,7 @@ def terminate(self, exception=ActionKilledException):
314314
self.progress = None
315315
return True
316316

317-
def stop(self, timeout=None, exception=ActionKilledException):
317+
def stop(self, timeout=None, exception=ActionKilledException) -> bool:
318318
"""Sets the threads internal stopped event, waits for timeout seconds for the
319319
thread to stop nicely, then forcefully kills the thread.
320320

src/labthings/apispec/plugins.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22

3-
from apispec import BasePlugin
4-
from apispec.ext.marshmallow import MarshmallowPlugin as _MarshmallowPlugin
3+
from apispec import BasePlugin # type: ignore
4+
from apispec.ext.marshmallow import MarshmallowPlugin as _MarshmallowPlugin # type: ignore
55
from apispec.ext.marshmallow import OpenAPIConverter
66
from flask.views import http_method_funcs
77

src/labthings/extensions.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from flask import url_for
99

10+
from typing import List, Dict, Callable
11+
1012
from .utilities import camel_to_snake, get_docstring, snake_to_spine
1113
from .views.builder import static_from
1214

@@ -27,27 +29,27 @@ def __init__(
2729
static_url_path="/static",
2830
static_folder=None,
2931
):
30-
self._views = (
32+
self._views: dict = (
3133
{}
3234
) # Key: Full, Python-safe ID. Val: Original rule, and view class
33-
self._rules = {} # Key: Original rule. Val: View class
34-
self._meta = {} # Extra metadata to add to the extension description
35+
self._rules: dict = {} # Key: Original rule. Val: View class
36+
self._meta: dict = {} # Extra metadata to add to the extension description
3537

36-
self._on_registers = (
37-
[]
38-
) # List of dictionaries of functions to run on registration
38+
self._on_registers: List[
39+
Dict
40+
] = [] # List of dictionaries of functions to run on registration
3941

40-
self._on_components = (
41-
[]
42-
) # List of dictionaries of functions to run as components are added
42+
self._on_components: List[
43+
Dict
44+
] = [] # List of dictionaries of functions to run as components are added
4345

4446
self._cls = str(self) # String description of extension instance
4547

4648
self._name = name
4749
self.description = description or get_docstring(self)
4850
self.version = str(version)
4951

50-
self.methods = {}
52+
self.methods: Dict[str, Callable] = {}
5153

5254
self.static_view_class = static_from(static_folder)
5355
self.add_view(
@@ -169,7 +171,7 @@ def _name_uri_safe(self):
169171
""" """
170172
return snake_to_spine(self._name_python_safe)
171173

172-
def add_method(self, method, method_name):
174+
def add_method(self, method: Callable, method_name: str):
173175
"""
174176
175177
:param method:
@@ -240,15 +242,17 @@ def find_extensions_in_file(extension_path: str, module_name="extensions") -> li
240242
sys.modules[spec.name] = mod
241243

242244
try:
243-
spec.loader.exec_module(mod)
245+
spec.loader.exec_module(mod) # type: ignore
244246
except Exception: # skipcq: PYL-W0703
245247
logging.error(
246248
f"Exception in extension path {extension_path}: \n{traceback.format_exc()}"
247249
)
248250
return []
249251
else:
250252
if hasattr(mod, "__extensions__"):
251-
return [getattr(mod, ext_name) for ext_name in mod.__extensions__]
253+
return [
254+
getattr(mod, ext_name) for ext_name in getattr(mod, "__extensions__")
255+
]
252256
else:
253257
return find_instances_in_module(mod, BaseExtension)
254258

src/labthings/find.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import logging
21
import weakref
32

43
from flask import current_app, url_for

0 commit comments

Comments
 (0)