def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node (astroid.node_classes.NodeNG): AST node to be checked. format_arg (int): Index of the format string in the node arguments. """ num_args = _count_supplied_tokens(node.args[format_arg + 1 :]) if not num_args: # If no args were supplied, then all format strings are valid - # don't check any further. return format_string = node.args[format_arg].value if not isinstance(format_string, six.string_types): # If the log format is constant non-string (e.g. logging.debug(5)), # ensure there are no arguments. required_num_args = 0 else: try: keyword_args, required_num_args = utils.parse_format_string(format_string) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return except utils.UnsupportedFormatCharacter as ex: char = format_string[ex.index] self.add_message("logging-unsupported-format", node=node, args=(char, ord(char), ex.index)) return except utils.IncompleteFormatString: self.add_message("logging-format-truncated", node=node) return if num_args > required_num_args: self.add_message("logging-too-many-args", node=node) elif num_args < required_num_args: self.add_message("logging-too-few-args", node=node)
def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node: AST node to be checked. format_arg: Index of the format string in the node arguments. """ num_args = self._count_supplied_tokens(node.args[format_arg + 1:]) if not num_args: # If no args were supplied, then all format strings are valid - # don't check any further. return format_string = node.args[format_arg].value if not isinstance(format_string, basestring): # If the log format is constant non-string (e.g. logging.debug(5)), # ensure there are no arguments. required_num_args = 0 else: try: keyword_args, required_num_args = \ utils.parse_format_string(format_string) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return except utils.UnsupportedFormatCharacter, e: c = format_string[e.index] self.add_message('E1200', node=node, args=(c, ord(c), e.index)) return except utils.IncompleteFormatString: self.add_message('E1201', node=node) return
def visit_binop(self, node): if not self.config.enforce_string_formatting_over_substitution: return if node.op != '%': return if not (isinstance(node.left, astroid.Const) and isinstance(node.left.value, basestring)): return try: required_keys, required_num_args = parse_format_string( node.left.value) except (utils.UnsupportedFormatCharacter, utils.IncompleteFormatString): # This is handled elsewere return if required_keys or required_num_args: if self.config.string_substitutions_usage_is_an_error: msgid = 'E1321' else: msgid = 'W1321' self.add_message(msgid, node=node.left, args=node.left.value)
def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node (astroid.node_classes.NodeNG): AST node to be checked. format_arg (int): Index of the format string in the node arguments. """ num_args = _count_supplied_tokens(node.args[format_arg + 1:]) if not num_args: # If no args were supplied the string is not interpolated and can contain # formatting characters - it's used verbatim. Don't check any further. return format_string = node.args[format_arg].value required_num_args = 0 if isinstance(format_string, bytes): format_string = format_string.decode() if isinstance(format_string, str): try: if self._format_style == "old": keyword_args, required_num_args, _, _ = utils.parse_format_string( format_string) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return elif self._format_style == "new": ( keyword_arguments, implicit_pos_args, explicit_pos_args, ) = utils.parse_format_method_string(format_string) keyword_args_cnt = len( set(k for k, l in keyword_arguments if not isinstance(k, int))) required_num_args = (keyword_args_cnt + implicit_pos_args + explicit_pos_args) else: self.add_message( "logging-format-interpolation", node=node, args=self._format_style_args, ) return except utils.UnsupportedFormatCharacter as ex: char = format_string[ex.index] self.add_message( "logging-unsupported-format", node=node, args=(char, ord(char), ex.index), ) return except utils.IncompleteFormatString: self.add_message("logging-format-truncated", node=node) return if num_args > required_num_args: self.add_message("logging-too-many-args", node=node) elif num_args < required_num_args: self.add_message("logging-too-few-args", node=node)
def visit_binop(self, node): if not self.config.enforce_string_formatting_over_substitution: return if node.op != '%': return if not (isinstance(node.left, astroid.Const) and isinstance(node.left.value, six.string_types)): return try: required_keys, required_num_args = parse_format_string(node.left.value) except (utils.UnsupportedFormatCharacter, utils.IncompleteFormatString): # This is handled elsewere return if required_keys or required_num_args: if self.config.string_substitutions_usage_is_an_error: msgid = 'E1321' else: msgid = 'W1321' self.add_message( msgid, node=node.left, args=node.left.value ) if '!r}' in node.left.value: self.add_message( 'E1322', node=node.left, args=node.left.value )
def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node (astroid.node_classes.NodeNG): AST node to be checked. format_arg (int): Index of the format string in the node arguments. """ num_args = _count_supplied_tokens(node.args[format_arg + 1 :]) if not num_args: # If no args were supplied the string is not interpolated and can contain # formatting characters - it's used verbatim. Don't check any further. return format_string = node.args[format_arg].value if not isinstance(format_string, str): # If the log format is constant non-string (e.g. logging.debug(5)), # ensure there are no arguments. required_num_args = 0 else: try: if self._format_style == "old": keyword_args, required_num_args, _, _ = utils.parse_format_string( format_string ) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return elif self._format_style == "new": keyword_arguments, implicit_pos_args, explicit_pos_args = utils.parse_format_method_string( format_string ) keyword_args_cnt = len( set(k for k, l in keyword_arguments if not isinstance(k, int)) ) required_num_args = ( keyword_args_cnt + implicit_pos_args + explicit_pos_args ) except utils.UnsupportedFormatCharacter as ex: char = format_string[ex.index] self.add_message( "logging-unsupported-format", node=node, args=(char, ord(char), ex.index), ) return except utils.IncompleteFormatString: self.add_message("logging-format-truncated", node=node) return if num_args > required_num_args: self.add_message("logging-too-many-args", node=node) elif num_args < required_num_args: self.add_message("logging-too-few-args", node=node)
def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node (astroid.node_classes.NodeNG): AST node to be checked. format_arg (int): Index of the format string in the node arguments. """ num_args = _count_supplied_tokens(node.args[format_arg + 1:]) if not num_args: # If no args were supplied, then all format strings are valid - # don't check any further. return format_string = node.args[format_arg].value if not isinstance(format_string, str): # If the log format is constant non-string (e.g. logging.debug(5)), # ensure there are no arguments. required_num_args = 0 else: try: if self._format_style == "%": keyword_args, required_num_args, _, _ = utils.parse_format_string( format_string) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return elif self._format_style == "{": keys, num_args, manual_pos_arg = utils.parse_format_method_string( format_string) kargs = len( set(k for k, l in keys if not isinstance(k, int))) required_num_args = kargs + num_args + manual_pos_arg except utils.UnsupportedFormatCharacter as ex: char = format_string[ex.index] self.add_message( "logging-unsupported-format", node=node, args=(char, ord(char), ex.index), ) return except utils.IncompleteFormatString: self.add_message("logging-format-truncated", node=node) return if num_args > required_num_args: self.add_message("logging-too-many-args", node=node) elif num_args < required_num_args: self.add_message("logging-too-few-args", node=node)
def visit_binop(self, node): if node.op != '%': return left = node.left args = node.right if not (isinstance(left, astroid.Const) and isinstance(left.value, basestring)): return format_string = left.value try: required_keys, required_num_args = \ utils.parse_format_string(format_string) except utils.UnsupportedFormatCharacter, e: c = format_string[e.index] self.add_message('bad-format-character', node=node, args=(c, ord(c), e.index)) return
def visit_binop(self, node): if node.op != '%': return left = node.left args = node.right if not (isinstance(left, astng.Const) and isinstance(left.value, basestring)): return format_string = left.value try: required_keys, required_num_args = \ utils.parse_format_string(format_string) except utils.UnsupportedFormatCharacter, e: c = format_string[e.index] self.add_message('E1300', node=node, args=(c, ord(c), e.index)) return
def _check_format_string(self, node, format_arg): """Checks that format string tokens match the supplied arguments. Args: node: AST node to be checked. format_arg: Index of the format string in the node arguments. """ num_args = _count_supplied_tokens(node.args[format_arg + 1:]) if not num_args: # If no args were supplied, then all format strings are valid - # don't check any further. return format_string = node.args[format_arg].value if not isinstance(format_string, six.string_types): # If the log format is constant non-string (e.g. logging.debug(5)), # ensure there are no arguments. required_num_args = 0 else: try: keyword_args, required_num_args = \ utils.parse_format_string(format_string) if keyword_args: # Keyword checking on logging strings is complicated by # special keywords - out of scope. return except utils.UnsupportedFormatCharacter as ex: char = format_string[ex.index] self.add_message('logging-unsupported-format', node=node, args=(char, ord(char), ex.index)) return except utils.IncompleteFormatString: self.add_message('logging-format-truncated', node=node) return if num_args > required_num_args: self.add_message('logging-too-many-args', node=node) elif num_args < required_num_args: self.add_message('logging-too-few-args', node=node)
def visit_binop(self, node): if node.op != "%": return left = node.left args = node.right if not (isinstance(left, astroid.Const) and isinstance(left.value, str)): return format_string = left.value try: ( required_keys, required_num_args, required_key_types, required_arg_types, ) = utils.parse_format_string(format_string) except utils.UnsupportedFormatCharacter as exc: formatted = format_string[exc.index] self.add_message( "bad-format-character", node=node, args=(formatted, ord(formatted), exc.index), ) return except utils.IncompleteFormatString: self.add_message("truncated-format-string", node=node) return if required_keys and required_num_args: # The format string uses both named and unnamed format # specifiers. self.add_message("mixed-format-string", 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, astroid.Dict): keys = set() unknown_keys = False for k, _ in args.items: if isinstance(k, astroid.Const): key = k.value if isinstance(key, str): keys.add(key) else: self.add_message( "bad-format-string-key", node=node, args=key ) else: # One of the keys was something other than a # constant. Since we can't tell what it is, # suppress 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( "missing-format-string-key", node=node, args=key ) for key in keys: if key not in required_keys: self.add_message( "unused-format-string-key", node=node, args=key ) for key, arg in args.items: if not isinstance(key, astroid.Const): continue format_type = required_key_types.get(key.value, None) arg_type = utils.safe_infer(arg) if ( format_type is not None and arg_type not in (None, astroid.Uninferable) and not arg_matches_format_type(arg_type, format_type) ): self.add_message( "bad-string-format-type", node=node, args=(arg_type.pytype(), format_type), ) elif isinstance(args, (OTHER_NODES, astroid.Tuple)): type_name = type(args).__name__ self.add_message("format-needs-mapping", 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. args_elts = () if isinstance(args, astroid.Tuple): rhs_tuple = utils.safe_infer(args) num_args = None if hasattr(rhs_tuple, "elts"): args_elts = rhs_tuple.elts num_args = len(args_elts) elif isinstance(args, (OTHER_NODES, (astroid.Dict, astroid.DictComp))): args_elts = [args] 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("too-many-format-args", node=node) elif num_args < required_num_args: self.add_message("too-few-format-args", node=node) for arg, format_type in zip(args_elts, required_arg_types): if not arg: continue arg_type = utils.safe_infer(arg) if ( arg_type not in ( None, astroid.Uninferable, ) and not arg_matches_format_type(arg_type, format_type) ): self.add_message( "bad-string-format-type", node=node, args=(arg_type.pytype(), format_type), )
def visit_binop(self, node): if node.op != "%": return left = node.left args = node.right if not (isinstance(left, astroid.Const) and isinstance(left.value, str)): return format_string = left.value try: required_keys, required_num_args, required_key_types, required_arg_types = utils.parse_format_string( format_string ) except utils.UnsupportedFormatCharacter as e: c = format_string[e.index] self.add_message( "bad-format-character", node=node, args=(c, ord(c), e.index) ) return except utils.IncompleteFormatString: self.add_message("truncated-format-string", node=node) return if required_keys and required_num_args: # The format string uses both named and unnamed format # specifiers. self.add_message("mixed-format-string", 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, astroid.Dict): keys = set() unknown_keys = False for k, _ in args.items: if isinstance(k, astroid.Const): key = k.value if isinstance(key, str): keys.add(key) else: self.add_message( "bad-format-string-key", node=node, args=key ) else: # One of the keys was something other than a # constant. Since we can't tell what it is, # suppress 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( "missing-format-string-key", node=node, args=key ) for key in keys: if key not in required_keys: self.add_message( "unused-format-string-key", node=node, args=key ) for key, arg in args.items: if not isinstance(key, astroid.Const): continue format_type = required_key_types.get(key.value, None) arg_type = utils.safe_infer(arg) if ( format_type is not None and arg_type not in (None, astroid.Uninferable) and not arg_matches_format_type(arg_type, format_type) ): self.add_message( "bad-string-format-type", node=node, args=(arg_type.pytype(), format_type), ) elif isinstance(args, (OTHER_NODES, astroid.Tuple)): type_name = type(args).__name__ self.add_message("format-needs-mapping", 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. args_elts = () if isinstance(args, astroid.Tuple): rhs_tuple = utils.safe_infer(args) num_args = None if hasattr(rhs_tuple, "elts"): args_elts = rhs_tuple.elts num_args = len(args_elts) elif isinstance(args, (OTHER_NODES, (astroid.Dict, astroid.DictComp))): args_elts = [args] 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("too-many-format-args", node=node) elif num_args < required_num_args: self.add_message("too-few-format-args", node=node) for arg, format_type in zip(args_elts, required_arg_types): if not arg: continue arg_type = utils.safe_infer(arg) if arg_type not in ( None, astroid.Uninferable, ) and not arg_matches_format_type(arg_type, format_type): self.add_message( "bad-string-format-type", node=node, args=(arg_type.pytype(), format_type), )
def visit_binop(self, node): if node.op != '%': return left = node.left args = node.right if not (isinstance(left, astroid.Const) and isinstance(left.value, six.string_types)): return format_string = left.value try: required_keys, required_num_args = \ utils.parse_format_string(format_string) except utils.UnsupportedFormatCharacter as e: c = format_string[e.index] self.add_message('bad-format-character', node=node, args=(c, ord(c), e.index)) return except utils.IncompleteFormatString: self.add_message('truncated-format-string', node=node) return if required_keys and required_num_args: # The format string uses both named and unnamed format # specifiers. self.add_message('mixed-format-string', 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, astroid.Dict): keys = set() unknown_keys = False for k, _ in args.items: if isinstance(k, astroid.Const): key = k.value if isinstance(key, six.string_types): keys.add(key) else: self.add_message('bad-format-string-key', 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('missing-format-string-key', node=node, args=key) for key in keys: if key not in required_keys: self.add_message('unused-format-string-key', node=node, args=key) elif isinstance(args, OTHER_NODES + (astroid.Tuple,)): type_name = type(args).__name__ self.add_message('format-needs-mapping', 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, astroid.Tuple): num_args = len(args.elts) elif isinstance(args, OTHER_NODES + (astroid.Dict, astroid.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('too-many-format-args', node=node) elif num_args < required_num_args: self.add_message('too-few-format-args', node=node)