diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-10-25 09:27:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-25 09:27:47 +0200 |
commit | 8cfce138e9519f63e969e89359e86e140b2f0f13 (patch) | |
tree | eff12c3d285d53b7a6e4cf387f265ca029c72b51 /pylint | |
parent | ed3449fee063d91f050c6b733030d3b3d7ad719f (diff) | |
download | pylint-git-8cfce138e9519f63e969e89359e86e140b2f0f13.tar.gz |
Add ``mixin-class-rgx`` option (#5203)
Co-authored-by: Alpha <alpha@pokesplash.net>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Diffstat (limited to 'pylint')
-rw-r--r-- | pylint/checkers/async.py | 10 | ||||
-rw-r--r-- | pylint/checkers/classes.py | 5 | ||||
-rw-r--r-- | pylint/checkers/typecheck.py | 29 | ||||
-rw-r--r-- | pylint/utils/utils.py | 5 |
4 files changed, 38 insertions, 11 deletions
diff --git a/pylint/checkers/async.py b/pylint/checkers/async.py index f9d1e15dd..9aaead7c4 100644 --- a/pylint/checkers/async.py +++ b/pylint/checkers/async.py @@ -44,6 +44,7 @@ class AsyncChecker(checkers.BaseChecker): self._ignore_mixin_members = utils.get_global_option( self, "ignore-mixin-members" ) + self._mixin_class_rgx = utils.get_global_option(self, "mixin-class-rgx") self._async_generators = ["contextlib.asynccontextmanager"] @checker_utils.check_messages("yield-inside-async-function") @@ -81,10 +82,11 @@ class AsyncChecker(checkers.BaseChecker): # just skip it. if not checker_utils.has_known_bases(inferred): continue - # Just ignore mixin classes. - if self._ignore_mixin_members: - if inferred.name[-5:].lower() == "mixin": - continue + # Ignore mixin classes if they match the rgx option. + if self._ignore_mixin_members and self._mixin_class_rgx.match( + inferred.name + ): + continue else: continue self.add_message( diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py index 0b15861b0..2ab66fd0b 100644 --- a/pylint/checkers/classes.py +++ b/pylint/checkers/classes.py @@ -808,6 +808,9 @@ a metaclass class method.", self._first_attrs = [] self._meth_could_be_func = None + def open(self) -> None: + self._mixin_class_rgx = get_global_option(self, "mixin-class-rgx") + @astroid.decorators.cachedproperty def _dummy_rgx(self): return get_global_option(self, "dummy-variables-rgx", default=None) @@ -1029,7 +1032,7 @@ a metaclass class method.", def _check_attribute_defined_outside_init(self, cnode: nodes.ClassDef) -> None: # check access to existent members on non metaclass classes - if self._ignore_mixin and cnode.name[-5:].lower() == "mixin": + if self._ignore_mixin and self._mixin_class_rgx.match(cnode.name): # We are in a mixin class. No need to try to figure out if # something is missing, since it is most likely that it will # miss. diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 8fa80ee21..549cd7f4c 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -442,7 +442,14 @@ SEQUENCE_TYPES = { } -def _emit_no_member(node, owner, owner_name, ignored_mixins=True, ignored_none=True): +def _emit_no_member( + node, + owner, + owner_name, + mixin_class_rgx: Pattern[str], + ignored_mixins=True, + ignored_none=True, +): """Try to see if no-member should be emitted for the given owner. The following cases are ignored: @@ -462,7 +469,7 @@ def _emit_no_member(node, owner, owner_name, ignored_mixins=True, ignored_none=T return False if is_super(owner) or getattr(owner, "type", None) == "metaclass": return False - if owner_name and ignored_mixins and owner_name[-5:].lower() == "mixin": + if owner_name and ignored_mixins and mixin_class_rgx.match(owner_name): return False if isinstance(owner, nodes.FunctionDef) and ( owner.decorators or owner.is_abstract() @@ -781,14 +788,24 @@ class TypeChecker(BaseChecker): }, ), ( + "mixin-class-rgx", + { + "default": ".*[Mm]ixin", + "type": "regexp", + "metavar": "<regexp>", + "help": "Regex pattern to define which classes are considered mixins " + "ignore-mixin-members is set to 'yes'", + }, + ), + ( "ignore-mixin-members", { "default": True, "type": "yn", "metavar": "<y_or_n>", - "help": 'Tells whether missing members accessed in mixin \ -class should be ignored. A mixin class is detected if its name ends with \ -"mixin" (case insensitive).', + "help": "Tells whether missing members accessed in mixin " + "class should be ignored. A class is considered mixin if its name matches " + "the mixin-class-rgx option.", }, ), ( @@ -898,6 +915,7 @@ accessed. Python regular expressions are accepted.", def open(self) -> None: py_version = get_global_option(self, "py-version") self._py310_plus = py_version >= (3, 10) + self._mixin_class_rgx = get_global_option(self, "mixin-class-rgx") @astroid.decorators.cachedproperty def _suggestion_mode(self): @@ -1040,6 +1058,7 @@ accessed. Python regular expressions are accepted.", node, owner, name, + self._mixin_class_rgx, ignored_mixins=self.config.ignore_mixin_members, ignored_none=self.config.ignore_none, ): diff --git a/pylint/utils/utils.py b/pylint/utils/utils.py index 6c9f11298..8243bc322 100644 --- a/pylint/utils/utils.py +++ b/pylint/utils/utils.py @@ -54,7 +54,10 @@ GLOBAL_OPTION_BOOL = Literal[ GLOBAL_OPTION_INT = Literal["max-line-length", "docstring-min-length"] GLOBAL_OPTION_LIST = Literal["ignored-modules"] GLOBAL_OPTION_PATTERN = Literal[ - "no-docstring-rgx", "dummy-variables-rgx", "ignored-argument-names" + "no-docstring-rgx", + "dummy-variables-rgx", + "ignored-argument-names", + "mixin-class-rgx", ] GLOBAL_OPTION_PATTERN_LIST = Literal["ignore-paths"] GLOBAL_OPTION_TUPLE_INT = Literal["py-version"] |