Add string_format pylint plugin.
This commit is contained in:
parent
a9fe30e34b
commit
8c1353537d
1 changed files with 86 additions and 0 deletions
86
test/sanity/pylint/plugins/string_format.py
Normal file
86
test/sanity/pylint/plugins/string_format.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
# (c) 2018, Matt Martz <matt@sivel.net>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
import astroid
|
||||
from pylint.interfaces import IAstroidChecker
|
||||
from pylint.checkers import BaseChecker
|
||||
from pylint.checkers import utils
|
||||
from pylint.checkers.utils import check_messages
|
||||
from pylint.checkers.strings import parse_format_method_string
|
||||
|
||||
_PY3K = sys.version_info[:2] >= (3, 0)
|
||||
|
||||
MSGS = {
|
||||
'E9305': ("Format string contains automatic field numbering "
|
||||
"specification",
|
||||
"ansible-format-automatic-specification",
|
||||
"Used when a PEP 3101 format string contains automatic "
|
||||
"field numbering (e.g. '{}').",
|
||||
{'minversion': (2, 6)}),
|
||||
'E9390': ("bytes object has no .format attribute",
|
||||
"ansible-no-format-on-bytestring",
|
||||
"Used when a bytestring was used as a PEP 3101 format string "
|
||||
"as Python3 bytestrings do not have a .format attribute",
|
||||
{'minversion': (3, 0)}),
|
||||
}
|
||||
|
||||
|
||||
class AnsibleStringFormatChecker(BaseChecker):
|
||||
"""Checks string formatting operations to ensure that the format string
|
||||
is valid and the arguments match the format string.
|
||||
"""
|
||||
|
||||
__implements__ = (IAstroidChecker,)
|
||||
name = 'string'
|
||||
msgs = MSGS
|
||||
|
||||
@check_messages(*(MSGS.keys()))
|
||||
def visit_call(self, node):
|
||||
func = utils.safe_infer(node.func)
|
||||
if (isinstance(func, astroid.BoundMethod)
|
||||
and isinstance(func.bound, astroid.Instance)
|
||||
and func.bound.name in ('str', 'unicode', 'bytes')):
|
||||
if func.name == 'format':
|
||||
self._check_new_format(node, func)
|
||||
|
||||
def _check_new_format(self, node, func):
|
||||
""" Check the new string formatting """
|
||||
if (isinstance(node.func, astroid.Attribute)
|
||||
and not isinstance(node.func.expr, astroid.Const)):
|
||||
return
|
||||
try:
|
||||
strnode = next(func.bound.infer())
|
||||
except astroid.InferenceError:
|
||||
return
|
||||
if not isinstance(strnode, astroid.Const):
|
||||
return
|
||||
|
||||
if _PY3K and isinstance(strnode.value, six.binary_type):
|
||||
self.add_message('ansible-no-format-on-bytestring', node=node)
|
||||
return
|
||||
if not isinstance(strnode.value, six.string_types):
|
||||
return
|
||||
|
||||
if node.starargs or node.kwargs:
|
||||
return
|
||||
try:
|
||||
fields, num_args, manual_pos = parse_format_method_string(strnode.value)
|
||||
except utils.IncompleteFormatString:
|
||||
return
|
||||
|
||||
if num_args:
|
||||
self.add_message('ansible-format-automatic-specification',
|
||||
node=node)
|
||||
return
|
||||
|
||||
|
||||
def register(linter):
|
||||
"""required method to auto register this checker """
|
||||
linter.register_checker(AnsibleStringFormatChecker(linter))
|
Loading…
Reference in a new issue