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