Skip to content

Commit

Permalink
Version 0.3: remove ontimeout and params arguments (deprecated in 0.2…
Browse files Browse the repository at this point in the history
…), properly pass args to RepeatingTimer, fix error if .stop() called before .start()
  • Loading branch information
Josh Burnett committed Nov 27, 2020
1 parent 8459fef commit 7200abb
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 156 deletions.
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ Start this timer by calling `.start()`. Once started, calling `.stop()` will te
timer's loop and not produce any further calls to _function_. Note that if _function_ is
currently in the middle of running, it will finish the current iteration and not be interrupted.

_ontimeout_ and _params_ are deprecated in 0.2, and replaced by _function_, _args_
and _kwargs_, to match the `threading.Timer` API.
_ontimeout_ and _params_ were deprecated in 0.2 and replaced by _function_, _args_
and _kwargs_ to match the `threading.Timer` API. _ontimeout_ and _params_ have been removed in 0.3.

Since the underlying mechanism is purely based on python threads & events, the overall processor
load & memory usage are minimal. Note that the timing accuracy is typically to within about 10 ms,
depending on the platform.
Expand Down Expand Up @@ -79,6 +79,11 @@ timer.start()
time.sleep(3.5)
output['foo'] = "I'd like to be done now."

# Note: While this feature can be useful, be aware that changing arguments while the timer is running may result in some
# race conditions. multitimer is multithreaded but does not currently have any sort of locking mechanisms in place to
# ensure that operations are atomic.


# And a MultiTimer can be re-started by just calling start() again
time.sleep(2)
output['foo'] = 'Please just let me be...'
Expand All @@ -90,16 +95,23 @@ timer.stop()
Releases
--------

### 0.1, 2018-02-15
### 0.3, 2020-11-27

* Initial release
* Add a .join() method to wait for a timer that has been stopped to complete its final iteration. (Thanks, @pakal!)
* Remove _ontimeout_ and _params_ arguments (deprecated in 0.2)
* Properly pass args to RepeatingTimer
* Fix error if .stop() called before .start()

### 0.2, 2019-01-17

* Replace time.clock() calls with time.perf_counter(), as [time.clock is deprecated since python 3.3](https://docs.python.org/3/library/time.html#time.clock) and doesn't provide consistent behavior across different platforms.
* Replace _ontimeout_ with _function_, and _params_ with _args_ and _kwargs_, to match the `threading.Timer` API.
_ontimeout_ and _params_ are deprecated and will be removed in v0.3.
* Added lots of code comments to better explain how the module works.
* Add lots of code comments to better explain how the module works.

### 0.1, 2018-02-15

* Initial release

Meta
----
Expand Down
76 changes: 0 additions & 76 deletions README.rst

This file was deleted.

2 changes: 1 addition & 1 deletion __version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
# 88 88 88 "8a, ,a88 88 88, 88 88, 88 88 88 88 "8b, ,aa 88
# 88 88 88 `"YbbdP'Y8 88 "Y888 88 "Y888 88 88 88 88 `"Ybbd8"' 88

__version__ = '0.2'
__version__ = '0.3'
84 changes: 19 additions & 65 deletions multitimer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from threading import Thread, Event
from time import perf_counter
import warnings


class RepeatingTimer(Thread):
Expand All @@ -24,26 +23,17 @@ class RepeatingTimer(Thread):
Note that is function() it is currently in the middle of running, it will finish the
current iteration and not be interrupted.
_ontimeout_ and _params_ are deprecated in 0.2, and replaced by _function_, _args_
and _kwargs_, to match the threading.Timer API.
_ontimeout_ and _params_ were deprecated in 0.2 and replaced by _function_, _args_
and _kwargs_ to match the threading.Timer API. _ontimeout_ and _params_ have been removed
in 0.3.
"""

def __init__(self, interval, function=None, args=None, kwargs=None, count=-1, runonstart=True,
ontimeout=None, params=None):
def __init__(self, interval, function=None, args=None, kwargs=None, count=-1, runonstart=True):
Thread.__init__(self)
if count == 0:
raise ValueError('count must be -1 or greater than 1, not zero.')
if function is None and ontimeout is None:
raise ValueError('function or ontimeout must be specified (and ontimeout is deprecated since'
'multitimer v0.2)')
if ontimeout is not None:
warnings.warn("'ontimeout' is deprecated since multitimer v0.2. Use 'function' instead.",
DeprecationWarning)
function = ontimeout
if params is not None:
warnings.warn("'params' is deprecated since multitimer v0.2. Use 'args' and 'kwargs' instead.",
DeprecationWarning)
kwargs = params
if function is None:
raise ValueError('function must be specified')

self.interval = interval
self.function = function
Expand Down Expand Up @@ -111,26 +101,17 @@ class MultiTimer(object):
currently in the middle of running, it will finish the current iteration and not be interrupted.
By calling .join(), one can wait for the timer to finish its task (if any) before proceeding further.
_ontimeout_ and _params_ are deprecated in 0.2, and replaced by _function_, _args_
and _kwargs_, to match the threading.Timer API.
_ontimeout_ and _params_ were deprecated in 0.2 and replaced by _function_, _args_
and _kwargs_ to match the threading.Timer API. _ontimeout_ and _params_ have been removed
in 0.3.
"""

def __init__(self, interval, function=None, args=None, kwargs=None, count=-1, runonstart=True,
ontimeout=None, params=None):
def __init__(self, interval, function=None, args=None, kwargs=None, count=-1, runonstart=True):
# First, check for appropriate parameters, issue relevant deprecation warnings.
if count == 0:
raise ValueError('count must be -1 or greater than 1, not zero.')
if function is None and ontimeout is None:
raise ValueError('function or ontimeout must be specified (and ontimeout is deprecated since'
'multitimer v0.2)')
if ontimeout is not None:
warnings.warn("'ontimeout' is deprecated since multitimer v0.2. Use 'function' instead.",
DeprecationWarning)
function = ontimeout
if params is not None:
warnings.warn("'params' is deprecated since multitimer v0.2. Use 'args' and 'kwargs' instead.",
DeprecationWarning)
kwargs = params
if function is None:
raise ValueError('function must be specified')

# Store parameters internally
self._interval = interval
Expand All @@ -153,12 +134,17 @@ def start(self):
pass

self._timer = RepeatingTimer(interval=self._interval, function=self._function,
kwargs=self._kwargs, count=self._count,
args=self._args, kwargs=self._kwargs, count=self._count,
runonstart=self._runonstart)
self._timer.start()

def stop(self):
self._timer.stop()
try:
self._timer.stop()
except AttributeError:
# If .stop() is called without previously starting the MultiTimer, the RepeatingTimer won't have been
# created yet.
pass

def join(self):
"""Wait for the current task to finish, if any."""
Expand All @@ -178,22 +164,6 @@ def interval(self, value):
except AttributeError:
pass

@property
def ontimeout(self):
warnings.warn("'ontimeout' is deprecated since MultiTimer v0.2. Use 'function' instead.",
DeprecationWarning)
return self._function

@ontimeout.setter
def ontimeout(self, value):
warnings.warn("'ontimeout' is deprecated since MultiTimer v0.2. Use 'function' instead.",
DeprecationWarning)
self._function = value
try:
self._timer.function = value
except AttributeError:
pass

@property
def function(self):
return self._function
Expand All @@ -206,22 +176,6 @@ def function(self, value):
except AttributeError:
pass

@property
def params(self):
warnings.warn("'params' is deprecated since MultiTimer v0.2. Use 'args' and 'kwargs' instead.",
DeprecationWarning)
return self._kwargs

@params.setter
def params(self, value):
warnings.warn("'params' is deprecated since MultiTimer v0.2. Use 'args' and 'kwargs' instead.",
DeprecationWarning)
self._kwargs = value
try:
self._timer.params = value
except AttributeError:
pass

@property
def args(self):
return self._args
Expand Down
10 changes: 2 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,11 @@
# What packages are required for this module to be executed?
REQUIRED = []

# The rest you shouldn't have to touch too much :)
# ------------------------------------------------
# Except, perhaps the License and Trove Classifiers!
# If you do change the License, remember to change the Trove Classifier for that!

here = os.path.abspath(os.path.dirname(__file__))

# Import the README and use it as the long-description.
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
long_description = '\n' + f.read()

# Load the package's __version__.py module as a dictionary.
about = {}
with open(os.path.join(here, '__version__.py')) as f:
exec(f.read(), about)
Expand Down Expand Up @@ -98,6 +90,8 @@ def run(self):
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
],
Expand Down

0 comments on commit 7200abb

Please sign in to comment.