Make scheduler.Timeout exception hashable

The python standard library in Python 3.6.3 and earlier has a bug with
handling unhashable exceptions: https://bugs.python.org/issue28603

Although oslo_log will catch the error, make scheduler.Timeout hashable so
that all exceptions will be printable.

Prior to 640abe0c12 we just used __cmp__(),
but that isn't used in Python 3. Defining __eq__(), which is required for
the total_ordering decorator, makes the class unhashable in Python 3.

Change-Id: Idde65b2d41490ab8318b5a8b95ea74e9b96b4e5c
Related-Bug: #1724366
Related-Bug: #1721654
This commit is contained in:
Zane Bitter 2017-10-18 16:46:39 -04:00
parent fe45b745e5
commit 6a9672a264
2 changed files with 8 additions and 15 deletions

View File

@ -11,7 +11,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
import sys
import types
@ -47,7 +46,6 @@ def task_description(task):
return encodeutils.safe_decode(repr(task))
@functools.total_ordering
class Timeout(BaseException):
"""Raised when task has exceeded its allotted (wallclock) running time.
@ -78,14 +76,11 @@ class Timeout(BaseException):
generator.close()
return False
def __eq__(self, other):
if not isinstance(other, Timeout):
return NotImplemented
return not (self < other or other < self)
def earlier_than(self, other):
if other is None:
return True
def __lt__(self, other):
if not isinstance(other, Timeout):
return NotImplemented
assert isinstance(other, Timeout), "Invalid type for Timeout compare"
return self._duration.endtime() < other._duration.endtime()
@ -245,7 +240,7 @@ class TaskRunner(object):
else:
if timeout is not None:
new_timeout = Timeout(self, timeout)
if self._timeout is None or new_timeout < self._timeout:
if new_timeout.earlier_than(self._timeout):
self._timeout = new_timeout
done = self.step() if resuming else self.done()
@ -281,7 +276,7 @@ class TaskRunner(object):
self._runner.close()
else:
timeout = TimedCancel(self, grace_period)
if self._timeout is None or timeout < self._timeout:
if timeout.earlier_than(self._timeout):
self._timeout = timeout
def started(self):

View File

@ -1283,10 +1283,8 @@ class TimeoutTest(common.HeatTestCase):
eventlet.sleep(0.01)
later = scheduler.Timeout(task, 10)
self.assertLess(earlier, later)
self.assertGreater(later, earlier)
self.assertEqual(earlier, earlier)
self.assertNotEqual(earlier, later)
self.assertTrue(earlier.earlier_than(later))
self.assertFalse(later.earlier_than(earlier))
class DescriptionTest(common.HeatTestCase):