From 307939e80ac9c4da73ed66e08a6eb13c388ccee0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 1 Jan 2015 17:02:35 -0800 Subject: Added a utility for deprecating a module attribute --- src/cryptography/utils.py | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index ac2f787d..250e14b4 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -7,12 +7,17 @@ from __future__ import absolute_import, division, print_function import abc import inspect import sys +import warnings # DeprecatedIn07 objects exist. This comment exists to remind developers to # look for them when it's time for the ninth release cycle deprecation dance. +def read_only_property(name): + return property(lambda self: getattr(self, name)) + + def register_interface(iface): def register_decorator(klass): verify_interface(iface, klass) @@ -21,10 +26,6 @@ def register_interface(iface): return register_decorator -def read_only_property(name): - return property(lambda self: getattr(self, name)) - - class InterfaceNotImplemented(Exception): pass @@ -55,3 +56,36 @@ if sys.version_info >= (2, 7): else: def bit_length(x): return len(bin(x)) - (2 + (x <= 0)) + + +class _DeprecatedValue(object): + def __init__(self, value, message, warning_class): + self.value = value + self.message = message + self.warning_class = warning_class + + +class _ModuleWithDeprecations(object): + def __init__(self, module): + self.__dict__["_module"] = module + + def __getattr__(self, attr): + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + obj = obj.value + return obj + + def __setattr__(self, attr, value): + setattr(self._module, attr, value) + + def __dir__(self): + return ["_module"] + dir(self._module) + + + +def deprecated(value, module_name, message, warning_class): + module = sys.modules[module_name] + if not isinstance(module, _ModuleWithDeprecations): + sys.modules[module_name] = module = _ModuleWithDeprecations(module) + return _DeprecatedValue(value, message, warning_class) -- cgit v1.2.3 From 408fc4ee2833fcd5db315564f7f6961ec426365b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 1 Jan 2015 17:21:59 -0800 Subject: flake8 --- src/cryptography/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 250e14b4..72f9a347 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -83,7 +83,6 @@ class _ModuleWithDeprecations(object): return ["_module"] + dir(self._module) - def deprecated(value, module_name, message, warning_class): module = sys.modules[module_name] if not isinstance(module, _ModuleWithDeprecations): -- cgit v1.2.3 From d27856c33df1cba86a3c1f61123106787bc35c0d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 1 Jan 2015 20:29:13 -0800 Subject: Added some tests --- tests/test_warnings.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/test_warnings.py diff --git a/tests/test_warnings.py b/tests/test_warnings.py new file mode 100644 index 00000000..dd1b6a54 --- /dev/null +++ b/tests/test_warnings.py @@ -0,0 +1,43 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import sys +import types +import warnings + +from cryptography.utils import deprecated + + +class TestDeprecated(object): + def test_deprecated(self, monkeypatch): + mod = types.ModuleType("TestDeprecated/test_deprecated") + monkeypatch.setitem(sys.modules, mod.__name__, mod) + mod.X = deprecated( + value=1, + module_name=mod.__name__, + message="deprecated message text", + warning_class=DeprecationWarning + ) + mod.Y = deprecated( + value=2, + module_name=mod.__name__, + message="more deprecated text", + warning_class=PendingDeprecationWarning, + ) + mod = sys.modules[mod.__name__] + + with warnings.catch_warnings(record=True) as log: + warnings.simplefilter("always", PendingDeprecationWarning) + warnings.simplefilter("always", DeprecationWarning) + assert mod.X == 1 + assert mod.Y == 2 + + [msg1, msg2] = log + assert msg1.category is DeprecationWarning + assert msg1.message.args == ("deprecated message text",) + + assert msg2.category is PendingDeprecationWarning + assert msg2.message.args == ("more deprecated text",) -- cgit v1.2.3 From 75341e185b48100b9acda696d173990e6eb4624c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 2 Jan 2015 09:18:17 -0800 Subject: get coverage up to 100% --- tests/test_warnings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_warnings.py b/tests/test_warnings.py index dd1b6a54..9946baa7 100644 --- a/tests/test_warnings.py +++ b/tests/test_warnings.py @@ -28,12 +28,14 @@ class TestDeprecated(object): warning_class=PendingDeprecationWarning, ) mod = sys.modules[mod.__name__] + mod.Z = 3 with warnings.catch_warnings(record=True) as log: warnings.simplefilter("always", PendingDeprecationWarning) warnings.simplefilter("always", DeprecationWarning) assert mod.X == 1 assert mod.Y == 2 + assert mod.Z == 3 [msg1, msg2] = log assert msg1.category is DeprecationWarning @@ -41,3 +43,5 @@ class TestDeprecated(object): assert msg2.category is PendingDeprecationWarning assert msg2.message.args == ("more deprecated text",) + + assert "Y" in dir(mod) -- cgit v1.2.3