Hello community,

here is the log from the commit of package python-futurist for openSUSE:Factory 
checked in at 2016-01-11 19:12:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-futurist (Old)
 and      /work/SRC/openSUSE:Factory/.python-futurist.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-futurist"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-futurist/python-futurist.changes  
2015-09-11 09:04:38.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-futurist.new/python-futurist.changes     
2016-01-11 19:12:18.000000000 +0100
@@ -1,0 +2,18 @@
+Mon Jan 11 09:03:28 UTC 2016 - [email protected]
+
+- Update to version 0.9.0
+  * Allow for providing different run work sync functions
+  * Have the executor stats object repr look like the watcher repr
+  * Add useful watcher '__repr__' function
+  * Some minor refactoring and comment/note addition
+  * No need for Oslo Incubator Sync
+  * Move most of green helper classes -> '_green.py'
+  * Add 'enabled' parameter to @periodic decorator
+  * Remove green worker reference to its executor
+  * Change ignore-errors to ignore_errors
+  * Activate pep8 check that _ is imported
+  * Handle the case where 0.199 is provided as runtime
+  * Just use a deque vs reverse pushing/popping
+  * Ensure new entry in immediates gets processed during wait(s)
+
+-------------------------------------------------------------------

Old:
----
  futurist-0.5.0.tar.gz

New:
----
  futurist-0.9.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-futurist.spec ++++++
--- /var/tmp/diff_new_pack.mk2Be8/_old  2016-01-11 19:12:19.000000000 +0100
+++ /var/tmp/diff_new_pack.mk2Be8/_new  2016-01-11 19:12:19.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-futurist
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           python-futurist
-Version:        0.5.0
+Version:        0.9.0
 Release:        0
 Summary:        Useful additions to futures, from the future
 License:        Apache-2.0

++++++ futurist-0.5.0.tar.gz -> futurist-0.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/.coveragerc 
new/futurist-0.9.0/.coveragerc
--- old/futurist-0.5.0/.coveragerc      2015-09-08 17:31:37.000000000 +0200
+++ new/futurist-0.9.0/.coveragerc      2015-12-21 20:52:23.000000000 +0100
@@ -1,7 +1,8 @@
 [run]
 branch = True
 source = futurist
-omit = futurist/openstack/*
+omit = futurist/tests/*,futurist/openstack/*
 
 [report]
-ignore-errors = True
+ignore_errors = True
+precision = 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/AUTHORS new/futurist-0.9.0/AUTHORS
--- old/futurist-0.5.0/AUTHORS  2015-09-08 17:31:59.000000000 +0200
+++ new/futurist-0.9.0/AUTHORS  2015-12-21 20:52:56.000000000 +0100
@@ -1,2 +1,7 @@
+Davanum Srinivas <[email protected]>
+Dmitry Tantsur <[email protected]>
 Joshua Harlow <[email protected]>
 Joshua Harlow <[email protected]>
+Monty Taylor <[email protected]>
+Ronald Bradford <[email protected]>
+THOMAS J. COCOZZELLO <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/ChangeLog new/futurist-0.9.0/ChangeLog
--- old/futurist-0.5.0/ChangeLog        2015-09-08 17:31:59.000000000 +0200
+++ new/futurist-0.9.0/ChangeLog        2015-12-21 20:52:56.000000000 +0100
@@ -1,6 +1,41 @@
 CHANGES
 =======
 
+0.9.0
+-----
+
+* Updated from global requirements
+* Allow for providing different run work sync functions
+
+0.8.0
+-----
+
+* Have the executor stats object repr look like the watcher repr
+
+0.7.0
+-----
+
+* Add useful watcher '__repr__' function
+* Some minor refactoring and comment/note addition
+* Remove tests output from code coverage
+* No need for Oslo Incubator Sync
+* Move most of green helper classes -> '_green.py'
+
+0.6.0
+-----
+
+* Add 'enabled' parameter to @periodic decorator
+* docs - Set pbr warnerrors option for doc build
+* Remove dummy/placeholder 'ChangeLog' as its not needed
+* Enhance the README
+* Remove green worker reference to its executor
+* Change ignore-errors to ignore_errors
+* Updated from global requirements
+* Activate pep8 check that _ is imported
+* Handle the case where 0.199 is provided as runtime
+* Just use a deque vs reverse pushing/popping
+* Ensure new entry in immediates gets processed during wait(s)
+
 0.5.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/PKG-INFO new/futurist-0.9.0/PKG-INFO
--- old/futurist-0.5.0/PKG-INFO 2015-09-08 17:31:59.000000000 +0200
+++ new/futurist-0.9.0/PKG-INFO 2015-12-21 20:52:56.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: futurist
-Version: 0.5.0
+Version: 0.9.0
 Summary: Useful additions to futures, from the future.
 Home-page: http://www.openstack.org/
 Author: OpenStack
@@ -18,7 +18,11 @@
             :target: https://pypi.python.org/pypi/futurist/
             :alt: Downloads
         
-        Code from the future, delivered to you in the **now**.
+        Code from the future, delivered to you in the **now**. The goal of 
this library
+        would be to provide a well documented futures 
classes/utilities/additions that
+        allows for providing a level of transparency in how asynchronous work 
gets
+        executed. This library currently adds statistics gathering, an eventlet
+        executor, a synchronous executor etc.
         
         * Free software: Apache license
         * Documentation: http://docs.openstack.org/developer/futurist
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/README.rst 
new/futurist-0.9.0/README.rst
--- old/futurist-0.5.0/README.rst       2015-09-08 17:31:37.000000000 +0200
+++ new/futurist-0.9.0/README.rst       2015-12-21 20:52:23.000000000 +0100
@@ -10,7 +10,11 @@
     :target: https://pypi.python.org/pypi/futurist/
     :alt: Downloads
 
-Code from the future, delivered to you in the **now**.
+Code from the future, delivered to you in the **now**. The goal of this library
+would be to provide a well documented futures classes/utilities/additions that
+allows for providing a level of transparency in how asynchronous work gets
+executed. This library currently adds statistics gathering, an eventlet
+executor, a synchronous executor etc.
 
 * Free software: Apache license
 * Documentation: http://docs.openstack.org/developer/futurist
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/_futures.py 
new/futurist-0.9.0/futurist/_futures.py
--- old/futurist-0.5.0/futurist/_futures.py     2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/futurist/_futures.py     2015-12-21 20:52:23.000000000 
+0100
@@ -15,7 +15,6 @@
 #    under the License.
 
 import functools
-import sys
 import threading
 
 from concurrent import futures as _futures
@@ -23,16 +22,7 @@
 from concurrent.futures import thread as _thread
 import six
 
-try:
-    from eventlet import greenpool
-    from eventlet import patcher as greenpatcher
-    from eventlet import queue as greenqueue
-
-    from eventlet.green import threading as greenthreading
-except ImportError:
-    greenpatcher, greenpool, greenqueue, greenthreading = (None, None,
-                                                           None, None)
-
+from futurist import _green
 from futurist import _utils
 
 
@@ -227,56 +217,6 @@
         return self._gatherer.submit(fn, *args, **kwargs)
 
 
-class _WorkItem(object):
-    def __init__(self, future, fn, args, kwargs):
-        self.future = future
-        self.fn = fn
-        self.args = args
-        self.kwargs = kwargs
-
-    def run(self):
-        if not self.future.set_running_or_notify_cancel():
-            return
-        try:
-            result = self.fn(*self.args, **self.kwargs)
-        except BaseException:
-            exc_type, exc_value, exc_tb = sys.exc_info()
-            try:
-                if six.PY2:
-                    self.future.set_exception_info(exc_value, exc_tb)
-                else:
-                    self.future.set_exception(exc_value)
-            finally:
-                del(exc_type, exc_value, exc_tb)
-        else:
-            self.future.set_result(result)
-
-
-if _utils.EVENTLET_AVAILABLE:
-
-    class _GreenThreading(object):
-
-        @staticmethod
-        def event_object(*args, **kwargs):
-            return greenthreading.Event(*args, **kwargs)
-
-        @staticmethod
-        def lock_object(*args, **kwargs):
-            return greenthreading.Lock(*args, **kwargs)
-
-        @staticmethod
-        def rlock_object(*args, **kwargs):
-            return greenthreading.RLock(*args, **kwargs)
-
-        @staticmethod
-        def condition_object(*args, **kwargs):
-            return greenthreading.Condition(*args, **kwargs)
-
-    _green_threading = _GreenThreading()
-else:
-    _green_threading = None
-
-
 class SynchronousExecutor(_futures.Executor):
     """Executor that uses the caller to execute calls synchronously.
 
@@ -290,23 +230,30 @@
 
     threading = _Threading()
 
-    def __init__(self, green=False):
+    def __init__(self, green=False, run_work_func=lambda work: work.run()):
         """Synchronous executor constructor.
 
         :param green: when enabled this forces the usage of greened lock
                       classes and green futures (so that the internals of this
                       object operate correctly under eventlet)
         :type green: bool
+        :param run_work_func: callable that takes a single work item and
+                              runs it (typically in a blocking manner)
+        :param run_work_func: callable
         """
         if green and not _utils.EVENTLET_AVAILABLE:
             raise RuntimeError('Eventlet is needed to use a green'
                                ' synchronous executor')
+        if not six.callable(run_work_func):
+            raise ValueError("Run work parameter expected to be callable")
+        self._run_work_func = run_work_func
         self._shutoff = False
         if green:
-            self.threading = _green_threading
+            self.threading = _green.threading
             self._future_cls = GreenFuture
         else:
             self._future_cls = Future
+        self._run_work_func = run_work_func
         self._gatherer = _Gatherer(self._submit,
                                    self.threading.lock_object,
                                    start_before_submit=True)
@@ -342,37 +289,10 @@
 
     def _submit(self, fn, *args, **kwargs):
         fut = self._future_cls()
-        runner = _WorkItem(fut, fn, args, kwargs)
-        runner.run()
+        self._run_work_func(_utils.WorkItem(fut, fn, args, kwargs))
         return fut
 
 
-class _GreenWorker(object):
-    def __init__(self, executor, work, work_queue):
-        self.executor = executor
-        self.work = work
-        self.work_queue = work_queue
-
-    def __call__(self):
-        # Run our main piece of work.
-        try:
-            self.work.run()
-        finally:
-            # Consume any delayed work before finishing (this is how we finish
-            # work that was to big for the pool size, but needs to be finished
-            # no matter).
-            while True:
-                try:
-                    w = self.work_queue.get_nowait()
-                except greenqueue.Empty:
-                    break
-                else:
-                    try:
-                        w.run()
-                    finally:
-                        self.work_queue.task_done()
-
-
 class GreenFuture(Future):
     __doc__ = Future.__doc__
 
@@ -385,8 +305,8 @@
         # functions will correctly yield to eventlet. If this is not done then
         # waiting on the future never actually causes the greenthreads to run
         # and thus you wait for infinity.
-        if not greenpatcher.is_monkey_patched('threading'):
-            self._condition = greenthreading.Condition()
+        if not _green.is_monkey_patched('threading'):
+            self._condition = _green.threading.condition_object()
 
 
 class GreenThreadPoolExecutor(_futures.Executor):
@@ -399,7 +319,7 @@
     It gathers statistics about the submissions executed for post-analysis...
     """
 
-    threading = _green_threading
+    threading = _green.threading
 
     def __init__(self, max_workers=1000, check_and_reject=None):
         """Initializes a green thread pool executor.
@@ -424,10 +344,10 @@
         if max_workers <= 0:
             raise ValueError("Max workers must be greater than zero")
         self._max_workers = max_workers
-        self._pool = greenpool.GreenPool(self._max_workers)
-        self._delayed_work = greenqueue.Queue()
+        self._pool = _green.Pool(self._max_workers)
+        self._delayed_work = _green.Queue()
         self._check_and_reject = check_and_reject or (lambda e, waiting: None)
-        self._shutdown_lock = greenthreading.Lock()
+        self._shutdown_lock = self.threading.lock_object()
         self._shutdown = False
         self._gatherer = _Gatherer(self._submit,
                                    self.threading.lock_object)
@@ -459,7 +379,7 @@
 
     def _submit(self, fn, *args, **kwargs):
         f = GreenFuture()
-        work = _WorkItem(f, fn, args, kwargs)
+        work = _utils.WorkItem(f, fn, args, kwargs)
         if not self._spin_up(work):
             self._delayed_work.put(work)
         return f
@@ -473,7 +393,7 @@
         """
         alive = self._pool.running() + self._pool.waiting()
         if alive < self._max_workers:
-            self._pool.spawn_n(_GreenWorker(self, work, self._delayed_work))
+            self._pool.spawn_n(_green.GreenWorker(work, self._delayed_work))
             return True
         return False
 
@@ -494,8 +414,10 @@
 
     __slots__ = ['_failures', '_executed', '_runtime', '_cancelled']
 
-    __repr_format = ("failures=%(failures)s, executed=%(executed)s, "
-                     "runtime=%(runtime)s, cancelled=%(cancelled)s")
+    _REPR_MSG_TPL = ("<ExecutorStatistics object at 0x%(ident)x"
+                     " (failures=%(failures)s,"
+                     " executed=%(executed)s, runtime=%(runtime)0.2f,"
+                     " cancelled=%(cancelled)s)>")
 
     def __init__(self, failures=0, executed=0, runtime=0.0, cancelled=0):
         self._failures = failures
@@ -550,13 +472,10 @@
         return self._runtime / self._executed
 
     def __repr__(self):
-        r = self.__class__.__name__
-        r += "("
-        r += self.__repr_format % ({
+        return self._REPR_MSG_TPL % ({
+            'ident': id(self),
             'failures': self._failures,
             'executed': self._executed,
             'runtime': self._runtime,
             'cancelled': self._cancelled,
         })
-        r += ")"
-        return r
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/_green.py 
new/futurist-0.9.0/futurist/_green.py
--- old/futurist-0.5.0/futurist/_green.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/futurist-0.9.0/futurist/_green.py       2015-12-21 20:52:23.000000000 
+0100
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+#    Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from futurist import _utils
+
+try:
+    from eventlet import greenpool
+    from eventlet import patcher as greenpatcher
+    from eventlet import queue as greenqueue
+
+    from eventlet.green import threading as greenthreading
+except ImportError:
+    greenpatcher, greenpool, greenqueue, greenthreading = (None, None,
+                                                           None, None)
+
+
+if _utils.EVENTLET_AVAILABLE:
+    # Aliases that we use and only expose vs the whole of eventlet...
+    Pool = greenpool.GreenPool
+    Queue = greenqueue.Queue
+    is_monkey_patched = greenpatcher.is_monkey_patched
+
+    class GreenThreading(object):
+
+        @staticmethod
+        def event_object(*args, **kwargs):
+            return greenthreading.Event(*args, **kwargs)
+
+        @staticmethod
+        def lock_object(*args, **kwargs):
+            return greenthreading.Lock(*args, **kwargs)
+
+        @staticmethod
+        def rlock_object(*args, **kwargs):
+            return greenthreading.RLock(*args, **kwargs)
+
+        @staticmethod
+        def condition_object(*args, **kwargs):
+            return greenthreading.Condition(*args, **kwargs)
+
+    threading = GreenThreading()
+else:
+    threading = None
+    Pool = None
+    Queue = None
+    is_monkey_patched = lambda mod: False
+
+
+class GreenWorker(object):
+    def __init__(self, work, work_queue):
+        self.work = work
+        self.work_queue = work_queue
+
+    def __call__(self):
+        # Run our main piece of work.
+        try:
+            self.work.run()
+        finally:
+            # Consume any delayed work before finishing (this is how we finish
+            # work that was to big for the pool size, but needs to be finished
+            # no matter).
+            while True:
+                try:
+                    w = self.work_queue.get_nowait()
+                except greenqueue.Empty:
+                    break
+                else:
+                    try:
+                        w.run()
+                    finally:
+                        self.work_queue.task_done()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/_utils.py 
new/futurist-0.9.0/futurist/_utils.py
--- old/futurist-0.5.0/futurist/_utils.py       2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/futurist/_utils.py       2015-12-21 20:52:23.000000000 
+0100
@@ -20,6 +20,7 @@
 import traceback
 
 from monotonic import monotonic as now  # noqa
+import six
 
 try:
     import eventlet as _eventlet  # noqa
@@ -28,6 +29,31 @@
     EVENTLET_AVAILABLE = False
 
 
+class WorkItem(object):
+    def __init__(self, future, fn, args, kwargs):
+        self.future = future
+        self.fn = fn
+        self.args = args
+        self.kwargs = kwargs
+
+    def run(self):
+        if not self.future.set_running_or_notify_cancel():
+            return
+        try:
+            result = self.fn(*self.args, **self.kwargs)
+        except BaseException:
+            exc_type, exc_value, exc_tb = sys.exc_info()
+            try:
+                if six.PY2:
+                    self.future.set_exception_info(exc_value, exc_tb)
+                else:
+                    self.future.set_exception(exc_value)
+            finally:
+                del(exc_type, exc_value, exc_tb)
+        else:
+            self.future.set_result(result)
+
+
 class Failure(object):
     """Object that captures a exception (and its associated information)."""
 
@@ -81,14 +107,6 @@
         return ".".join(segments)
 
 
-def reverse_enumerate(items):
-    """Yields (index, item) from given list/tuple in reverse order."""
-    idx = len(items)
-    while idx > 0:
-        yield (idx - 1, items[idx - 1])
-        idx -= 1
-
-
 def get_optimal_thread_count(default=2):
     """Try to guess optimal thread count for current system."""
     try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/periodics.py 
new/futurist-0.9.0/futurist/periodics.py
--- old/futurist-0.5.0/futurist/periodics.py    2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/futurist/periodics.py    2015-12-21 20:52:23.000000000 
+0100
@@ -14,6 +14,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import collections
 import fractions
 import functools
 import heapq
@@ -45,9 +46,21 @@
 class Watcher(object):
     """A **read-only** object representing a periodics callbacks activities."""
 
+    _REPR_MSG_TPL = ("<Watcher object at 0x%(ident)x "
+                     "("
+                     "runs=%(runs)s,"
+                     " successes=%(successes)s,"
+                     " failures=%(failures)s,"
+                     " elapsed=%(elapsed)0.2f,"
+                     " elapsed_waiting=%(elapsed_waiting)0.2f"
+                     ")>")
+
     def __init__(self, metrics):
         self._metrics = metrics
 
+    def __repr__(self):
+        return self._REPR_MSG_TPL % dict(ident=id(self), **self._metrics)
+
     @property
     def runs(self):
         """How many times the periodic callback has been ran."""
@@ -102,7 +115,7 @@
     return missing_attrs
 
 
-def periodic(spacing, run_immediately=False):
+def periodic(spacing, run_immediately=False, enabled=True):
     """Tags a method/function as wanting/able to execute periodically.
 
     :param spacing: how often to run the decorated function (required)
@@ -111,6 +124,8 @@
                             immediately or wait until the spacing provided has
                             elapsed before running for the first time
     :type run_immediately: boolean
+    :param enabled: whether the task is enabled to run
+    :type enabled: boolean
     """
 
     if spacing <= 0:
@@ -118,7 +133,7 @@
                          " zero instead of %s" % spacing)
 
     def wrapper(f):
-        f._is_periodic = True
+        f._is_periodic = enabled
         f._periodic_spacing = spacing
         f._periodic_run_immediately = run_immediately
 
@@ -257,12 +272,8 @@
 def _build(now_func, callables, next_run_scheduler):
     schedule = _Schedule()
     now = None
-    immediates = []
-    # Reverse order is used since these are later popped off (and to
-    # ensure the popping order is first -> last we need to append them
-    # in the opposite ordering last -> first).
-    reverse_it = utils.reverse_enumerate(callables)
-    for index, (cb, _cb_name, args, kwargs) in reverse_it:
+    immediates = collections.deque()
+    for index, (cb, _cb_name, args, kwargs) in enumerate(callables):
         if cb._periodic_run_immediately:
             immediates.append(index)
         else:
@@ -531,6 +542,61 @@
     def _run(self, executor, runner):
         """Main worker run loop."""
 
+        def _process_scheduled():
+            # Figure out when we should run next (by selecting the
+            # minimum item from the heap, where the minimum should be
+            # the callable that needs to run next and has the lowest
+            # next desired run time).
+            with self._waiter:
+                while (not self._schedule and
+                       not self._tombstone.is_set() and
+                       not self._immediates):
+                    self._waiter.wait(self.MAX_LOOP_IDLE)
+                if self._tombstone.is_set():
+                    # We were requested to stop, so stop.
+                    return
+                if self._immediates:
+                    # This will get processed in _process_immediates()
+                    # in the next loop call.
+                    return
+                submitted_at = now = self._now_func()
+                next_run, index = self._schedule.pop()
+                when_next = next_run - now
+                if when_next <= 0:
+                    # Run & schedule its next execution.
+                    cb, cb_name, args, kwargs = self._callables[index]
+                    self._log.debug("Submitting periodic function '%s'",
+                                    cb_name)
+                    fut = executor.submit(runner,
+                                          self._now_func,
+                                          cb, *args, **kwargs)
+                    fut.add_done_callback(functools.partial(_on_done,
+                                                            PERIODIC,
+                                                            cb, cb_name,
+                                                            index,
+                                                            submitted_at))
+                else:
+                    # Gotta wait...
+                    self._schedule.push(next_run, index)
+                    when_next = min(when_next, self.MAX_LOOP_IDLE)
+                    self._waiter.wait(when_next)
+
+        def _process_immediates():
+            try:
+                index = self._immediates.popleft()
+            except IndexError:
+                pass
+            else:
+                cb, cb_name, args, kwargs = self._callables[index]
+                submitted_at = self._now_func()
+                self._log.debug("Submitting immediate function '%s'", cb_name)
+                fut = executor.submit(runner, self._now_func,
+                                      cb, *args, **kwargs)
+                fut.add_done_callback(functools.partial(_on_done,
+                                                        IMMEDIATE,
+                                                        cb, cb_name,
+                                                        index, submitted_at))
+
         def _on_done(kind, cb, cb_name, index, submitted_at, fut):
             started_at, finished_at, failure = fut.result()
             cb_metrics, _watcher = self._watchers[index]
@@ -553,57 +619,8 @@
                 self._waiter.notify_all()
 
         while not self._tombstone.is_set():
-            if self._immediates:
-                # Run & schedule its next execution.
-                try:
-                    index = self._immediates.pop()
-                except IndexError:
-                    pass
-                else:
-                    cb, cb_name, args, kwargs = self._callables[index]
-                    submitted_at = self._now_func()
-                    self._log.debug("Submitting immediate function '%s'",
-                                    cb_name)
-                    fut = executor.submit(runner,
-                                          self._now_func,
-                                          cb, *args, **kwargs)
-                    fut.add_done_callback(functools.partial(_on_done,
-                                                            IMMEDIATE,
-                                                            cb, cb_name,
-                                                            index,
-                                                            submitted_at))
-            else:
-                # Figure out when we should run next (by selecting the
-                # minimum item from the heap, where the minimum should be
-                # the callable that needs to run next and has the lowest
-                # next desired run time).
-                with self._waiter:
-                    while (not self._schedule and
-                           not self._tombstone.is_set()):
-                        self._waiter.wait(self.MAX_LOOP_IDLE)
-                    if self._tombstone.is_set():
-                        break
-                    submitted_at = now = self._now_func()
-                    next_run, index = self._schedule.pop()
-                    when_next = next_run - now
-                    if when_next <= 0:
-                        # Run & schedule its next execution.
-                        cb, cb_name, args, kwargs = self._callables[index]
-                        self._log.debug("Submitting periodic function '%s'",
-                                        cb_name)
-                        fut = executor.submit(runner,
-                                              self._now_func,
-                                              cb, *args, **kwargs)
-                        fut.add_done_callback(functools.partial(_on_done,
-                                                                PERIODIC,
-                                                                cb, cb_name,
-                                                                index,
-                                                                submitted_at))
-                    else:
-                        # Gotta wait...
-                        self._schedule.push(next_run, index)
-                        when_next = min(when_next, self.MAX_LOOP_IDLE)
-                        self._waiter.wait(when_next)
+            _process_immediates()
+            _process_scheduled()
 
     def _on_finish(self):
         # TODO(harlowja): this may be to verbose for people?
@@ -718,6 +735,9 @@
         self._dead.clear()
         for cb_metrics, _watcher in self._watchers:
             for k in list(six.iterkeys(cb_metrics)):
+                # NOTE(harlowja): mutate the original dictionaries keys
+                # so that the watcher (which references the same dictionary
+                # keys) is able to see those changes.
                 cb_metrics[k] = 0
         self._immediates, self._schedule = _build(
             self._now_func, self._callables, self._initial_schedule_strategy)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/tests/base.py 
new/futurist-0.9.0/futurist/tests/base.py
--- old/futurist-0.5.0/futurist/tests/base.py   2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/futurist/tests/base.py   2015-12-21 20:52:23.000000000 
+0100
@@ -19,5 +19,4 @@
 
 
 class TestCase(base.BaseTestCase):
-
     """Test case base class for all unit tests."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/tests/test_executors.py 
new/futurist-0.9.0/futurist/tests/test_executors.py
--- old/futurist-0.5.0/futurist/tests/test_executors.py 2015-09-08 
17:31:37.000000000 +0200
+++ new/futurist-0.9.0/futurist/tests/test_executors.py 2015-12-21 
20:52:23.000000000 +0100
@@ -79,7 +79,13 @@
 
         self.assertEqual(3, self.executor.statistics.executed)
         self.assertEqual(1, self.executor.statistics.failures)
-        self.assertGreaterEqual(self.executor.statistics.runtime, 0.2)
+        self.assertGreaterEqual(self.executor.statistics.runtime,
+                                # It appears that the the thread run loop
+                                # may call this before 0.2 seconds (or 0.2
+                                # will not be represented as a float correctly)
+                                # is really up so accommodate for that
+                                # happening...
+                                0.199)
 
     def test_post_shutdown_raises(self):
         executor = self.executor_cls(**self.executor_kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist/tests/test_periodics.py 
new/futurist-0.9.0/futurist/tests/test_periodics.py
--- old/futurist-0.5.0/futurist/tests/test_periodics.py 2015-09-08 
17:31:37.000000000 +0200
+++ new/futurist-0.9.0/futurist/tests/test_periodics.py 2015-12-21 
20:52:23.000000000 +0100
@@ -133,6 +133,22 @@
         nows = list(reversed(nows))
         self._test_strategy('last_finished', nows, last_now, 5.0)
 
+    def test_waiting_immediate_add_processed(self):
+        ran_at = []
+
+        @periodics.periodic(0.1, run_immediately=True)
+        def activated_periodic():
+            ran_at.append(time.time())
+
+        w = periodics.PeriodicWorker([], **self.worker_kwargs)
+        with self.create_destroy(w.start, allow_empty=True):
+            # Give some time for the thread to start...
+            self.sleep(0.5)
+            w.add(activated_periodic)
+            while len(ran_at) == 0:
+                self.sleep(0.1)
+            w.stop()
+
     def test_double_start_fail(self):
         w = periodics.PeriodicWorker([], **self.worker_kwargs)
         with self.create_destroy(w.start, allow_empty=True):
@@ -200,14 +216,12 @@
                 self.sleep(0.1)
             w.stop()
 
-    def test_not_added(self):
+    def test_disabled(self):
 
-        @periodics.periodic(0.5)
+        @periodics.periodic(0.5, enabled=False)
         def no_add_me():
             pass
 
-        no_add_me._is_periodic = False
-
         @periodics.periodic(0.5)
         def add_me():
             pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist.egg-info/PKG-INFO 
new/futurist-0.9.0/futurist.egg-info/PKG-INFO
--- old/futurist-0.5.0/futurist.egg-info/PKG-INFO       2015-09-08 
17:31:59.000000000 +0200
+++ new/futurist-0.9.0/futurist.egg-info/PKG-INFO       2015-12-21 
20:52:56.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: futurist
-Version: 0.5.0
+Version: 0.9.0
 Summary: Useful additions to futures, from the future.
 Home-page: http://www.openstack.org/
 Author: OpenStack
@@ -18,7 +18,11 @@
             :target: https://pypi.python.org/pypi/futurist/
             :alt: Downloads
         
-        Code from the future, delivered to you in the **now**.
+        Code from the future, delivered to you in the **now**. The goal of 
this library
+        would be to provide a well documented futures 
classes/utilities/additions that
+        allows for providing a level of transparency in how asynchronous work 
gets
+        executed. This library currently adds statistics gathering, an eventlet
+        executor, a synchronous executor etc.
         
         * Free software: Apache license
         * Documentation: http://docs.openstack.org/developer/futurist
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist.egg-info/SOURCES.txt 
new/futurist-0.9.0/futurist.egg-info/SOURCES.txt
--- old/futurist-0.5.0/futurist.egg-info/SOURCES.txt    2015-09-08 
17:31:59.000000000 +0200
+++ new/futurist-0.9.0/futurist.egg-info/SOURCES.txt    2015-12-21 
20:52:56.000000000 +0100
@@ -9,7 +9,6 @@
 MANIFEST.in
 README.rst
 babel.cfg
-openstack-common.conf
 requirements.txt
 setup.cfg
 setup.py
@@ -25,6 +24,7 @@
 doc/source/installation.rst
 futurist/__init__.py
 futurist/_futures.py
+futurist/_green.py
 futurist/_utils.py
 futurist/periodics.py
 futurist/rejection.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist.egg-info/pbr.json 
new/futurist-0.9.0/futurist.egg-info/pbr.json
--- old/futurist-0.5.0/futurist.egg-info/pbr.json       2015-09-08 
17:31:59.000000000 +0200
+++ new/futurist-0.9.0/futurist.egg-info/pbr.json       2015-12-21 
20:52:56.000000000 +0100
@@ -1 +1 @@
-{"is_release": true, "git_version": "27772ae"}
\ No newline at end of file
+{"is_release": true, "git_version": "d9231f5"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/futurist.egg-info/requires.txt 
new/futurist-0.9.0/futurist.egg-info/requires.txt
--- old/futurist-0.5.0/futurist.egg-info/requires.txt   2015-09-08 
17:31:59.000000000 +0200
+++ new/futurist-0.9.0/futurist.egg-info/requires.txt   2015-12-21 
20:52:56.000000000 +0100
@@ -1,4 +1,4 @@
-pbr<2.0,>=1.6
+pbr>=1.6
 six>=1.9.0
 monotonic>=0.3
 contextlib2>=0.4.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/openstack-common.conf 
new/futurist-0.9.0/openstack-common.conf
--- old/futurist-0.5.0/openstack-common.conf    2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/openstack-common.conf    1970-01-01 01:00:00.000000000 
+0100
@@ -1,6 +0,0 @@
-[DEFAULT]
-
-# The list of modules to copy from oslo-incubator.git
-
-# The base module to hold the copy of openstack.common
-base=futurist
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/requirements.txt 
new/futurist-0.9.0/requirements.txt
--- old/futurist-0.5.0/requirements.txt 2015-09-08 17:31:37.000000000 +0200
+++ new/futurist-0.9.0/requirements.txt 2015-12-21 20:52:23.000000000 +0100
@@ -2,7 +2,7 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-pbr<2.0,>=1.6
+pbr>=1.6
 six>=1.9.0
 monotonic>=0.3 # Apache-2.0
 futures>=3.0;python_version=='2.7' or python_version=='2.6'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/setup.cfg new/futurist-0.9.0/setup.cfg
--- old/futurist-0.5.0/setup.cfg        2015-09-08 17:31:59.000000000 +0200
+++ new/futurist-0.9.0/setup.cfg        2015-12-21 20:52:56.000000000 +0100
@@ -34,6 +34,9 @@
 directory = futurist/locale
 domain = futurist
 
+[pbr]
+warnerrors = True
+
 [wheel]
 universal = 1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/setup.py new/futurist-0.9.0/setup.py
--- old/futurist-0.5.0/setup.py 2015-09-08 17:31:37.000000000 +0200
+++ new/futurist-0.9.0/setup.py 2015-12-21 20:52:23.000000000 +0100
@@ -25,5 +25,5 @@
     pass
 
 setuptools.setup(
-    setup_requires=['pbr>=1.3'],
+    setup_requires=['pbr>=1.8'],
     pbr=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/test-requirements.txt 
new/futurist-0.9.0/test-requirements.txt
--- old/futurist-0.5.0/test-requirements.txt    2015-09-08 17:31:37.000000000 
+0200
+++ new/futurist-0.9.0/test-requirements.txt    2015-12-21 20:52:23.000000000 
+0100
@@ -12,7 +12,7 @@
 discover
 python-subunit>=0.0.18
 sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
-oslosphinx>=2.5.0 # Apache-2.0
+oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
 testrepository>=0.0.18
 testscenarios>=0.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/futurist-0.5.0/tox.ini new/futurist-0.9.0/tox.ini
--- old/futurist-0.5.0/tox.ini  2015-09-08 17:31:37.000000000 +0200
+++ new/futurist-0.9.0/tox.ini  2015-12-21 20:52:23.000000000 +0100
@@ -25,7 +25,7 @@
 commands =
     python setup.py testr --slowest --testr-args='{posargs}'
     sphinx-build -b doctest doc/source doc/build
-    doc8 doc/source
+    doc8 --ignore-path "doc/source/history.rst" doc/source
 
 [testenv:docs]
 commands = python setup.py build_sphinx
@@ -38,5 +38,4 @@
 
 show-source = True
 ignore = E123,E125
-builtins = _
 exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build


Reply via email to