Skip to content

Commit

Permalink
Merge 32c9c71 into d378fc5
Browse files Browse the repository at this point in the history
  • Loading branch information
mdickinson committed Dec 18, 2014
2 parents d378fc5 + 32c9c71 commit c1068cb
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 23 deletions.
35 changes: 35 additions & 0 deletions traits/testing/tests/test_unittest_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@
#------------------------------------------------------------------------------
import threading
import time
import warnings

from traits import _py2to3

from traits.testing.unittest_tools import unittest
from traits.api import (Bool, Event, Float, HasTraits, Int, List,
on_trait_change)
from traits.testing.api import UnittestTools
from traits.util.api import deprecated


@deprecated("This function is outdated. Use 'shiny' instead!")
def old_and_dull():
""" A deprecated function, for use in assertDeprecated tests.
"""
pass


class TestObject(HasTraits):
Expand Down Expand Up @@ -360,6 +370,31 @@ def condition(a_object):
timeout=10.0,
)

def test_assert_deprecated(self):
with self.assertDeprecated():
old_and_dull()

def test_assert_deprecated_failures(self):
with self.assertRaises(self.failureException):
with self.assertDeprecated():
pass

def test_assert_deprecated_when_warning_already_issued(self):
# Exercise a problematic case where previous calls to a function or
# method that issues a DeprecationWarning have already polluted the
# __warningregistry__. For this, we need a single call-point to
# old_and_dull, since distinct call-points have separate entries in
# __warningregistry__.
def old_and_dull_caller():
old_and_dull()

# Pollute the registry by pre-calling the function.
old_and_dull_caller()

# Check that we can still detect the DeprecationWarning.
with self.assertDeprecated():
old_and_dull_caller()


if __name__ == '__main__':
unittest.main()
26 changes: 25 additions & 1 deletion traits/testing/unittest_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@

import contextlib
import threading
import sys
import warnings

from traits.api import (Any, Event, HasStrictTraits, Instance, Int, List,
Property, Str)
from traits.util.async_trait_wait import wait_for_condition

# Compatibility layer for Python 2.6: try loading unittest2
import sys
from traits import _py2to3
if sys.version_info[:2] == (2, 6):
import unittest2 as unittest
Expand Down Expand Up @@ -439,3 +440,26 @@ def assertEventuallyTrue(self, obj, trait, condition, timeout=5.0):
self.fail(
"Timed out waiting for condition. "
"At timeout, condition was {0}.".format(condition_at_timeout))

@contextlib.contextmanager
def assertDeprecated(self):
"""
Assert that the code inside the with block is deprecated. Intended
for testing uses of traits.util.deprecated.deprecated.
"""
# Ugly hack copied from the core Python code (see
# Lib/test/test_support.py) to reset the warnings registry
# for the module making use of this context manager.
#
# Note that this hack is unnecessary in Python 3.4 and later; see
# http://bugs.python.org/issue4180 for the background.
registry = sys._getframe(2).f_globals.get('__warningregistry__')
if registry:
registry.clear()

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always', DeprecationWarning)
yield w
self.assertGreater(len(w), 0, msg="Expected a DeprecationWarning, "
"but none was issued")
37 changes: 15 additions & 22 deletions traits/util/deprecated.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
""" A decorator for marking methods/functions as deprecated. """
#------------------------------------------------------------------------------
# Copyright (c) 2005-2014, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in /LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
# Thanks for using Enthought open source!
#------------------------------------------------------------------------------

""" A decorator for marking methods/functions as deprecated. """

# Standard library imports.
import logging

# We only warn about each function or method once!
_cache = {}
import functools
import warnings


def deprecated(message):
Expand All @@ -16,28 +24,13 @@ def deprecated(message):
def decorator(fn):
""" A decorator for marking methods/functions as deprecated. """

@functools.wraps(fn)
def wrapper(*args, **kw):
""" The method/function wrapper. """

global _cache

module_name = fn.__module__
function_name = fn.__name__

if (module_name, function_name) not in _cache:
logging.getLogger(module_name).warning(
'DEPRECATED: %s.%s, %s' % (
module_name, function_name, message
)
)

_cache[(module_name, function_name)] = True

warnings.warn(message, DeprecationWarning, stacklevel=2)
return fn(*args, **kw)

wrapper.__doc__ = fn.__doc__
wrapper.__name__ = fn.__name__

return wrapper

return decorator
Expand Down
60 changes: 60 additions & 0 deletions traits/util/tests/test_deprecated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#------------------------------------------------------------------------------
# Copyright (c) 2005-2014, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in /LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
# Thanks for using Enthought open source!
#------------------------------------------------------------------------------

import unittest

from traits.testing.api import UnittestTools
from traits.util.api import deprecated


@deprecated("Addition is deprecated; use subtraction instead.")
def my_deprecated_addition(x, y):
return x + y


@deprecated("Broken code. Use something else.")
def my_bad_function():
1 / 0


class ClassWithDeprecatedBits(object):
@deprecated('bits are deprecated; use bytes')
def bits(self):
return 42

@deprecated('bytes are deprecated too. Use base 10.')
def bytes(self, required_arg, *args, **kwargs):
return required_arg, args, kwargs


class TestDeprecated(unittest.TestCase, UnittestTools):
def test_deprecated_function(self):
with self.assertDeprecated():
result = my_deprecated_addition(42, 1729)
self.assertEqual(result, 1771)

def test_deprecated_exception_raising_function(self):
with self.assertRaises(ZeroDivisionError):
with self.assertDeprecated():
my_bad_function()

def test_deprecated_method(self):
obj = ClassWithDeprecatedBits()
with self.assertDeprecated():
result = obj.bits()
self.assertEqual(result, 42)

def test_deprecated_method_with_fancy_signature(self):
obj = ClassWithDeprecatedBits()
with self.assertDeprecated():
result = obj.bytes(3, 27, 65, name='Boris', age=-3.2)
self.assertEqual(
result, (3, (27, 65), {'name': 'Boris', 'age': -3.2}))

0 comments on commit c1068cb

Please sign in to comment.