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