Skip to content

Add configuration option exclude-too-few-public-methods #5191

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

Conversation

miketheman
Copy link
Contributor

@miketheman miketheman commented Oct 20, 2021

  • Add yourself to CONTRIBUTORS if you are a new contributor.
  • Add a ChangeLog entry describing what your PR does.
  • If it's a new feature, or an important bug fix, add a What's New entry in
    doc/whatsnew/<current release.rst>.
  • Write a good description on what the PR does.

Type of Changes

Type
✨ New feature

Description

Add feature to exclude classes from too-few-public-methods

Instead of adding specific packages to an in-code exclusion list,
add a configuration value that allows the end user to set values
for packages/modules and classes to exclude from evaluation.

Closes #3370

Copy link
Contributor Author

@miketheman miketheman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pierre-Sassoulas et al - here's what I've come up with so far. Looking forward to your review!

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like where this is going! Would be good to see an issue with (relatively) many upvotes get fixed!

I'm happy to assist with any of the changes I suggested!

@DanielNoord DanielNoord added Enhancement ✨ Improvement to a component Configuration Related to configuration labels Oct 20, 2021
@coveralls
Copy link

coveralls commented Oct 20, 2021

Pull Request Test Coverage Report for Build 1383302578

  • 6 of 6 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.002%) to 93.338%

Totals Coverage Status
Change from base Build 1383025181: 0.002%
Covered Lines: 13688
Relevant Lines: 14665

💛 - Coveralls

@miketheman miketheman marked this pull request as ready for review October 20, 2021 23:35
Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will really need to use get_global_option here to make this option and its implementation future-proof.

A good example of how to do this can be found here:
https://github.com/PyCQA/pylint/blob/80205dc813e17fc416e56bace982c971a10553fb/pylint/checkers/imports.py#L477
get_global_option is used to create a private attribute for which we do know the type. We do this in the open method because then it is called as soon as the checker class is "opened".

We get type inference because we have "overloaded" get_global_option here:
https://github.com/PyCQA/pylint/blob/80205dc813e17fc416e56bace982c971a10553fb/pylint/utils/utils.py#L232-L236

You will notice currently there is no GLOBAL_OPTION_PATTERN_LIST at the top of the file.
Furthermore, in T_GlobalOptionReturnTypes List[Pattern[str]] is not included. https://github.com/PyCQA/pylint/blob/80205dc813e17fc416e56bace982c971a10553fb/pylint/utils/utils.py#L67-L69

So to make this work and prepare it for a type-proof future we will need to do three things:

  1. Add get_global_option() to the open method of the class to create a private attribute and use that attribute in the checker
  2. Add a GLOBAL_OPTION_PATTERN_LIST variable to the utils/utils.py file
  3. Add the return type of GLOBAL_OPTION_PATTERN_LIST options (which is List[Pattern[str]] to T_GlobalOptionReturnTypes
  4. Add GLOBAL_OPTION_PATTERN_LIST to GLOBAL_OPTION_NAMES
  5. Create a new overload based on GLOBAL_OPTION_PATTERN_LIST and its return type

I know this might be a little more than you initially signed up for, so please let me know if I can help with anything or if you would like me to show how this should be done! As I said, I'm happy to help and think this is a valuable addition to pylint!

@DanielNoord
Copy link
Collaborator

@miketheman Just to let you know, I actually had to create a list of regex patterns option type myself 😄

It's located in this PR: DanielNoord#20 However, I need #5195 to be merged before I can create a PR for this change.
But to spare yourself some time you might want to wait for my PR to be merged. It should be much easier to add this option to GLOBAL_OPTION_PATTERN_LIST afterwards as I have already done step 2, 3, 4 and 5!

@miketheman
Copy link
Contributor Author

miketheman commented Oct 23, 2021

... you might want to wait for my PR to be merged ...

@DanielNoord Thanks for the guidance! I saw the dependent PR get merged, so am in no rush. I think the code works just fine, and no mypy errors are currently emitted, so I'm not clear how to test this if/when I make that change?

@DanielNoord
Copy link
Collaborator

@DanielNoord Thanks for the guidance! I saw the dependent PR get merged, so am in no rush. I think the code works just fine, and no mypy errors are currently emitted, so I'm not clear how to test this if/when I make that change?

I'm going to go over some of the review comments I got on some of my own existing PRs and then submit the PR which I talked about. I will split the commits so you can follow along and see what you would need to add once mine has been merged. You could also duplicate those commits here and then we would just resolve merge conflicts once both have been approved!

@DanielNoord
Copy link
Collaborator

I've cleaned up the PR and the commit history. You can look at it here:
#5201

To make your new option work you will need to add exclude-too-few-public-methods to the Literal list of GLOBAL_OPTION_PATTERN_LIST. This will tell mypy that when exclude-too-few-public-methods is used in get_global_option it should expect a List[Pattern[str]] return. See the relevant commit for my own PR here:
8a8e7a5

Next comes the slightly more difficult task of adding unittests for the new option. You can look at what I did here:
4b52567
You will need to do this in the TestDesignChecker class you already added your previous tests to:
https://github.com/PyCQA/pylint/blob/19b92aa4a717680361f9994110775afa6e76974d/tests/checkers/unittest_design.py#L16
Basically, by calling the set_config decorator you can "emulate" the process of setting a config in pylintrc (or any other config option). So you should create a simple test where the function is decorated with a string like you would normally use in pylintrc and see if get_global_option returns the expected list of compiled patterns. The tests I added in that commit both test the default value (which should be a list even if it is not provided) and the possibility of matching patterns using the any pattern.

You can wait for my PR to be merged or copy the work from 8a8e7a5 and you should be able to add the test yourself. That way you don't need to wait for me and we can just solve possible merge conflicts when the time comes.

Hopefully this explains it well enough, but please let me know if you have any further questions. I know this is all quite a bit of extra work for a simple new option, without any clear previous examples of how to do this. We need to improve our testing of setting configs with tests so this serves as a good learning case for us as well!

@DanielNoord
Copy link
Collaborator

@miketheman My PR has been merged, so if you merge main into your branch you should be able to built upon it!

@miketheman
Copy link
Contributor Author

I'll revisit soon!

@miketheman miketheman force-pushed the miketheman/exclude-class-from-too-few-public branch from 19b92aa to f47e156 Compare October 24, 2021 21:17
@miketheman
Copy link
Contributor Author

@DanielNoord I was confused about the test failure - I don't see that locally, and looks like I had misnamed a test output file. I've renamed the file in the most recent commit.

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! Perfect use of the get_global_option util :)

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for nitpicking so much on the option description. I believe this is the most true to what it actually does.

The failing tests seem to be a case of adding some disables to the functional test file!

@miketheman
Copy link
Contributor Author

The failing tests seem to be a case of adding some disables to the functional test file!

I'm not sure I understand this - as the test seems to only fail on Windows and pypy3 - is it possible those envs don't have the yaml/toml packages included?

@DanielNoord
Copy link
Collaborator

I guess so. Can we change the tests to not require an import? Just by inheriting from another class within the same file and then adding that classes name to the regex?

@miketheman
Copy link
Contributor Author

miketheman commented Oct 24, 2021

Sure, I can do that. But I was really trying to embody the capability of the original intent - excluding an imported module's inherited class - is there one from the Python stdlib you think would work better?

@DanielNoord
Copy link
Collaborator

I can't think of one immediately. Perhaps @Pierre-Sassoulas has some good suggestions here!

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job 👍

Before changing anything about the code, make sure we have a unit
test that covers the basic behavior.

Signed-off-by: Mike Fiedler <[email protected]>
Instead of adding specific packages to an in-code exclusion list,
add a configuration value that allows the end user to set values
for packages/modules and classes to exclude from evaluation.

TODO: needs documentation and examples

Signed-off-by: Mike Fiedler <[email protected]>
miketheman and others added 14 commits October 25, 2021 19:08
Also update the help string.

Signed-off-by: Mike Fiedler <[email protected]>
Signed-off-by: Mike Fiedler <[email protected]>
Signed-off-by: Mike Fiedler <[email protected]>
Signed-off-by: Mike Fiedler <[email protected]>
Co-authored-by: Daniël van Noord <[email protected]>
Signed-off-by: Mike Fiedler <[email protected]>
Using a stdlib of json ought to be future-proof enough to traverse
platforms.

Signed-off-by: Mike Fiedler <[email protected]>
Co-authored-by: Daniël van Noord <[email protected]>
@miketheman miketheman force-pushed the miketheman/exclude-class-from-too-few-public branch from 7f5af68 to bbfbffa Compare October 25, 2021 23:08
Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good choice!

Thanks for your work @miketheman! This is a really nice contribution and good and concise PR :)

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, very nice evolution !

@DanielNoord DanielNoord merged commit 448485a into pylint-dev:main Oct 26, 2021
@DanielNoord DanielNoord added this to the 2.12.0 milestone Oct 26, 2021
@miketheman miketheman deleted the miketheman/exclude-class-from-too-few-public branch October 26, 2021 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Configuration Related to configuration Enhancement ✨ Improvement to a component Hacktoberfest
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pydantic models should not trigger too-few-public-methods
4 participants