1import sys 2 3from . import check, v 4 5assert v # Silence pyflakes. 6 7 8def test_function_object1(v): 9 v.scan( 10 """\ 11def func(): 12 pass 13 14a = func 15""" 16 ) 17 check(v.defined_funcs, ["func"]) 18 check(v.unused_funcs, []) 19 20 21def test_function_object2(v): 22 v.scan( 23 """\ 24def func(): 25 pass 26 27func 28""" 29 ) 30 check(v.defined_funcs, ["func"]) 31 check(v.unused_funcs, []) 32 33 34def test_function1(v): 35 v.scan( 36 """\ 37def func1(a): 38 pass 39 40def func2(b): 41 func1(b) 42""" 43 ) 44 check(v.defined_funcs, ["func1", "func2"]) 45 check(v.unused_funcs, ["func2"]) 46 47 48def test_function2(v): 49 v.scan( 50 """\ 51def func(a): 52 pass 53 54func(5) 55""" 56 ) 57 check(v.unused_funcs, []) 58 check(v.defined_funcs, ["func"]) 59 60 61def test_function3(v): 62 v.scan( 63 """\ 64def foo(a): 65 pass 66 67b = foo(5) 68""" 69 ) 70 check(v.unused_funcs, []) 71 check(v.defined_funcs, ["foo"]) 72 73 74def test_async_function(v): 75 v.scan( 76 """\ 77async def foo(): 78 pass 79""" 80 ) 81 check(v.defined_funcs, ["foo"]) 82 check(v.unused_funcs, ["foo"]) 83 84 85def test_async_method(v): 86 v.scan( 87 """\ 88class Foo: 89 async def bar(self): 90 pass 91""" 92 ) 93 check(v.defined_classes, ["Foo"]) 94 check(v.defined_funcs, []) 95 check(v.defined_methods, ["bar"]) 96 check(v.unused_classes, ["Foo"]) 97 check(v.unused_methods, ["bar"]) 98 99 100def test_function_and_method1(v): 101 v.scan( 102 """\ 103class Bar(object): 104 def func(self): 105 pass 106 107def func(): 108 pass 109 110func() 111""" 112 ) 113 check(v.defined_classes, ["Bar"]) 114 check(v.defined_funcs, ["func"]) 115 check(v.defined_methods, ["func"]) 116 check(v.unused_classes, ["Bar"]) 117 check(v.unused_funcs, []) 118 # Bar.func is unused, but it's hard to detect this without producing a 119 # false positive in test_function_and_method2. 120 check(v.unused_methods, []) 121 122 123def test_function_and_method2(v): 124 v.scan( 125 """\ 126class Bar(object): 127 def func(self): 128 pass 129 130 other_name_for_func = func 131 132Bar().other_name_for_func() 133""" 134 ) 135 check(v.defined_classes, ["Bar"]) 136 check(v.defined_funcs, []) 137 check(v.defined_methods, ["func"]) 138 check(v.defined_vars, ["other_name_for_func"]) 139 check(v.unused_classes, []) 140 check(v.unused_funcs, []) 141 check(v.unused_methods, []) 142 check(v.unused_vars, []) 143 144 145def test_attribute1(v): 146 v.scan( 147 """\ 148foo.bar = 1 149foo.bar = 2 150""" 151 ) 152 check(v.unused_funcs, []) 153 check(v.defined_funcs, []) 154 check(v.defined_attrs, ["bar", "bar"]) 155 check(v.used_names, ["foo"]) 156 check(v.unused_attrs, ["bar", "bar"]) 157 158 159def test_ignored_attributes(v): 160 v.scan( 161 """\ 162A._ = 0 163A._a = 1 164A.__b = 2 165A.__c__ = 3 166A._d_ = 4 167""" 168 ) 169 check(v.defined_attrs, ["_", "_a", "__b", "__c__", "_d_"]) 170 check(v.used_names, ["A"]) 171 check(v.unused_attrs, ["_", "__b", "__c__", "_a", "_d_"]) 172 check(v.unused_vars, []) 173 174 175def test_getattr(v): 176 v.scan( 177 """\ 178class Thing: 179 used_attr1 = 1 180 used_attr2 = 2 181 used_attr3 = 3 182 unused_attr = 4 183 184getattr(Thing, "used_attr1") 185getattr(Thing, "used_attr2", None) 186hasattr(Thing, "used_attr3") 187 188# Weird calls ignored 189hasattr(Thing, "unused_attr", None) 190getattr(Thing) 191getattr("unused_attr") 192getattr(Thing, "unused_attr", 1, 2) 193""" 194 ) 195 check(v.unused_vars, ["unused_attr"]) 196 check( 197 v.used_names, 198 [ 199 "Thing", 200 "getattr", 201 "hasattr", 202 "used_attr1", 203 "used_attr2", 204 "used_attr3", 205 ], 206 ) 207 208 209def test_callback1(v): 210 v.scan( 211 """\ 212class Bar(object): 213 def foo(self): 214 pass 215 216b = Bar() 217b.foo 218""" 219 ) 220 check(v.used_names, ["Bar", "b", "foo"]) 221 check(v.defined_classes, ["Bar"]) 222 check(v.defined_funcs, []) 223 check(v.defined_methods, ["foo"]) 224 check(v.unused_classes, []) 225 check(v.unused_funcs, []) 226 227 228def test_class1(v): 229 v.scan( 230 """\ 231class Bar(object): 232 pass 233""" 234 ) 235 check(v.used_names, []) 236 check(v.defined_classes, ["Bar"]) 237 check(v.unused_classes, ["Bar"]) 238 239 240def test_class2(v): 241 v.scan( 242 """\ 243class Bar(): 244 pass 245class Foo(Bar): 246 pass 247Foo() 248""" 249 ) 250 check(v.used_names, ["Bar", "Foo"]) 251 check(v.defined_classes, ["Bar", "Foo"]) 252 check(v.unused_classes, []) 253 254 255def test_class3(v): 256 v.scan( 257 """\ 258class Bar(): 259 pass 260[Bar] 261""" 262 ) 263 check(v.used_names, ["Bar"]) 264 check(v.defined_classes, ["Bar"]) 265 check(v.unused_classes, []) 266 267 268def test_class4(v): 269 v.scan( 270 """\ 271class Bar(): 272 pass 273Bar() 274""" 275 ) 276 check(v.used_names, ["Bar"]) 277 check(v.defined_classes, ["Bar"]) 278 check(v.unused_classes, []) 279 280 281def test_class5(v): 282 v.scan( 283 """\ 284class Bar(): 285 pass 286b = Bar() 287""" 288 ) 289 check(v.used_names, ["Bar"]) 290 check(v.defined_classes, ["Bar"]) 291 check(v.unused_classes, []) 292 check(v.unused_vars, ["b"]) 293 294 295def test_class6(v): 296 v.scan( 297 """\ 298class Bar(): 299 pass 300a = [] 301a.insert(0, Bar()) 302""" 303 ) 304 check(v.defined_classes, ["Bar"]) 305 check(v.unused_classes, []) 306 307 308def test_class7(v): 309 v.scan( 310 """\ 311class Bar(object): 312 pass 313 314class Foo(object): 315 def __init__(self): 316 self.b = xyz.Bar(self) 317""" 318 ) 319 check(v.defined_classes, ["Bar", "Foo"]) 320 check(v.unused_classes, ["Foo"]) 321 322 323def test_method1(v): 324 v.scan( 325 """\ 326def __init__(self): 327 self.a.foo() 328 329class Bar(object): 330 def foo(self): 331 pass 332 333 @classmethod 334 def bar(cls): 335 pass 336 337 @staticmethod 338 def foobar(): 339 pass 340""" 341 ) 342 check(v.defined_classes, ["Bar"]) 343 check(v.defined_funcs, []) 344 check(v.defined_methods, ["foo", "bar", "foobar"]) 345 check(v.unused_classes, ["Bar"]) 346 check(v.unused_funcs, []) 347 check(v.unused_methods, ["bar", "foobar"]) 348 349 350def test_token_types(v): 351 v.scan( 352 """\ 353a 354b = 2 355c() 356x.d 357""" 358 ) 359 check(v.defined_funcs, []) 360 check(v.defined_vars, ["b"]) 361 check(v.used_names, ["a", "c", "d", "x"]) 362 check(v.unused_attrs, []) 363 check(v.unused_funcs, []) 364 check(v.unused_props, []) 365 check(v.unused_vars, ["b"]) 366 367 368def test_variable1(v): 369 v.scan("a = 1\nb = a") 370 check(v.defined_funcs, []) 371 check(v.used_names, ["a"]) 372 check(v.defined_vars, ["a", "b"]) 373 check(v.unused_vars, ["b"]) 374 375 376def test_variable2(v): 377 v.scan("a = 1\nc = b.a") 378 check(v.defined_funcs, []) 379 check(v.defined_vars, ["a", "c"]) 380 check(v.used_names, ["a", "b"]) 381 check(v.unused_vars, ["c"]) 382 383 384def test_variable3(v): 385 v.scan("(a, b), c = (d, e, f)") 386 check(v.defined_funcs, []) 387 check(v.defined_vars, ["a", "b", "c"]) 388 check(v.used_names, ["d", "e", "f"]) 389 check(v.unused_vars, ["a", "b", "c"]) 390 391 392def test_variable4(v): 393 v.scan("for a, b in func(): a") 394 check(v.defined_funcs, []) 395 check(v.defined_vars, ["a", "b"]) 396 check(v.used_names, ["a", "func"]) 397 check(v.unused_vars, ["b"]) 398 399 400def test_variable5(v): 401 v.scan("[a for a, b in func()]") 402 check(v.defined_vars, ["a", "b"]) 403 check(v.used_names, ["a", "func"]) 404 check(v.unused_vars, ["b"]) 405 406 407def test_ignored_variables(v): 408 v.scan( 409 """\ 410_ = 0 411_a = 1 412__b = 2 413__c__ = 3 414_d_ = 4 415""" 416 ) 417 check(v.defined_vars, ["__b"]) 418 check(sorted(v.used_names), []) 419 check(v.unused_vars, ["__b"]) 420 421 422def test_prop1(v): 423 v.scan( 424 """\ 425class Bar(object): 426 @property 427 def prop(self): 428 pass 429 430c = Bar() 431c.prop 432""" 433 ) 434 check(v.defined_classes, ["Bar"]) 435 check(v.defined_props, ["prop"]) 436 check(v.unused_classes, []) 437 check(v.unused_props, []) 438 439 440def test_prop2(v): 441 v.scan( 442 """\ 443class Bar(object): 444 @property 445 def prop(self): 446 pass 447 448prop = 1 449""" 450 ) 451 check(v.defined_classes, ["Bar"]) 452 check(v.defined_props, ["prop"]) 453 check(v.defined_vars, ["prop"]) 454 check(v.unused_classes, ["Bar"]) 455 check(v.unused_props, ["prop"]) 456 457 458def test_object_attribute(v): 459 v.scan( 460 """\ 461class Bar(object): 462 def __init__(self): 463 self.a = [] 464""" 465 ) 466 check(v.defined_attrs, ["a"]) 467 check(v.defined_classes, ["Bar"]) 468 check(v.defined_vars, []) 469 check(v.used_names, []) 470 check(v.unused_attrs, ["a"]) 471 check(v.unused_classes, ["Bar"]) 472 473 474def test_function_names_in_test_file(v): 475 v.scan( 476 """\ 477def test_func(): 478 pass 479 480def other_func(): 481 pass 482 483class TestClass: 484 pass 485 486class BasicTestCase: 487 pass 488 489class OtherClass: 490 pass 491""", 492 filename="dir/test_function_names.py", 493 ) 494 check(v.defined_attrs, []) 495 check(v.defined_classes, ["OtherClass"]) 496 check(v.defined_funcs, ["other_func"]) 497 check(v.defined_vars, []) 498 check(v.used_names, []) 499 check(v.unused_attrs, []) 500 check(v.unused_classes, ["OtherClass"]) 501 check(v.unused_funcs, ["other_func"]) 502 503 504def test_async_function_name_in_test_file(v): 505 v.scan( 506 """\ 507async def test_func(): 508 pass 509 510async def other_func(): 511 pass 512""", 513 filename="dir/test_function_names.py", 514 ) 515 check(v.defined_funcs, ["other_func"]) 516 check(v.unused_funcs, ["other_func"]) 517 518 519def test_async_function_name_in_normal_file(v): 520 v.scan( 521 """\ 522async def test_func(): 523 pass 524 525async def other_func(): 526 pass 527""", 528 filename="dir/function_names.py", 529 ) 530 check(v.defined_funcs, ["test_func", "other_func"]) 531 check(v.unused_funcs, ["other_func", "test_func"]) 532 533 534def test_function_names_in_normal_file(v): 535 v.scan( 536 """\ 537def test_func(): 538 pass 539 540def other_func(): 541 pass 542 543class TestClass: 544 pass 545 546class BasicTestCase: 547 pass 548 549class OtherClass: 550 pass 551""" 552 ) 553 check(v.defined_attrs, []) 554 check(v.defined_classes, ["BasicTestCase", "OtherClass", "TestClass"]) 555 check(v.defined_funcs, ["test_func", "other_func"]) 556 check(v.defined_vars, []) 557 check(v.used_names, []) 558 check(v.unused_attrs, []) 559 check(v.unused_classes, ["BasicTestCase", "OtherClass", "TestClass"]) 560 check(v.unused_funcs, ["other_func", "test_func"]) 561 562 563def test_global_attribute(v): 564 v.scan( 565 """\ 566# Module foo: 567a = 1 568if a == 1: 569 pass 570 571# Module bar: 572import foo 573foo.a = 2 574""" 575 ) 576 check(v.defined_attrs, ["a"]) 577 check(v.defined_vars, ["a"]) 578 check(v.used_names, ["a", "foo"]) 579 check(v.unused_attrs, []) 580 581 582def test_boolean(v): 583 v.scan( 584 """\ 585a = True 586a 587""" 588 ) 589 check(v.defined_vars, ["a"]) 590 check(v.used_names, ["a"]) 591 check(v.unused_vars, []) 592 593 594def test_builtin_types(v): 595 v.scan( 596 """\ 597a = b 598a = 1 599a = "s" 600a = object 601a = False 602""" 603 ) 604 check(v.defined_vars, ["a"] * 5) 605 check(v.used_names, ["b"]) 606 check(v.unused_vars, ["a"] * 5) 607 608 609def test_unused_args(v): 610 v.scan( 611 """\ 612def foo(x, y): 613 return x + 1 614""" 615 ) 616 check(v.defined_vars, ["x", "y"]) 617 check(v.used_names, ["x"]) 618 check(v.unused_vars, ["y"]) 619 620 621def test_unused_kwargs(v): 622 v.scan( 623 """\ 624def foo(x, y=3, **kwargs): 625 return x + 1 626""" 627 ) 628 check(v.defined_vars, ["kwargs", "x", "y"]) 629 check(v.used_names, ["x"]) 630 check(v.unused_vars, ["kwargs", "y"]) 631 632 633def test_unused_kwargs_with_odd_name(v): 634 v.scan( 635 """\ 636def foo(**bar): 637 pass 638""" 639 ) 640 check(v.defined_vars, ["bar"]) 641 check(v.used_names, []) 642 check(v.unused_vars, ["bar"]) 643 644 645def test_unused_vararg(v): 646 v.scan( 647 """\ 648def foo(*bar): 649 pass 650""" 651 ) 652 check(v.defined_vars, ["bar"]) 653 check(v.used_names, []) 654 check(v.unused_vars, ["bar"]) 655 656 657def test_multiple_definition(v): 658 v.scan( 659 """\ 660a = 1 661a = 2 662""" 663 ) 664 check(v.defined_vars, ["a", "a"]) 665 check(v.used_names, []) 666 check(v.unused_vars, ["a", "a"]) 667 668 669def test_arg_type_annotation(v): 670 v.scan( 671 """\ 672from typing import Iterable 673 674def f(n: int) -> Iterable[int]: 675 yield n 676""" 677 ) 678 679 check(v.unused_vars, []) 680 check(v.unused_funcs, ["f"]) 681 check(v.unused_imports, []) 682 683 684def test_var_type_annotation(v): 685 v.scan( 686 """\ 687from typing import List 688 689x: List[int] = [1] 690""" 691 ) 692 693 check(v.unused_vars, ["x"]) 694 check(v.unused_funcs, []) 695 check(v.unused_imports, []) 696 697 698def test_type_hint_comments(v): 699 v.scan( 700 """\ 701from typing import Any, Dict, List, Text, Tuple 702 703 704def plain_function(arg): 705 # type: (Text) -> None 706 pass 707 708async def async_function(arg): 709 # type: (List[int]) -> None 710 pass 711 712some_var = {} # type: Dict[str, str] 713 714class Thing: 715 def __init__(self): 716 self.some_attr = (1, 2) # type: Tuple[int, int] 717 718for x in []: # type: Any 719 print(x) 720""" 721 ) 722 723 if sys.version_info < (3, 8): 724 check(v.unused_imports, ["Any", "Dict", "List", "Text", "Tuple"]) 725 else: 726 check(v.unused_imports, []) 727 assert not v.found_dead_code_or_error 728 729 730def test_invalid_type_comment(v): 731 v.scan( 732 """\ 733def bad(): 734 # type: bogus 735 pass 736bad() 737""" 738 ) 739 740 if sys.version_info < (3, 8): 741 assert not v.found_dead_code_or_error 742 else: 743 assert v.found_dead_code_or_error 744