]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | """ |
2 | Tests for various Pyflakes behavior. | |
3 | """ | |
4 | ||
5 | from sys import version_info | |
6 | ||
7 | from pyflakes import messages as m | |
8 | from pyflakes.test.harness import TestCase, skip, skipIf | |
9 | ||
10 | ||
11 | class Test(TestCase): | |
12 | ||
13 | def test_duplicateArgs(self): | |
14 | self.flakes('def fu(bar, bar): pass', m.DuplicateArgument) | |
15 | ||
16 | def test_localReferencedBeforeAssignment(self): | |
17 | self.flakes(''' | |
18 | a = 1 | |
19 | def f(): | |
20 | a; a=1 | |
21 | f() | |
22 | ''', m.UndefinedLocal, m.UnusedVariable) | |
23 | ||
24 | def test_redefinedInGenerator(self): | |
25 | """ | |
26 | Test that reusing a variable in a generator does not raise | |
27 | a warning. | |
28 | """ | |
29 | self.flakes(''' | |
30 | a = 1 | |
31 | (1 for a, b in [(1, 2)]) | |
32 | ''') | |
33 | self.flakes(''' | |
34 | class A: | |
35 | a = 1 | |
36 | list(1 for a, b in [(1, 2)]) | |
37 | ''') | |
38 | self.flakes(''' | |
39 | def f(): | |
40 | a = 1 | |
41 | (1 for a, b in [(1, 2)]) | |
42 | ''', m.UnusedVariable) | |
43 | self.flakes(''' | |
44 | (1 for a, b in [(1, 2)]) | |
45 | (1 for a, b in [(1, 2)]) | |
46 | ''') | |
47 | self.flakes(''' | |
48 | for a, b in [(1, 2)]: | |
49 | pass | |
50 | (1 for a, b in [(1, 2)]) | |
51 | ''') | |
52 | ||
53 | def test_redefinedInSetComprehension(self): | |
54 | """ | |
55 | Test that reusing a variable in a set comprehension does not raise | |
56 | a warning. | |
57 | """ | |
58 | self.flakes(''' | |
59 | a = 1 | |
60 | {1 for a, b in [(1, 2)]} | |
61 | ''') | |
62 | self.flakes(''' | |
63 | class A: | |
64 | a = 1 | |
65 | {1 for a, b in [(1, 2)]} | |
66 | ''') | |
67 | self.flakes(''' | |
68 | def f(): | |
69 | a = 1 | |
70 | {1 for a, b in [(1, 2)]} | |
71 | ''', m.UnusedVariable) | |
72 | self.flakes(''' | |
73 | {1 for a, b in [(1, 2)]} | |
74 | {1 for a, b in [(1, 2)]} | |
75 | ''') | |
76 | self.flakes(''' | |
77 | for a, b in [(1, 2)]: | |
78 | pass | |
79 | {1 for a, b in [(1, 2)]} | |
80 | ''') | |
81 | ||
82 | def test_redefinedInDictComprehension(self): | |
83 | """ | |
84 | Test that reusing a variable in a dict comprehension does not raise | |
85 | a warning. | |
86 | """ | |
87 | self.flakes(''' | |
88 | a = 1 | |
89 | {1: 42 for a, b in [(1, 2)]} | |
90 | ''') | |
91 | self.flakes(''' | |
92 | class A: | |
93 | a = 1 | |
94 | {1: 42 for a, b in [(1, 2)]} | |
95 | ''') | |
96 | self.flakes(''' | |
97 | def f(): | |
98 | a = 1 | |
99 | {1: 42 for a, b in [(1, 2)]} | |
100 | ''', m.UnusedVariable) | |
101 | self.flakes(''' | |
102 | {1: 42 for a, b in [(1, 2)]} | |
103 | {1: 42 for a, b in [(1, 2)]} | |
104 | ''') | |
105 | self.flakes(''' | |
106 | for a, b in [(1, 2)]: | |
107 | pass | |
108 | {1: 42 for a, b in [(1, 2)]} | |
109 | ''') | |
110 | ||
111 | def test_redefinedFunction(self): | |
112 | """ | |
113 | Test that shadowing a function definition with another one raises a | |
114 | warning. | |
115 | """ | |
116 | self.flakes(''' | |
117 | def a(): pass | |
118 | def a(): pass | |
119 | ''', m.RedefinedWhileUnused) | |
120 | ||
121 | def test_redefined_function_shadows_variable(self): | |
122 | self.flakes(''' | |
123 | x = 1 | |
124 | def x(): pass | |
125 | ''', m.RedefinedWhileUnused) | |
126 | ||
127 | def test_redefinedUnderscoreFunction(self): | |
128 | """ | |
129 | Test that shadowing a function definition named with underscore doesn't | |
130 | raise anything. | |
131 | """ | |
132 | self.flakes(''' | |
133 | def _(): pass | |
134 | def _(): pass | |
135 | ''') | |
136 | ||
137 | def test_redefinedUnderscoreImportation(self): | |
138 | """ | |
139 | Test that shadowing an underscore importation raises a warning. | |
140 | """ | |
141 | self.flakes(''' | |
142 | from .i18n import _ | |
143 | def _(): pass | |
144 | ''', m.RedefinedWhileUnused) | |
145 | ||
146 | def test_redefinedClassFunction(self): | |
147 | """ | |
148 | Test that shadowing a function definition in a class suite with another | |
149 | one raises a warning. | |
150 | """ | |
151 | self.flakes(''' | |
152 | class A: | |
153 | def a(): pass | |
154 | def a(): pass | |
155 | ''', m.RedefinedWhileUnused) | |
156 | ||
157 | def test_redefinedIfElseFunction(self): | |
158 | """ | |
159 | Test that shadowing a function definition twice in an if | |
160 | and else block does not raise a warning. | |
161 | """ | |
162 | self.flakes(''' | |
163 | if True: | |
164 | def a(): pass | |
165 | else: | |
166 | def a(): pass | |
167 | ''') | |
168 | ||
169 | def test_redefinedIfFunction(self): | |
170 | """ | |
171 | Test that shadowing a function definition within an if block | |
172 | raises a warning. | |
173 | """ | |
174 | self.flakes(''' | |
175 | if True: | |
176 | def a(): pass | |
177 | def a(): pass | |
178 | ''', m.RedefinedWhileUnused) | |
179 | ||
180 | def test_redefinedTryExceptFunction(self): | |
181 | """ | |
182 | Test that shadowing a function definition twice in try | |
183 | and except block does not raise a warning. | |
184 | """ | |
185 | self.flakes(''' | |
186 | try: | |
187 | def a(): pass | |
188 | except: | |
189 | def a(): pass | |
190 | ''') | |
191 | ||
192 | def test_redefinedTryFunction(self): | |
193 | """ | |
194 | Test that shadowing a function definition within a try block | |
195 | raises a warning. | |
196 | """ | |
197 | self.flakes(''' | |
198 | try: | |
199 | def a(): pass | |
200 | def a(): pass | |
201 | except: | |
202 | pass | |
203 | ''', m.RedefinedWhileUnused) | |
204 | ||
205 | def test_redefinedIfElseInListComp(self): | |
206 | """ | |
207 | Test that shadowing a variable in a list comprehension in | |
208 | an if and else block does not raise a warning. | |
209 | """ | |
210 | self.flakes(''' | |
211 | if False: | |
212 | a = 1 | |
213 | else: | |
214 | [a for a in '12'] | |
215 | ''') | |
216 | ||
217 | def test_functionDecorator(self): | |
218 | """ | |
219 | Test that shadowing a function definition with a decorated version of | |
220 | that function does not raise a warning. | |
221 | """ | |
222 | self.flakes(''' | |
223 | from somewhere import somedecorator | |
224 | ||
225 | def a(): pass | |
226 | a = somedecorator(a) | |
227 | ''') | |
228 | ||
229 | def test_classFunctionDecorator(self): | |
230 | """ | |
231 | Test that shadowing a function definition in a class suite with a | |
232 | decorated version of that function does not raise a warning. | |
233 | """ | |
234 | self.flakes(''' | |
235 | class A: | |
236 | def a(): pass | |
237 | a = classmethod(a) | |
238 | ''') | |
239 | ||
240 | def test_modernProperty(self): | |
241 | self.flakes(""" | |
242 | class A: | |
243 | @property | |
244 | def t(self): | |
245 | pass | |
246 | @t.setter | |
247 | def t(self, value): | |
248 | pass | |
249 | @t.deleter | |
250 | def t(self): | |
251 | pass | |
252 | """) | |
253 | ||
254 | def test_unaryPlus(self): | |
255 | """Don't die on unary +.""" | |
256 | self.flakes('+1') | |
257 | ||
258 | def test_undefinedBaseClass(self): | |
259 | """ | |
260 | If a name in the base list of a class definition is undefined, a | |
261 | warning is emitted. | |
262 | """ | |
263 | self.flakes(''' | |
264 | class foo(foo): | |
265 | pass | |
266 | ''', m.UndefinedName) | |
267 | ||
268 | def test_classNameUndefinedInClassBody(self): | |
269 | """ | |
270 | If a class name is used in the body of that class's definition and | |
271 | the name is not already defined, a warning is emitted. | |
272 | """ | |
273 | self.flakes(''' | |
274 | class foo: | |
275 | foo | |
276 | ''', m.UndefinedName) | |
277 | ||
278 | def test_classNameDefinedPreviously(self): | |
279 | """ | |
280 | If a class name is used in the body of that class's definition and | |
281 | the name was previously defined in some other way, no warning is | |
282 | emitted. | |
283 | """ | |
284 | self.flakes(''' | |
285 | foo = None | |
286 | class foo: | |
287 | foo | |
288 | ''') | |
289 | ||
290 | def test_classRedefinition(self): | |
291 | """ | |
292 | If a class is defined twice in the same module, a warning is emitted. | |
293 | """ | |
294 | self.flakes(''' | |
295 | class Foo: | |
296 | pass | |
297 | class Foo: | |
298 | pass | |
299 | ''', m.RedefinedWhileUnused) | |
300 | ||
301 | def test_functionRedefinedAsClass(self): | |
302 | """ | |
303 | If a function is redefined as a class, a warning is emitted. | |
304 | """ | |
305 | self.flakes(''' | |
306 | def Foo(): | |
307 | pass | |
308 | class Foo: | |
309 | pass | |
310 | ''', m.RedefinedWhileUnused) | |
311 | ||
312 | def test_classRedefinedAsFunction(self): | |
313 | """ | |
314 | If a class is redefined as a function, a warning is emitted. | |
315 | """ | |
316 | self.flakes(''' | |
317 | class Foo: | |
318 | pass | |
319 | def Foo(): | |
320 | pass | |
321 | ''', m.RedefinedWhileUnused) | |
322 | ||
323 | def test_classWithReturn(self): | |
324 | """ | |
325 | If a return is used inside a class, a warning is emitted. | |
326 | """ | |
327 | self.flakes(''' | |
328 | class Foo(object): | |
329 | return | |
330 | ''', m.ReturnOutsideFunction) | |
331 | ||
332 | def test_moduleWithReturn(self): | |
333 | """ | |
334 | If a return is used at the module level, a warning is emitted. | |
335 | """ | |
336 | self.flakes(''' | |
337 | return | |
338 | ''', m.ReturnOutsideFunction) | |
339 | ||
340 | def test_classWithYield(self): | |
341 | """ | |
342 | If a yield is used inside a class, a warning is emitted. | |
343 | """ | |
344 | self.flakes(''' | |
345 | class Foo(object): | |
346 | yield | |
347 | ''', m.YieldOutsideFunction) | |
348 | ||
349 | def test_moduleWithYield(self): | |
350 | """ | |
351 | If a yield is used at the module level, a warning is emitted. | |
352 | """ | |
353 | self.flakes(''' | |
354 | yield | |
355 | ''', m.YieldOutsideFunction) | |
356 | ||
357 | def test_classWithYieldFrom(self): | |
358 | """ | |
359 | If a yield from is used inside a class, a warning is emitted. | |
360 | """ | |
361 | self.flakes(''' | |
362 | class Foo(object): | |
363 | yield from range(10) | |
364 | ''', m.YieldOutsideFunction) | |
365 | ||
366 | def test_moduleWithYieldFrom(self): | |
367 | """ | |
368 | If a yield from is used at the module level, a warning is emitted. | |
369 | """ | |
370 | self.flakes(''' | |
371 | yield from range(10) | |
372 | ''', m.YieldOutsideFunction) | |
373 | ||
374 | def test_continueOutsideLoop(self): | |
375 | self.flakes(''' | |
376 | continue | |
377 | ''', m.ContinueOutsideLoop) | |
378 | ||
379 | self.flakes(''' | |
380 | def f(): | |
381 | continue | |
382 | ''', m.ContinueOutsideLoop) | |
383 | ||
384 | self.flakes(''' | |
385 | while True: | |
386 | pass | |
387 | else: | |
388 | continue | |
389 | ''', m.ContinueOutsideLoop) | |
390 | ||
391 | self.flakes(''' | |
392 | while True: | |
393 | pass | |
394 | else: | |
395 | if 1: | |
396 | if 2: | |
397 | continue | |
398 | ''', m.ContinueOutsideLoop) | |
399 | ||
400 | self.flakes(''' | |
401 | while True: | |
402 | def f(): | |
403 | continue | |
404 | ''', m.ContinueOutsideLoop) | |
405 | ||
406 | self.flakes(''' | |
407 | while True: | |
408 | class A: | |
409 | continue | |
410 | ''', m.ContinueOutsideLoop) | |
411 | ||
412 | def test_continueInsideLoop(self): | |
413 | self.flakes(''' | |
414 | while True: | |
415 | continue | |
416 | ''') | |
417 | ||
418 | self.flakes(''' | |
419 | for i in range(10): | |
420 | continue | |
421 | ''') | |
422 | ||
423 | self.flakes(''' | |
424 | while True: | |
425 | if 1: | |
426 | continue | |
427 | ''') | |
428 | ||
429 | self.flakes(''' | |
430 | for i in range(10): | |
431 | if 1: | |
432 | continue | |
433 | ''') | |
434 | ||
435 | self.flakes(''' | |
436 | while True: | |
437 | while True: | |
438 | pass | |
439 | else: | |
440 | continue | |
441 | else: | |
442 | pass | |
443 | ''') | |
444 | ||
445 | self.flakes(''' | |
446 | while True: | |
447 | try: | |
448 | pass | |
449 | finally: | |
450 | while True: | |
451 | continue | |
452 | ''') | |
453 | ||
454 | def test_breakOutsideLoop(self): | |
455 | self.flakes(''' | |
456 | break | |
457 | ''', m.BreakOutsideLoop) | |
458 | ||
459 | self.flakes(''' | |
460 | def f(): | |
461 | break | |
462 | ''', m.BreakOutsideLoop) | |
463 | ||
464 | self.flakes(''' | |
465 | while True: | |
466 | pass | |
467 | else: | |
468 | break | |
469 | ''', m.BreakOutsideLoop) | |
470 | ||
471 | self.flakes(''' | |
472 | while True: | |
473 | pass | |
474 | else: | |
475 | if 1: | |
476 | if 2: | |
477 | break | |
478 | ''', m.BreakOutsideLoop) | |
479 | ||
480 | self.flakes(''' | |
481 | while True: | |
482 | def f(): | |
483 | break | |
484 | ''', m.BreakOutsideLoop) | |
485 | ||
486 | self.flakes(''' | |
487 | while True: | |
488 | class A: | |
489 | break | |
490 | ''', m.BreakOutsideLoop) | |
491 | ||
492 | self.flakes(''' | |
493 | try: | |
494 | pass | |
495 | finally: | |
496 | break | |
497 | ''', m.BreakOutsideLoop) | |
498 | ||
499 | def test_breakInsideLoop(self): | |
500 | self.flakes(''' | |
501 | while True: | |
502 | break | |
503 | ''') | |
504 | ||
505 | self.flakes(''' | |
506 | for i in range(10): | |
507 | break | |
508 | ''') | |
509 | ||
510 | self.flakes(''' | |
511 | while True: | |
512 | if 1: | |
513 | break | |
514 | ''') | |
515 | ||
516 | self.flakes(''' | |
517 | for i in range(10): | |
518 | if 1: | |
519 | break | |
520 | ''') | |
521 | ||
522 | self.flakes(''' | |
523 | while True: | |
524 | while True: | |
525 | pass | |
526 | else: | |
527 | break | |
528 | else: | |
529 | pass | |
530 | ''') | |
531 | ||
532 | self.flakes(''' | |
533 | while True: | |
534 | try: | |
535 | pass | |
536 | finally: | |
537 | while True: | |
538 | break | |
539 | ''') | |
540 | ||
541 | self.flakes(''' | |
542 | while True: | |
543 | try: | |
544 | pass | |
545 | finally: | |
546 | break | |
547 | ''') | |
548 | ||
549 | self.flakes(''' | |
550 | while True: | |
551 | try: | |
552 | pass | |
553 | finally: | |
554 | if 1: | |
555 | if 2: | |
556 | break | |
557 | ''') | |
558 | ||
559 | def test_defaultExceptLast(self): | |
560 | """ | |
561 | A default except block should be last. | |
562 | ||
563 | YES: | |
564 | ||
565 | try: | |
566 | ... | |
567 | except Exception: | |
568 | ... | |
569 | except: | |
570 | ... | |
571 | ||
572 | NO: | |
573 | ||
574 | try: | |
575 | ... | |
576 | except: | |
577 | ... | |
578 | except Exception: | |
579 | ... | |
580 | """ | |
581 | self.flakes(''' | |
582 | try: | |
583 | pass | |
584 | except ValueError: | |
585 | pass | |
586 | ''') | |
587 | ||
588 | self.flakes(''' | |
589 | try: | |
590 | pass | |
591 | except ValueError: | |
592 | pass | |
593 | except: | |
594 | pass | |
595 | ''') | |
596 | ||
597 | self.flakes(''' | |
598 | try: | |
599 | pass | |
600 | except: | |
601 | pass | |
602 | ''') | |
603 | ||
604 | self.flakes(''' | |
605 | try: | |
606 | pass | |
607 | except ValueError: | |
608 | pass | |
609 | else: | |
610 | pass | |
611 | ''') | |
612 | ||
613 | self.flakes(''' | |
614 | try: | |
615 | pass | |
616 | except: | |
617 | pass | |
618 | else: | |
619 | pass | |
620 | ''') | |
621 | ||
622 | self.flakes(''' | |
623 | try: | |
624 | pass | |
625 | except ValueError: | |
626 | pass | |
627 | except: | |
628 | pass | |
629 | else: | |
630 | pass | |
631 | ''') | |
632 | ||
633 | def test_defaultExceptNotLast(self): | |
634 | self.flakes(''' | |
635 | try: | |
636 | pass | |
637 | except: | |
638 | pass | |
639 | except ValueError: | |
640 | pass | |
641 | ''', m.DefaultExceptNotLast) | |
642 | ||
643 | self.flakes(''' | |
644 | try: | |
645 | pass | |
646 | except: | |
647 | pass | |
648 | except: | |
649 | pass | |
650 | ''', m.DefaultExceptNotLast) | |
651 | ||
652 | self.flakes(''' | |
653 | try: | |
654 | pass | |
655 | except: | |
656 | pass | |
657 | except ValueError: | |
658 | pass | |
659 | except: | |
660 | pass | |
661 | ''', m.DefaultExceptNotLast) | |
662 | ||
663 | self.flakes(''' | |
664 | try: | |
665 | pass | |
666 | except: | |
667 | pass | |
668 | except ValueError: | |
669 | pass | |
670 | except: | |
671 | pass | |
672 | except ValueError: | |
673 | pass | |
674 | ''', m.DefaultExceptNotLast, m.DefaultExceptNotLast) | |
675 | ||
676 | self.flakes(''' | |
677 | try: | |
678 | pass | |
679 | except: | |
680 | pass | |
681 | except ValueError: | |
682 | pass | |
683 | else: | |
684 | pass | |
685 | ''', m.DefaultExceptNotLast) | |
686 | ||
687 | self.flakes(''' | |
688 | try: | |
689 | pass | |
690 | except: | |
691 | pass | |
692 | except: | |
693 | pass | |
694 | else: | |
695 | pass | |
696 | ''', m.DefaultExceptNotLast) | |
697 | ||
698 | self.flakes(''' | |
699 | try: | |
700 | pass | |
701 | except: | |
702 | pass | |
703 | except ValueError: | |
704 | pass | |
705 | except: | |
706 | pass | |
707 | else: | |
708 | pass | |
709 | ''', m.DefaultExceptNotLast) | |
710 | ||
711 | self.flakes(''' | |
712 | try: | |
713 | pass | |
714 | except: | |
715 | pass | |
716 | except ValueError: | |
717 | pass | |
718 | except: | |
719 | pass | |
720 | except ValueError: | |
721 | pass | |
722 | else: | |
723 | pass | |
724 | ''', m.DefaultExceptNotLast, m.DefaultExceptNotLast) | |
725 | ||
726 | self.flakes(''' | |
727 | try: | |
728 | pass | |
729 | except: | |
730 | pass | |
731 | except ValueError: | |
732 | pass | |
733 | finally: | |
734 | pass | |
735 | ''', m.DefaultExceptNotLast) | |
736 | ||
737 | self.flakes(''' | |
738 | try: | |
739 | pass | |
740 | except: | |
741 | pass | |
742 | except: | |
743 | pass | |
744 | finally: | |
745 | pass | |
746 | ''', m.DefaultExceptNotLast) | |
747 | ||
748 | self.flakes(''' | |
749 | try: | |
750 | pass | |
751 | except: | |
752 | pass | |
753 | except ValueError: | |
754 | pass | |
755 | except: | |
756 | pass | |
757 | finally: | |
758 | pass | |
759 | ''', m.DefaultExceptNotLast) | |
760 | ||
761 | self.flakes(''' | |
762 | try: | |
763 | pass | |
764 | except: | |
765 | pass | |
766 | except ValueError: | |
767 | pass | |
768 | except: | |
769 | pass | |
770 | except ValueError: | |
771 | pass | |
772 | finally: | |
773 | pass | |
774 | ''', m.DefaultExceptNotLast, m.DefaultExceptNotLast) | |
775 | ||
776 | self.flakes(''' | |
777 | try: | |
778 | pass | |
779 | except: | |
780 | pass | |
781 | except ValueError: | |
782 | pass | |
783 | else: | |
784 | pass | |
785 | finally: | |
786 | pass | |
787 | ''', m.DefaultExceptNotLast) | |
788 | ||
789 | self.flakes(''' | |
790 | try: | |
791 | pass | |
792 | except: | |
793 | pass | |
794 | except: | |
795 | pass | |
796 | else: | |
797 | pass | |
798 | finally: | |
799 | pass | |
800 | ''', m.DefaultExceptNotLast) | |
801 | ||
802 | self.flakes(''' | |
803 | try: | |
804 | pass | |
805 | except: | |
806 | pass | |
807 | except ValueError: | |
808 | pass | |
809 | except: | |
810 | pass | |
811 | else: | |
812 | pass | |
813 | finally: | |
814 | pass | |
815 | ''', m.DefaultExceptNotLast) | |
816 | ||
817 | self.flakes(''' | |
818 | try: | |
819 | pass | |
820 | except: | |
821 | pass | |
822 | except ValueError: | |
823 | pass | |
824 | except: | |
825 | pass | |
826 | except ValueError: | |
827 | pass | |
828 | else: | |
829 | pass | |
830 | finally: | |
831 | pass | |
832 | ''', m.DefaultExceptNotLast, m.DefaultExceptNotLast) | |
833 | ||
834 | def test_starredAssignmentNoError(self): | |
835 | """ | |
836 | Python 3 extended iterable unpacking | |
837 | """ | |
838 | self.flakes(''' | |
839 | a, *b = range(10) | |
840 | ''') | |
841 | ||
842 | self.flakes(''' | |
843 | *a, b = range(10) | |
844 | ''') | |
845 | ||
846 | self.flakes(''' | |
847 | a, *b, c = range(10) | |
848 | ''') | |
849 | ||
850 | self.flakes(''' | |
851 | (a, *b) = range(10) | |
852 | ''') | |
853 | ||
854 | self.flakes(''' | |
855 | (*a, b) = range(10) | |
856 | ''') | |
857 | ||
858 | self.flakes(''' | |
859 | (a, *b, c) = range(10) | |
860 | ''') | |
861 | ||
862 | self.flakes(''' | |
863 | [a, *b] = range(10) | |
864 | ''') | |
865 | ||
866 | self.flakes(''' | |
867 | [*a, b] = range(10) | |
868 | ''') | |
869 | ||
870 | self.flakes(''' | |
871 | [a, *b, c] = range(10) | |
872 | ''') | |
873 | ||
874 | # Taken from test_unpack_ex.py in the cPython source | |
875 | s = ", ".join("a%d" % i for i in range(1 << 8 - 1)) + \ | |
876 | ", *rest = range(1<<8)" | |
877 | self.flakes(s) | |
878 | ||
879 | s = "(" + ", ".join("a%d" % i for i in range(1 << 8 - 1)) + \ | |
880 | ", *rest) = range(1<<8)" | |
881 | self.flakes(s) | |
882 | ||
883 | s = "[" + ", ".join("a%d" % i for i in range(1 << 8 - 1)) + \ | |
884 | ", *rest] = range(1<<8)" | |
885 | self.flakes(s) | |
886 | ||
887 | def test_starredAssignmentErrors(self): | |
888 | """ | |
889 | SyntaxErrors (not encoded in the ast) surrounding Python 3 extended | |
890 | iterable unpacking | |
891 | """ | |
892 | # Taken from test_unpack_ex.py in the cPython source | |
893 | s = ", ".join("a%d" % i for i in range(1 << 8)) + \ | |
894 | ", *rest = range(1<<8 + 1)" | |
895 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
896 | ||
897 | s = "(" + ", ".join("a%d" % i for i in range(1 << 8)) + \ | |
898 | ", *rest) = range(1<<8 + 1)" | |
899 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
900 | ||
901 | s = "[" + ", ".join("a%d" % i for i in range(1 << 8)) + \ | |
902 | ", *rest] = range(1<<8 + 1)" | |
903 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
904 | ||
905 | s = ", ".join("a%d" % i for i in range(1 << 8 + 1)) + \ | |
906 | ", *rest = range(1<<8 + 2)" | |
907 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
908 | ||
909 | s = "(" + ", ".join("a%d" % i for i in range(1 << 8 + 1)) + \ | |
910 | ", *rest) = range(1<<8 + 2)" | |
911 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
912 | ||
913 | s = "[" + ", ".join("a%d" % i for i in range(1 << 8 + 1)) + \ | |
914 | ", *rest] = range(1<<8 + 2)" | |
915 | self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
916 | ||
917 | # No way we can actually test this! | |
918 | # s = "*rest, " + ", ".join("a%d" % i for i in range(1<<24)) + \ | |
919 | # ", *rest = range(1<<24 + 1)" | |
920 | # self.flakes(s, m.TooManyExpressionsInStarredAssignment) | |
921 | ||
922 | self.flakes(''' | |
923 | a, *b, *c = range(10) | |
924 | ''', m.TwoStarredExpressions) | |
925 | ||
926 | self.flakes(''' | |
927 | a, *b, c, *d = range(10) | |
928 | ''', m.TwoStarredExpressions) | |
929 | ||
930 | self.flakes(''' | |
931 | *a, *b, *c = range(10) | |
932 | ''', m.TwoStarredExpressions) | |
933 | ||
934 | self.flakes(''' | |
935 | (a, *b, *c) = range(10) | |
936 | ''', m.TwoStarredExpressions) | |
937 | ||
938 | self.flakes(''' | |
939 | (a, *b, c, *d) = range(10) | |
940 | ''', m.TwoStarredExpressions) | |
941 | ||
942 | self.flakes(''' | |
943 | (*a, *b, *c) = range(10) | |
944 | ''', m.TwoStarredExpressions) | |
945 | ||
946 | self.flakes(''' | |
947 | [a, *b, *c] = range(10) | |
948 | ''', m.TwoStarredExpressions) | |
949 | ||
950 | self.flakes(''' | |
951 | [a, *b, c, *d] = range(10) | |
952 | ''', m.TwoStarredExpressions) | |
953 | ||
954 | self.flakes(''' | |
955 | [*a, *b, *c] = range(10) | |
956 | ''', m.TwoStarredExpressions) | |
957 | ||
958 | @skip("todo: Too hard to make this warn but other cases stay silent") | |
959 | def test_doubleAssignment(self): | |
960 | """ | |
961 | If a variable is re-assigned to without being used, no warning is | |
962 | emitted. | |
963 | """ | |
964 | self.flakes(''' | |
965 | x = 10 | |
966 | x = 20 | |
967 | ''', m.RedefinedWhileUnused) | |
968 | ||
969 | def test_doubleAssignmentConditionally(self): | |
970 | """ | |
971 | If a variable is re-assigned within a conditional, no warning is | |
972 | emitted. | |
973 | """ | |
974 | self.flakes(''' | |
975 | x = 10 | |
976 | if True: | |
977 | x = 20 | |
978 | ''') | |
979 | ||
980 | def test_doubleAssignmentWithUse(self): | |
981 | """ | |
982 | If a variable is re-assigned to after being used, no warning is | |
983 | emitted. | |
984 | """ | |
985 | self.flakes(''' | |
986 | x = 10 | |
987 | y = x * 2 | |
988 | x = 20 | |
989 | ''') | |
990 | ||
991 | def test_comparison(self): | |
992 | """ | |
993 | If a defined name is used on either side of any of the six comparison | |
994 | operators, no warning is emitted. | |
995 | """ | |
996 | self.flakes(''' | |
997 | x = 10 | |
998 | y = 20 | |
999 | x < y | |
1000 | x <= y | |
1001 | x == y | |
1002 | x != y | |
1003 | x >= y | |
1004 | x > y | |
1005 | ''') | |
1006 | ||
1007 | def test_identity(self): | |
1008 | """ | |
1009 | If a defined name is used on either side of an identity test, no | |
1010 | warning is emitted. | |
1011 | """ | |
1012 | self.flakes(''' | |
1013 | x = 10 | |
1014 | y = 20 | |
1015 | x is y | |
1016 | x is not y | |
1017 | ''') | |
1018 | ||
1019 | def test_containment(self): | |
1020 | """ | |
1021 | If a defined name is used on either side of a containment test, no | |
1022 | warning is emitted. | |
1023 | """ | |
1024 | self.flakes(''' | |
1025 | x = 10 | |
1026 | y = 20 | |
1027 | x in y | |
1028 | x not in y | |
1029 | ''') | |
1030 | ||
1031 | def test_loopControl(self): | |
1032 | """ | |
1033 | break and continue statements are supported. | |
1034 | """ | |
1035 | self.flakes(''' | |
1036 | for x in [1, 2]: | |
1037 | break | |
1038 | ''') | |
1039 | self.flakes(''' | |
1040 | for x in [1, 2]: | |
1041 | continue | |
1042 | ''') | |
1043 | ||
1044 | def test_ellipsis(self): | |
1045 | """ | |
1046 | Ellipsis in a slice is supported. | |
1047 | """ | |
1048 | self.flakes(''' | |
1049 | [1, 2][...] | |
1050 | ''') | |
1051 | ||
1052 | def test_extendedSlice(self): | |
1053 | """ | |
1054 | Extended slices are supported. | |
1055 | """ | |
1056 | self.flakes(''' | |
1057 | x = 3 | |
1058 | [1, 2][x,:] | |
1059 | ''') | |
1060 | ||
1061 | def test_varAugmentedAssignment(self): | |
1062 | """ | |
1063 | Augmented assignment of a variable is supported. | |
1064 | We don't care about var refs. | |
1065 | """ | |
1066 | self.flakes(''' | |
1067 | foo = 0 | |
1068 | foo += 1 | |
1069 | ''') | |
1070 | ||
1071 | def test_attrAugmentedAssignment(self): | |
1072 | """ | |
1073 | Augmented assignment of attributes is supported. | |
1074 | We don't care about attr refs. | |
1075 | """ | |
1076 | self.flakes(''' | |
1077 | foo = None | |
1078 | foo.bar += foo.baz | |
1079 | ''') | |
1080 | ||
1081 | def test_globalDeclaredInDifferentScope(self): | |
1082 | """ | |
1083 | A 'global' can be declared in one scope and reused in another. | |
1084 | """ | |
1085 | self.flakes(''' | |
1086 | def f(): global foo | |
1087 | def g(): foo = 'anything'; foo.is_used() | |
1088 | ''') | |
1089 | ||
1090 | def test_function_arguments(self): | |
1091 | """ | |
1092 | Test to traverse ARG and ARGUMENT handler | |
1093 | """ | |
1094 | self.flakes(''' | |
1095 | def foo(a, b): | |
1096 | pass | |
1097 | ''') | |
1098 | ||
1099 | self.flakes(''' | |
1100 | def foo(a, b, c=0): | |
1101 | pass | |
1102 | ''') | |
1103 | ||
1104 | self.flakes(''' | |
1105 | def foo(a, b, c=0, *args): | |
1106 | pass | |
1107 | ''') | |
1108 | ||
1109 | self.flakes(''' | |
1110 | def foo(a, b, c=0, *args, **kwargs): | |
1111 | pass | |
1112 | ''') | |
1113 | ||
1114 | def test_function_arguments_python3(self): | |
1115 | self.flakes(''' | |
1116 | def foo(a, b, c=0, *args, d=0, **kwargs): | |
1117 | pass | |
1118 | ''') | |
1119 | ||
1120 | ||
1121 | class TestUnusedAssignment(TestCase): | |
1122 | """ | |
1123 | Tests for warning about unused assignments. | |
1124 | """ | |
1125 | ||
1126 | def test_unusedVariable(self): | |
1127 | """ | |
1128 | Warn when a variable in a function is assigned a value that's never | |
1129 | used. | |
1130 | """ | |
1131 | self.flakes(''' | |
1132 | def a(): | |
1133 | b = 1 | |
1134 | ''', m.UnusedVariable) | |
1135 | ||
1136 | def test_unusedUnderscoreVariable(self): | |
1137 | """ | |
1138 | Don't warn when the magic "_" (underscore) variable is unused. | |
1139 | See issue #202. | |
1140 | """ | |
1141 | self.flakes(''' | |
1142 | def a(unused_param): | |
1143 | _ = unused_param | |
1144 | ''') | |
1145 | ||
1146 | def test_unusedVariableAsLocals(self): | |
1147 | """ | |
1148 | Using locals() it is perfectly valid to have unused variables | |
1149 | """ | |
1150 | self.flakes(''' | |
1151 | def a(): | |
1152 | b = 1 | |
1153 | return locals() | |
1154 | ''') | |
1155 | ||
1156 | def test_unusedVariableNoLocals(self): | |
1157 | """ | |
1158 | Using locals() in wrong scope should not matter | |
1159 | """ | |
1160 | self.flakes(''' | |
1161 | def a(): | |
1162 | locals() | |
1163 | def a(): | |
1164 | b = 1 | |
1165 | return | |
1166 | ''', m.UnusedVariable) | |
1167 | ||
1168 | @skip("todo: Difficult because it doesn't apply in the context of a loop") | |
1169 | def test_unusedReassignedVariable(self): | |
1170 | """ | |
1171 | Shadowing a used variable can still raise an UnusedVariable warning. | |
1172 | """ | |
1173 | self.flakes(''' | |
1174 | def a(): | |
1175 | b = 1 | |
1176 | b.foo() | |
1177 | b = 2 | |
1178 | ''', m.UnusedVariable) | |
1179 | ||
1180 | def test_variableUsedInLoop(self): | |
1181 | """ | |
1182 | Shadowing a used variable cannot raise an UnusedVariable warning in the | |
1183 | context of a loop. | |
1184 | """ | |
1185 | self.flakes(''' | |
1186 | def a(): | |
1187 | b = True | |
1188 | while b: | |
1189 | b = False | |
1190 | ''') | |
1191 | ||
1192 | def test_assignToGlobal(self): | |
1193 | """ | |
1194 | Assigning to a global and then not using that global is perfectly | |
1195 | acceptable. Do not mistake it for an unused local variable. | |
1196 | """ | |
1197 | self.flakes(''' | |
1198 | b = 0 | |
1199 | def a(): | |
1200 | global b | |
1201 | b = 1 | |
1202 | ''') | |
1203 | ||
1204 | def test_assignToNonlocal(self): | |
1205 | """ | |
1206 | Assigning to a nonlocal and then not using that binding is perfectly | |
1207 | acceptable. Do not mistake it for an unused local variable. | |
1208 | """ | |
1209 | self.flakes(''' | |
1210 | b = b'0' | |
1211 | def a(): | |
1212 | nonlocal b | |
1213 | b = b'1' | |
1214 | ''') | |
1215 | ||
1216 | def test_assignToMember(self): | |
1217 | """ | |
1218 | Assigning to a member of another object and then not using that member | |
1219 | variable is perfectly acceptable. Do not mistake it for an unused | |
1220 | local variable. | |
1221 | """ | |
1222 | # XXX: Adding this test didn't generate a failure. Maybe not | |
1223 | # necessary? | |
1224 | self.flakes(''' | |
1225 | class b: | |
1226 | pass | |
1227 | def a(): | |
1228 | b.foo = 1 | |
1229 | ''') | |
1230 | ||
1231 | def test_assignInForLoop(self): | |
1232 | """ | |
1233 | Don't warn when a variable in a for loop is assigned to but not used. | |
1234 | """ | |
1235 | self.flakes(''' | |
1236 | def f(): | |
1237 | for i in range(10): | |
1238 | pass | |
1239 | ''') | |
1240 | ||
1241 | def test_assignInListComprehension(self): | |
1242 | """ | |
1243 | Don't warn when a variable in a list comprehension is | |
1244 | assigned to but not used. | |
1245 | """ | |
1246 | self.flakes(''' | |
1247 | def f(): | |
1248 | [None for i in range(10)] | |
1249 | ''') | |
1250 | ||
1251 | def test_generatorExpression(self): | |
1252 | """ | |
1253 | Don't warn when a variable in a generator expression is | |
1254 | assigned to but not used. | |
1255 | """ | |
1256 | self.flakes(''' | |
1257 | def f(): | |
1258 | (None for i in range(10)) | |
1259 | ''') | |
1260 | ||
1261 | def test_assignmentInsideLoop(self): | |
1262 | """ | |
1263 | Don't warn when a variable assignment occurs lexically after its use. | |
1264 | """ | |
1265 | self.flakes(''' | |
1266 | def f(): | |
1267 | x = None | |
1268 | for i in range(10): | |
1269 | if i > 2: | |
1270 | return x | |
1271 | x = i * 2 | |
1272 | ''') | |
1273 | ||
1274 | def test_tupleUnpacking(self): | |
1275 | """ | |
1276 | Don't warn when a variable included in tuple unpacking is unused. It's | |
1277 | very common for variables in a tuple unpacking assignment to be unused | |
1278 | in good Python code, so warning will only create false positives. | |
1279 | """ | |
1280 | self.flakes(''' | |
1281 | def f(tup): | |
1282 | (x, y) = tup | |
1283 | ''') | |
1284 | self.flakes(''' | |
1285 | def f(): | |
1286 | (x, y) = 1, 2 | |
1287 | ''', m.UnusedVariable, m.UnusedVariable) | |
1288 | self.flakes(''' | |
1289 | def f(): | |
1290 | (x, y) = coords = 1, 2 | |
1291 | if x > 1: | |
1292 | print(coords) | |
1293 | ''') | |
1294 | self.flakes(''' | |
1295 | def f(): | |
1296 | (x, y) = coords = 1, 2 | |
1297 | ''', m.UnusedVariable) | |
1298 | self.flakes(''' | |
1299 | def f(): | |
1300 | coords = (x, y) = 1, 2 | |
1301 | ''', m.UnusedVariable) | |
1302 | ||
1303 | def test_listUnpacking(self): | |
1304 | """ | |
1305 | Don't warn when a variable included in list unpacking is unused. | |
1306 | """ | |
1307 | self.flakes(''' | |
1308 | def f(tup): | |
1309 | [x, y] = tup | |
1310 | ''') | |
1311 | self.flakes(''' | |
1312 | def f(): | |
1313 | [x, y] = [1, 2] | |
1314 | ''', m.UnusedVariable, m.UnusedVariable) | |
1315 | ||
1316 | def test_closedOver(self): | |
1317 | """ | |
1318 | Don't warn when the assignment is used in an inner function. | |
1319 | """ | |
1320 | self.flakes(''' | |
1321 | def barMaker(): | |
1322 | foo = 5 | |
1323 | def bar(): | |
1324 | return foo | |
1325 | return bar | |
1326 | ''') | |
1327 | ||
1328 | def test_doubleClosedOver(self): | |
1329 | """ | |
1330 | Don't warn when the assignment is used in an inner function, even if | |
1331 | that inner function itself is in an inner function. | |
1332 | """ | |
1333 | self.flakes(''' | |
1334 | def barMaker(): | |
1335 | foo = 5 | |
1336 | def bar(): | |
1337 | def baz(): | |
1338 | return foo | |
1339 | return bar | |
1340 | ''') | |
1341 | ||
1342 | def test_tracebackhideSpecialVariable(self): | |
1343 | """ | |
1344 | Do not warn about unused local variable __tracebackhide__, which is | |
1345 | a special variable for py.test. | |
1346 | """ | |
1347 | self.flakes(""" | |
1348 | def helper(): | |
1349 | __tracebackhide__ = True | |
1350 | """) | |
1351 | ||
1352 | def test_ifexp(self): | |
1353 | """ | |
1354 | Test C{foo if bar else baz} statements. | |
1355 | """ | |
1356 | self.flakes("a = 'moo' if True else 'oink'") | |
1357 | self.flakes("a = foo if True else 'oink'", m.UndefinedName) | |
1358 | self.flakes("a = 'moo' if True else bar", m.UndefinedName) | |
1359 | ||
1360 | def test_if_tuple(self): | |
1361 | """ | |
1362 | Test C{if (foo,)} conditions. | |
1363 | """ | |
1364 | self.flakes("""if (): pass""") | |
1365 | self.flakes(""" | |
1366 | if ( | |
1367 | True | |
1368 | ): | |
1369 | pass | |
1370 | """) | |
1371 | self.flakes(""" | |
1372 | if ( | |
1373 | True, | |
1374 | ): | |
1375 | pass | |
1376 | """, m.IfTuple) | |
1377 | self.flakes(""" | |
1378 | x = 1 if ( | |
1379 | True, | |
1380 | ) else 2 | |
1381 | """, m.IfTuple) | |
1382 | ||
1383 | def test_withStatementNoNames(self): | |
1384 | """ | |
1385 | No warnings are emitted for using inside or after a nameless C{with} | |
1386 | statement a name defined beforehand. | |
1387 | """ | |
1388 | self.flakes(''' | |
1389 | bar = None | |
1390 | with open("foo"): | |
1391 | bar | |
1392 | bar | |
1393 | ''') | |
1394 | ||
1395 | def test_withStatementSingleName(self): | |
1396 | """ | |
1397 | No warnings are emitted for using a name defined by a C{with} statement | |
1398 | within the suite or afterwards. | |
1399 | """ | |
1400 | self.flakes(''' | |
1401 | with open('foo') as bar: | |
1402 | bar | |
1403 | bar | |
1404 | ''') | |
1405 | ||
1406 | def test_withStatementAttributeName(self): | |
1407 | """ | |
1408 | No warnings are emitted for using an attribute as the target of a | |
1409 | C{with} statement. | |
1410 | """ | |
1411 | self.flakes(''' | |
1412 | import foo | |
1413 | with open('foo') as foo.bar: | |
1414 | pass | |
1415 | ''') | |
1416 | ||
1417 | def test_withStatementSubscript(self): | |
1418 | """ | |
1419 | No warnings are emitted for using a subscript as the target of a | |
1420 | C{with} statement. | |
1421 | """ | |
1422 | self.flakes(''' | |
1423 | import foo | |
1424 | with open('foo') as foo[0]: | |
1425 | pass | |
1426 | ''') | |
1427 | ||
1428 | def test_withStatementSubscriptUndefined(self): | |
1429 | """ | |
1430 | An undefined name warning is emitted if the subscript used as the | |
1431 | target of a C{with} statement is not defined. | |
1432 | """ | |
1433 | self.flakes(''' | |
1434 | import foo | |
1435 | with open('foo') as foo[bar]: | |
1436 | pass | |
1437 | ''', m.UndefinedName) | |
1438 | ||
1439 | def test_withStatementTupleNames(self): | |
1440 | """ | |
1441 | No warnings are emitted for using any of the tuple of names defined by | |
1442 | a C{with} statement within the suite or afterwards. | |
1443 | """ | |
1444 | self.flakes(''' | |
1445 | with open('foo') as (bar, baz): | |
1446 | bar, baz | |
1447 | bar, baz | |
1448 | ''') | |
1449 | ||
1450 | def test_withStatementListNames(self): | |
1451 | """ | |
1452 | No warnings are emitted for using any of the list of names defined by a | |
1453 | C{with} statement within the suite or afterwards. | |
1454 | """ | |
1455 | self.flakes(''' | |
1456 | with open('foo') as [bar, baz]: | |
1457 | bar, baz | |
1458 | bar, baz | |
1459 | ''') | |
1460 | ||
1461 | def test_withStatementComplicatedTarget(self): | |
1462 | """ | |
1463 | If the target of a C{with} statement uses any or all of the valid forms | |
1464 | for that part of the grammar (See | |
1465 | U{http://docs.python.org/reference/compound_stmts.html#the-with-statement}), | |
1466 | the names involved are checked both for definedness and any bindings | |
1467 | created are respected in the suite of the statement and afterwards. | |
1468 | """ | |
1469 | self.flakes(''' | |
1470 | c = d = e = g = h = i = None | |
1471 | with open('foo') as [(a, b), c[d], e.f, g[h:i]]: | |
1472 | a, b, c, d, e, g, h, i | |
1473 | a, b, c, d, e, g, h, i | |
1474 | ''') | |
1475 | ||
1476 | def test_withStatementSingleNameUndefined(self): | |
1477 | """ | |
1478 | An undefined name warning is emitted if the name first defined by a | |
1479 | C{with} statement is used before the C{with} statement. | |
1480 | """ | |
1481 | self.flakes(''' | |
1482 | bar | |
1483 | with open('foo') as bar: | |
1484 | pass | |
1485 | ''', m.UndefinedName) | |
1486 | ||
1487 | def test_withStatementTupleNamesUndefined(self): | |
1488 | """ | |
1489 | An undefined name warning is emitted if a name first defined by the | |
1490 | tuple-unpacking form of the C{with} statement is used before the | |
1491 | C{with} statement. | |
1492 | """ | |
1493 | self.flakes(''' | |
1494 | baz | |
1495 | with open('foo') as (bar, baz): | |
1496 | pass | |
1497 | ''', m.UndefinedName) | |
1498 | ||
1499 | def test_withStatementSingleNameRedefined(self): | |
1500 | """ | |
1501 | A redefined name warning is emitted if a name bound by an import is | |
1502 | rebound by the name defined by a C{with} statement. | |
1503 | """ | |
1504 | self.flakes(''' | |
1505 | import bar | |
1506 | with open('foo') as bar: | |
1507 | pass | |
1508 | ''', m.RedefinedWhileUnused) | |
1509 | ||
1510 | def test_withStatementTupleNamesRedefined(self): | |
1511 | """ | |
1512 | A redefined name warning is emitted if a name bound by an import is | |
1513 | rebound by one of the names defined by the tuple-unpacking form of a | |
1514 | C{with} statement. | |
1515 | """ | |
1516 | self.flakes(''' | |
1517 | import bar | |
1518 | with open('foo') as (bar, baz): | |
1519 | pass | |
1520 | ''', m.RedefinedWhileUnused) | |
1521 | ||
1522 | def test_withStatementUndefinedInside(self): | |
1523 | """ | |
1524 | An undefined name warning is emitted if a name is used inside the | |
1525 | body of a C{with} statement without first being bound. | |
1526 | """ | |
1527 | self.flakes(''' | |
1528 | with open('foo') as bar: | |
1529 | baz | |
1530 | ''', m.UndefinedName) | |
1531 | ||
1532 | def test_withStatementNameDefinedInBody(self): | |
1533 | """ | |
1534 | A name defined in the body of a C{with} statement can be used after | |
1535 | the body ends without warning. | |
1536 | """ | |
1537 | self.flakes(''' | |
1538 | with open('foo') as bar: | |
1539 | baz = 10 | |
1540 | baz | |
1541 | ''') | |
1542 | ||
1543 | def test_withStatementUndefinedInExpression(self): | |
1544 | """ | |
1545 | An undefined name warning is emitted if a name in the I{test} | |
1546 | expression of a C{with} statement is undefined. | |
1547 | """ | |
1548 | self.flakes(''' | |
1549 | with bar as baz: | |
1550 | pass | |
1551 | ''', m.UndefinedName) | |
1552 | ||
1553 | self.flakes(''' | |
1554 | with bar as bar: | |
1555 | pass | |
1556 | ''', m.UndefinedName) | |
1557 | ||
1558 | def test_dictComprehension(self): | |
1559 | """ | |
1560 | Dict comprehensions are properly handled. | |
1561 | """ | |
1562 | self.flakes(''' | |
1563 | a = {1: x for x in range(10)} | |
1564 | ''') | |
1565 | ||
1566 | def test_setComprehensionAndLiteral(self): | |
1567 | """ | |
1568 | Set comprehensions are properly handled. | |
1569 | """ | |
1570 | self.flakes(''' | |
1571 | a = {1, 2, 3} | |
1572 | b = {x for x in range(10)} | |
1573 | ''') | |
1574 | ||
1575 | def test_exceptionUsedInExcept(self): | |
1576 | self.flakes(''' | |
1577 | try: pass | |
1578 | except Exception as e: e | |
1579 | ''') | |
1580 | ||
1581 | self.flakes(''' | |
1582 | def download_review(): | |
1583 | try: pass | |
1584 | except Exception as e: e | |
1585 | ''') | |
1586 | ||
1587 | def test_exceptionUnusedInExcept(self): | |
1588 | self.flakes(''' | |
1589 | try: pass | |
1590 | except Exception as e: pass | |
1591 | ''', m.UnusedVariable) | |
1592 | ||
1593 | @skipIf(version_info < (3, 11), 'new in Python 3.11') | |
1594 | def test_exception_unused_in_except_star(self): | |
1595 | self.flakes(''' | |
1596 | try: | |
1597 | pass | |
1598 | except* OSError as e: | |
1599 | pass | |
1600 | ''', m.UnusedVariable) | |
1601 | ||
1602 | def test_exceptionUnusedInExceptInFunction(self): | |
1603 | self.flakes(''' | |
1604 | def download_review(): | |
1605 | try: pass | |
1606 | except Exception as e: pass | |
1607 | ''', m.UnusedVariable) | |
1608 | ||
1609 | def test_exceptWithoutNameInFunction(self): | |
1610 | """ | |
1611 | Don't issue false warning when an unnamed exception is used. | |
1612 | Previously, there would be a false warning, but only when the | |
1613 | try..except was in a function | |
1614 | """ | |
1615 | self.flakes(''' | |
1616 | import tokenize | |
1617 | def foo(): | |
1618 | try: pass | |
1619 | except tokenize.TokenError: pass | |
1620 | ''') | |
1621 | ||
1622 | def test_exceptWithoutNameInFunctionTuple(self): | |
1623 | """ | |
1624 | Don't issue false warning when an unnamed exception is used. | |
1625 | This example catches a tuple of exception types. | |
1626 | """ | |
1627 | self.flakes(''' | |
1628 | import tokenize | |
1629 | def foo(): | |
1630 | try: pass | |
1631 | except (tokenize.TokenError, IndentationError): pass | |
1632 | ''') | |
1633 | ||
1634 | def test_augmentedAssignmentImportedFunctionCall(self): | |
1635 | """ | |
1636 | Consider a function that is called on the right part of an | |
1637 | augassign operation to be used. | |
1638 | """ | |
1639 | self.flakes(''' | |
1640 | from foo import bar | |
1641 | baz = 0 | |
1642 | baz += bar() | |
1643 | ''') | |
1644 | ||
1645 | def test_assert_without_message(self): | |
1646 | """An assert without a message is not an error.""" | |
1647 | self.flakes(''' | |
1648 | a = 1 | |
1649 | assert a | |
1650 | ''') | |
1651 | ||
1652 | def test_assert_with_message(self): | |
1653 | """An assert with a message is not an error.""" | |
1654 | self.flakes(''' | |
1655 | a = 1 | |
1656 | assert a, 'x' | |
1657 | ''') | |
1658 | ||
1659 | def test_assert_tuple(self): | |
1660 | """An assert of a non-empty tuple is always True.""" | |
1661 | self.flakes(''' | |
1662 | assert (False, 'x') | |
1663 | assert (False, ) | |
1664 | ''', m.AssertTuple, m.AssertTuple) | |
1665 | ||
1666 | def test_assert_tuple_empty(self): | |
1667 | """An assert of an empty tuple is always False.""" | |
1668 | self.flakes(''' | |
1669 | assert () | |
1670 | ''') | |
1671 | ||
1672 | def test_assert_static(self): | |
1673 | """An assert of a static value is not an error.""" | |
1674 | self.flakes(''' | |
1675 | assert True | |
1676 | assert 1 | |
1677 | ''') | |
1678 | ||
1679 | def test_yieldFromUndefined(self): | |
1680 | """ | |
1681 | Test C{yield from} statement | |
1682 | """ | |
1683 | self.flakes(''' | |
1684 | def bar(): | |
1685 | yield from foo() | |
1686 | ''', m.UndefinedName) | |
1687 | ||
1688 | def test_f_string(self): | |
1689 | """Test PEP 498 f-strings are treated as a usage.""" | |
1690 | self.flakes(''' | |
1691 | baz = 0 | |
1692 | print(f'\x7b4*baz\N{RIGHT CURLY BRACKET}') | |
1693 | ''') | |
1694 | ||
1695 | def test_assign_expr(self): | |
1696 | """Test PEP 572 assignment expressions are treated as usage / write.""" | |
1697 | self.flakes(''' | |
1698 | from foo import y | |
1699 | print(x := y) | |
1700 | print(x) | |
1701 | ''') | |
1702 | ||
1703 | def test_assign_expr_generator_scope(self): | |
1704 | """Test assignment expressions in generator expressions.""" | |
1705 | self.flakes(''' | |
1706 | if (any((y := x[0]) for x in [[True]])): | |
1707 | print(y) | |
1708 | ''') | |
1709 | ||
1710 | def test_assign_expr_nested(self): | |
1711 | """Test assignment expressions in nested expressions.""" | |
1712 | self.flakes(''' | |
1713 | if ([(y:=x) for x in range(4) if [(z:=q) for q in range(4)]]): | |
1714 | print(y) | |
1715 | print(z) | |
1716 | ''') | |
1717 | ||
1718 | ||
1719 | class TestStringFormatting(TestCase): | |
1720 | ||
1721 | def test_f_string_without_placeholders(self): | |
1722 | self.flakes("f'foo'", m.FStringMissingPlaceholders) | |
1723 | self.flakes(''' | |
1724 | f"""foo | |
1725 | bar | |
1726 | """ | |
1727 | ''', m.FStringMissingPlaceholders) | |
1728 | self.flakes(''' | |
1729 | print( | |
1730 | f'foo' | |
1731 | f'bar' | |
1732 | ) | |
1733 | ''', m.FStringMissingPlaceholders) | |
1734 | # this is an "escaped placeholder" but not a placeholder | |
1735 | self.flakes("f'{{}}'", m.FStringMissingPlaceholders) | |
1736 | # ok: f-string with placeholders | |
1737 | self.flakes(''' | |
1738 | x = 5 | |
1739 | print(f'{x}') | |
1740 | ''') | |
1741 | # ok: f-string with format specifiers | |
1742 | self.flakes(''' | |
1743 | x = 'a' * 90 | |
1744 | print(f'{x:.8}') | |
1745 | ''') | |
1746 | # ok: f-string with multiple format specifiers | |
1747 | self.flakes(''' | |
1748 | x = y = 5 | |
1749 | print(f'{x:>2} {y:>2}') | |
1750 | ''') | |
1751 | ||
1752 | def test_invalid_dot_format_calls(self): | |
1753 | self.flakes(''' | |
1754 | '{'.format(1) | |
1755 | ''', m.StringDotFormatInvalidFormat) | |
1756 | self.flakes(''' | |
1757 | '{} {1}'.format(1, 2) | |
1758 | ''', m.StringDotFormatMixingAutomatic) | |
1759 | self.flakes(''' | |
1760 | '{0} {}'.format(1, 2) | |
1761 | ''', m.StringDotFormatMixingAutomatic) | |
1762 | self.flakes(''' | |
1763 | '{}'.format(1, 2) | |
1764 | ''', m.StringDotFormatExtraPositionalArguments) | |
1765 | self.flakes(''' | |
1766 | '{}'.format(1, bar=2) | |
1767 | ''', m.StringDotFormatExtraNamedArguments) | |
1768 | self.flakes(''' | |
1769 | '{} {}'.format(1) | |
1770 | ''', m.StringDotFormatMissingArgument) | |
1771 | self.flakes(''' | |
1772 | '{2}'.format() | |
1773 | ''', m.StringDotFormatMissingArgument) | |
1774 | self.flakes(''' | |
1775 | '{bar}'.format() | |
1776 | ''', m.StringDotFormatMissingArgument) | |
1777 | # too much string recursion (placeholder-in-placeholder) | |
1778 | self.flakes(''' | |
1779 | '{:{:{}}}'.format(1, 2, 3) | |
1780 | ''', m.StringDotFormatInvalidFormat) | |
1781 | # ok: dotted / bracketed names need to handle the param differently | |
1782 | self.flakes("'{.__class__}'.format('')") | |
1783 | self.flakes("'{foo[bar]}'.format(foo={'bar': 'barv'})") | |
1784 | # ok: placeholder-placeholders | |
1785 | self.flakes(''' | |
1786 | print('{:{}} {}'.format(1, 15, 2)) | |
1787 | ''') | |
1788 | # ok: not a placeholder-placeholder | |
1789 | self.flakes(''' | |
1790 | print('{:2}'.format(1)) | |
1791 | ''') | |
1792 | # ok: not mixed automatic | |
1793 | self.flakes(''' | |
1794 | '{foo}-{}'.format(1, foo=2) | |
1795 | ''') | |
1796 | # ok: we can't determine statically the format args | |
1797 | self.flakes(''' | |
1798 | a = () | |
1799 | "{}".format(*a) | |
1800 | ''') | |
1801 | self.flakes(''' | |
1802 | k = {} | |
1803 | "{foo}".format(**k) | |
1804 | ''') | |
1805 | ||
1806 | def test_invalid_percent_format_calls(self): | |
1807 | self.flakes(''' | |
1808 | '%(foo)' % {'foo': 'bar'} | |
1809 | ''', m.PercentFormatInvalidFormat) | |
1810 | self.flakes(''' | |
1811 | '%s %(foo)s' % {'foo': 'bar'} | |
1812 | ''', m.PercentFormatMixedPositionalAndNamed) | |
1813 | self.flakes(''' | |
1814 | '%(foo)s %s' % {'foo': 'bar'} | |
1815 | ''', m.PercentFormatMixedPositionalAndNamed) | |
1816 | self.flakes(''' | |
1817 | '%j' % (1,) | |
1818 | ''', m.PercentFormatUnsupportedFormatCharacter) | |
1819 | self.flakes(''' | |
1820 | '%s %s' % (1,) | |
1821 | ''', m.PercentFormatPositionalCountMismatch) | |
1822 | self.flakes(''' | |
1823 | '%s %s' % (1, 2, 3) | |
1824 | ''', m.PercentFormatPositionalCountMismatch) | |
1825 | self.flakes(''' | |
1826 | '%(bar)s' % {} | |
1827 | ''', m.PercentFormatMissingArgument,) | |
1828 | self.flakes(''' | |
1829 | '%(bar)s' % {'bar': 1, 'baz': 2} | |
1830 | ''', m.PercentFormatExtraNamedArguments) | |
1831 | self.flakes(''' | |
1832 | '%(bar)s' % (1, 2, 3) | |
1833 | ''', m.PercentFormatExpectedMapping) | |
1834 | self.flakes(''' | |
1835 | '%s %s' % {'k': 'v'} | |
1836 | ''', m.PercentFormatExpectedSequence) | |
1837 | self.flakes(''' | |
1838 | '%(bar)*s' % {'bar': 'baz'} | |
1839 | ''', m.PercentFormatStarRequiresSequence) | |
1840 | # ok: single %s with mapping | |
1841 | self.flakes(''' | |
1842 | '%s' % {'foo': 'bar', 'baz': 'womp'} | |
1843 | ''') | |
1844 | # ok: does not cause a MemoryError (the strings aren't evaluated) | |
1845 | self.flakes(''' | |
1846 | "%1000000000000f" % 1 | |
1847 | ''') | |
1848 | # ok: %% should not count towards placeholder count | |
1849 | self.flakes(''' | |
1850 | '%% %s %% %s' % (1, 2) | |
1851 | ''') | |
1852 | # ok: * consumes one positional argument | |
1853 | self.flakes(''' | |
1854 | '%.*f' % (2, 1.1234) | |
1855 | '%*.*f' % (5, 2, 3.1234) | |
1856 | ''') | |
1857 | ||
1858 | def test_ok_percent_format_cannot_determine_element_count(self): | |
1859 | self.flakes(''' | |
1860 | a = [] | |
1861 | '%s %s' % [*a] | |
1862 | '%s %s' % (*a,) | |
1863 | ''') | |
1864 | self.flakes(''' | |
1865 | k = {} | |
1866 | '%(k)s' % {**k} | |
1867 | ''') | |
1868 | ||
1869 | ||
1870 | class TestAsyncStatements(TestCase): | |
1871 | ||
1872 | def test_asyncDef(self): | |
1873 | self.flakes(''' | |
1874 | async def bar(): | |
1875 | return 42 | |
1876 | ''') | |
1877 | ||
1878 | def test_asyncDefAwait(self): | |
1879 | self.flakes(''' | |
1880 | async def read_data(db): | |
1881 | await db.fetch('SELECT ...') | |
1882 | ''') | |
1883 | ||
1884 | def test_asyncDefUndefined(self): | |
1885 | self.flakes(''' | |
1886 | async def bar(): | |
1887 | return foo() | |
1888 | ''', m.UndefinedName) | |
1889 | ||
1890 | def test_asyncFor(self): | |
1891 | self.flakes(''' | |
1892 | async def read_data(db): | |
1893 | output = [] | |
1894 | async for row in db.cursor(): | |
1895 | output.append(row) | |
1896 | return output | |
1897 | ''') | |
1898 | ||
1899 | def test_asyncForUnderscoreLoopVar(self): | |
1900 | self.flakes(''' | |
1901 | async def coro(it): | |
1902 | async for _ in it: | |
1903 | pass | |
1904 | ''') | |
1905 | ||
1906 | def test_loopControlInAsyncFor(self): | |
1907 | self.flakes(''' | |
1908 | async def read_data(db): | |
1909 | output = [] | |
1910 | async for row in db.cursor(): | |
1911 | if row[0] == 'skip': | |
1912 | continue | |
1913 | output.append(row) | |
1914 | return output | |
1915 | ''') | |
1916 | ||
1917 | self.flakes(''' | |
1918 | async def read_data(db): | |
1919 | output = [] | |
1920 | async for row in db.cursor(): | |
1921 | if row[0] == 'stop': | |
1922 | break | |
1923 | output.append(row) | |
1924 | return output | |
1925 | ''') | |
1926 | ||
1927 | def test_loopControlInAsyncForElse(self): | |
1928 | self.flakes(''' | |
1929 | async def read_data(db): | |
1930 | output = [] | |
1931 | async for row in db.cursor(): | |
1932 | output.append(row) | |
1933 | else: | |
1934 | continue | |
1935 | return output | |
1936 | ''', m.ContinueOutsideLoop) | |
1937 | ||
1938 | self.flakes(''' | |
1939 | async def read_data(db): | |
1940 | output = [] | |
1941 | async for row in db.cursor(): | |
1942 | output.append(row) | |
1943 | else: | |
1944 | break | |
1945 | return output | |
1946 | ''', m.BreakOutsideLoop) | |
1947 | ||
1948 | def test_asyncWith(self): | |
1949 | self.flakes(''' | |
1950 | async def commit(session, data): | |
1951 | async with session.transaction(): | |
1952 | await session.update(data) | |
1953 | ''') | |
1954 | ||
1955 | def test_asyncWithItem(self): | |
1956 | self.flakes(''' | |
1957 | async def commit(session, data): | |
1958 | async with session.transaction() as trans: | |
1959 | await trans.begin() | |
1960 | ... | |
1961 | await trans.end() | |
1962 | ''') | |
1963 | ||
1964 | def test_matmul(self): | |
1965 | self.flakes(''' | |
1966 | def foo(a, b): | |
1967 | return a @ b | |
1968 | ''') | |
1969 | ||
1970 | def test_formatstring(self): | |
1971 | self.flakes(''' | |
1972 | hi = 'hi' | |
1973 | mom = 'mom' | |
1974 | f'{hi} {mom}' | |
1975 | ''') | |
1976 | ||
1977 | def test_raise_notimplemented(self): | |
1978 | self.flakes(''' | |
1979 | raise NotImplementedError("This is fine") | |
1980 | ''') | |
1981 | ||
1982 | self.flakes(''' | |
1983 | raise NotImplementedError | |
1984 | ''') | |
1985 | ||
1986 | self.flakes(''' | |
1987 | raise NotImplemented("This isn't gonna work") | |
1988 | ''', m.RaiseNotImplemented) | |
1989 | ||
1990 | self.flakes(''' | |
1991 | raise NotImplemented | |
1992 | ''', m.RaiseNotImplemented) | |
1993 | ||
1994 | ||
1995 | class TestIncompatiblePrintOperator(TestCase): | |
1996 | """ | |
1997 | Tests for warning about invalid use of print function. | |
1998 | """ | |
1999 | ||
2000 | def test_valid_print(self): | |
2001 | self.flakes(''' | |
2002 | print("Hello") | |
2003 | ''') | |
2004 | ||
2005 | def test_invalid_print_when_imported_from_future(self): | |
2006 | exc = self.flakes(''' | |
2007 | from __future__ import print_function | |
2008 | import sys | |
2009 | print >>sys.stderr, "Hello" | |
2010 | ''', m.InvalidPrintSyntax).messages[0] | |
2011 | ||
2012 | self.assertEqual(exc.lineno, 4) | |
2013 | self.assertEqual(exc.col, 0) | |
2014 | ||
2015 | def test_print_augmented_assign(self): | |
2016 | # nonsense, but shouldn't crash pyflakes | |
2017 | self.flakes('print += 1') | |
2018 | ||
2019 | def test_print_function_assignment(self): | |
2020 | """ | |
2021 | A valid assignment, tested for catching false positives. | |
2022 | """ | |
2023 | self.flakes(''' | |
2024 | from __future__ import print_function | |
2025 | log = print | |
2026 | log("Hello") | |
2027 | ''') | |
2028 | ||
2029 | def test_print_in_lambda(self): | |
2030 | self.flakes(''' | |
2031 | from __future__ import print_function | |
2032 | a = lambda: print | |
2033 | ''') | |
2034 | ||
2035 | def test_print_returned_in_function(self): | |
2036 | self.flakes(''' | |
2037 | from __future__ import print_function | |
2038 | def a(): | |
2039 | return print | |
2040 | ''') | |
2041 | ||
2042 | def test_print_as_condition_test(self): | |
2043 | self.flakes(''' | |
2044 | from __future__ import print_function | |
2045 | if print: pass | |
2046 | ''') |