Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/util/deprecation.py: 19%
237 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-05 06:32 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-05 06:32 +0000
1# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Tensor utility functions."""
16import collections
17import functools
18import inspect
19import re
21from tensorflow.python.platform import tf_logging as logging
22from tensorflow.python.util import decorator_utils
23from tensorflow.python.util import is_in_graph_mode
24from tensorflow.python.util import tf_contextlib
25from tensorflow.python.util import tf_decorator
26from tensorflow.python.util import tf_inspect
27from tensorflow.tools.docs import doc_controls
29# Allow deprecation warnings to be silenced temporarily with a context manager.
30_PRINT_DEPRECATION_WARNINGS = True
32# Remember which deprecation warnings have been printed already.
33_PRINTED_WARNING = {}
36class DeprecatedNamesAlreadySet(Exception):
37 """Raised when setting deprecated names multiple times for the same symbol."""
38 pass
41def _add_deprecated_function_notice_to_docstring(doc, date, instructions):
42 """Adds a deprecation notice to a docstring for deprecated functions."""
43 main_text = [
44 'THIS FUNCTION IS DEPRECATED. It will be removed %s.' %
45 ('in a future version' if date is None else ('after %s' % date))
46 ]
47 if instructions:
48 main_text.append('Instructions for updating:')
49 return decorator_utils.add_notice_to_docstring(
50 doc,
51 instructions,
52 'DEPRECATED FUNCTION',
53 '(deprecated)',
54 main_text,
55 notice_type='Deprecated')
58def _add_deprecated_arg_notice_to_docstring(doc, date, instructions,
59 deprecated_names):
60 """Adds a deprecation notice to a docstring for deprecated arguments."""
62 deprecation_string = ', '.join(sorted(deprecated_names))
64 return decorator_utils.add_notice_to_docstring(
65 doc,
66 instructions,
67 'DEPRECATED FUNCTION ARGUMENTS',
68 '(deprecated arguments)', [
69 'SOME ARGUMENTS ARE DEPRECATED: `(%s)`. '
70 'They will be removed %s.' %
71 (deprecation_string, 'in a future version' if date is None else
72 ('after %s' % date)), 'Instructions for updating:'
73 ],
74 notice_type='Deprecated')
77def _add_deprecated_arg_value_notice_to_docstring(doc, date, instructions,
78 deprecated_name_value_dict):
79 """Adds a deprecation notice to a docstring for deprecated arguments."""
81 deprecation_string = ', '.join(
82 '%s=%r' % (key, value)
83 for key, value in sorted(deprecated_name_value_dict.items()))
85 when = 'in a future version' if date is None else ('after %s' % date)
87 return decorator_utils.add_notice_to_docstring(
88 doc,
89 instructions,
90 'DEPRECATED FUNCTION ARGUMENT VALUES',
91 '(deprecated argument values)', [
92 'SOME ARGUMENT VALUES ARE DEPRECATED: `(%s)`. '
93 'They will be removed %s.' %
94 (deprecation_string, when), 'Instructions for updating:'
95 ],
96 notice_type='Deprecated')
99def _validate_deprecation_args(date, instructions):
100 if date is not None and not re.match(r'20\d\d-[01]\d-[0123]\d', date):
101 raise ValueError(f'Date must be in format YYYY-MM-DD. Received: {date}')
102 if not instructions:
103 raise ValueError(
104 'Don\'t deprecate things without conversion instructions! Specify '
105 'the `instructions` argument.')
108def _call_location(outer=False):
109 """Returns call location given level up from current call."""
110 # Two up: <_call_location>, <_call_location's caller>
111 # tf_inspect is not required here. Please ignore the lint warning by adding
112 # DISABLE_IMPORT_INSPECT_CHECK=TRUE to your cl description. Using it caused
113 # test timeouts (b/189384061).
114 f = inspect.currentframe().f_back.f_back
115 parent = f and f.f_back
116 if outer and parent is not None:
117 f = parent
118 return '{}:{}'.format(f.f_code.co_filename, f.f_lineno)
121def _safe_eq(a, b):
122 if a is None or b is None:
123 return a is None and b is None
124 return a == b
127def _wrap_decorator(wrapped_function, decorator_name):
128 """Indicate that one function wraps another.
130 This decorator wraps a function using `tf_decorator.make_decorator`
131 so that doc generation scripts can pick up original function
132 signature.
133 It would be better to use @functools.wrap decorator, but it would
134 not update function signature to match wrapped function in Python 2.
136 Args:
137 wrapped_function: The function that decorated function wraps.
138 decorator_name: The name of the decorator.
140 Returns:
141 Function that accepts wrapper function as an argument and returns
142 `TFDecorator` instance.
143 """
145 def wrapper(wrapper_func):
146 return tf_decorator.make_decorator(wrapped_function, wrapper_func,
147 decorator_name)
149 return wrapper
152def deprecated_alias(deprecated_name, name, func_or_class, warn_once=True):
153 """Deprecate a symbol in favor of a new name with identical semantics.
155 This function is meant to be used when defining a backwards-compatibility
156 alias for a symbol which has been moved. For example:
158 module1.py:
159 ```python
160 class NewNameForClass: pass
161 ```
163 module2.py:
164 ```python
165 import module1
167 DeprecatedNameForClass = deprecated_alias(
168 deprecated_name='module2.DeprecatedNameForClass',
169 name='module1.NewNameForClass',
170 func_or_class=module1.NewNameForClass)
171 ```
173 This function works for classes and functions.
175 For classes, it creates a new class which is functionally identical (it
176 inherits from the original, and overrides its constructor), but which prints
177 a deprecation warning when an instance is created. It also adds a deprecation
178 notice to the class' docstring.
180 For functions, it returns a function wrapped by `tf_decorator.make_decorator`.
181 That function prints a warning when used, and has a deprecation notice in its
182 docstring. This is more or less equivalent (the deprecation warning has
183 slightly different text) to writing:
185 ```python
186 @deprecated
187 def deprecated_alias(original_args):
188 real_function(original_args)
189 ```
191 Args:
192 deprecated_name: The name of the symbol that is being deprecated, to be used
193 in the warning message. This should be its fully qualified name to avoid
194 confusion.
195 name: The name of the symbol that is to be used instead of the deprecated
196 name. This should be a fully qualified name to avoid confusion.
197 func_or_class: The (non-deprecated) class or function for which a deprecated
198 alias should be created.
199 warn_once: If True (the default), only print a deprecation warning the first
200 time this function is used, or the class is instantiated.
202 Returns:
203 A wrapped version of `func_or_class` which prints a deprecation warning on
204 use and has a modified docstring.
205 """
206 if tf_inspect.isclass(func_or_class):
208 # Make a new class with __init__ wrapped in a warning.
209 class _NewClass(func_or_class): # pylint: disable=missing-docstring
210 __doc__ = decorator_utils.add_notice_to_docstring(
211 func_or_class.__doc__,
212 'Please use %s instead.' % name,
213 'DEPRECATED CLASS',
214 '(deprecated)', [('THIS CLASS IS DEPRECATED. '
215 'It will be removed in a future version. ')],
216 notice_type='Deprecated')
217 __name__ = func_or_class.__name__
218 __module__ = _call_location(outer=True)
220 @_wrap_decorator(func_or_class.__init__, 'deprecated_alias')
221 def __init__(self, *args, **kwargs):
222 if hasattr(_NewClass.__init__, '__func__'):
223 # Python 2
224 _NewClass.__init__.__func__.__doc__ = func_or_class.__init__.__doc__
225 else:
226 # Python 3
227 _NewClass.__init__.__doc__ = func_or_class.__init__.__doc__
229 if _PRINT_DEPRECATION_WARNINGS:
230 # We're making the alias as we speak. The original may have other
231 # aliases, so we cannot use it to check for whether it's already been
232 # warned about.
233 if _NewClass.__init__ not in _PRINTED_WARNING:
234 if warn_once:
235 _PRINTED_WARNING[_NewClass.__init__] = True
236 logging.warning(
237 'From %s: The name %s is deprecated. Please use %s instead.\n',
238 _call_location(), deprecated_name, name)
239 super(_NewClass, self).__init__(*args, **kwargs)
241 return _NewClass
242 else:
243 decorator_utils.validate_callable(func_or_class, 'deprecated')
245 # Make a wrapper for the original
246 @functools.wraps(func_or_class)
247 def new_func(*args, **kwargs): # pylint: disable=missing-docstring
248 if _PRINT_DEPRECATION_WARNINGS:
249 # We're making the alias as we speak. The original may have other
250 # aliases, so we cannot use it to check for whether it's already been
251 # warned about.
252 if new_func not in _PRINTED_WARNING:
253 if warn_once:
254 _PRINTED_WARNING[new_func] = True
255 logging.warning(
256 'From %s: The name %s is deprecated. Please use %s instead.\n',
257 _call_location(), deprecated_name, name)
258 return func_or_class(*args, **kwargs)
260 return tf_decorator.make_decorator(
261 func_or_class, new_func, 'deprecated',
262 _add_deprecated_function_notice_to_docstring(
263 func_or_class.__doc__, None, 'Please use %s instead.' % name))
266def deprecated_endpoints(*args):
267 """Decorator for marking endpoints deprecated.
269 This decorator does not print deprecation messages.
270 TODO(annarev): eventually start printing deprecation warnings when
271 @deprecation_endpoints decorator is added.
273 Args:
274 *args: Deprecated endpoint names.
276 Returns:
277 A function that takes symbol as an argument and adds
278 _tf_deprecated_api_names to that symbol.
279 _tf_deprecated_api_names would be set to a list of deprecated
280 endpoint names for the symbol.
281 """
283 def deprecated_wrapper(func):
284 # pylint: disable=protected-access
285 if '_tf_deprecated_api_names' in func.__dict__:
286 raise DeprecatedNamesAlreadySet(
287 f'Cannot set deprecated names for {func.__name__} to {args}. '
288 'Deprecated names are already set to '
289 f'{func._tf_deprecated_api_names}.')
290 func._tf_deprecated_api_names = args
291 # pylint: disable=protected-access
292 return func
294 return deprecated_wrapper
297def deprecated(date, instructions, warn_once=True):
298 """Decorator for marking functions or methods deprecated.
300 This decorator logs a deprecation warning whenever the decorated function is
301 called. It has the following format:
303 <function> (from <module>) is deprecated and will be removed after <date>.
304 Instructions for updating:
305 <instructions>
307 If `date` is None, 'after <date>' is replaced with 'in a future version'.
308 <function> will include the class name if it is a method.
310 It also edits the docstring of the function: ' (deprecated)' is appended
311 to the first line of the docstring and a deprecation notice is prepended
312 to the rest of the docstring.
314 Args:
315 date: String or None. The date the function is scheduled to be removed. Must
316 be ISO 8601 (YYYY-MM-DD), or None.
317 instructions: String. Instructions on how to update code using the
318 deprecated function.
319 warn_once: Boolean. Set to `True` to warn only the first time the decorated
320 function is called. Otherwise, every call will log a warning.
322 Returns:
323 Decorated function or method.
325 Raises:
326 ValueError: If date is not None or in ISO 8601 format, or instructions are
327 empty.
328 """
329 _validate_deprecation_args(date, instructions)
331 def deprecated_wrapper(func_or_class):
332 """Deprecation wrapper."""
333 if isinstance(func_or_class, type):
334 # If a class is deprecated, you actually want to wrap the constructor.
335 cls = func_or_class
336 if cls.__new__ is object.__new__:
337 # If a class defaults to its parent's constructor, wrap that instead.
338 func = cls.__init__
339 constructor_name = '__init__'
340 decorators, _ = tf_decorator.unwrap(func)
341 for decorator in decorators:
342 if decorator.decorator_name == 'deprecated':
343 # If the parent is already deprecated, there's nothing to do.
344 return cls
345 else:
346 func = cls.__new__
347 constructor_name = '__new__'
349 else:
350 cls = None
351 constructor_name = None
352 func = func_or_class
354 decorator_utils.validate_callable(func, 'deprecated')
356 @_wrap_decorator(func, 'deprecated')
357 def new_func(*args, **kwargs): # pylint: disable=missing-docstring
358 if _PRINT_DEPRECATION_WARNINGS:
359 if func not in _PRINTED_WARNING and cls not in _PRINTED_WARNING:
360 if warn_once:
361 _PRINTED_WARNING[func] = True
362 if cls:
363 _PRINTED_WARNING[cls] = True
364 logging.warning(
365 'From %s: %s (from %s) is deprecated and will be removed %s.\n'
366 'Instructions for updating:\n%s', _call_location(),
367 decorator_utils.get_qualified_name(func),
368 func_or_class.__module__,
369 'in a future version' if date is None else ('after %s' % date),
370 instructions)
371 return func(*args, **kwargs)
373 doc_controls.set_deprecated(new_func)
374 new_func = tf_decorator.make_decorator(
375 func, new_func, 'deprecated',
376 _add_deprecated_function_notice_to_docstring(func.__doc__, date,
377 instructions))
378 new_func.__signature__ = inspect.signature(func)
380 if cls is None:
381 return new_func
382 else:
383 # Insert the wrapped function as the constructor
384 setattr(cls, constructor_name, new_func)
386 # And update the docstring of the class.
387 cls.__doc__ = _add_deprecated_function_notice_to_docstring(
388 cls.__doc__, date, instructions)
390 return cls
392 return deprecated_wrapper
395DeprecatedArgSpec = collections.namedtuple(
396 'DeprecatedArgSpec', ['position', 'has_ok_value', 'ok_value'])
399def deprecated_args(date, instructions, *deprecated_arg_names_or_tuples,
400 **kwargs):
401 """Decorator for marking specific function arguments as deprecated.
403 This decorator logs a deprecation warning whenever the decorated function is
404 called with the deprecated argument. It has the following format:
406 Calling <function> (from <module>) with <arg> is deprecated and will be
407 removed after <date>. Instructions for updating:
408 <instructions>
410 If `date` is None, 'after <date>' is replaced with 'in a future version'.
411 <function> includes the class name if it is a method.
413 It also edits the docstring of the function: ' (deprecated arguments)' is
414 appended to the first line of the docstring and a deprecation notice is
415 prepended to the rest of the docstring.
417 Args:
418 date: String or None. The date the function is scheduled to be removed. Must
419 be ISO 8601 (YYYY-MM-DD), or None.
420 instructions: String. Instructions on how to update code using the
421 deprecated function.
422 *deprecated_arg_names_or_tuples: String or 2-Tuple (String, ok_val). The
423 string is the deprecated argument name. Optionally, an ok-value may be
424 provided. If the user provided argument equals this value, the warning is
425 suppressed.
426 **kwargs: If `warn_once=False` is passed, every call with a deprecated
427 argument will log a warning. The default behavior is to only warn the
428 first time the function is called with any given deprecated argument. All
429 other kwargs raise `ValueError`.
431 Returns:
432 Decorated function or method.
434 Raises:
435 ValueError: If date is not None or in ISO 8601 format, instructions are
436 empty, the deprecated arguments are not present in the function
437 signature, the second element of a deprecated_tuple is not a
438 list, or if a kwarg other than `warn_once` is passed.
439 """
440 _validate_deprecation_args(date, instructions)
441 if not deprecated_arg_names_or_tuples:
442 raise ValueError('Specify which argument is deprecated.')
443 if kwargs and list(kwargs.keys()) != ['warn_once']:
444 kwargs.pop('warn_once', None)
445 raise ValueError(f'Illegal argument passed to deprecated_args: {kwargs}')
446 warn_once = kwargs.get('warn_once', True)
448 def _get_arg_names_to_ok_vals():
449 """Returns a dict mapping arg_name to DeprecatedArgSpec w/o position."""
450 d = {}
451 for name_or_tuple in deprecated_arg_names_or_tuples:
452 if isinstance(name_or_tuple, tuple):
453 d[name_or_tuple[0]] = DeprecatedArgSpec(-1, True, name_or_tuple[1])
454 else:
455 d[name_or_tuple] = DeprecatedArgSpec(-1, False, None)
456 return d
458 def _get_deprecated_positional_arguments(names_to_ok_vals, arg_spec):
459 """Builds a dictionary from deprecated arguments to their spec.
461 Returned dict is keyed by argument name.
462 Each value is a DeprecatedArgSpec with the following fields:
463 position: The zero-based argument position of the argument
464 within the signature. None if the argument isn't found in
465 the signature.
466 ok_values: Values of this argument for which warning will be
467 suppressed.
469 Args:
470 names_to_ok_vals: dict from string arg_name to a list of values, possibly
471 empty, which should not elicit a warning.
472 arg_spec: Output from tf_inspect.getfullargspec on the called function.
474 Returns:
475 Dictionary from arg_name to DeprecatedArgSpec.
476 """
477 # Extract argument list
478 arg_space = arg_spec.args + arg_spec.kwonlyargs
479 arg_name_to_pos = {name: pos for pos, name in enumerate(arg_space)}
480 deprecated_positional_args = {}
481 for arg_name, spec in iter(names_to_ok_vals.items()):
482 if arg_name in arg_name_to_pos:
483 pos = arg_name_to_pos[arg_name]
484 deprecated_positional_args[arg_name] = DeprecatedArgSpec(
485 pos, spec.has_ok_value, spec.ok_value)
486 return deprecated_positional_args
488 deprecated_arg_names = _get_arg_names_to_ok_vals()
490 def deprecated_wrapper(func):
491 """Deprecation decorator."""
492 decorator_utils.validate_callable(func, 'deprecated_args')
494 arg_spec = tf_inspect.getfullargspec(func)
495 deprecated_positions = _get_deprecated_positional_arguments(
496 deprecated_arg_names, arg_spec)
498 is_varargs_deprecated = arg_spec.varargs in deprecated_arg_names
499 is_kwargs_deprecated = arg_spec.varkw in deprecated_arg_names
501 if (len(deprecated_positions) + is_varargs_deprecated + is_kwargs_deprecated
502 != len(deprecated_arg_names_or_tuples)):
503 known_args = (
504 arg_spec.args + arg_spec.kwonlyargs +
505 [arg_spec.varargs, arg_spec.varkw])
506 missing_args = [
507 arg_name for arg_name in deprecated_arg_names
508 if arg_name not in known_args
509 ]
510 raise ValueError('The following deprecated arguments are not present '
511 f'in the function signature: {missing_args}. '
512 'Expected arguments from the following list: '
513 f'{known_args}.')
515 def _same_value(a, b):
516 """A comparison operation that works for multiple object types.
518 Returns True for two empty lists, two numeric values with the
519 same value, etc.
521 Returns False for (pd.DataFrame, None), and other pairs which
522 should not be considered equivalent.
524 Args:
525 a: value one of the comparison.
526 b: value two of the comparison.
528 Returns:
529 A boolean indicating whether the two inputs are the same value
530 for the purposes of deprecation.
531 """
532 if a is b:
533 return True
534 try:
535 equality = a == b
536 if isinstance(equality, bool):
537 return equality
538 except TypeError:
539 return False
540 return False
542 @functools.wraps(func)
543 def new_func(*args, **kwargs):
544 """Deprecation wrapper."""
545 # TODO(apassos) figure out a way to have reasonable performance with
546 # deprecation warnings and eager mode.
547 if is_in_graph_mode.IS_IN_GRAPH_MODE() and _PRINT_DEPRECATION_WARNINGS:
548 invalid_args = []
549 named_args = tf_inspect.getcallargs(func, *args, **kwargs)
550 for arg_name, spec in iter(deprecated_positions.items()):
551 if (spec.position < len(args) and
552 not (spec.has_ok_value and
553 _same_value(named_args[arg_name], spec.ok_value))):
554 invalid_args.append(arg_name)
555 if is_varargs_deprecated and len(args) > len(arg_spec.args):
556 invalid_args.append(arg_spec.varargs)
557 if is_kwargs_deprecated and kwargs:
558 invalid_args.append(arg_spec.varkw)
559 for arg_name in deprecated_arg_names:
560 if (arg_name in kwargs and
561 not (deprecated_positions[arg_name].has_ok_value and
562 _same_value(named_args[arg_name],
563 deprecated_positions[arg_name].ok_value))):
564 invalid_args.append(arg_name)
565 for arg_name in invalid_args:
566 if (func, arg_name) not in _PRINTED_WARNING:
567 if warn_once:
568 _PRINTED_WARNING[(func, arg_name)] = True
569 logging.warning(
570 'From %s: calling %s (from %s) with %s is deprecated and will '
571 'be removed %s.\nInstructions for updating:\n%s',
572 _call_location(), decorator_utils.get_qualified_name(func),
573 func.__module__, arg_name,
574 'in a future version' if date is None else ('after %s' % date),
575 instructions)
576 return func(*args, **kwargs)
578 doc = _add_deprecated_arg_notice_to_docstring(
579 func.__doc__, date, instructions, sorted(deprecated_arg_names.keys()))
580 return tf_decorator.make_decorator(func, new_func, 'deprecated', doc)
582 return deprecated_wrapper
585def deprecated_arg_values(date,
586 instructions,
587 warn_once=True,
588 **deprecated_kwargs):
589 """Decorator for marking specific function argument values as deprecated.
591 This decorator logs a deprecation warning whenever the decorated function is
592 called with the deprecated argument values. It has the following format:
594 Calling <function> (from <module>) with <arg>=<value> is deprecated and
595 will be removed after <date>. Instructions for updating:
596 <instructions>
598 If `date` is None, 'after <date>' is replaced with 'in a future version'.
599 <function> will include the class name if it is a method.
601 It also edits the docstring of the function: ' (deprecated arguments)' is
602 appended to the first line of the docstring and a deprecation notice is
603 prepended to the rest of the docstring.
605 Args:
606 date: String or None. The date the function is scheduled to be removed. Must
607 be ISO 8601 (YYYY-MM-DD), or None
608 instructions: String. Instructions on how to update code using the
609 deprecated function.
610 warn_once: If `True`, warn only the first time this function is called with
611 deprecated argument values. Otherwise, every call (with a deprecated
612 argument value) will log a warning.
613 **deprecated_kwargs: The deprecated argument values.
615 Returns:
616 Decorated function or method.
618 Raises:
619 ValueError: If date is not None or in ISO 8601 format, or instructions are
620 empty.
621 """
622 _validate_deprecation_args(date, instructions)
623 if not deprecated_kwargs:
624 raise ValueError('Specify which argument values are deprecated.')
626 def deprecated_wrapper(func):
627 """Deprecation decorator."""
628 decorator_utils.validate_callable(func, 'deprecated_arg_values')
630 @functools.wraps(func)
631 def new_func(*args, **kwargs):
632 """Deprecation wrapper."""
633 if _PRINT_DEPRECATION_WARNINGS:
634 named_args = tf_inspect.getcallargs(func, *args, **kwargs)
635 for arg_name, arg_value in deprecated_kwargs.items():
636 if arg_name in named_args and _safe_eq(named_args[arg_name],
637 arg_value):
638 if (func, arg_name) not in _PRINTED_WARNING:
639 if warn_once:
640 _PRINTED_WARNING[(func, arg_name)] = True
641 logging.warning(
642 'From %s: calling %s (from %s) with %s=%s is deprecated and '
643 'will be removed %s.\nInstructions for updating:\n%s',
644 _call_location(), decorator_utils.get_qualified_name(func),
645 func.__module__, arg_name, arg_value,
646 'in a future version' if date is None else
647 ('after %s' % date), instructions)
648 return func(*args, **kwargs)
650 doc = _add_deprecated_arg_value_notice_to_docstring(func.__doc__, date,
651 instructions,
652 deprecated_kwargs)
653 return tf_decorator.make_decorator(func, new_func, 'deprecated', doc)
655 return deprecated_wrapper
658def deprecated_argument_lookup(new_name, new_value, old_name, old_value):
659 """Looks up deprecated argument name and ensures both are not used.
661 Args:
662 new_name: new name of argument
663 new_value: value of new argument (or None if not used)
664 old_name: old name of argument
665 old_value: value of old argument (or None if not used)
667 Returns:
668 The effective argument that should be used.
669 Raises:
670 ValueError: if new_value and old_value are both non-null
671 """
672 if old_value is not None:
673 if new_value is not None:
674 raise ValueError(f"Cannot specify both '{old_name}' and '{new_name}'.")
675 return old_value
676 return new_value
679def rewrite_argument_docstring(old_doc, old_argument, new_argument):
680 return old_doc.replace('`%s`' % old_argument,
681 '`%s`' % new_argument).replace('%s:' % old_argument,
682 '%s:' % new_argument)
685@tf_contextlib.contextmanager
686def silence():
687 """Temporarily silence deprecation warnings."""
688 global _PRINT_DEPRECATION_WARNINGS
689 print_deprecation_warnings = _PRINT_DEPRECATION_WARNINGS
690 _PRINT_DEPRECATION_WARNINGS = False
691 yield
692 _PRINT_DEPRECATION_WARNINGS = print_deprecation_warnings
695def deprecate_moved_module(deprecated_name, new_module, deletion_version):
696 """Logs a warning when a module that has been moved to a new location is used.
698 Copy the following code into the old module:
700 ```
701 import deprecation
702 import new_module
704 __getattr__ = deprecation.deprecate_moved_module(
705 __name__, new_module, "2.9") # adjust version number.
706 ```
708 Args:
709 deprecated_name: Name of old module.
710 new_module: Module to replace the old module.
711 deletion_version: Version of TensorFlow in which the old module will be
712 removed.
714 Returns:
715 A function that logs a warning and returns the symbol from the new module.
716 Set this function as the module's `__getattr__`.
717 """
719 def getter(name):
720 if getter not in _PRINTED_WARNING and _PRINT_DEPRECATION_WARNINGS:
721 _PRINTED_WARNING[getter] = True
722 logging.warning(
723 'Please fix your imports. Module %s has been moved to %s. The old '
724 'module will be deleted in version %s.', deprecated_name,
725 new_module.__name__, deletion_version)
726 return getattr(new_module, name)
728 return getter
731class HiddenTfApiAttribute(property):
732 """Hides a class attribute from the public API.
734 Attributes in public classes can be hidden from the API by having an '_' in
735 front of the name (e.g. ClassName._variables). This doesn't work when
736 attributes or methods are inherited from a parent class. To hide inherited
737 attributes, set their values to be `deprecation.hide_attribute_from_api`.
738 For example, this is used in V2 Estimator to hide the deprecated
739 export_savedmodel method:
740 class EstimatorV2(Estimator):
741 export_savedmodel = deprecation.hide_attribute_from_api('...')
742 """
744 def __init__(self, deprecation_message):
746 def raise_error(unused_self):
747 raise AttributeError(deprecation_message)
749 super(HiddenTfApiAttribute, self).__init__(raise_error)
752hide_attribute_from_api = HiddenTfApiAttribute # pylint: disable=invalid-name
754# TODO(kathywu): Remove once cl/246395236 is submitted.
755HIDDEN_ATTRIBUTE = HiddenTfApiAttribute('This attribute has been deprecated.')