Skip to content

Create a TypeVar style for invalid-name #5894

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

Merged
merged 12 commits into from
Mar 24, 2022

Conversation

DanielNoord
Copy link
Collaborator

@DanielNoord DanielNoord commented Mar 11, 2022

  • Add yourself to CONTRIBUTORS if you are a new contributor.
  • Write a good description on what the PR does.

Type of Changes

Type
✨ New feature
🔨 Refactoring

Description

Not sure if we want to do this, but:
After merging #5825, we can merge this. It only adds the necessary boilerplate for typevar name checking, but uses the pattern as set for classes.
This makes the diff of #5221 even smaller and should help getting that merged asap after #5825 has been merged.

Closes #3401.

@DanielNoord DanielNoord added Enhancement ✨ Improvement to a component Maintenance Discussion or action around maintaining pylint or the dev workflow labels Mar 11, 2022
@DanielNoord DanielNoord added this to the 2.13.0 milestone Mar 11, 2022
@coveralls
Copy link

coveralls commented Mar 11, 2022

Pull Request Test Coverage Report for Build 1986086805

  • 27 of 27 (100.0%) changed or added relevant lines in 2 files are covered.
  • 321 unchanged lines in 34 files lost coverage.
  • Overall coverage increased (+0.06%) to 94.093%

Files with Coverage Reduction New Missed Lines %
pylint/checkers/newstyle.py 1 96.23%
pylint/checkers/spelling.py 1 76.41%
pylint/checkers/strings.py 1 93.78%
pylint/extensions/comparetozero.py 1 97.14%
pylint/extensions/emptystring.py 1 96.88%
pylint/extensions/typing.py 1 97.08%
pylint/pyreverse/mermaidjs_printer.py 1 98.18%
pylint/testutils/pyreverse.py 1 95.0%
pylint/checkers/deprecated.py 2 97.67%
pylint/checkers/design_analysis.py 2 98.91%
Totals Coverage Status
Change from base Build 1969334727: 0.06%
Covered Lines: 15196
Relevant Lines: 16150

💛 - Coveralls

pylintrc Outdated
Comment on lines 356 to 357
# Naming style used for type variables. Default is PascalCase.
typevar-naming-style=PascalCase
Copy link
Member

Choose a reason for hiding this comment

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

I believe this was the most recent discussion we had: Should we add a typevar-naming-style add all or only have a typevar-rgx option?

The arguments so far

  • If we say the default is PascalCase, it will be difficult to explain why PathType is invalid and PathT valid when both are PascalCase.
  • It's unclear what the regex patterns for the other styles should be and how they should interact with the _co and _contra suffixes.
  • Having only the the rgx option (with default) would still allow for customizability if wanted.
  • What should be done in similar cases, e.g. for ParamSpec names or Type aliases?

Changing it should be possible if we modify _create_naming_rules and _create_naming_options to allow for rgx only options.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was hesitant to do this at first, but turned out to be relatively easy to implement. I have pushed an iteration which does this to this branch. This basically supersedes #5221. I'm also fine with pushing it to that branch to keep the discussion in one place, but perhaps a relatively clean slate is helpful here.

@DanielNoord DanielNoord changed the title Add TypeVar name checking boilerplate Create a TypeVar style for invalid-name Mar 11, 2022
@DanielNoord DanielNoord requested a review from cdce8p March 11, 2022 16:06
Copy link
Member

@cdce8p cdce8p 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 like the solution I had in mind. 👍🏻
I think it's a good idea to do the changes here and not in the old PR.

pylintrc Outdated
Comment on lines 356 to 358
# Regular expression which can overwrite the naming style set by typevar-naming-style.
# If left empty, type variables will be checked with the set naming style.
typevar-rgx=
Copy link
Member

Choose a reason for hiding this comment

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

That doesn't work. If pattern is empty, it will match an empty pattern.
https://github.com/PyCQA/pylint/blob/d01e5e167834097ff7e5bf26a069aa1339669183/pylint/config/option.py#L102

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I checked. If it is empty the setting will be None (I think this is due to how the config file is parsed). The following lines make sure that the pattern is only picked up if the pattern is set. (Note that this is also how this works for all other patterns).

custom_regex = getattr(self.config, custom_regex_setting_name, None)
if custom_regex is not None:
    regexps[name_type] = custom_regex

Copy link
Member

Choose a reason for hiding this comment

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

An empty setting will be re.compile('') and thus overwrite regexps[name_type]. That isn't bad, we just can't leave it empty in pylintrc. Otherwise TypeVar names in pylint itself won't be checked. That's similar to the other regex settings in pylintrc, eg. class-rgx.

Alternatively, an possibly my preference would be the comment out that line. Similar to #class-const-rgx=.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah I understand why I was mistaken. The functional test don't actually use this pylintrc so they passed even with this uncommented.

Commented it out!

@DanielNoord DanielNoord requested a review from cdce8p March 12, 2022 09:21

The following type of names are checked with a predefined pattern:

- TypeVars. Accepted names include: `T`, `TypeVar`, `_CallableT`, `_T_co`.
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if a table would make sense here? With Name type, Good names, and Bad names.

I would prefer not to suggest TypeVar. True it's valid, but it shouldn't be used IMO. Let's use something like MyClassT to highlight PascalCase. For bad names, we should definitely mention something like T_Class, and MyClassType.

Some other names from the tests: AnyStr, DeviceTypeT, DeviceType, CALLABLE_T.

pylintrc Outdated
Comment on lines 356 to 358
# Regular expression which can overwrite the naming style set by typevar-naming-style.
# If left empty, type variables will be checked with the set naming style.
typevar-rgx=
Copy link
Member

Choose a reason for hiding this comment

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

An empty setting will be re.compile('') and thus overwrite regexps[name_type]. That isn't bad, we just can't leave it empty in pylintrc. Otherwise TypeVar names in pylint itself won't be checked. That's similar to the other regex settings in pylintrc, eg. class-rgx.

Alternatively, an possibly my preference would be the comment out that line. Similar to #class-const-rgx=.

Comment on lines 11 to 33
GoodNameWithoutContra = TypeVar( # [typevar-name-incorrect-variance]
"GoodNameWithoutContra", contravariant=True
)
GoodNameT_co = TypeVar("GoodNameT_co", covariant=True)
GoodNameT_contra = TypeVar("GoodNameT_contra", contravariant=True)
GoodBoundNameT = TypeVar("GoodBoundNameT", bound=int)
GoodBoundNameT_co = TypeVar( # [typevar-name-incorrect-variance]
"GoodBoundNameT_co", bound=int
)
GoodBoundNameT_contra = TypeVar( # [typevar-name-incorrect-variance]
"GoodBoundNameT_contra", bound=int
)
GoodBoundNameT_co = TypeVar("GoodBoundNameT_co", bound=int, covariant=True)
GoodBoundNameT_contra = TypeVar("GoodBoundNameT_contra", bound=int, contravariant=True)

GoodBoundNameT_co = TypeVar("GoodBoundNameT_co", int, str, covariant=True)
GoodBoundNameT_co = TypeVar( # [typevar-name-incorrect-variance]
"GoodBoundNameT_co", int, str, contravariant=True
)
GoodBoundNameT_contra = TypeVar("GoodBoundNameT_contra", int, str, contravariant=True)
GoodBoundNameT_contra = TypeVar( # [typevar-name-incorrect-variance]
"GoodBoundNameT_contra", int, str, covariant=True
)
Copy link
Member

Choose a reason for hiding this comment

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

Can we remove some of the GoodName TypeVars here? We already have dedicated tests for the typevar-name-incorrect-variance so I don't think we need to test this again here.

Basically just keep

# PascalCase names with prefix
GoodNameT = TypeVar("GoodNameT")
_T = TypeVar("_T")
_GoodNameT = TypeVar("_GoodNameT")
__GoodNameT = TypeVar("__GoodNameT")
GoodNameT_co = TypeVar("GoodNameT_co", covariant=True)
GoodNameT_contra = TypeVar("GoodNameT_contra", contravariant=True)

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.

Looks good !

@DanielNoord DanielNoord requested a review from cdce8p March 14, 2022 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement ✨ Improvement to a component Maintenance Discussion or action around maintaining pylint or the dev workflow
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pylint should not use Class name regex for TypeVar names
4 participants