I originally asked the following question on Stack Overflowhttp://stackoverflow.com/questions/18500998/extending-pylint-to-deal-with-template-variables. It was suggested that this would be the better venue for discussion.
--
I wrote the say https://pypi.python.org/pypi/say module to make formatted printing simpler and more straightforward. E.g.
say("{len(items)} retrieved; {n_errors} encountered")
rather than:
print("{0} retrieved; {1} encountered".format(len(items), n_errors))
That part is going great. But I like to run pylint to look for gotchas and mistakes. Unfortunately, many data values are constructed solely for their usefulness in output operations, and pylint cannot "see" that use in a say call (or any other templates output mechanism) constitutes a genuine use of the variable. Wave after wave of W0612 (unused-variable) warnings can result.
It's possible to simply put in ignore comments, but that seems retrograde. I'd rather just extend pylint to understand that variables used in say() templates are, in fact, used.
.../pylint/checkers/variables.py appears to be the place to add this check, but I'm unfamiliar with the codebase. Any hints or suggestions as to how to register variables used in format-style strings are, indeed, properly used?
--
One SO commenter suggested that since pylint doesn't do much with strings, this may be a fair amount of work. But I already know how to parse format-style strings; I just use Python's own string.Formatter.parse. Creating an AST from the contents of the format braces and walking it to find what names are referenced--I've got that covered. What I most need is insight into how to communicate to pylint that it should consider the identifiers I've found to be used.
I'd also seen at least one comment online suggesting that pylint doesn't really have an extensions/plugin mechanism. Is that true? Either way, what would be the best way to provide extended functionality atop pylint? Is the team receptive to code contributions?
Hi Jonathan,
On 29 août 13:41, Jonathan Eunice wrote:
I originally asked the following question on Stack Overflowhttp://stackoverflow.com/questions/18500998/extending-pylint-to-deal-with-template-variables. It was suggested that this would be the better venue for discussion.
I've seen this, even added some hint there.
[snip]
One SO commenter suggested that since pylint doesn't do much with strings, this may be a fair amount of work. But I already know how to parse format-style strings; I just use Python's own string.Formatter.parse. Creating an AST from the contents of the format braces and walking it to find what names are referenced--I've got that covered. What I most need is insight into how to communicate to pylint that it should consider the identifiers I've found to be used.
I'd also seen at least one comment online suggesting that pylint doesn't really have an extensions/plugin mechanism. Is that true? Either way, what would be the best way to provide extended functionality atop pylint? Is the team receptive to code contributions?
Pylint has some extensions/plugin mecanism and we're definitly receptive to code contribution. For instance, contribution avoiding false positive when variables are used in (new or old style) format strings w/ usage of locals() or other kind of magic will be greatly appreciated.
In the case of your custom say() function, the "problem" is that you want to change the behaviour of some existing checker, while the bare plugins api is intended to provide new checkers (or other kind of objects used by pylint). So you're left with the following options:
* monkey-patch the existing checker in a plugin module
* provide a whole replacement for the variable checker, probably by inheriting from the original one. This will require a 'replace_checker' API in addition to the existing 'register_checker' method on the linter class. If you like this option, I may implement this method for you
* modify the original variable checker so that one may specify that additional names have been consumed, then write a plugin that use the newly introduced API to handle 'say()'
IMO the long term solution is the last option (even though having the 'replace_checker' method may be of interest anyway ;).
BTW, a Pylint plugin is simply a python module with a function like
def register(linter): ...
function in it, that may then register custom checkers, reporters and so on (do some monkey-patch, call some variable checker module function, etc.). There is also some extensions points at the astroid (ie AST) level but I don't think it will help in your case.
Note that this isn't peculiar to the say module. You can generate these false positives with dict format expansions in Python without using an external module. For instance:
x = 4 print("%(x)s" % locals())
Pylint can't tell that x is used because it's use is buried in the format string. I have stumbled on this before and ignored it, but I think it would be a useful improvement.
Skip