-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement reusable Method Deprecation checker. #4051
Implement reusable Method Deprecation checker. #4051
Conversation
5a9a6af
to
dd516d4
Compare
I am not able to reproduce failing test in CI. Locally, all tests are passing. |
@matusvalo do not care about failing CI. The reason of such failure is my last commit on astroid master branch. I am currently working on a fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the merge request, this seems reasonable. I left a minor comment, but we could merge once astroid is fixed.
Thank you @Pierre-Sassoulas for your comments. I will Implement your proposals. |
dd516d4
to
cb3cd75
Compare
A have pushed new version of PR. I have implemented the feedback, cleaned the code (mainly docstrings) and added unittests. In the next step, I would like to add documentation to How To guide: http://pylint.pycqa.org/en/latest/how_tos/custom_checkers.html Should it go to this PR or, should I create new PR? |
cb3cd75
to
880b16b
Compare
Thanks a lot ! Documentation is much needed and very appreciated. Usually I would say to open another MR but the pipeline for next release is getting crowded so we could do with fewer pipelines to run and rebase to do especially for such a clear and straigthforward merge request :) |
I was thinking about documentation. Where do you think is the best place documenting it? I was thinking about two places:
I am not sure whether 1. is the best place since how to should be light. Good place can be 2. but here I would document it together with other classes (and hence it's better in separate MR). |
Maybe you could add another example next to the example checker in the repository for those wanting more details ?
=>
|
30c1455
to
38b81ae
Compare
I have implemented the example as discussed. The changes are pushed to MR. Moreover, I have one though about the MR: The mixin class is raising "W1505": (
"Using deprecated method %s()",
"deprecated-method",
"The method is marked as deprecated and will be removed in "
"a future version of Python. Consider looking for an "
"alternative in the documentation.",
) Otherwise following error is raised:
Hence we should somehow
I am not sure what is the best way how to do it. |
I don't think I have a very elegant way to fix this, the faster would be to rename the msgid/symbol to something like "W1234", "django-deprecated-method". The other one would be to find a way for the MessageStore to know that a message can be shared between Checker as long as the msgid/symbol is the same. (I thought it would be the case ? Do you have the problem if you use the original "W0002" and "deprecated-message" ?) It could be a constant |
Yes, the problem is that if I am not sure whether sharing msgid and msg symbol between multiple checker is the right approach - in documentation it is explicitly said that each checker should have it's own set of errors:
The I was thinking about simple passing of msg symbol as attribute. Does it make sense to let user define its own checker as class attribute:
class DeprecatedMixin(metaclass=abc.ABCMeta):
# Message Symbol to be issued for deprecated method
deprecated_method_msg_symbol = None
@abc.abstractmethod
def deprecated_methods(self):
pass
def check_deprecated_method(self, node, inferred):
# Code iterating over methods/functions omited
if any(name in self.deprecated_methods() for name in (qname, func_name)):
# We are raising message defined in deprecated_method_msg_symbol
self.add_message(self.deprecated_method_msg_symbol, node=node, args=(func_name,))
import astroid
from pylint.checkers import BaseChecker, DeprecatedMixin, utils
from pylint.interfaces import IAstroidChecker
class DeprecationChecker(BaseChecker, DeprecatedMixin):
__implements__ = (IAstroidChecker,)
name = "deprecated"
msgs = {
"W0002": (
"Using deprecated method %s()",
"mymethod-deprecated-method",
"The method is marked as deprecated and will be removed in "
"the future.",
),
}
deprecated_method_msg_symbol = 'mymethod-deprecated-method'
def visit_call(self, node):
try:
for inferred in node.func.infer():
# Calling entry point for deprecation check logic.
self.check_deprecated_method(node, inferred)
except astroid.InferenceError:
return
def deprecated_methods(self):
return {'mymodule.deprecated_function', 'mymodule.MyClass.deprecated_method'}
def register(linter):
linter.register_checker(DeprecationChecker(linter))
|
Yeap, it would makes sense with what is said in the documentation. Or we could define the |
38b81ae
to
38548cd
Compare
I am not 100% familiar with pylint internals so it is difficult to say for me, but it make sense what you are proposing. Could you please guide what changes needs to be done in this MR in order to finish it? |
Can you try putting the message for deprecation in DeprecatedMixin, and see what goes wrong, first ? There is probably some change to do in the way the message are registered for it to work, I could find time to do these. |
7d9a90f
to
b9ad228
Compare
I have put the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having to inherit in a specific order is not ideal but the code is a lot cleaner than first version and I think pretty elegant now. Also it beats having to touch the internal of pylint to make the feature. It's well documented too and we even made a small optimization... I'm glad it's ready for 2.7 :) !
This PR is moving deprecated check logic to separate mixin class
DeprecatedMixin
. This enables plugins to implement their own deprecation checks. The most visible use case can be pylint-django. Here is the example of simple plugin:Current desing has multiple design choices which can be discussed:
DeprecatedMixin
requires to definedeprecated-method
msg in Checker class. This can be cumbersome, but it is backwards compatible and it conforms rule that each checker has it's own isolated set of IDs.Current state of PR is mainly a starting point for final implementation. The following parts needs to be done:
Steps
doc/whatsnew/<current release.rst>
.Description
Type of Changes
Related Issue
Closes #4049