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