Created
September 25, 2017 03:06
-
-
Save jude/aa599e3f9ea43fc0fa2f490dd5845690 to your computer and use it in GitHub Desktop.
pylint plugin example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Checker for unneccessary use of str() in format() arguments.""" | |
import six | |
import astroid | |
from pylint.checkers import BaseChecker, utils | |
from pylint.interfaces import IAstroidChecker | |
#from .common import BASE_ID | |
BASE_ID=99 | |
def register(linter): | |
"""Register checkers.""" | |
linter.register_checker(format_str_checker(linter)) | |
class format_str_checker(BaseChecker): | |
""" | |
Checks that the arguments to format() are not str(something) | |
Bad: | |
"Bad {}".format(str(a)) | |
"Bad {nope}".format(nope=str(a)) | |
OK: | |
"Good".format(a) | |
"Good {yeah}".format(yeah=a) | |
""" | |
__implements__ = (IAstroidChecker,) | |
name = 'no-need-to-call-str-on-format-args-checker' | |
POSITIONAL_MESSAGE_ID = 'str-used-on-positional-format-argument' | |
KEYWORD_MESSAGE_ID = 'str-used-on-keyword-format-argument' | |
msgs = { | |
'C%d10' % BASE_ID: ( | |
"format argument #%d should be called without str()", | |
POSITIONAL_MESSAGE_ID, | |
"format() already converts its arguments to strings", | |
), | |
'C%d11' % BASE_ID: ( | |
"format argument '%s' should be called without str()", | |
KEYWORD_MESSAGE_ID, | |
"format() already converts its arguments to strings", | |
), | |
} | |
@utils.check_messages(POSITIONAL_MESSAGE_ID, KEYWORD_MESSAGE_ID) | |
def visit_callfunc(self, node): | |
"""Called for every function call in the source code.""" | |
if not isinstance(node.func, astroid.Attribute): | |
return | |
if node.func.attrname != "format": | |
# Be gone | |
return | |
if not self.linter.is_message_enabled(self.POSITIONAL_MESSAGE_ID, line=node.fromlineno): | |
return | |
# Check the positional args | |
index = 0 | |
for child in node.args: | |
index += 1 | |
if isinstance(child, astroid.Call): | |
if child.func.name == "str": | |
self.add_message(self.POSITIONAL_MESSAGE_ID, args=index, node=node) | |
if not self.linter.is_message_enabled(self.KEYWORD_MESSAGE_ID, line=node.fromlineno): | |
return | |
# Check the keyword args | |
if not node.keywords: | |
return | |
for child in node.keywords: | |
if isinstance(child.value, astroid.Call): | |
if child.value.func.name == "str": | |
self.add_message(self.KEYWORD_MESSAGE_ID, args=child.arg, node=node) | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment