diff --git a/tensorflow/python/tools/api/generator/create_python_api.py b/tensorflow/python/tools/api/generator/create_python_api.py index 1af498a2ec8..c11900d397b 100644 --- a/tensorflow/python/tools/api/generator/create_python_api.py +++ b/tensorflow/python/tools/api/generator/create_python_api.py @@ -85,14 +85,6 @@ def format_import(source_module_name, source_name, dest_name): return 'import %s as %s' % (source_name, dest_name) -def is_supported_type_for_deprecation(symbol): - # Exclude Exception subclasses since users should be able to - # "except" the same type of exception that was "raised" (i.e. we - # shouldn't wrap it with deprecation alias). - return tf_inspect.isfunction(symbol) or ( - tf_inspect.isclass(symbol) and not issubclass(symbol, Exception)) - - class _ModuleInitCodeBuilder(object): """Builds a map from module name to imports included in that module.""" @@ -338,9 +330,10 @@ def add_imports_for_symbol( dest_module = _join_modules(output_module_prefix, dest_module) # Add deprecated alias if only some of the endpoints are deprecated # and symbol is not under compat.v*. + # TODO(annarev): handle deprecated class endpoints as well. if (export not in exports_v2 and canonical_endpoint and not dest_module.startswith(_COMPAT_MODULE_PREFIX) and - is_supported_type_for_deprecation(symbol)): + tf_inspect.isfunction(symbol)): module_code_builder.add_deprecated_endpoint( id(symbol), dest_module, source_module_name, source_name, dest_name, canonical_endpoint) diff --git a/tensorflow/python/util/deprecation.py b/tensorflow/python/util/deprecation.py index 1bb270628a4..5f93bb971ef 100644 --- a/tensorflow/python/util/deprecation.py +++ b/tensorflow/python/util/deprecation.py @@ -38,7 +38,7 @@ _PRINT_DEPRECATION_WARNINGS = True _PRINTED_WARNING = {} -class DeprecatedNamesAlreadySetError(Exception): +class DeprecatedNamesAlreadySet(Exception): """Raised when setting deprecated names multiple times for the same symbol.""" pass @@ -97,11 +97,6 @@ def _validate_deprecation_args(date, instructions): raise ValueError('Don\'t deprecate things without conversion instructions!') -def istuplesubclass(f): - """Returns True if the argument inherits from tuple.""" - return tuple in tf_inspect.getmro(f) - - def _call_location(outer=False): """Returns call location given level up from current call.""" stack = tf_stack.extract_stack_file_and_line(max_length=4) @@ -191,75 +186,39 @@ def deprecated_alias(deprecated_name, name, func_or_class, warn_once=True): use and has a modified docstring. """ if tf_inspect.isclass(func_or_class): - # In most cases, we want to override __init__ to print deprecation warning. - # However, if a class inherits from immutable type, then we need to - # override __new__ instead. Unfortunately, there doesn't seem to be an - # easy way to check if a type is immutable. - if istuplesubclass(func_or_class): - # Make a new class with __new__ wrapped in a warning. - class _NewClass(func_or_class): # pylint: disable=missing-docstring - __doc__ = decorator_utils.add_notice_to_docstring( - func_or_class.__doc__, 'Please use %s instead.' % name, - 'DEPRECATED CLASS', - '(deprecated)', ['THIS CLASS IS DEPRECATED. ' - 'It will be removed in a future version. ']) - __name__ = func_or_class.__name__ - __module__ = _call_location(outer=True) + # Make a new class with __init__ wrapped in a warning. + class _NewClass(func_or_class): # pylint: disable=missing-docstring + __doc__ = decorator_utils.add_notice_to_docstring( + func_or_class.__doc__, 'Please use %s instead.' % name, + 'DEPRECATED CLASS', + '(deprecated)', ['THIS CLASS IS DEPRECATED. ' + 'It will be removed in a future version. ']) + __name__ = func_or_class.__name__ + __module__ = _call_location(outer=True) - @_wrap_decorator(func_or_class.__new__) - def __new__(cls, *args, **kwargs): - _NewClass.__new__.__doc__ = func_or_class.__new__.__doc__ + @_wrap_decorator(func_or_class.__init__) + def __init__(self, *args, **kwargs): + if hasattr(_NewClass.__init__, '__func__'): + # Python 2 + _NewClass.__init__.__func__.__doc__ = func_or_class.__init__.__doc__ + else: + # Python 3 + _NewClass.__init__.__doc__ = func_or_class.__init__.__doc__ - if _PRINT_DEPRECATION_WARNINGS: - # We're making the alias as we speak. The original may have other - # aliases, so we cannot use it to check for whether it's already - # been warned about. - if _NewClass.__new__ not in _PRINTED_WARNING: - if warn_once: - _PRINTED_WARNING[_NewClass.__new__] = True - logging.warning( - 'From %s: The name %s is deprecated. ' - 'Please use %s instead.\n', - _call_location(), deprecated_name, name) - return super(_NewClass, cls).__new__(cls, *args, **kwargs) + if _PRINT_DEPRECATION_WARNINGS: + # We're making the alias as we speak. The original may have other + # aliases, so we cannot use it to check for whether it's already been + # warned about. + if _NewClass.__init__ not in _PRINTED_WARNING: + if warn_once: + _PRINTED_WARNING[_NewClass.__init__] = True + logging.warning( + 'From %s: The name %s is deprecated. Please use %s instead.\n', + _call_location(), deprecated_name, name) + super(_NewClass, self).__init__(*args, **kwargs) - return _NewClass - else: - - # Make a new class with __init__ wrapped in a warning. - class _NewClass(func_or_class): # pylint: disable=missing-docstring - __doc__ = decorator_utils.add_notice_to_docstring( - func_or_class.__doc__, 'Please use %s instead.' % name, - 'DEPRECATED CLASS', - '(deprecated)', ['THIS CLASS IS DEPRECATED. ' - 'It will be removed in a future version. ']) - __name__ = func_or_class.__name__ - __module__ = _call_location(outer=True) - - @_wrap_decorator(func_or_class.__init__) - def __init__(self, *args, **kwargs): - if hasattr(_NewClass.__init__, '__func__'): - # Python 2 - _NewClass.__init__.__func__.__doc__ = func_or_class.__init__.__doc__ - else: - # Python 3 - _NewClass.__init__.__doc__ = func_or_class.__init__.__doc__ - - if _PRINT_DEPRECATION_WARNINGS: - # We're making the alias as we speak. The original may have other - # aliases, so we cannot use it to check for whether it's already - # been warned about. - if _NewClass.__init__ not in _PRINTED_WARNING: - if warn_once: - _PRINTED_WARNING[_NewClass.__init__] = True - logging.warning( - 'From %s: The name %s is deprecated. ' - 'Please use %s instead.\n', - _call_location(), deprecated_name, name) - super(_NewClass, self).__init__(*args, **kwargs) # pylint: disable=bad-super-call - - return _NewClass + return _NewClass else: decorator_utils.validate_callable(func_or_class, 'deprecated') @@ -302,7 +261,7 @@ def deprecated_endpoints(*args): def deprecated_wrapper(func): # pylint: disable=protected-access if '_tf_deprecated_api_names' in func.__dict__: - raise DeprecatedNamesAlreadySetError( + raise DeprecatedNamesAlreadySet( 'Cannot set deprecated names for %s to %s. ' 'Deprecated names are already set to %s.' % ( func.__name__, str(args), str(func._tf_deprecated_api_names))) diff --git a/tensorflow/python/util/deprecation_test.py b/tensorflow/python/util/deprecation_test.py index 2cdebc82661..035c416d793 100644 --- a/tensorflow/python/util/deprecation_test.py +++ b/tensorflow/python/util/deprecation_test.py @@ -976,7 +976,7 @@ class DeprecatedEndpointsTest(test.TestCase): self.assertEqual(("foo1", "foo2"), foo._tf_deprecated_api_names) def testCannotSetDeprecatedEndpointsTwice(self): - with self.assertRaises(deprecation.DeprecatedNamesAlreadySetError): + with self.assertRaises(deprecation.DeprecatedNamesAlreadySet): @deprecation.deprecated_endpoints("foo1") @deprecation.deprecated_endpoints("foo2") def foo(): # pylint: disable=unused-variable