1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5# Original (c) 2005 Divmod, Inc.  See __init__.py file for details
6#
7# This module is based on pyflakes, but was modified to
8# be integrated into eric
9
10"""
11Module providing the class Message and its subclasses.
12"""
13
14
15class Message():
16    """
17    Class defining the base for all specific message classes.
18    """
19    message_id = 'F00'
20    message = ''
21    message_args = ()
22
23    def __init__(self, filename, loc):
24        """
25        Constructor
26
27        @param filename name of the file
28        @type str
29        @param loc location of the issue
30        """
31        self.filename = filename
32        self.lineno = loc.lineno
33        self.col = getattr(loc, 'col_offset', 0)
34
35    def __str__(self):
36        """
37        Special method return a string representation of the instance object.
38
39        @return string representation of the object
40        @rtype str
41        """
42        return '{0}:{1}:{2} {3}'.format(
43            self.filename, self.lineno, self.col + 1,
44            self.message % self.message_args)
45
46    def getMessageData(self):
47        """
48        Public method to get the individual message data elements.
49
50        @return tuple containing file name, line number, column, message ID
51            and message arguments
52        @rtype tuple of (str, int, int, str, list)
53        """
54        return (self.filename, self.lineno, self.col, self.message_id,
55                self.message_args)
56
57
58class UnusedImport(Message):
59    """
60    Class defining the "Unused Import" message.
61    """
62    message_id = 'F01'
63    message = '%r imported but unused'
64
65    def __init__(self, filename, loc, name):
66        """
67        Constructor
68
69        @param filename name of the file (string)
70        @param loc location of the issue
71        @param name name of the unused import (string)
72        """
73        Message.__init__(self, filename, loc)
74        self.message_args = (name,)
75
76
77class RedefinedWhileUnused(Message):
78    """
79    Class defining the "Redefined While Unused" message.
80    """
81    message_id = 'F02'
82    message = 'redefinition of unused %r from line %r'
83
84    def __init__(self, filename, loc, name, orig_loc):
85        """
86        Constructor
87
88        @param filename name of the file (string)
89        @param loc location of the issue
90        @param name name of the redefined object (string)
91        @param orig_loc location of the original definition
92        """
93        Message.__init__(self, filename, loc)
94        self.message_args = (name, orig_loc.lineno)
95
96
97class RedefinedInListComp(Message):
98    """
99    Class defining the "Redefined In List Comprehension" message.
100    """
101    message_id = 'F12'
102    message = 'list comprehension redefines %r from line %r'
103
104    def __init__(self, filename, loc, name, orig_loc):
105        """
106        Constructor
107
108        @param filename name of the file (string)
109        @param loc location of the issue
110        @param name name of the redefined object (string)
111        @param orig_loc location of the original definition
112        """
113        Message.__init__(self, filename, loc)
114        self.message_args = (name, orig_loc.lineno)
115
116
117class ImportShadowedByLoopVar(Message):
118    """
119    Class defining the "Import Shadowed By Loop Var" message.
120    """
121    message_id = 'F03'
122    message = 'import %r from line %r shadowed by loop variable'
123
124    def __init__(self, filename, loc, name, orig_loc):
125        """
126        Constructor
127
128        @param filename name of the file (string)
129        @param loc location of the issue
130        @param name name of the shadowed import (string)
131        @param orig_loc location of the import
132        """
133        Message.__init__(self, filename, loc)
134        self.message_args = (name, orig_loc.lineno)
135
136
137class ImportStarNotPermitted(Message):
138    """
139    Class defining the "Import * not permitted" message.
140    """
141    message_id = 'F16'
142    message = "'from %s import *' only allowed at module level"
143
144    def __init__(self, filename, loc, modname):
145        """
146        Constructor
147
148        @param filename name of the file (string)
149        @param loc location of the issue
150        @param modname name of the module (string)
151        """
152        Message.__init__(self, filename, loc)
153        self.message_args = (modname,)
154
155
156class ImportStarUsed(Message):
157    """
158    Class defining the "Import Star Used" message.
159    """
160    message_id = 'F04'
161    message = "'from %s import *' used; unable to detect undefined names"
162
163    def __init__(self, filename, loc, modname):
164        """
165        Constructor
166
167        @param filename name of the file (string)
168        @param loc location of the issue
169        @param modname name of the module imported using star import (string)
170        """
171        Message.__init__(self, filename, loc)
172        self.message_args = (modname,)
173
174
175class ImportStarUsage(Message):
176    """
177    Class defining the "Import Star Usage" message.
178    """
179    message_id = 'F17'
180    message = "%r may be undefined, or defined from star imports: %s"
181
182    def __init__(self, filename, loc, name, from_list):
183        """
184        Constructor
185
186        @param filename name of the file (string)
187        @param loc location of the issue
188        @param name name of the variable (string)
189        @param from_list list of modules imported from with * (string)
190        """
191        Message.__init__(self, filename, loc)
192        self.message_args = (name, from_list)
193
194
195class UndefinedName(Message):
196    """
197    Class defining the "Undefined Name" message.
198    """
199    message_id = 'F05'
200    message = 'undefined name %r'
201
202    def __init__(self, filename, loc, name):
203        """
204        Constructor
205
206        @param filename name of the file (string)
207        @param loc location of the issue
208        @param name undefined name (string)
209        """
210        Message.__init__(self, filename, loc)
211        self.message_args = (name,)
212
213
214class DoctestSyntaxError(Message):
215    """
216    Class defining the "Doctest syntax Error" message.
217    """
218    message_id = 'F13'
219    message = 'syntax error in doctest'
220
221    def __init__(self, filename, loc, position=None):
222        """
223        Constructor
224
225        @param filename name of the file (string)
226        @param loc location of the issue
227        @param position position of the syntax error
228        """
229        Message.__init__(self, filename, loc)
230        if position:
231            (self.lineno, self.col) = position
232        self.message_args = ()
233
234
235class UndefinedExport(Message):
236    """
237    Class defining the "Undefined Export" message.
238    """
239    message_id = 'F06'
240    message = 'undefined name %r in __all__'
241
242    def __init__(self, filename, loc, name):
243        """
244        Constructor
245
246        @param filename name of the file (string)
247        @param loc location of the issue
248        @param name undefined exported name (string)
249        """
250        Message.__init__(self, filename, loc)
251        self.message_args = (name,)
252
253
254class UndefinedLocal(Message):
255    """
256    Class defining the "Undefined Local Variable" message.
257    """
258    message_id = 'F07'
259    message = 'local variable %r {0} referenced before assignment'
260
261    default = 'defined in enclosing scope on line %r'
262    builtin = 'defined as a builtin'
263
264    def __init__(self, filename, loc, name, orig_loc):
265        """
266        Constructor
267
268        @param filename name of the file (string)
269        @param loc location of the issue
270        @param name name of the prematurely referenced variable (string)
271        @param orig_loc location of the variable definition
272        """
273        Message.__init__(self, filename, loc)
274        if orig_loc is None:
275            self.message = self.message.format(self.builtin)
276            self.message_args = (name,)
277            self.message_id = 'F07B'
278        else:
279            self.message = self.message.format(self.default)
280            self.message_args = (name, orig_loc.lineno)
281            self.message_id = 'F07A'
282
283
284class DuplicateArgument(Message):
285    """
286    Class defining the "Duplicate Argument" message.
287    """
288    message_id = 'F08'
289    message = 'duplicate argument %r in function definition'
290
291    def __init__(self, filename, loc, name):
292        """
293        Constructor
294
295        @param filename name of the file (string)
296        @param loc location of the issue
297        @param name name of the duplicate argument (string)
298        """
299        Message.__init__(self, filename, loc)
300        self.message_args = (name,)
301
302
303class MultiValueRepeatedKeyLiteral(Message):
304    """
305    Class defining the multiple used dictionary key message.
306    """
307    message_id = 'F18'
308    message = 'dictionary key %r repeated with different values'
309
310    def __init__(self, filename, loc, key):
311        """
312        Constructor
313
314        @param filename name of the file (string)
315        @param loc location of the issue
316        @param key dictionary key (string)
317        """
318        Message.__init__(self, filename, loc)
319        self.message_args = (key,)
320
321
322class MultiValueRepeatedKeyVariable(Message):
323    """
324    Class defining the multiple used dictionary key variable message.
325    """
326    message_id = 'F19'
327    message = 'dictionary key variable %s repeated with different values'
328
329    def __init__(self, filename, loc, key):
330        """
331        Constructor
332
333        @param filename name of the file (string)
334        @param loc location of the issue
335        @param key dictionary key variable (string)
336        """
337        Message.__init__(self, filename, loc)
338        self.message_args = (key,)
339
340
341class LateFutureImport(Message):
342    """
343    Class defining the "Late Future Import" message.
344    """
345    message_id = 'F10'
346    message = 'from __future__ imports must occur at the beginning of the file'
347
348    def __init__(self, filename, loc, names):
349        """
350        Constructor
351
352        @param filename name of the file (string)
353        @param loc location of the issue
354        @param names names of the imported futures (string)
355        """
356        Message.__init__(self, filename, loc)
357        self.message_args = ()
358
359
360class FutureFeatureNotDefined(Message):
361    """
362    Class defining the undefined __future__ feature message.
363    """
364    message_id = 'F20'
365    message = 'future feature %s is not defined'
366
367    def __init__(self, filename, loc, name):
368        """
369        Constructor
370
371        @param filename name of the file (string)
372        @param loc location of the issue
373        @param name name of the imported undefined future feature (string)
374        """
375        Message.__init__(self, filename, loc)
376        self.message_args = (name,)
377
378
379class UnusedVariable(Message):
380    """
381    Class defining the "Unused Variable" message.
382
383    Indicates that a variable has been explicitly assigned to but not actually
384    used.
385    """
386    message_id = 'F11'
387    message = 'local variable %r is assigned to but never used'
388
389    def __init__(self, filename, loc, names):
390        """
391        Constructor
392
393        @param filename name of the file (string)
394        @param loc location of the issue
395        @param names names of unused variable (string)
396        """
397        Message.__init__(self, filename, loc)
398        self.message_args = (names,)
399
400
401class ReturnWithArgsInsideGenerator(Message):
402    """
403    Class defining the "Return values in generator" message.
404
405    Indicates a return statement with arguments inside a generator.
406    """
407    message_id = 'F14'
408    message = '\'return\' with argument inside generator'
409
410
411class ReturnOutsideFunction(Message):
412    """
413    Class defining the "Return outside function" message.
414
415    Indicates a return statement outside of a function/method.
416    """
417    message_id = 'F15'
418    message = '\'return\' outside function'
419
420
421class YieldOutsideFunction(Message):
422    """
423    Class defining the "Yield outside function" message.
424
425    Indicates a yield or yield from statement outside of a function/method.
426    """
427    message_id = 'F21'
428    message = '\'yield\' outside function'
429
430
431# For whatever reason, Python gives different error messages for these two. We
432# match the Python error message exactly.
433class ContinueOutsideLoop(Message):
434    """
435    Class defining the "Continue outside loop" message.
436
437    Indicates a continue statement outside of a while or for loop.
438    """
439    message_id = 'F22'
440    message = '\'continue\' not properly in loop'
441
442
443class BreakOutsideLoop(Message):
444    """
445    Class defining the "Break outside loop" message.
446
447    Indicates a break statement outside of a while or for loop.
448    """
449    message_id = 'F23'
450    message = '\'break\' outside loop'
451
452
453class ContinueInFinally(Message):
454    """
455    Class defining the "Continue in finally block" message.
456
457    Indicates a continue statement in a finally block in a while or for loop.
458    """
459    message_id = 'F24'
460    message = '\'continue\' not supported inside \'finally\' clause'
461
462
463class DefaultExceptNotLast(Message):
464    """
465    Class defining the "Default except not being the last" message.
466
467    Indicates an except: block as not the last exception handler.
468    """
469    message_id = 'F25'
470    message = 'default \'except:\' must be last'
471
472
473class TwoStarredExpressions(Message):
474    """
475    Class defining the "multiple starred expressions" message.
476
477    Two or more starred expressions in an assignment (a, *b, *c = d).
478    """
479    message_id = 'F26'
480    message = 'two starred expressions in assignment'
481
482
483class TooManyExpressionsInStarredAssignment(Message):
484    """
485    Class defining the "too many starred expressions" message.
486
487    Too many expressions in an assignment with star-unpacking
488    """
489    message_id = 'F27'
490    message = 'too many expressions in star-unpacking assignment'
491
492
493class IfTuple(Message):
494    """
495    Class defining the "non-empty tuple literal" message.
496
497    Conditional test is a non-empty tuple literal, which are always True.
498    """
499    message_id = 'F49'
500    message = (
501        '\'if tuple literal\' is always true, perhaps remove accidental comma?'
502    )
503
504
505class AssertTuple(Message):
506    """
507    Class defining the "tuple assertion" message.
508
509    Assertion test is a tuple, which are always True.
510    """
511    message_id = 'F28'
512    message = 'assertion is always true, perhaps remove parentheses?'
513
514
515class ForwardAnnotationSyntaxError(Message):
516    """
517    Class defining the "forward annotation syntax error" message.
518
519    Found a syntax error in forward annotation.
520    """
521    message_id = 'F29'
522    message = 'syntax error in forward annotation %r'
523
524    def __init__(self, filename, loc, annotation):
525        """
526        Constructor
527
528        @param filename name of the file (string)
529        @param loc location of the issue
530        @param annotation erroneous forward annotation (string)
531        """
532        Message.__init__(self, filename, loc)
533        self.message_args = (annotation,)
534
535
536class CommentAnnotationSyntaxError(Message):
537    """
538    Class defining the "Comment Annotation Syntax Error" message.
539
540    Indicates a syntax error in a type comment.
541    """
542    message_id = 'F31'
543    message = 'syntax error in type comment %r'
544
545    def __init__(self, filename, loc, annotation):
546        """
547        Constructor
548
549        @param filename name of the file (string)
550        @param loc location of the issue
551        @param annotation erroneous forward annotation (string)
552        """
553        Message.__init__(self, filename, loc)
554        self.message_args = (annotation,)
555
556
557class RaiseNotImplemented(Message):
558    """
559    Class defining the "raise not implemented" message.
560
561    Use NotImplementedError instead of NotImplemented.
562    """
563    message_id = 'F30'
564    message = "'raise NotImplemented' should be 'raise NotImplementedError'"
565
566
567class InvalidPrintSyntax(Message):
568    """
569    Class defining the "Invalid Print Syntax" message.
570
571    Indicates the use of >> with a print function.
572    """
573    message_id = 'F32'
574    message = 'use of >> is invalid with print function'
575
576
577class IsLiteral(Message):
578    """
579    Class defining the "Is Literal" message.
580
581    Indicates the use of "is" or "is not" against str, int and bytes.
582    """
583    message_id = 'F33'
584    message = 'use ==/!= to compare str, bytes, and int literals'
585
586
587class FStringMissingPlaceholders(Message):
588    """
589    Class defining the "Missing Placeholder" message.
590
591    Indicates that an f-string is missing some placeholders.
592    """
593    message_id = 'F34'
594    message = 'f-string is missing placeholders'
595
596
597class StringDotFormatExtraPositionalArguments(Message):
598    """
599    Class defining the "Unused Arguments" message.
600
601    Indicates that an f-string has unused arguments.
602    """
603    message_id = 'F35'
604    message = "'...'.format(...) has unused arguments at position(s): %s"
605
606    def __init__(self, filename, loc, extra_positions):
607        """
608        Constructor
609
610        @param filename name of the file (string)
611        @param loc location of the issue
612        @param extra_positions indexes of unused arguments
613        """
614        Message.__init__(self, filename, loc)
615        self.message_args = (extra_positions,)
616
617
618class StringDotFormatExtraNamedArguments(Message):
619    """
620    Class defining the "Unused Named Arguments" message.
621
622    Indicates that an f-string has unused named arguments.
623    """
624    message_id = 'F36'
625    message = "'...'.format(...) has unused named argument(s): %s"
626
627    def __init__(self, filename, loc, extra_keywords):
628        """
629        Constructor
630
631        @param filename name of the file (string)
632        @param loc location of the issue
633        @param extra_keywords index of unused named arguments
634        """
635        Message.__init__(self, filename, loc)
636        self.message_args = (extra_keywords,)
637
638
639class StringDotFormatMissingArgument(Message):
640    """
641    Class defining the "Missing Arguments" message.
642
643    Indicates that an f-string is missing some arguments.
644    """
645    message_id = 'F37'
646    message = "'...'.format(...) is missing argument(s) for placeholder(s): %s"
647
648    def __init__(self, filename, loc, missing_arguments):
649        """
650        Constructor
651
652        @param filename name of the file (string)
653        @param loc location of the issue
654        @param missing_arguments missing arguments
655        """
656        Message.__init__(self, filename, loc)
657        self.message_args = (missing_arguments,)
658
659
660class StringDotFormatMixingAutomatic(Message):
661    """
662    Class defining the "Mixing Automatic and Manual" message.
663
664    Indicates that an f-string mixes automatic and manual numbering.
665    """
666    message_id = 'F38'
667    message = "'...'.format(...) mixes automatic and manual numbering"
668
669
670class StringDotFormatInvalidFormat(Message):
671    """
672    Class defining the "Invalid Format String" message.
673
674    Indicates that an f-string contains an invalid format string.
675    """
676    message_id = 'F39'
677    message = "'...'.format(...) has invalid format string: %s"
678
679    def __init__(self, filename, loc, error):
680        """
681        Constructor
682
683        @param filename name of the file (string)
684        @param loc location of the issue
685        @param error error details
686        """
687        Message.__init__(self, filename, loc)
688        if not isinstance(error, str):
689            error = str(error)
690        self.message_args = (error,)
691
692
693class PercentFormatInvalidFormat(Message):
694    """
695    Class defining the "Invalid Percent Format String" message.
696
697    Indicates that a percent format has an invalid format string.
698    """
699    message_id = 'F40'
700    message = "'...' %% ... has invalid format string: %s"
701
702    def __init__(self, filename, loc, error):
703        """
704        Constructor
705
706        @param filename name of the file (string)
707        @param loc location of the issue
708        @param error error details
709        """
710        Message.__init__(self, filename, loc)
711        self.message_args = (error,)
712
713
714class PercentFormatMixedPositionalAndNamed(Message):
715    """
716    Class defining the "Mixed Positional and Named" message.
717
718    Indicates that a percent format has mixed positional and named
719    placeholders.
720    """
721    message_id = 'F41'
722    message = "'...' %% ... has mixed positional and named placeholders"
723
724
725class PercentFormatUnsupportedFormatCharacter(Message):
726    """
727    Class defining the "Unsupported Format Character" message.
728
729    Indicates that a percent format has an unsupported format character.
730    """
731    message_id = 'F42'
732    message = "'...' %% ... has unsupported format character %r"
733
734    def __init__(self, filename, loc, c):
735        """
736        Constructor
737
738        @param filename name of the file (string)
739        @param loc location of the issue
740        @param c unsupported format character
741        """
742        Message.__init__(self, filename, loc)
743        self.message_args = (c,)
744
745
746class PercentFormatPositionalCountMismatch(Message):
747    """
748    Class defining the "Placeholder Substitution Mismatch" message.
749
750    Indicates that a percent format has a mismatching number of placeholders
751    and substitutions.
752    """
753    message_id = 'F43'
754    message = "'...' %% ... has %d placeholder(s) but %d substitution(s)"
755
756    def __init__(self, filename, loc, n_placeholders, n_substitutions):
757        """
758        Constructor
759
760        @param filename name of the file (string)
761        @param loc location of the issue
762        @param n_placeholders number of placeholders (integer)
763        @param n_substitutions number of substitutions (integer)
764        """
765        Message.__init__(self, filename, loc)
766        self.message_args = (n_placeholders, n_substitutions)
767
768
769class PercentFormatExtraNamedArguments(Message):
770    """
771    Class defining the "Unused Named Arguments" message.
772
773    Indicates that a percent format has unused named arguments.
774    """
775    message_id = 'F44'
776    message = "'...' %% ... has unused named argument(s): %s"
777
778    def __init__(self, filename, loc, extra_keywords):
779        """
780        Constructor
781
782        @param filename name of the file (string)
783        @param loc location of the issue
784        @param extra_keywords index of unused named arguments
785        """
786        Message.__init__(self, filename, loc)
787        self.message_args = (extra_keywords,)
788
789
790class PercentFormatMissingArgument(Message):
791    """
792    Class defining the "Missing Arguments" message.
793
794    Indicates that a percent format is missing arguments for some placeholders.
795    """
796    message_id = 'F45'
797    message = "'...' %% ... is missing argument(s) for placeholder(s): %s"
798
799    def __init__(self, filename, loc, missing_arguments):
800        """
801        Constructor
802
803        @param filename name of the file (string)
804        @param loc location of the issue
805        @param missing_arguments missing arguments
806        """
807        Message.__init__(self, filename, loc)
808        self.message_args = (missing_arguments,)
809
810
811class PercentFormatExpectedMapping(Message):
812    """
813    Class defining the "Sequence instead of Mapping" message.
814
815    Indicates that a percent format expected a mapping but got a sequence.
816    """
817    message_id = 'F46'
818    message = "'...' %% ... expected mapping but got sequence"
819
820
821class PercentFormatExpectedSequence(Message):
822    """
823    Class defining the "Mapping instead of Sequence" message.
824
825    Indicates that a percent format expected a sequence but got a mapping.
826    """
827    message_id = 'F47'
828    message = "'...' %% ... expected sequence but got mapping"
829
830
831class PercentFormatStarRequiresSequence(Message):
832    """
833    Class defining the "'*' Requires Sequence" message.
834
835    Indicates that a percent format expected a sequence.
836    """
837    message_id = 'F48'
838    message = "'...' %% ... `*` specifier requires sequence"
839