xref: /aosp_15_r20/external/tensorflow/tensorflow/python/util/deprecation_test.py (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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"""Deprecation tests."""
16
17# pylint: disable=unused-import
18import collections
19import enum
20
21import numpy as np
22
23
24from tensorflow.python.eager import context
25from tensorflow.python.framework import constant_op
26from tensorflow.python.framework import ops
27from tensorflow.python.framework import test_util
28from tensorflow.python.ops import variables
29from tensorflow.python.platform import test
30from tensorflow.python.platform import tf_logging as logging
31from tensorflow.python.util import deprecation
32from tensorflow.python.util import tf_inspect
33
34
35class DeprecatedAliasTest(test.TestCase):
36
37  @test.mock.patch.object(logging, "warning", autospec=True)
38  def test_function_alias(self, mock_warning):
39    deprecated_func = deprecation.deprecated_alias("deprecated.func",
40                                                   "real.func",
41                                                   logging.error)
42
43    logging.error("fake error logged")
44    self.assertEqual(0, mock_warning.call_count)
45    deprecated_func("FAKE ERROR!")
46    self.assertEqual(1, mock_warning.call_count)
47    # Make sure the error points to the right file.
48    self.assertRegex(mock_warning.call_args[0][1], r"deprecation_test\.py:")
49    deprecated_func("ANOTHER FAKE ERROR!")
50    self.assertEqual(1, mock_warning.call_count)
51
52  @test.mock.patch.object(logging, "warning", autospec=True)
53  def test_class_alias(self, mock_warning):
54    class MyClass(object):
55      """My docstring."""
56
57      init_args = []
58
59      def __init__(self, arg):
60        MyClass.init_args.append(arg)
61
62    deprecated_cls = deprecation.deprecated_alias("deprecated.cls",
63                                                  "real.cls",
64                                                  MyClass)
65
66    print(deprecated_cls.__name__)
67    print(deprecated_cls.__module__)
68    print(deprecated_cls.__doc__)
69
70    MyClass("test")
71    self.assertEqual(0, mock_warning.call_count)
72    deprecated_cls("deprecated")
73    self.assertEqual(1, mock_warning.call_count)
74    # Make sure the error points to the right file.
75    self.assertRegex(mock_warning.call_args[0][1], r"deprecation_test\.py:")
76    deprecated_cls("deprecated again")
77    self.assertEqual(1, mock_warning.call_count)
78
79    self.assertEqual(["test", "deprecated", "deprecated again"],
80                     MyClass.init_args)
81
82    # Check __init__ signature matches for doc generation.
83    self.assertEqual(
84        tf_inspect.getfullargspec(MyClass.__init__),
85        tf_inspect.getfullargspec(deprecated_cls.__init__))
86
87
88class DeprecationTest(test.TestCase):
89
90  @test.mock.patch.object(logging, "warning", autospec=True)
91  def test_deprecated_once(self, mock_warning):
92    date = "2016-07-04"
93    instructions = "This is how you update..."
94
95    @deprecation.deprecated(date, instructions, warn_once=True)
96    def _fn():
97      pass
98
99    _fn()
100    self.assertEqual(1, mock_warning.call_count)
101    _fn()
102    self.assertEqual(1, mock_warning.call_count)
103
104  @test.mock.patch.object(logging, "warning", autospec=True)
105  def test_deprecated_init_class(self, mock_warning):
106    date = "2016-07-04"
107    instructions = "This is how you update..."
108
109    @deprecation.deprecated(date, instructions, warn_once=True)
110    class MyClass():
111      """A test class."""
112
113      def __init__(self, a):
114        pass
115
116    MyClass("")
117    self.assertEqual(1, mock_warning.call_count)
118    MyClass("")
119    self.assertEqual(1, mock_warning.call_count)
120    self.assertIn("IS DEPRECATED", MyClass.__doc__)
121
122  @test.mock.patch.object(logging, "warning", autospec=True)
123  def test_deprecated_new_class(self, mock_warning):
124    date = "2016-07-04"
125    instructions = "This is how you update..."
126
127    @deprecation.deprecated(date, instructions, warn_once=True)
128    class MyStr(str):
129
130      def __new__(cls, value):
131        return str.__new__(cls, value)
132
133    MyStr("abc")
134    self.assertEqual(1, mock_warning.call_count)
135    MyStr("abc")
136    self.assertEqual(1, mock_warning.call_count)
137    self.assertIn("IS DEPRECATED", MyStr.__doc__)
138
139  @test.mock.patch.object(logging, "warning", autospec=True)
140  def test_deprecated_enum(self, mock_warning):
141    date = "2016-07-04"
142    instructions = "This is how you update..."
143
144    @deprecation.deprecated(date, instructions, warn_once=True)
145    class MyEnum(enum.Enum):
146      a = 1
147      b = 2
148
149    self.assertIs(MyEnum(1), MyEnum.a)
150    self.assertEqual(1, mock_warning.call_count)
151    self.assertIs(MyEnum(2), MyEnum.b)
152    self.assertEqual(1, mock_warning.call_count)
153    self.assertIn("IS DEPRECATED", MyEnum.__doc__)
154
155  @test.mock.patch.object(logging, "warning", autospec=True)
156  def test_deprecated_namedtuple(self, mock_warning):
157    date = "2016-07-04"
158    instructions = "This is how you update..."
159
160    mytuple = deprecation.deprecated(
161        date, instructions, warn_once=True)(
162            collections.namedtuple("my_tuple", ["field1", "field2"]))
163
164    mytuple(1, 2)
165    self.assertEqual(1, mock_warning.call_count)
166    mytuple(3, 4)
167    self.assertEqual(1, mock_warning.call_count)
168    self.assertIn("IS DEPRECATED", mytuple.__doc__)
169
170  @test.mock.patch.object(logging, "warning", autospec=True)
171  def test_silence(self, mock_warning):
172    date = "2016-07-04"
173    instructions = "This is how you update..."
174
175    @deprecation.deprecated(date, instructions, warn_once=False)
176    def _fn():
177      pass
178
179    _fn()
180    self.assertEqual(1, mock_warning.call_count)
181
182    with deprecation.silence():
183      _fn()
184    self.assertEqual(1, mock_warning.call_count)
185
186    _fn()
187    self.assertEqual(2, mock_warning.call_count)
188
189  def _assert_subset(self, expected_subset, actual_set):
190    self.assertTrue(
191        actual_set.issuperset(expected_subset),
192        msg="%s is not a superset of %s." % (actual_set, expected_subset))
193
194  def test_deprecated_illegal_args(self):
195    instructions = "This is how you update..."
196    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
197      deprecation.deprecated("", instructions)
198    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
199      deprecation.deprecated("07-04-2016", instructions)
200    date = "2016-07-04"
201    with self.assertRaisesRegex(ValueError, "instructions"):
202      deprecation.deprecated(date, None)
203    with self.assertRaisesRegex(ValueError, "instructions"):
204      deprecation.deprecated(date, "")
205
206  @test.mock.patch.object(logging, "warning", autospec=True)
207  def test_no_date(self, mock_warning):
208    date = None
209    instructions = "This is how you update..."
210
211    @deprecation.deprecated(date, instructions)
212    def _fn(arg0, arg1):
213      """fn doc.
214
215      Args:
216        arg0: Arg 0.
217        arg1: Arg 1.
218
219      Returns:
220        Sum of args.
221      """
222      return arg0 + arg1
223
224    self.assertEqual(
225        "fn doc. (deprecated)"
226        "\n"
227        "\nDeprecated: THIS FUNCTION IS DEPRECATED. "
228        "It will be removed in a future version."
229        "\nInstructions for updating:\n%s"
230        "\n"
231        "\nArgs:"
232        "\n  arg0: Arg 0."
233        "\n  arg1: Arg 1."
234        "\n"
235        "\nReturns:"
236        "\n  Sum of args." % instructions, _fn.__doc__)
237
238    # Assert calling new fn issues log warning.
239    self.assertEqual(3, _fn(1, 2))
240    self.assertEqual(1, mock_warning.call_count)
241    (args, _) = mock_warning.call_args
242    self.assertRegex(args[0], r"deprecated and will be removed")
243    self._assert_subset(set(["in a future version", instructions]),
244                        set(args[1:]))
245
246  @test.mock.patch.object(logging, "warning", autospec=True)
247  @test_util.run_deprecated_v1
248  def test_static_fn_with_doc(self, mock_warning):
249    date = "2016-07-04"
250    instructions = "This is how you update..."
251
252    @deprecation.deprecated(date, instructions)
253    def _fn(arg0, arg1):
254      """fn doc.
255
256      Args:
257        arg0: Arg 0.
258        arg1: Arg 1.
259
260      Returns:
261        Sum of args.
262      """
263      return arg0 + arg1
264
265    # Assert function docs are properly updated.
266    self.assertEqual("_fn", _fn.__name__)
267    self.assertEqual(
268        "fn doc. (deprecated)"
269        "\n"
270        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
271        "\nInstructions for updating:\n%s"
272        "\n"
273        "\nArgs:"
274        "\n  arg0: Arg 0."
275        "\n  arg1: Arg 1."
276        "\n"
277        "\nReturns:"
278        "\n  Sum of args." % (date, instructions), _fn.__doc__)
279
280    # Assert calling new fn issues log warning.
281    self.assertEqual(3, _fn(1, 2))
282    self.assertEqual(1, mock_warning.call_count)
283    (args, _) = mock_warning.call_args
284    self.assertRegex(args[0], r"deprecated and will be removed")
285    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
286
287  @test.mock.patch.object(logging, "warning", autospec=True)
288  @test_util.run_deprecated_v1
289  def test_static_fn_with_one_line_doc(self, mock_warning):
290    date = "2016-07-04"
291    instructions = "This is how you update..."
292
293    @deprecation.deprecated(date, instructions)
294    def _fn(arg0, arg1):
295      """fn doc."""
296      return arg0 + arg1
297
298    # Assert function docs are properly updated.
299    self.assertEqual("_fn", _fn.__name__)
300    self.assertEqual(
301        "fn doc. (deprecated)"
302        "\n"
303        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
304        "\nInstructions for updating:\n%s" % (date, instructions), _fn.__doc__)
305
306    # Assert calling new fn issues log warning.
307    self.assertEqual(3, _fn(1, 2))
308    self.assertEqual(1, mock_warning.call_count)
309    (args, _) = mock_warning.call_args
310    self.assertRegex(args[0], r"deprecated and will be removed")
311    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
312
313  @test.mock.patch.object(logging, "warning", autospec=True)
314  @test_util.run_deprecated_v1
315  def test_static_fn_no_doc(self, mock_warning):
316    date = "2016-07-04"
317    instructions = "This is how you update..."
318
319    @deprecation.deprecated(date, instructions)
320    def _fn(arg0, arg1):
321      return arg0 + arg1
322
323    # Assert function docs are properly updated.
324    self.assertEqual("_fn", _fn.__name__)
325    self.assertEqual(
326        "DEPRECATED FUNCTION"
327        "\n"
328        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
329        "\nInstructions for updating:"
330        "\n%s" % (date, instructions), _fn.__doc__)
331
332    # Assert calling new fn issues log warning.
333    self.assertEqual(3, _fn(1, 2))
334    self.assertEqual(1, mock_warning.call_count)
335    (args, _) = mock_warning.call_args
336    self.assertRegex(args[0], r"deprecated and will be removed")
337    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
338
339  @test.mock.patch.object(logging, "warning", autospec=True)
340  def test_instance_fn_with_doc(self, mock_warning):
341    date = "2016-07-04"
342    instructions = "This is how you update..."
343
344    class _Object(object):
345
346      def __init(self):
347        pass
348
349      @deprecation.deprecated(date, instructions)
350      def _fn(self, arg0, arg1):
351        """fn doc.
352
353        Args:
354          arg0: Arg 0.
355          arg1: Arg 1.
356
357        Returns:
358          Sum of args.
359        """
360        return arg0 + arg1
361
362    # Assert function docs are properly updated.
363    self.assertEqual(
364        "fn doc. (deprecated)"
365        "\n"
366        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
367        "\nInstructions for updating:\n%s"
368        "\n"
369        "\nArgs:"
370        "\n  arg0: Arg 0."
371        "\n  arg1: Arg 1."
372        "\n"
373        "\nReturns:"
374        "\n  Sum of args." % (date, instructions),
375        getattr(_Object, "_fn").__doc__)
376
377    # Assert calling new fn issues log warning.
378    self.assertEqual(3, _Object()._fn(1, 2))
379    self.assertEqual(1, mock_warning.call_count)
380    (args, _) = mock_warning.call_args
381    self.assertRegex(args[0], r"deprecated and will be removed")
382    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
383
384  @test.mock.patch.object(logging, "warning", autospec=True)
385  def test_instance_fn_with_one_line_doc(self, mock_warning):
386    date = "2016-07-04"
387    instructions = "This is how you update..."
388
389    class _Object(object):
390
391      def __init(self):
392        pass
393
394      @deprecation.deprecated(date, instructions)
395      def _fn(self, arg0, arg1):
396        """fn doc."""
397        return arg0 + arg1
398
399    # Assert function docs are properly updated.
400    self.assertEqual(
401        "fn doc. (deprecated)"
402        "\n"
403        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
404        "\nInstructions for updating:\n%s" % (date, instructions),
405        getattr(_Object, "_fn").__doc__)
406
407    # Assert calling new fn issues log warning.
408    self.assertEqual(3, _Object()._fn(1, 2))
409    self.assertEqual(1, mock_warning.call_count)
410    (args, _) = mock_warning.call_args
411    self.assertRegex(args[0], r"deprecated and will be removed")
412    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
413
414  @test.mock.patch.object(logging, "warning", autospec=True)
415  def test_instance_fn_no_doc(self, mock_warning):
416    date = "2016-07-04"
417    instructions = "This is how you update..."
418
419    class _Object(object):
420
421      def __init(self):
422        pass
423
424      @deprecation.deprecated(date, instructions)
425      def _fn(self, arg0, arg1):
426        return arg0 + arg1
427
428    # Assert function docs are properly updated.
429    self.assertEqual(
430        "DEPRECATED FUNCTION"
431        "\n"
432        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
433        "\nInstructions for updating:"
434        "\n%s" % (date, instructions),
435        getattr(_Object, "_fn").__doc__)
436
437    # Assert calling new fn issues log warning.
438    self.assertEqual(3, _Object()._fn(1, 2))
439    self.assertEqual(1, mock_warning.call_count)
440    (args, _) = mock_warning.call_args
441    self.assertRegex(args[0], r"deprecated and will be removed")
442    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
443
444  def test_prop_wrong_order(self):
445    with self.assertRaisesRegex(
446        ValueError,
447        "make sure @property appears before @deprecated in your source code"):
448      # pylint: disable=unused-variable
449
450      class _Object(object):
451
452        def __init(self):
453          pass
454
455        @deprecation.deprecated("2016-07-04", "Instructions.")
456        @property
457        def _prop(self):
458          return "prop_wrong_order"
459
460  @test.mock.patch.object(logging, "warning", autospec=True)
461  def test_prop_with_doc(self, mock_warning):
462    date = "2016-07-04"
463    instructions = "This is how you update..."
464
465    class _Object(object):
466
467      def __init(self):
468        pass
469
470      @property
471      @deprecation.deprecated(date, instructions)
472      def _prop(self):
473        """prop doc.
474
475        Returns:
476          String.
477        """
478        return "prop_with_doc"
479
480    # Assert function docs are properly updated.
481    self.assertEqual(
482        "prop doc. (deprecated)"
483        "\n"
484        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
485        "\nInstructions for updating:"
486        "\n%s"
487        "\n"
488        "\nReturns:"
489        "\n  String." % (date, instructions),
490        getattr(_Object, "_prop").__doc__)
491
492    # Assert calling new fn issues log warning.
493    self.assertEqual("prop_with_doc", _Object()._prop)
494    self.assertEqual(1, mock_warning.call_count)
495    (args, _) = mock_warning.call_args
496    self.assertRegex(args[0], r"deprecated and will be removed")
497    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
498
499  @test.mock.patch.object(logging, "warning", autospec=True)
500  def test_prop_no_doc(self, mock_warning):
501    date = "2016-07-04"
502    instructions = "This is how you update..."
503
504    class _Object(object):
505
506      def __init(self):
507        pass
508
509      @property
510      @deprecation.deprecated(date, instructions)
511      def _prop(self):
512        return "prop_no_doc"
513
514    # Assert function docs are properly updated.
515    self.assertEqual(
516        "DEPRECATED FUNCTION"
517        "\n"
518        "\nDeprecated: THIS FUNCTION IS DEPRECATED. It will be removed after %s."
519        "\nInstructions for updating:"
520        "\n%s" % (date, instructions),
521        getattr(_Object, "_prop").__doc__)
522
523    # Assert calling new fn issues log warning.
524    self.assertEqual("prop_no_doc", _Object()._prop)
525    self.assertEqual(1, mock_warning.call_count)
526    (args, _) = mock_warning.call_args
527    self.assertRegex(args[0], r"deprecated and will be removed")
528    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
529
530
531class DeprecatedArgsTest(test.TestCase):
532
533  def _assert_subset(self, expected_subset, actual_set):
534    self.assertTrue(
535        actual_set.issuperset(expected_subset),
536        msg="%s is not a superset of %s." % (actual_set, expected_subset))
537
538  def test_deprecated_illegal_args(self):
539    instructions = "This is how you update..."
540    date = "2016-07-04"
541    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
542      deprecation.deprecated_args("", instructions, "deprecated")
543    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
544      deprecation.deprecated_args("07-04-2016", instructions, "deprecated")
545    with self.assertRaisesRegex(ValueError, "instructions"):
546      deprecation.deprecated_args(date, None, "deprecated")
547    with self.assertRaisesRegex(ValueError, "instructions"):
548      deprecation.deprecated_args(date, "", "deprecated")
549    with self.assertRaisesRegex(ValueError, "argument"):
550      deprecation.deprecated_args(date, instructions)
551
552  def test_deprecated_missing_args(self):
553    date = "2016-07-04"
554    instructions = "This is how you update..."
555
556    def _fn(arg0, arg1, deprecated=None):
557      return arg0 + arg1 if deprecated else arg1 + arg0
558
559    # Assert calls without the deprecated argument log nothing.
560    with self.assertRaisesRegex(ValueError, "not present.*\\['missing'\\]"):
561      deprecation.deprecated_args(date, instructions, "missing")(_fn)
562
563  @test.mock.patch.object(logging, "warning", autospec=True)
564  @test_util.run_deprecated_v1
565  def test_static_fn_with_doc(self, mock_warning):
566    date = "2016-07-04"
567    instructions = "This is how you update..."
568
569    @deprecation.deprecated_args(date, instructions, "deprecated")
570    def _fn(arg0, arg1, deprecated=True):
571      """fn doc.
572
573      Args:
574        arg0: Arg 0.
575        arg1: Arg 1.
576        deprecated: Deprecated!
577
578      Returns:
579        Sum of args.
580      """
581      return arg0 + arg1 if deprecated else arg1 + arg0
582
583    # Assert function docs are properly updated.
584    self.assertEqual("_fn", _fn.__name__)
585    self.assertEqual(
586        "fn doc. (deprecated arguments)"
587        "\n"
588        "\nDeprecated: SOME ARGUMENTS ARE DEPRECATED: `(deprecated)`. "
589        "They will be removed after %s."
590        "\nInstructions for updating:\n%s"
591        "\n"
592        "\nArgs:"
593        "\n  arg0: Arg 0."
594        "\n  arg1: Arg 1."
595        "\n  deprecated: Deprecated!"
596        "\n"
597        "\nReturns:"
598        "\n  Sum of args." % (date, instructions), _fn.__doc__)
599
600    # Assert calls without the deprecated argument log nothing.
601    self.assertEqual(3, _fn(1, 2))
602    self.assertEqual(0, mock_warning.call_count)
603
604    # Assert calls with the deprecated argument log a warning.
605    self.assertEqual(3, _fn(1, 2, True))
606    self.assertEqual(1, mock_warning.call_count)
607    (args, _) = mock_warning.call_args
608    self.assertRegex(args[0], r"deprecated and will be removed")
609    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
610
611  @test.mock.patch.object(logging, "warning", autospec=True)
612  @test_util.run_deprecated_v1
613  def test_static_fn_with_one_line_doc(self, mock_warning):
614    date = "2016-07-04"
615    instructions = "This is how you update..."
616
617    @deprecation.deprecated_args(date, instructions, "deprecated")
618    def _fn(arg0, arg1, deprecated=True):
619      """fn doc."""
620      return arg0 + arg1 if deprecated else arg1 + arg0
621
622    # Assert function docs are properly updated.
623    self.assertEqual("_fn", _fn.__name__)
624    self.assertEqual(
625        "fn doc. (deprecated arguments)"
626        "\n"
627        "\nDeprecated: SOME ARGUMENTS ARE DEPRECATED: `(deprecated)`. "
628        "They will be removed after %s."
629        "\nInstructions for updating:\n%s" % (date, instructions), _fn.__doc__)
630
631    # Assert calls without the deprecated argument log nothing.
632    self.assertEqual(3, _fn(1, 2))
633    self.assertEqual(0, mock_warning.call_count)
634
635    # Assert calls with the deprecated argument log a warning.
636    self.assertEqual(3, _fn(1, 2, True))
637    self.assertEqual(1, mock_warning.call_count)
638    (args, _) = mock_warning.call_args
639    self.assertRegex(args[0], r"deprecated and will be removed")
640    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
641
642  @test.mock.patch.object(logging, "warning", autospec=True)
643  @test_util.run_deprecated_v1
644  def test_static_fn_no_doc(self, mock_warning):
645    date = "2016-07-04"
646    instructions = "This is how you update..."
647
648    @deprecation.deprecated_args(date, instructions, "deprecated")
649    def _fn(arg0, arg1, deprecated=True):
650      return arg0 + arg1 if deprecated else arg1 + arg0
651
652    # Assert function docs are properly updated.
653    self.assertEqual("_fn", _fn.__name__)
654    self.assertEqual(
655        "DEPRECATED FUNCTION ARGUMENTS"
656        "\n"
657        "\nDeprecated: SOME ARGUMENTS ARE DEPRECATED: `(deprecated)`. "
658        "They will be removed after %s."
659        "\nInstructions for updating:"
660        "\n%s" % (date, instructions), _fn.__doc__)
661
662    # Assert calls without the deprecated argument log nothing.
663    self.assertEqual(3, _fn(1, 2))
664    self.assertEqual(0, mock_warning.call_count)
665
666    # Assert calls with the deprecated argument log a warning.
667    self.assertEqual(3, _fn(1, 2, True))
668    self.assertEqual(1, mock_warning.call_count)
669    (args, _) = mock_warning.call_args
670    self.assertRegex(args[0], r"deprecated and will be removed")
671    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
672
673  @test.mock.patch.object(logging, "warning", autospec=True)
674  @test_util.run_deprecated_v1
675  def test_varargs(self, mock_warning):
676    date = "2016-07-04"
677    instructions = "This is how you update..."
678
679    @deprecation.deprecated_args(date, instructions, "deprecated")
680    def _fn(arg0, arg1, *deprecated):
681      return arg0 + arg1 if deprecated else arg1 + arg0
682
683    # Assert calls without the deprecated argument log nothing.
684    self.assertEqual(3, _fn(1, 2))
685    self.assertEqual(0, mock_warning.call_count)
686
687    # Assert calls with the deprecated argument log a warning.
688    self.assertEqual(3, _fn(1, 2, True, False))
689    self.assertEqual(1, mock_warning.call_count)
690    (args, _) = mock_warning.call_args
691    self.assertRegex(args[0], r"deprecated and will be removed")
692    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
693
694  @test.mock.patch.object(logging, "warning", autospec=True)
695  @test_util.run_deprecated_v1
696  def test_kwargs(self, mock_warning):
697    date = "2016-07-04"
698    instructions = "This is how you update..."
699
700    @deprecation.deprecated_args(date, instructions, "deprecated")
701    def _fn(arg0, arg1, **deprecated):
702      return arg0 + arg1 if deprecated else arg1 + arg0
703
704    # Assert calls without the deprecated argument log nothing.
705    self.assertEqual(3, _fn(1, 2))
706    self.assertEqual(0, mock_warning.call_count)
707
708    # Assert calls with the deprecated argument log a warning.
709    self.assertEqual(3, _fn(1, 2, a=True, b=False))
710    self.assertEqual(1, mock_warning.call_count)
711    (args, _) = mock_warning.call_args
712    self.assertRegex(args[0], r"deprecated and will be removed")
713    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
714
715  @test.mock.patch.object(logging, "warning", autospec=True)
716  @test_util.run_deprecated_v1
717  def test_positional_and_named(self, mock_warning):
718    date = "2016-07-04"
719    instructions = "This is how you update..."
720
721    @deprecation.deprecated_args(date, instructions, "d1", "d2")
722    def _fn(arg0, d1=None, arg1=2, d2=None):
723      return arg0 + arg1 if d1 else arg1 + arg0 if d2 else arg0 * arg1
724
725    # Assert calls without the deprecated arguments log nothing.
726    self.assertEqual(2, _fn(1, arg1=2))
727    self.assertEqual(0, mock_warning.call_count)
728
729    # Assert calls with the deprecated arguments log warnings.
730    self.assertEqual(2, _fn(1, None, 2, d2=False))
731    self.assertEqual(2, mock_warning.call_count)
732    (args1, _) = mock_warning.call_args_list[0]
733    self.assertRegex(args1[0], r"deprecated and will be removed")
734    self._assert_subset(set(["after " + date, instructions, "d1"]),
735                        set(args1[1:]))
736    (args2, _) = mock_warning.call_args_list[1]
737    self.assertRegex(args2[0], r"deprecated and will be removed")
738    self._assert_subset(set(["after " + date, instructions, "d2"]),
739                        set(args2[1:]))
740
741  @test.mock.patch.object(logging, "warning", autospec=True)
742  @test_util.run_deprecated_v1
743  def test_positional_and_named_with_ok_vals(self, mock_warning):
744    date = "2016-07-04"
745    instructions = "This is how you update..."
746
747    @deprecation.deprecated_args(date, instructions, ("d1", None),
748                                 ("d2", "my_ok_val"))
749    def _fn(arg0, d1=None, arg1=2, d2=None):
750      return arg0 + arg1 if d1 else arg1 + arg0 if d2 else arg0 * arg1
751
752    # Assert calls without the deprecated arguments log nothing.
753    self.assertEqual(2, _fn(1, arg1=2))
754    self.assertEqual(0, mock_warning.call_count)
755
756    # Assert calls with the deprecated arguments log warnings.
757    self.assertEqual(2, _fn(1, False, 2, d2=False))
758    self.assertEqual(2, mock_warning.call_count)
759    (args1, _) = mock_warning.call_args_list[0]
760    self.assertRegex(args1[0], r"deprecated and will be removed")
761    self._assert_subset(set(["after " + date, instructions, "d1"]),
762                        set(args1[1:]))
763    (args2, _) = mock_warning.call_args_list[1]
764    self.assertRegex(args2[0], r"deprecated and will be removed")
765    self._assert_subset(set(["after " + date, instructions, "d2"]),
766                        set(args2[1:]))
767
768    # Assert calls with the deprecated arguments don't log warnings if
769    # the value matches the 'ok_val'.
770    mock_warning.reset_mock()
771    self.assertEqual(3, _fn(1, None, 2, d2="my_ok_val"))
772    self.assertEqual(0, mock_warning.call_count)
773
774  @test.mock.patch.object(logging, "warning", autospec=True)
775  @test_util.run_deprecated_v1
776  def test_kwonlyargs(self, mock_warning):
777    date = "2016-07-04"
778    instructions = "This is how you update..."
779
780    @deprecation.deprecated_args(date, instructions, "deprecated")
781    def _fn(*, arg0, arg1, deprecated=None):
782      return arg0 + arg1 if deprecated is not None else arg1 + arg0
783
784    # Assert calls without the deprecated argument log nothing.
785    self.assertEqual(3, _fn(arg0=1, arg1=2))
786    self.assertEqual(0, mock_warning.call_count)
787
788    # Assert calls with the deprecated argument log a warning.
789    self.assertEqual(3, _fn(arg0=1, arg1=2, deprecated=2))
790    self.assertEqual(1, mock_warning.call_count)
791    (args, _) = mock_warning.call_args
792    self.assertRegex(args[0], r"deprecated and will be removed")
793    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
794
795  @test.mock.patch.object(logging, "warning", autospec=True)
796  @test_util.run_deprecated_v1
797  def test_kwonlyargs_and_args(self, mock_warning):
798    date = "2016-07-04"
799    instructions = "This is how you update..."
800
801    @deprecation.deprecated_args(date, instructions,
802                                 ("deprecated_arg1", "deprecated_arg2"))
803    def _fn(arg0, arg1, *, kw1,
804            deprecated_arg1=None,
805            deprecated_arg2=None):
806      res = arg0 + arg1 + kw1
807      if deprecated_arg1 is not None:
808        res += deprecated_arg1
809      if deprecated_arg2 is not None:
810        res += deprecated_arg2
811      return res
812
813    # Assert calls without the deprecated argument log nothing.
814    self.assertEqual(6, _fn(1, 2, kw1=3))
815    self.assertEqual(0, mock_warning.call_count)
816
817    # Assert calls with the deprecated_arg1 argument log a warning.
818    self.assertEqual(8, _fn(1, 2, kw1=3, deprecated_arg1=2))
819    self.assertEqual(1, mock_warning.call_count)
820    (args, _) = mock_warning.call_args
821    self.assertRegex(args[0], r"deprecated and will be removed")
822    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
823
824    # Assert calls with the deprecated arguments log a warning.
825    self.assertEqual(12, _fn(1, 2, kw1=3, deprecated_arg1=2, deprecated_arg2=4))
826    self.assertEqual(1, mock_warning.call_count)
827    (args, _) = mock_warning.call_args
828    self.assertRegex(args[0], r"deprecated and will be removed")
829    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
830
831  @test.mock.patch.object(logging, "warning", autospec=True)
832  @test_util.run_deprecated_v1
833  def test_deprecated_args_once(self, mock_warning):
834    date = "2016-07-04"
835    instructions = "This is how you update..."
836
837    @deprecation.deprecated_args(date, instructions, "arg", warn_once=True)
838    def _fn(arg=0):  # pylint: disable=unused-argument
839      pass
840
841    _fn()
842    self.assertEqual(0, mock_warning.call_count)
843    _fn(arg=0)
844    self.assertEqual(1, mock_warning.call_count)
845    _fn(arg=1)
846    self.assertEqual(1, mock_warning.call_count)
847
848  @test.mock.patch.object(logging, "warning", autospec=True)
849  @test_util.run_deprecated_v1
850  def test_deprecated_multiple_args_once_each(self, mock_warning):
851    date = "2016-07-04"
852    instructions = "This is how you update..."
853
854    @deprecation.deprecated_args(date, instructions, "arg0", "arg1",
855                                 warn_once=True)
856    def _fn(arg0=0, arg1=0):  # pylint: disable=unused-argument
857      pass
858
859    _fn(arg0=0)
860    self.assertEqual(1, mock_warning.call_count)
861    _fn(arg0=0)
862    self.assertEqual(1, mock_warning.call_count)
863    _fn(arg1=0)
864    self.assertEqual(2, mock_warning.call_count)
865    _fn(arg0=0)
866    self.assertEqual(2, mock_warning.call_count)
867    _fn(arg1=0)
868    self.assertEqual(2, mock_warning.call_count)
869
870
871class DeprecatedArgValuesTest(test.TestCase):
872
873  def _assert_subset(self, expected_subset, actual_set):
874    self.assertTrue(
875        actual_set.issuperset(expected_subset),
876        msg="%s is not a superset of %s." % (actual_set, expected_subset))
877
878  def test_deprecated_illegal_args(self):
879    instructions = "This is how you update..."
880    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
881      deprecation.deprecated_arg_values("", instructions, deprecated=True)
882    with self.assertRaisesRegex(ValueError, "YYYY-MM-DD"):
883      deprecation.deprecated_arg_values(
884          "07-04-2016", instructions, deprecated=True)
885    date = "2016-07-04"
886    with self.assertRaisesRegex(ValueError, "instructions"):
887      deprecation.deprecated_arg_values(date, None, deprecated=True)
888    with self.assertRaisesRegex(ValueError, "instructions"):
889      deprecation.deprecated_arg_values(date, "", deprecated=True)
890    with self.assertRaisesRegex(ValueError, "argument"):
891      deprecation.deprecated_arg_values(date, instructions)
892
893  @test.mock.patch.object(logging, "warning", autospec=True)
894  @test_util.run_deprecated_v1
895  def test_static_fn_with_doc(self, mock_warning):
896    date = "2016-07-04"
897    instructions = "This is how you update..."
898
899    @deprecation.deprecated_arg_values(date, instructions, warn_once=False,
900                                       deprecated=True)
901    def _fn(arg0, arg1, deprecated=True):
902      """fn doc.
903
904      Args:
905        arg0: Arg 0.
906        arg1: Arg 1.
907        deprecated: Deprecated!
908
909      Returns:
910        Sum of args.
911      """
912      return arg0 + arg1 if deprecated else arg1 + arg0
913
914    # Assert function docs are properly updated.
915    self.assertEqual("_fn", _fn.__name__)
916    self.assertEqual(
917        "fn doc. (deprecated argument values)"
918        "\n"
919        "\nDeprecated: SOME ARGUMENT VALUES ARE DEPRECATED: `(deprecated=True)`. "
920        "They will be removed after %s."
921        "\nInstructions for updating:\n%s"
922        "\n"
923        "\nArgs:"
924        "\n  arg0: Arg 0."
925        "\n  arg1: Arg 1."
926        "\n  deprecated: Deprecated!"
927        "\n"
928        "\nReturns:"
929        "\n  Sum of args." % (date, instructions), _fn.__doc__)
930
931    # Assert calling new fn with non-deprecated value logs nothing.
932    self.assertEqual(3, _fn(1, 2, deprecated=False))
933    self.assertEqual(0, mock_warning.call_count)
934
935    # Assert calling new fn with deprecated value issues log warning.
936    self.assertEqual(3, _fn(1, 2, deprecated=True))
937    self.assertEqual(1, mock_warning.call_count)
938    (args, _) = mock_warning.call_args
939    self.assertRegex(args[0], r"deprecated and will be removed")
940    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
941
942    # Assert calling new fn with default deprecated value issues log warning.
943    self.assertEqual(3, _fn(1, 2))
944    self.assertEqual(2, mock_warning.call_count)
945
946  @test.mock.patch.object(logging, "warning", autospec=True)
947  @test_util.run_deprecated_v1
948  def test_static_fn_with_one_line_doc(self, mock_warning):
949    date = "2016-07-04"
950    instructions = "This is how you update..."
951
952    @deprecation.deprecated_arg_values(date, instructions, warn_once=False,
953                                       deprecated=True)
954    def _fn(arg0, arg1, deprecated=True):
955      """fn doc."""
956      return arg0 + arg1 if deprecated else arg1 + arg0
957
958    # Assert function docs are properly updated.
959    self.assertEqual("_fn", _fn.__name__)
960    self.assertEqual(
961        "fn doc. (deprecated argument values)"
962        "\n"
963        "\nDeprecated: SOME ARGUMENT VALUES ARE DEPRECATED: `(deprecated=True)`. "
964        "They will be removed after %s."
965        "\nInstructions for updating:\n%s" % (date, instructions), _fn.__doc__)
966
967    # Assert calling new fn with non-deprecated value logs nothing.
968    self.assertEqual(3, _fn(1, 2, deprecated=False))
969    self.assertEqual(0, mock_warning.call_count)
970
971    # Assert calling new fn with deprecated value issues log warning.
972    self.assertEqual(3, _fn(1, 2, deprecated=True))
973    self.assertEqual(1, mock_warning.call_count)
974    (args, _) = mock_warning.call_args
975    self.assertRegex(args[0], r"deprecated and will be removed")
976    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
977
978    # Assert calling new fn with default deprecated value issues log warning.
979    self.assertEqual(3, _fn(1, 2))
980    self.assertEqual(2, mock_warning.call_count)
981
982  @test.mock.patch.object(logging, "warning", autospec=True)
983  @test_util.run_deprecated_v1
984  def test_static_fn_no_doc(self, mock_warning):
985    date = "2016-07-04"
986    instructions = "This is how you update..."
987
988    @deprecation.deprecated_arg_values(date, instructions, warn_once=False,
989                                       deprecated=True)
990    def _fn(arg0, arg1, deprecated=True):
991      return arg0 + arg1 if deprecated else arg1 + arg0
992
993    # Assert function docs are properly updated.
994    self.assertEqual("_fn", _fn.__name__)
995    self.assertEqual(
996        "DEPRECATED FUNCTION ARGUMENT VALUES"
997        "\n"
998        "\nDeprecated: SOME ARGUMENT VALUES ARE DEPRECATED: `(deprecated=True)`. "
999        "They will be removed after %s."
1000        "\nInstructions for updating:"
1001        "\n%s" % (date, instructions), _fn.__doc__)
1002
1003    # Assert calling new fn with non-deprecated value logs nothing.
1004    self.assertEqual(3, _fn(1, 2, deprecated=False))
1005    self.assertEqual(0, mock_warning.call_count)
1006
1007    # Assert calling new fn issues log warning.
1008    self.assertEqual(3, _fn(1, 2, deprecated=True))
1009    self.assertEqual(1, mock_warning.call_count)
1010    (args, _) = mock_warning.call_args
1011    self.assertRegex(args[0], r"deprecated and will be removed")
1012    self._assert_subset(set(["after " + date, instructions]), set(args[1:]))
1013
1014    # Assert calling new fn with default deprecated value issues log warning.
1015    self.assertEqual(3, _fn(1, 2))
1016    self.assertEqual(2, mock_warning.call_count)
1017
1018  @test.mock.patch.object(logging, "warning", autospec=True)
1019  def test_deprecated_arg_values_once(self, mock_warning):
1020    date = "2016-07-04"
1021    instructions = "This is how you update..."
1022
1023    @deprecation.deprecated_arg_values(date, instructions, warn_once=True,
1024                                       deprecated=True)
1025    def _fn(deprecated):  # pylint: disable=unused-argument
1026      pass
1027
1028    _fn(deprecated=False)
1029    self.assertEqual(0, mock_warning.call_count)
1030    _fn(deprecated=True)
1031    self.assertEqual(1, mock_warning.call_count)
1032    _fn(deprecated=True)
1033    self.assertEqual(1, mock_warning.call_count)
1034
1035  @test.mock.patch.object(logging, "warning", autospec=True)
1036  def test_deprecated_multiple_arg_values_once_each(self, mock_warning):
1037    date = "2016-07-04"
1038    instructions = "This is how you update..."
1039
1040    @deprecation.deprecated_arg_values(date, instructions, warn_once=True,
1041                                       arg0="forbidden", arg1="disallowed")
1042    def _fn(arg0, arg1):  # pylint: disable=unused-argument
1043      pass
1044
1045    _fn(arg0="allowed", arg1="also allowed")
1046    self.assertEqual(0, mock_warning.call_count)
1047    _fn(arg0="forbidden", arg1="disallowed")
1048    self.assertEqual(2, mock_warning.call_count)
1049    _fn(arg0="forbidden", arg1="allowed")
1050    self.assertEqual(2, mock_warning.call_count)
1051    _fn(arg0="forbidden", arg1="disallowed")
1052    self.assertEqual(2, mock_warning.call_count)
1053
1054  @test.mock.patch.object(logging, "warning", autospec=True)
1055  @test_util.run_in_graph_and_eager_modes
1056  def test_deprecated_arg_values_when_value_is_none(self, mock_warning):
1057
1058    @deprecation.deprecated_arg_values("2016-07-04",
1059                                       "This is how you update...",
1060                                       warn_once=True,
1061                                       arg0=None)
1062    def _fn(arg0):  # pylint: disable=unused-argument
1063      pass
1064
1065    ops.enable_tensor_equality()
1066    initial_count = mock_warning.call_count
1067    # Check that we avoid error from explicit `var == None` check.
1068    _fn(arg0=variables.Variable(0))
1069    self.assertEqual(initial_count, mock_warning.call_count)
1070    _fn(arg0=None)
1071    self.assertEqual(initial_count + 1, mock_warning.call_count)
1072    ops.disable_tensor_equality()
1073
1074
1075class DeprecationArgumentsTest(test.TestCase):
1076
1077  def testDeprecatedArgumentLookup(self):
1078    good_value = 3
1079    self.assertEqual(
1080        deprecation.deprecated_argument_lookup("val_new", good_value, "val_old",
1081                                               None), good_value)
1082    self.assertEqual(
1083        deprecation.deprecated_argument_lookup("val_new", None, "val_old",
1084                                               good_value), good_value)
1085    with self.assertRaisesRegex(ValueError,
1086                                "Cannot specify both 'val_old' and 'val_new'"):
1087
1088      deprecation.deprecated_argument_lookup("val_new", good_value,
1089                                             "val_old", good_value)
1090
1091  def testRewriteArgumentDocstring(self):
1092    docs = """Add `a` and `b`
1093
1094    Args:
1095      a: first arg
1096      b: second arg
1097    """
1098    new_docs = deprecation.rewrite_argument_docstring(
1099        deprecation.rewrite_argument_docstring(docs, "a", "left"), "b", "right")
1100    new_docs_ref = """Add `left` and `right`
1101
1102    Args:
1103      left: first arg
1104      right: second arg
1105    """
1106    self.assertEqual(new_docs, new_docs_ref)
1107
1108
1109class DeprecatedEndpointsTest(test.TestCase):
1110
1111  def testSingleDeprecatedEndpoint(self):
1112    @deprecation.deprecated_endpoints("foo1")
1113    def foo():
1114      pass
1115    self.assertEqual(("foo1",), foo._tf_deprecated_api_names)
1116
1117  def testMultipleDeprecatedEndpoint(self):
1118    @deprecation.deprecated_endpoints("foo1", "foo2")
1119    def foo():
1120      pass
1121    self.assertEqual(("foo1", "foo2"), foo._tf_deprecated_api_names)
1122
1123  def testCannotSetDeprecatedEndpointsTwice(self):
1124    with self.assertRaises(deprecation.DeprecatedNamesAlreadySet):
1125      @deprecation.deprecated_endpoints("foo1")
1126      @deprecation.deprecated_endpoints("foo2")
1127      def foo():  # pylint: disable=unused-variable
1128        pass
1129
1130
1131class DeprecateMovedModuleTest(test.TestCase):
1132
1133  @test.mock.patch.object(logging, "warning", autospec=True)
1134  def testCallDeprecatedModule(self, mock_warning):
1135    from tensorflow.python.util import deprecated_module  # pylint: disable=g-import-not-at-top
1136    self.assertEqual(0, mock_warning.call_count)
1137    result = deprecated_module.a()
1138    self.assertEqual(1, mock_warning.call_count)
1139    self.assertEqual(1, result)
1140
1141    deprecated_module.a()
1142    self.assertEqual(1, mock_warning.call_count)
1143
1144
1145if __name__ == "__main__":
1146  test.main()
1147