diff options
author | Emile Anclin <emile.anclin@logilab.fr> | 2010-12-08 10:38:22 +0100 |
---|---|---|
committer | Emile Anclin <emile.anclin@logilab.fr> | 2010-12-08 10:38:22 +0100 |
commit | abd3993e7455a2a62648908a2817bc1a0ea41485 (patch) | |
tree | dd55da6f19a8f29d5223a592f1d4adead39134b4 | |
parent | 25e31dd15b7a8ad53fdf8fc9a5478557b544ccdd (diff) | |
download | pylint-abd3993e7455a2a62648908a2817bc1a0ea41485.tar.gz |
format_string: melt indentation a bit down and rename some variables
-rw-r--r-- | checkers/string_format.py | 179 |
1 files changed, 84 insertions, 95 deletions
diff --git a/checkers/string_format.py b/checkers/string_format.py index f8f2389..ea47af4 100644 --- a/checkers/string_format.py +++ b/checkers/string_format.py @@ -57,11 +57,11 @@ MSGS = { specifiers is given too many arguments"), } -class IncompleteFormatStringException(Exception): +class IncompleteFormatString(Exception): """A format string ended in the middle of a format specifier.""" pass -class UnsupportedFormatCharacterException(Exception): +class UnsupportedFormatCharacter(Exception): """A format character in a format string is not one of the supported format characters.""" def __init__(self, index): @@ -72,14 +72,14 @@ def parse_format_string(format_string): """Parses a format string, returning a tuple of (keys, num_args), where keys is the set of mapping keys in the format string, and num_args is the number of arguments required by the format string. Raises - IncompleteFormatStringException or UnsupportedFormatCharacterException if a + IncompleteFormatString or UnsupportedFormatCharacter if a parse error occurs.""" keys = set() num_args = 0 def next_char(i): i += 1 if i == len(format_string): - raise IncompleteFormatStringException + raise IncompleteFormatString return (i, format_string[i]) i = 0 while i < len(format_string): @@ -125,7 +125,7 @@ def parse_format_string(format_string): i, c = next_char(i) # Parse the conversion type (mandatory). if c not in 'diouxXeEfFgGcrs%': - raise UnsupportedFormatCharacterException(i) + raise UnsupportedFormatCharacter(i) if key: keys.add(key) elif c != '%': @@ -133,108 +133,97 @@ def parse_format_string(format_string): i += 1 return keys, num_args +OTHER_NODES = (astng.Const, astng.List, astng.Backquote, + astng.Lambda, astng.Function, + astng.ListComp, astng.SetComp, astng.GenExpr) + class StringFormatChecker(BaseChecker): """Checks string formatting operations to ensure that the format string is valid and the arguments match the format string. """ + __implements__ = (IASTNGChecker,) name = 'string_format' msgs = MSGS + def visit_binop(self, node): if node.op != '%': return - f = node.left + left = node.left args = node.right - if isinstance(f, astng.Const) and isinstance(f.value, basestring): - format_string = f.value - try: - required_keys, required_num_args = \ - parse_format_string(format_string) - except UnsupportedFormatCharacterException, e: - c = format_string[e.index] - self.add_message('E9900', node=node, args=(c, ord(c), e.index)) - except IncompleteFormatStringException: - self.add_message('E9901', node=node) - else: - if required_keys and required_num_args: - # The format string uses both named and unnamed format - # specifiers. - self.add_message('E9902', node=node) - elif required_keys: - # The format string uses only named format specifiers. - # Check that the RHS of the % operator is a mapping object - # that contains precisely the set of keys required by the - # format string. - if isinstance(args, astng.Dict): - keys = set() - unknown_keys = False - for k, v in args.items: - if isinstance(k, astng.Const): - key = k.value - if isinstance(key, basestring): - keys.add(key) - else: - self.add_message('W9900', - node=node, - args=key) - else: - # One of the keys was something other than a - # constant. Since we can't tell what it is, - # supress checks for missing keys in the - # dictionary. - unknown_keys = True - if not unknown_keys: - for key in required_keys: - if key not in keys: - self.add_message('E9904', - node=node, - args=key) - for key in keys: - if key not in required_keys: - self.add_message('W9901', node=node, args=key) - elif (isinstance(args, astng.Const) or - isinstance(args, astng.Tuple) or - isinstance(args, astng.List) or - isinstance(args, astng.ListComp) or - isinstance(args, astng.SetComp) or - isinstance(args, astng.GenExpr) or - isinstance(args, astng.Backquote) or - isinstance(args, astng.Lambda)): - type_name = type(args).__name__ - self.add_message('E9903', node=node, args=type_name) - else: - # The RHS of the format specifier is a name or - # expression. It may be a mapping object, so - # there's nothing we can check. - pass - else: - # The format string uses only unnamed format specifiers. - # Check that the number of arguments passed to the RHS of - # the % operator matches the number required by the format - # string. - if isinstance(args, astng.Tuple): - num_args = len(args.elts) - elif (isinstance(args, astng.Const) or - isinstance(args, astng.Dict) or - isinstance(args, astng.List) or - isinstance(args, astng.ListComp) or - isinstance(args, astng.SetComp) or - isinstance(args, astng.DictComp) or - isinstance(args, astng.GenExpr) or - isinstance(args, astng.Backquote) or - isinstance(args, astng.Lambda) or - isinstance(args, astng.Function)): - num_args = 1 + + if not (isinstance(left, astng.Const) + and isinstance(left.value, basestring)): + return + format_string = left.value + try: + required_keys, required_num_args = \ + parse_format_string(format_string) + except UnsupportedFormatCharacter, e: + c = format_string[e.index] + self.add_message('E9900', node=node, args=(c, ord(c), e.index)) + return + except IncompleteFormatString: + self.add_message('E9901', node=node) + return + if required_keys and required_num_args: + # The format string uses both named and unnamed format + # specifiers. + self.add_message('E9902', node=node) + elif required_keys: + # The format string uses only named format specifiers. + # Check that the RHS of the % operator is a mapping object + # that contains precisely the set of keys required by the + # format string. + if isinstance(args, astng.Dict): + keys = set() + unknown_keys = False + for k, v in args.items: + if isinstance(k, astng.Const): + key = k.value + if isinstance(key, basestring): + keys.add(key) + else: + self.add_message('W9900', node=node, args=key) else: - # The RHS of the format specifier is a name or - # expression. It could be a tuple of unknown size, so - # there's nothing we can check. - num_args = None - if num_args is not None: - if num_args > required_num_args: - self.add_message('E9905', node=node) - elif num_args < required_num_args: - self.add_message('E9906', node=node) + # One of the keys was something other than a + # constant. Since we can't tell what it is, + # supress checks for missing keys in the + # dictionary. + unknown_keys = True + if not unknown_keys: + for key in required_keys: + if key not in keys: + self.add_message('E9904', node=node, args=key) + for key in keys: + if key not in required_keys: + self.add_message('W9901', node=node, args=key) + elif isinstance(args, OTHER_NODES + (astng.Tuple,)): + type_name = type(args).__name__ + self.add_message('E9903', node=node, args=type_name) + # else: + # The RHS of the format specifier is a name or + # expression. It may be a mapping object, so + # there's nothing we can check. + else: + # The format string uses only unnamed format specifiers. + # Check that the number of arguments passed to the RHS of + # the % operator matches the number required by the format + # string. + if isinstance(args, astng.Tuple): + num_args = len(args.elts) + elif isinstance(args, OTHER_NODES + (astng.Dict, astng.DictComp)): + num_args = 1 + else: + # The RHS of the format specifier is a name or + # expression. It could be a tuple of unknown size, so + # there's nothing we can check. + num_args = None + if num_args is not None: + if num_args > required_num_args: + self.add_message('E9905', node=node) + elif num_args < required_num_args: + self.add_message('E9906', node=node) def register(linter): |