[Python-checkins] cpython (merge 3.3 -> default): Merge #17435: Don't use mutable default values in Timer.
r.david.murray
python-checkins at python.org
Sat Mar 30 22:23:23 CET 2013
http://hg.python.org/cpython/rev/8c15e57830dd
changeset: 83030:8c15e57830dd
parent: 83026:411e5726f84d
parent: 83029:2698920eadcd
user: R David Murray <rdmurray at bitdance.com>
date: Sat Mar 30 17:22:30 2013 -0400
summary:
Merge #17435: Don't use mutable default values in Timer.
Patch by Denver Coneybeare with some test modifications by me.
files:
Doc/library/threading.rst | 4 ++-
Lib/test/test_threading.py | 39 ++++++++++++++++++--------
Lib/threading.py | 8 ++--
Misc/NEWS | 3 ++
4 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -839,10 +839,12 @@
t.start() # after 30 seconds, "hello, world" will be printed
-.. class:: Timer(interval, function, args=[], kwargs={})
+.. class:: Timer(interval, function, args=None, kwargs=None)
Create a timer that will run *function* with arguments *args* and keyword
arguments *kwargs*, after *interval* seconds have passed.
+ If *args* is None (the default) then an empty list will be used.
+ If *kwargs* is None (the default) then an empty dict will be used.
.. versionchanged:: 3.3
changed from a factory function to a class.
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -787,6 +787,32 @@
self.assertEqual(p.returncode, 0, "Unexpected error: " + stderr.decode())
self.assertEqual(data, expected_output)
+class TimerTests(BaseTestCase):
+
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.callback_args = []
+ self.callback_event = threading.Event()
+
+ def test_init_immutable_default_args(self):
+ # Issue 17435: constructor defaults were mutable objects, they could be
+ # mutated via the object attributes and affect other Timer objects.
+ timer1 = threading.Timer(0.01, self._callback_spy)
+ timer1.start()
+ self.callback_event.wait()
+ timer1.args.append("blah")
+ timer1.kwargs["foo"] = "bar"
+ self.callback_event.clear()
+ timer2 = threading.Timer(0.01, self._callback_spy)
+ timer2.start()
+ self.callback_event.wait()
+ self.assertEqual(len(self.callback_args), 2)
+ self.assertEqual(self.callback_args, [((), {}), ((), {})])
+
+ def _callback_spy(self, *args, **kwargs):
+ self.callback_args.append((args[:], kwargs.copy()))
+ self.callback_event.set()
+
class LockTests(lock_tests.LockTests):
locktype = staticmethod(threading.Lock)
@@ -816,16 +842,5 @@
class BarrierTests(lock_tests.BarrierTests):
barriertype = staticmethod(threading.Barrier)
-
-def test_main():
- test.support.run_unittest(LockTests, PyRLockTests, CRLockTests, EventTests,
- ConditionAsRLockTests, ConditionTests,
- SemaphoreTests, BoundedSemaphoreTests,
- ThreadTests,
- ThreadJoinOnShutdown,
- ThreadingExceptionTests,
- BarrierTests,
- )
-
if __name__ == "__main__":
- test_main()
+ unittest.main()
diff --git a/Lib/threading.py b/Lib/threading.py
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -807,17 +807,17 @@
class Timer(Thread):
"""Call a function after a specified number of seconds:
- t = Timer(30.0, f, args=[], kwargs={})
+ t = Timer(30.0, f, args=None, kwargs=None)
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
- def __init__(self, interval, function, args=[], kwargs={}):
+ def __init__(self, interval, function, args=None, kwargs=None):
Thread.__init__(self)
self.interval = interval
self.function = function
- self.args = args
- self.kwargs = kwargs
+ self.args = args if args is not None else []
+ self.kwargs = kwargs if kwargs is not None else {}
self.finished = Event()
def cancel(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -297,6 +297,9 @@
Library
-------
+- Issue #17435: threading.Timer's __init__ method no longer uses mutable
+ default values for the args and kwargs parameters.
+
- Issue #17526: fix an IndexError raised while passing code without filename to
inspect.findsource(). Initial patch by Tyler Doyle.
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list