diff --git a/.travis.yml b/.travis.yml index b7ad03c..ab48beb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,4 @@ install: script: - coverage run --source=. test.py - coverage report -m - - pycodestyle --format=pylint --count . + - pycodestyle --format=pylint --max-line-length=120 --count . diff --git a/panoply/constants.py b/panoply/constants.py index a096f5b..2bf2379 100644 --- a/panoply/constants.py +++ b/panoply/constants.py @@ -1,2 +1,2 @@ -__version__ = "2.0.3" +__version__ = "2.0.4" __package_name__ = "panoply-python-sdk" diff --git a/panoply/datasource.py b/panoply/datasource.py index 0911f0b..df7dca0 100644 --- a/panoply/datasource.py +++ b/panoply/datasource.py @@ -1,9 +1,13 @@ import base64 +import traceback +from concurrent.futures import ThreadPoolExecutor +from functools import wraps +from threading import Event import backoff -from . import events import requests -import traceback + +from . import events from .errors import PanoplyException @@ -143,3 +147,40 @@ def wrapper(*args): return f(*args) return wrapper return _validate_token + + +def background_progress(message, waiting_interval=10*60): + """ A decorator is used to emit progress while long operation is executed. + For example, for database's data sources such operations might be + declaration of the cursor or counting number of rows. + This decorator should only be used on methods that are waiting for + input/output operations to be completed. + + Parameters + ---------- + message : str + Message that will be emitted while waiting for operation to complete. + waiting_interval : float + Time in seconds to wait between progress emitting. + Defaults to 10 minutes + """ + def _background_progress(func): + @wraps(func) + def wrapper(*args, **kwargs): + self = args[0] + self.log('Creating background progress emitter') + finished = Event() + with ThreadPoolExecutor(max_workers=1) as executor: + func_future = executor.submit(func, *args, **kwargs) + func_future.add_done_callback(lambda future: finished.set()) + + while not func_future.done(): + self.log(message) + self.progress(None, None, message) + finished.wait(timeout=waiting_interval) + + return func_future.result() + + return wrapper + + return _background_progress