Files
ansible/test/lib/ansible_test/_internal/thread.py
Matt Clay a06fa496d3 ansible-test - Code cleanup and refactoring. (#77169)
* Remove unnecessary PyCharm ignores.
* Ignore intentional undefined attribute usage.
* Add missing type hints. Fix existing type hints.
* Fix docstrings and comments.
* Use function to register completion handler.
* Pass strings to display functions.
* Fix CompositeAction handling of dest argument.
* Use consistent types in expressions/assignments.
* Use custom function to keep linters happy.
* Add missing raise for custom exception.
* Clean up key/value type handling in cloud plugins.
* Use dataclass instead of dict for results.
* Add custom type_guard function to check lists.
* Ignore return type that can't be checked (yet).
* Avoid changing types on local variables.
2022-02-28 14:37:09 -08:00

62 lines
1.9 KiB
Python

"""Python threading tools."""
from __future__ import annotations
import functools
import sys
import threading
import queue
import typing as t
TCallable = t.TypeVar('TCallable', bound=t.Callable[..., t.Any])
class WrappedThread(threading.Thread):
"""Wrapper around Thread which captures results and exceptions."""
def __init__(self, action): # type: (t.Callable[[], t.Any]) -> None
super().__init__()
self._result = queue.Queue() # type: queue.Queue[t.Any]
self.action = action
self.result = None
def run(self):
"""
Run action and capture results or exception.
Do not override. Do not call directly. Executed by the start() method.
"""
# We truly want to catch anything that the worker thread might do including call sys.exit.
# Therefore, we catch *everything* (including old-style class exceptions)
# noinspection PyBroadException
try:
self._result.put((self.action(), None))
# pylint: disable=locally-disabled, bare-except
except: # noqa
self._result.put((None, sys.exc_info()))
def wait_for_result(self):
"""
Wait for thread to exit and return the result or raise an exception.
:rtype: any
"""
result, exception = self._result.get()
if exception:
raise exception[1].with_traceback(exception[2])
self.result = result
return result
def mutex(func): # type: (TCallable) -> TCallable
"""Enforce exclusive access on a decorated function."""
lock = threading.Lock()
@functools.wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper around `func` which uses a lock to provide exclusive access to the function."""
with lock:
return func(*args, **kwargs)
return wrapper # type: ignore[return-value] # requires https://www.python.org/dev/peps/pep-0612/ support