Question: Please provide a better entry point to pyreverse Currently, I have to do: I would like to do something like:

import os import sysfrom typing import List, Optional  from pylint.__pkginfo__ import __version__  # pylint: disable=import-outside-toplevel  def run_pylint():def run_pylint(*, arguments: Optional[List[str]] = None):    """Run pylint    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.lint import Run as PylintRun      try:        PylintRun(sys.argv[1:])        PylintRun(arguments or sys.argv[1:])     except KeyboardInterrupt:         sys.exit(1)


Question: Please provide a better entry point to pyreverse Currently, I have to do: I would like to do something like:

EpylintRun()  def run_pyreverse():    """run pyreverse"""def run_pyreverse(*, arguments: Optional[List[str]] = None):    """Run pyreverse    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.pyreverse.main import Run as PyreverseRun     PyreverseRun(sys.argv[1:])    PyreverseRun(arguments or sys.argv[1:]) def run_symilar(*, arguments: Optional[List[str]] = None):    """Run symilar def run_symilar():    """run symilar"""    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.checkers.similar import Run as SimilarRun     SimilarRun(sys.argv[1:])    SimilarRun(arguments or sys.argv[1:])   def modify_sys_path() -> None:


Question: [crash] doc params extension: --accept-no-param-doc: conflicting option string(s) There is a crash when using the doc_params extension. No crash.

from pylint.lint import PyLinter from pylint.utils import get_rst_title <del># Some modules have been renamed and deprecated under their old names.# Skip documenting these modules since:# 1) They are deprecated, why document them moving forward?# 2) We can't load the deprecated module and the newly renamed module at the# same time without getting naming conflictsDEPRECATED_MODULES = ["check_docs"]  # ==> docparams</del>  def builder_inited(app):     """Output full documentation in ReST format for all extension modules"""


Question: [crash] doc params extension: --accept-no-param-doc: conflicting option string(s) There is a crash when using the doc_params extension. No crash.

doc_files = {}     for filename in os.listdir(ext_path):         name, ext = os.path.splitext(filename)        if name[0] == "_" or name in DEPRECATED_MODULES:        if name[0] == "_":             continue         if ext == ".py":             modules.append(f"pylint.extensions.{name}")diff --git a/pylint/extensions/check_docs.py b/pylint/extensions/check_docs.pydeleted file mode 100644-- a/pylint/extensions/check_docs.py++ /dev/null


Question: [crash] doc params extension: --accept-no-param-doc: conflicting option string(s) There is a crash when using the doc_params extension. No crash.

# Copyright (c) 2014-2015 Bruno Daniel <bruno.daniel@blue-yonder.com># Copyright (c) 2015-2016, 2018, 2020 Claudiu Popa <pcmanticore@gmail.com># Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk># Copyright (c) 2020 hippo91 <guillaume.peillex@gmail.com># Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com># Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com># Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html# For details: https://github.com/PyCQA/pylint/blob/main/LICENSEimport warningsfrom typing import TYPE_CHECKINGfrom pylint.extensions import docparamsif TYPE_CHECKING:    from pylint.lint import PyLinterdef register(linter: "PyLinter") -> None:    warnings.warn(        "This plugin is deprecated, use pylint.extensions.docparams instead.",        DeprecationWarning,    )    linter.register_checker(docparams.DocstringParameterChecker(linter))diff --git a/pylint/lint/run.py b/pylint/lint/run.py-- a/pylint/lint/run.py++ b/pylint/lint/run.py


Question: [crash] doc params extension: --accept-no-param-doc: conflicting option string(s) There is a crash when using the doc_params extension. No crash.

def cb_enable_all_extensions(self, option_name: str, value: None) -> None:         """Callback to load and enable all available extensions"""         for filename in os.listdir(os.path.dirname(extensions.__file__)):            # pylint: disable=fixme            # TODO: Remove the check for deprecated check_docs after the extension has been removed            if (                filename.endswith(".py")                and not filename.startswith("_")                and not filename.startswith("check_docs")            ):            if filename.endswith(".py") and not filename.startswith("_"):                 extension_name = f"pylint.extensions.{filename[:-3]}"                 if extension_name not in self._plugins:                     self._plugins.append(extension_name)


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

13: string_format 14: string_constant 15: stdlib16: python316: python3 (This one was deleted but needs to be reserved for consistency with old messages) 17: refactoring . . . 24: non-ascii-names 25: unicode26-50: not yet used: reserved for future internal checkers.26: unsupported_version27-50: not yet used: reserved for future internal checkers. This file is not updated. Use    script/get_unused_message_id_category.py to get the next free checker id.diff --git a/pylint/checkers/unsupported_version.py b/pylint/checkers/unsupported_version.py-- a/pylint/checkers/unsupported_version.py++ b/pylint/checkers/unsupported_version.py


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

__implements__ = (IAstroidChecker,)     name = "unsupported_version"     msgs = {        "W1601": (        "W2601": (             "F-strings are not supported by all versions included in the py-version setting",             "using-f-string-in-unsupported-version",             "Used when the py-version set by the user is lower than 3.6 and pylint encounters "             "a f-string.",         ),        "W1602": (        "W2602": (             "typing.final is not supported by all versions included in the py-version setting",             "using-final-decorator-in-unsupported-version",             "Used when the py-version set by the user is lower than 3.8 and pylint encounters "diff --git a/pylint/constants.py b/pylint/constants.py-- a/pylint/constants.py++ b/pylint/constants.py


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE import platform import sysfrom typing import Dictfrom typing import Dict, List, NamedTuple, Tuple  import astroid import platformdirs


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

"class_const": "class constant",     "inlinevar": "inline iteration", }class DeletedMessage(NamedTuple):    msgid: str    symbol: str    old_names: List[Tuple[str, str]] = []DELETED_MSGID_PREFIXES = [    16,  # the PY3K+ checker, see https://github.com/PyCQA/pylint/pull/4942]DELETED_MESSAGES = [    # Everything until the next comment is from the    # PY3K+ checker, see https://github.com/PyCQA/pylint/pull/4942    DeletedMessage("W1601", "apply-builtin"),    DeletedMessage("E1601", "print-statement"),    DeletedMessage("E1602", "parameter-unpacking"),    DeletedMessage(        "E1603", "unpacking-in-except", [("W0712", "old-unpacking-in-except")]    ),    DeletedMessage("E1604", "old-raise-syntax", [("W0121", "old-old-raise-syntax")]),    DeletedMessage("E1605", "backtick", [("W0333", "old-backtick")]),    DeletedMessage("E1609", "import-star-module-level"),    DeletedMessage("W1601", "apply-builtin"),    DeletedMessage("W1602", "basestring-builtin"),    DeletedMessage("W1603", "buffer-builtin"),    DeletedMessage("W1604", "cmp-builtin"),    DeletedMessage("W1605", "coerce-builtin"),    DeletedMessage("W1606", "execfile-builtin"),    DeletedMessage("W1607", "file-builtin"),    DeletedMessage("W1608", "long-builtin"),    DeletedMessage("W1609", "raw_input-builtin"),    DeletedMessage("W1610", "reduce-builtin"),    DeletedMessage("W1611", "standarderror-builtin"),    DeletedMessage("W1612", "unicode-builtin"),    DeletedMessage("W1613", "xrange-builtin"),    DeletedMessage("W1614", "coerce-method"),    DeletedMessage("W1615", "delslice-method"),    DeletedMessage("W1616", "getslice-method"),    DeletedMessage("W1617", "setslice-method"),    DeletedMessage("W1618", "no-absolute-import"),    DeletedMessage("W1619", "old-division"),    DeletedMessage("W1620", "dict-iter-method"),    DeletedMessage("W1621", "dict-view-method"),    DeletedMessage("W1622", "next-method-called"),    DeletedMessage("W1623", "metaclass-assignment"),    DeletedMessage(        "W1624", "indexing-exception", [("W0713", "old-indexing-exception")]    ),    DeletedMessage("W1625", "raising-string", [("W0701", "old-raising-string")]),    DeletedMessage("W1626", "reload-builtin"),    DeletedMessage("W1627", "oct-method"),    DeletedMessage("W1628", "hex-method"),    DeletedMessage("W1629", "nonzero-method"),    DeletedMessage("W1630", "cmp-method"),    DeletedMessage("W1632", "input-builtin"),    DeletedMessage("W1633", "round-builtin"),    DeletedMessage("W1634", "intern-builtin"),    DeletedMessage("W1635", "unichr-builtin"),    DeletedMessage(        "W1636", "map-builtin-not-iterating", [("W1631", "implicit-map-evaluation")]    ),    DeletedMessage("W1637", "zip-builtin-not-iterating"),    DeletedMessage("W1638", "range-builtin-not-iterating"),    DeletedMessage("W1639", "filter-builtin-not-iterating"),    DeletedMessage("W1640", "using-cmp-argument"),    DeletedMessage("W1641", "eq-without-hash"),    DeletedMessage("W1642", "div-method"),    DeletedMessage("W1643", "idiv-method"),    DeletedMessage("W1644", "rdiv-method"),    DeletedMessage("W1645", "exception-message-attribute"),    DeletedMessage("W1646", "invalid-str-codec"),    DeletedMessage("W1647", "sys-max-int"),    DeletedMessage("W1648", "bad-python3-import"),    DeletedMessage("W1649", "deprecated-string-function"),    DeletedMessage("W1650", "deprecated-str-translate-call"),    DeletedMessage("W1651", "deprecated-itertools-function"),    DeletedMessage("W1652", "deprecated-types-field"),    DeletedMessage("W1653", "next-method-defined"),    DeletedMessage("W1654", "dict-items-not-iterating"),    DeletedMessage("W1655", "dict-keys-not-iterating"),    DeletedMessage("W1656", "dict-values-not-iterating"),    DeletedMessage("W1657", "deprecated-operator-function"),    DeletedMessage("W1658", "deprecated-urllib-function"),    DeletedMessage("W1659", "xreadlines-attribute"),    DeletedMessage("W1660", "deprecated-sys-function"),    DeletedMessage("W1661", "exception-escape"),    DeletedMessage("W1662", "comprehension-escape"),    # https://github.com/PyCQA/pylint/pull/3578    DeletedMessage("W0312", "mixed-indentation"),    # https://github.com/PyCQA/pylint/pull/3577    DeletedMessage(        "C0326",        "bad-whitespace",        [            ("C0323", "no-space-after-operator"),            ("C0324", "no-space-after-comma"),            ("C0322", "no-space-before-operator"),        ],    ),    # https://github.com/PyCQA/pylint/pull/3571    DeletedMessage("C0330", "bad-continuation"),]diff --git a/script/get_unused_message_id_category.py b/script/get_unused_message_id_category.py-- a/script/get_unused_message_id_category.py++ b/script/get_unused_message_id_category.py


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

from typing import List  from pylint.checkers import initialize as initialize_checkers<ins>from pylint.constants import DELETED_MSGID_PREFIXES</ins> from pylint.extensions import initialize as initialize_extensions from pylint.lint.pylinter import PyLinter


Question: Pylint needs to forbid to re-use the msgid or symbol of old deleted msgid/symbol Right now it's possible to reuse old msgid that were removed, for example, everything from the python 3 checker (the problem was detected with `), or mixed-indentation, bad-whitespace, bad-continuation... maybe other that I don't remember that we deleted. We have a mechanism in place for renamed message with old_name, but nothing for removed message. Related to and This is going to cause occasional bug, but more than that confusion and inconsistencies when searching for the msgid online. Impossible to use an old message id or symbol.

def get_next_code_category(message_ids: List[str]) -> int:     categories = sorted({int(i[:2]) for i in message_ids})<ins>    # We add the prefixes for deleted checkers    categories += DELETED_MSGID_PREFIXES</ins>     for i in categories:         if i + 1 not in categories:             return i + 1


Question: "--notes" option ignores note tags that are entirely punctuation If a note tag specified with the option is entirely punctuation, pylint won't report a fixme warning (W0511). will return a fixme warning (W0511) for the first line, but not the second. macOS 11.6.1 No response

notes = "|".join(re.escape(note) for note in self.config.notes)         if self.config.notes_rgx:            regex_string = rf"#\s*({notes}|{self.config.notes_rgx})\b"            regex_string = rf"#\s*({notes}|{self.config.notes_rgx})(?=(:|\s|\Z))"         else:            regex_string = rf"#\s*({notes})\b"            regex_string = rf"#\s*({notes})(?=(:|\s|\Z))"          self._fixme_pattern = re.compile(regex_string, re.I)


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

from astroid import nodes  from pylint.pyreverse.printer import EdgeType, Layout, NodeProperties, NodeType, Printerfrom pylint.pyreverse.utils import check_graphviz_availability, get_annotation_labelfrom pylint.pyreverse.utils import get_annotation_label  ALLOWED_CHARSETS: FrozenSet[str] = frozenset(("utf-8", "iso-8859-1", "latin1")) SHAPES: Dict[NodeType, str] = {


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

with open(dot_sourcepath, "w", encoding="utf8") as outfile:             outfile.writelines(self.lines)         if target not in graphviz_extensions:            check_graphviz_availability()             use_shell = sys.platform == "win32"             subprocess.call(                 ["dot", "-T", target, dot_sourcepath, "-o", outputfile],diff --git a/pylint/pyreverse/main.py b/pylint/pyreverse/main.py-- a/pylint/pyreverse/main.py++ b/pylint/pyreverse/main.py


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

from pylint.pyreverse import writer from pylint.pyreverse.diadefslib import DiadefsHandler from pylint.pyreverse.inspector import Linker, project_from_filesfrom pylint.pyreverse.utils import check_graphviz_availability, insert_default_optionsfrom pylint.pyreverse.utils import (    check_graphviz_availability,    check_if_graphviz_supports_format,    insert_default_options,)DIRECTLY_SUPPORTED_FORMATS = (    "dot",    "vcg",    "puml",    "plantuml",    "mmd",    "html",)  OPTIONS = (     (


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

action="store",             default="dot",             metavar="<format>",            help="create a *.<format> output file if format available.",            help=(                f"create a *.<format> output file if format is available. Available formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. "                f"Any other format will be tried to create by means of the 'dot' command line tool, which requires a graphviz installation."            ),         ),     ),     (


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

super().__init__(usage=__doc__)         insert_default_options()         args = self.load_command_line_configuration(args)        if self.config.output_format not in (            "dot",            "vcg",            "puml",            "plantuml",            "mmd",            "html",        ):        if self.config.output_format not in DIRECTLY_SUPPORTED_FORMATS:             check_graphviz_availability()            print(                f"Format {self.config.output_format} is not supported natively. Pyreverse will try to generate it using Graphviz..."            )            check_if_graphviz_supports_format(self.config.output_format)          sys.exit(self.run(args)) diff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py-- a/pylint/pyreverse/utils.py++ b/pylint/pyreverse/utils.py


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

import os import re import shutil<ins>import subprocess</ins> import sys from typing import Optional, Union


Question: DOC: pyreverse supported format not recognized missing puml, plantuml, mmd, etc Some supported formats are not listed in the error messaging: Here, I have made the mistake of prepending a to . The error output should list (and and and ) as . Without the preceding , the command runs as expected. All supported formats are listed when user makes a typo in the format argument OpenSUSE Tumbleweed

from *.dot or *.gv into the final output format.     """     if shutil.which("dot") is None:        print("'Graphviz' needs to be installed for your chosen output format.")        sys.exit(32)def check_if_graphviz_supports_format(output_format: str) -> None:    """Check if the ``dot`` command supports the requested output format.    This is needed if image output is desired and ``dot`` is used to convert    from *.gv into the final output format.    """    dot_output = subprocess.run(        ["dot", "-T?"], capture_output=True, check=False, encoding="utf-8"    )    match = re.match(        pattern=r".*Use one of: (?P<formats>(\S*\s?)+)",        string=dot_output.stderr.strip(),    )    if not match:        print(            "Unable to determine Graphviz supported output formats. "            "Pyreverse will continue, but subsequent error messages "            "regarding the output format may come from Graphviz directly."        )        return    supported_formats = match.group("formats")    if output_format not in supported_formats.split():         print(            "The requested output format is currently not available.\n"            "Please install 'Graphviz' to have other output formats "            "than 'dot' or 'vcg'."            f"Format {output_format} is not supported by Graphviz. It supports: {supported_formats}"         )         sys.exit(32)


Question: Is required As noted by ,  is not currently covered. If this required then we should add a unit test, otherwise we can remove this method. N/A No response No response

def __gt__(self, other):         """Permit to sort a list of Checker by name."""        return f"{self.name}{self.msgs}" > (f"{other.name}{other.msgs}")        return f"{self.name}{self.msgs}" > f"{other.name}{other.msgs}"    def __eq__(self, other):        """Permit to assert Checkers are equal."""        return f"{self.name}{self.msgs}" == f"{other.name}{other.msgs}"    def __hash__(self):        """Make Checker hashable."""        return hash(f"{self.name}{self.msgs}")      def __repr__(self):         status = "Checker" if self.enabled else "Disabled checker"


Question: Use, misuse and confusion of decorator The work on showed that specifically enabling just a single message is sometimes not working as expected. This is due to either missing message declaration in a checkers decorator. Ideally I would like to implement a new, optional checker aimed at Pylint core development and custom checker development. This checker would focus on correct message declaration and handling. I already started working on it, but noticed that there is especially quite some problems with the decorator. I totally understand that, because while being extensively used across all checker classes, there is not a single word on its purpose and effect in the documentation. Its docstring is also not really helpful, you have to dig deeper into the codebase to understand what it does. Before continuing my work on the new checker, I want to address and clarify some questions about the intended use of. After that this issue can be closed with a PR that extends the documentation, and if necessary some code changes. A brief explanation on what does: It helps the decide whether a callback for the current node type should be called or not. This is done by adding the list of messages passed in as a attribute on method object. When a checker is to the attribute: if the attribute does not exist, this method will be to the list of callbacks if it exists and at least one message of the list is enabled, this method will be to the list of callbacks otherwise, it will not be to the list of callbacks and will therefore not be executed Essentially this means: main (and only) intent of the decorator is to improve performance the does not have any effect to apply the decorator has no negative functional consequences, it only affects performance (which, of course, is always an issue) the decorator but forgetting to add messages that are emitted from this callback can lead to false negatives: if none of the messages actually included in the decorator are enabled, it will not be called the decorator to a callback that not only emits messages but also does other things can have nasty side effects (false positives, false negatives, crashes) What I want to gain a consensus on: we want to keep the name ? I don't think it really conveys the effect it has on the decorated method. shall we regard as best practice for this decorator? Should every callback be decorated and the list of messages must always be correct and consistent, or should we rather advise to use it only in cases where we expect a significant speedup when this callback is omitted? we want to keep the restriction that this decorator only has an effect on the "top level callbacks"? Seeing that a lot of those callbacks can emit quite a lot of messages and the logic for the checks is often split up into several subfunctions, it would be more flexible and also more robust (as it is easier to keep track of the messages that need to be included in the decorator) if one could apply it on the subfunctions rather than on the top level callback. Looking over the code base there are quite a lot of places where the decorator is not used correctly: used with simply passing in all messages (which has the same effect as just omitting it): used on methods that are not a callback (which has no effect) Used, but not including all messages possibly emitted by the callback No response_

import re import string import warningsfrom collections.abc import Callable, Iterablefrom collections.abc import Iterable from functools import lru_cache, partial from re import Matchfrom typing import TypeVarfrom typing import Callable, TypeVar  import _string import astroid.objects from astroid import TooManyLevelsError, nodes from astroid.context import InferenceContext from pylint.checkers.base_checker import BaseChecker from pylint.constants import TYPING_TYPE_CHECKS_GUARDS  COMP_NODE_TYPES = (


Question: Use, misuse and confusion of decorator The work on showed that specifically enabling just a single message is sometimes not working as expected. This is due to either missing message declaration in a checkers decorator. Ideally I would like to implement a new, optional checker aimed at Pylint core development and custom checker development. This checker would focus on correct message declaration and handling. I already started working on it, but noticed that there is especially quite some problems with the decorator. I totally understand that, because while being extensively used across all checker classes, there is not a single word on its purpose and effect in the documentation. Its docstring is also not really helpful, you have to dig deeper into the codebase to understand what it does. Before continuing my work on the new checker, I want to address and clarify some questions about the intended use of. After that this issue can be closed with a PR that extends the documentation, and if necessary some code changes. A brief explanation on what does: It helps the decide whether a callback for the current node type should be called or not. This is done by adding the list of messages passed in as a attribute on method object. When a checker is to the attribute: if the attribute does not exist, this method will be to the list of callbacks if it exists and at least one message of the list is enabled, this method will be to the list of callbacks otherwise, it will not be to the list of callbacks and will therefore not be executed Essentially this means: main (and only) intent of the decorator is to improve performance the does not have any effect to apply the decorator has no negative functional consequences, it only affects performance (which, of course, is always an issue) the decorator but forgetting to add messages that are emitted from this callback can lead to false negatives: if none of the messages actually included in the decorator are enabled, it will not be called the decorator to a callback that not only emits messages but also does other things can have nasty side effects (false positives, false negatives, crashes) What I want to gain a consensus on: we want to keep the name ? I don't think it really conveys the effect it has on the decorated method. shall we regard as best practice for this decorator? Should every callback be decorated and the list of messages must always be correct and consistent, or should we rather advise to use it only in cases where we expect a significant speedup when this callback is omitted? we want to keep the restriction that this decorator only has an effect on the "top level callbacks"? Seeing that a lot of those callbacks can emit quite a lot of messages and the logic for the checks is often split up into several subfunctions, it would be more flexible and also more robust (as it is easier to keep track of the messages that need to be included in the decorator) if one could apply it on the subfunctions rather than on the top level callback. Looking over the code base there are quite a lot of places where the decorator is not used correctly: used with simply passing in all messages (which has the same effect as just omitting it): used on methods that are not a callback (which has no effect) Used, but not including all messages possibly emitted by the callback No response_

)  T_Node = TypeVar("T_Node", bound=nodes.NodeNG)<ins>CheckerT = TypeVar("CheckerT", bound=BaseChecker)AstCallback = Callable[[CheckerT, T_Node], None]</ins>   class NoSuchArgumentError(Exception):


Question: Use, misuse and confusion of decorator The work on showed that specifically enabling just a single message is sometimes not working as expected. This is due to either missing message declaration in a checkers decorator. Ideally I would like to implement a new, optional checker aimed at Pylint core development and custom checker development. This checker would focus on correct message declaration and handling. I already started working on it, but noticed that there is especially quite some problems with the decorator. I totally understand that, because while being extensively used across all checker classes, there is not a single word on its purpose and effect in the documentation. Its docstring is also not really helpful, you have to dig deeper into the codebase to understand what it does. Before continuing my work on the new checker, I want to address and clarify some questions about the intended use of. After that this issue can be closed with a PR that extends the documentation, and if necessary some code changes. A brief explanation on what does: It helps the decide whether a callback for the current node type should be called or not. This is done by adding the list of messages passed in as a attribute on method object. When a checker is to the attribute: if the attribute does not exist, this method will be to the list of callbacks if it exists and at least one message of the list is enabled, this method will be to the list of callbacks otherwise, it will not be to the list of callbacks and will therefore not be executed Essentially this means: main (and only) intent of the decorator is to improve performance the does not have any effect to apply the decorator has no negative functional consequences, it only affects performance (which, of course, is always an issue) the decorator but forgetting to add messages that are emitted from this callback can lead to false negatives: if none of the messages actually included in the decorator are enabled, it will not be called the decorator to a callback that not only emits messages but also does other things can have nasty side effects (false positives, false negatives, crashes) What I want to gain a consensus on: we want to keep the name ? I don't think it really conveys the effect it has on the decorated method. shall we regard as best practice for this decorator? Should every callback be decorated and the list of messages must always be correct and consistent, or should we rather advise to use it only in cases where we expect a significant speedup when this callback is omitted? we want to keep the restriction that this decorator only has an effect on the "top level callbacks"? Seeing that a lot of those callbacks can emit quite a lot of messages and the logic for the checks is often split up into several subfunctions, it would be more flexible and also more robust (as it is easier to keep track of the messages that need to be included in the decorator) if one could apply it on the subfunctions rather than on the top level callback. Looking over the code base there are quite a lot of places where the decorator is not used correctly: used with simply passing in all messages (which has the same effect as just omitting it): used on methods that are not a callback (which has no effect) Used, but not including all messages possibly emitted by the callback No response_

return False  def check_messages(*messages: str) -> Callable:    """Decorator to store messages that are handled by a checker method."""def only_required_for_messages(*messages: str) -> Callable[[AstCallback], AstCallback]:    """Decorator to store messages that are handled by a checker method as an    attribute of the function object.    This information is used by ``ASTWalker`` to decide whether to call the decorated    method or not. If none of the messages is enabled, the method will be skipped.    Therefore, the list of messages must be well maintained at all times!    This decorator only has an effect on ``visit_*`` and ``leave_*`` methods    of a class inheriting from ``BaseChecker`` and implementing ``IAstroidChecker``.    """      def store_messages(func):         func.checks_msgs = messages


Question: Use, misuse and confusion of decorator The work on showed that specifically enabling just a single message is sometimes not working as expected. This is due to either missing message declaration in a checkers decorator. Ideally I would like to implement a new, optional checker aimed at Pylint core development and custom checker development. This checker would focus on correct message declaration and handling. I already started working on it, but noticed that there is especially quite some problems with the decorator. I totally understand that, because while being extensively used across all checker classes, there is not a single word on its purpose and effect in the documentation. Its docstring is also not really helpful, you have to dig deeper into the codebase to understand what it does. Before continuing my work on the new checker, I want to address and clarify some questions about the intended use of. After that this issue can be closed with a PR that extends the documentation, and if necessary some code changes. A brief explanation on what does: It helps the decide whether a callback for the current node type should be called or not. This is done by adding the list of messages passed in as a attribute on method object. When a checker is to the attribute: if the attribute does not exist, this method will be to the list of callbacks if it exists and at least one message of the list is enabled, this method will be to the list of callbacks otherwise, it will not be to the list of callbacks and will therefore not be executed Essentially this means: main (and only) intent of the decorator is to improve performance the does not have any effect to apply the decorator has no negative functional consequences, it only affects performance (which, of course, is always an issue) the decorator but forgetting to add messages that are emitted from this callback can lead to false negatives: if none of the messages actually included in the decorator are enabled, it will not be called the decorator to a callback that not only emits messages but also does other things can have nasty side effects (false positives, false negatives, crashes) What I want to gain a consensus on: we want to keep the name ? I don't think it really conveys the effect it has on the decorated method. shall we regard as best practice for this decorator? Should every callback be decorated and the list of messages must always be correct and consistent, or should we rather advise to use it only in cases where we expect a significant speedup when this callback is omitted? we want to keep the restriction that this decorator only has an effect on the "top level callbacks"? Seeing that a lot of those callbacks can emit quite a lot of messages and the logic for the checks is often split up into several subfunctions, it would be more flexible and also more robust (as it is easier to keep track of the messages that need to be included in the decorator) if one could apply it on the subfunctions rather than on the top level callback. Looking over the code base there are quite a lot of places where the decorator is not used correctly: used with simply passing in all messages (which has the same effect as just omitting it): used on methods that are not a callback (which has no effect) Used, but not including all messages possibly emitted by the callback No response_

return store_messages  <ins>def check_messages(*messages: str) -> Callable[[AstCallback], AstCallback]:    """Kept for backwards compatibility, deprecated.    Use only_required_for_messages instead, which conveys the intent of the decorator much clearer.    """    warnings.warn(        "utils.check_messages will be removed in favour of calling "        "utils.only_required_for_messages in pylint 3.0",        DeprecationWarning,    )    return only_required_for_messages(*messages)</ins> class IncompleteFormatString(Exception):     """A format string ended in the middle of a format specifier."""


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

import sys import warnings from collections import defaultdictfrom collections.abc import Generator, Iterablefrom collections.abc import Callable, Generator, Iterable from getopt import getopt from io import BufferedIOBase, BufferedReader, BytesIO from itertools import chain, groupby


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

readlines = decoding_stream(stream, encoding).readlines         else:             readlines = stream.readlines  # type: ignore[assignment] # hint parameter is incorrectly typed as non-optional         try:            active_lines: list[str] = []            if hasattr(self, "linter"):                # Remove those lines that should be ignored because of disables                for index, line in enumerate(readlines()):                    if self.linter._is_one_message_enabled("R0801", index + 1):  # type: ignore[attr-defined]                        active_lines.append(line)            else:                active_lines = readlines()            self.linesets.append(                LineSet(                    streamid,                    active_lines,                    self.namespace.ignore_comments,                    self.namespace.ignore_docstrings,                    self.namespace.ignore_imports,                    self.namespace.ignore_signatures,                )            )            lines = readlines()         except UnicodeDecodeError:            pass            lines = []        self.linesets.append(            LineSet(                streamid,                lines,                self.namespace.ignore_comments,                self.namespace.ignore_docstrings,                self.namespace.ignore_imports,                self.namespace.ignore_signatures,                line_enabled_callback=self.linter._is_one_message_enabled  # type: ignore[attr-defined]                if hasattr(self, "linter")                else None,            )        )      def run(self) -> None:         """Start looking for similarities and display results on stdout."""


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

ignore_docstrings: bool,     ignore_imports: bool,     ignore_signatures: bool,<ins>    line_enabled_callback: Callable[[str, int], bool] | None = None,</ins> ) -> list[LineSpecifs]:     """Return tuples of line/line number/line type with leading/trailing whitespace and any ignored code features removed.


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

:param ignore_docstrings: if true, any line that is a docstring is removed from the result     :param ignore_imports: if true, any line that is an import is removed from the result     :param ignore_signatures: if true, any line that is part of a function signature is removed from the result<ins>    :param line_enabled_callback: If called with "R0801" and a line number, a return value of False will disregard the line</ins>     :return: the collection of line/line number/line type tuples     """     if ignore_imports or ignore_signatures:


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

strippedlines = []     docstring = None     for lineno, line in enumerate(lines, start=1):<ins>        if line_enabled_callback is not None and not line_enabled_callback(            "R0801", lineno        ):            continue</ins>         line = line.strip()         if ignore_docstrings:             if not docstring:


Question: Crash When parsing the following file: <!-- If sharing the code is not an option, please state so, but providing only the stacktrace would still be helpful. --pylint crashed with a and with the following stacktrace: If I remove the comment, things work as expected. If I call without , things work as expected. If I downgrade (and ) to astroid-2.9.3 pylint-2.12.2, things work as expected. No response no astroid error ;-) Fedora 35 astroid==2.11.2 dill==0.3.4 flake8==4.0.1 isort==4.3.21 lazy-object-proxy==1.7.1 mccabe==0.6.1 platformdirs==2.5.1 pycodestyle==2.8.0 pyflakes==2.4.0 pylint==2.13.5 toml==0.10.2 tomli==2.0.1 wrapt==1.13.3

ignore_docstrings: bool = False,         ignore_imports: bool = False,         ignore_signatures: bool = False,        line_enabled_callback: Callable[[str, int], bool] | None = None,     ) -> None:         self.name = name         self._real_lines = lines         self._stripped_lines = stripped_lines(            lines, ignore_comments, ignore_docstrings, ignore_imports, ignore_signatures            lines,            ignore_comments,            ignore_docstrings,            ignore_imports,            ignore_signatures,            line_enabled_callback=line_enabled_callback,         )      def __str__(self):


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

from __future__ import annotations <ins>import argparse</ins> import copy import functools import itertools


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

from pylint.checkers import BaseChecker, MapReduceMixin, table_lines_from_stats from pylint.interfaces import IRawChecker from pylint.reporters.ureports.nodes import Tablefrom pylint.typing import OptionDict, Optionsfrom pylint.typing import Options from pylint.utils import LinterStats, decoding_stream  if TYPE_CHECKING:


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

ignore_imports: bool = False,         ignore_signatures: bool = False,     ) -> None:        self.min_lines = min_lines        self.ignore_comments = ignore_comments        self.ignore_docstrings = ignore_docstrings        self.ignore_imports = ignore_imports        self.ignore_signatures = ignore_signatures        # If we run in pylint mode we link the namespace objects        if isinstance(self, BaseChecker):            self.namespace = self.linter.config        else:            self.namespace = argparse.Namespace()        self.namespace.min_similarity_lines = min_lines        self.namespace.ignore_comments = ignore_comments        self.namespace.ignore_docstrings = ignore_docstrings        self.namespace.ignore_imports = ignore_imports        self.namespace.ignore_signatures = ignore_signatures         self.linesets: list[LineSet] = []      def append_stream(


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

LineSet(                     streamid,                     active_lines,                    self.ignore_comments,                    self.ignore_docstrings,                    self.ignore_imports,                    self.ignore_signatures,                    self.namespace.ignore_comments,                    self.namespace.ignore_docstrings,                    self.namespace.ignore_imports,                    self.namespace.ignore_signatures,                 )             )         except UnicodeDecodeError:


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

def run(self) -> None:         """Start looking for similarities and display results on stdout."""        if self.min_lines == 0:        if self.namespace.min_similarity_lines == 0:             return         self._display_sims(self._compute_sims())


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

hash_to_index_2: HashToIndex_T         index_to_lines_1: IndexToLines_T         index_to_lines_2: IndexToLines_T        hash_to_index_1, index_to_lines_1 = hash_lineset(lineset1, self.min_lines)        hash_to_index_2, index_to_lines_2 = hash_lineset(lineset2, self.min_lines)        hash_to_index_1, index_to_lines_1 = hash_lineset(            lineset1, self.namespace.min_similarity_lines        )        hash_to_index_2, index_to_lines_2 = hash_lineset(            lineset2, self.namespace.min_similarity_lines        )          hash_1: frozenset[LinesChunk] = frozenset(hash_to_index_1.keys())         hash_2: frozenset[LinesChunk] = frozenset(hash_to_index_2.keys())


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

] = CplSuccessiveLinesLimits(                     copy.copy(index_to_lines_1[index_1]),                     copy.copy(index_to_lines_2[index_2]),                    effective_cmn_lines_nb=self.min_lines,                    effective_cmn_lines_nb=self.namespace.min_similarity_lines,                 )          remove_successives(all_couples)


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

lineset1, start_index_1, lineset2, start_index_2, nb_common_lines             )             if eff_cmn_nb > self.min_lines:            if eff_cmn_nb > self.namespace.min_similarity_lines:                 yield com      def _iter_sims(self) -> Generator[Commonality, None, None]:


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

# reports     reports = (("RP0801", "Duplication", report_similarities),)     def __init__(self, linter=None) -> None:    def __init__(self, linter: PyLinter) -> None:         BaseChecker.__init__(self, linter)         Similar.__init__(             self,


Question: option ignored The option is ignored in 2.14. Place two files that both read like this (ideally in their own dir so you can just run that dir): Proper output in 2.12: Caused in No response No response

ignore_signatures=self.linter.config.ignore_signatures,         ) <del>    def set_option(        self,        optname: str,        value: Any,        action: str | None = "default_value",        optdict: None | str | OptionDict = "default_value",    ) -> None:        """Method called to set an option (registered in the options list).        Overridden to report options setting to Similar        """        # TODO: 3.0: Remove deprecated arguments. # pylint: disable=fixme        if action != "default_value":            warnings.warn(                "The 'action' argument has been deprecated. You can use set_option "                "without the 'action' or 'optdict' arguments.",                DeprecationWarning,            )        if optdict != "default_value":            warnings.warn(                "The 'optdict' argument has been deprecated. You can use set_option "                "without the 'action' or 'optdict' arguments.",                DeprecationWarning,            )        self.linter.set_option(optname, value)        if optname == "min-similarity-lines":            self.min_lines = self.linter.config.min_similarity_lines        elif optname == "ignore-comments":            self.ignore_comments = self.linter.config.ignore_comments        elif optname == "ignore-docstrings":            self.ignore_docstrings = self.linter.config.ignore_docstrings        elif optname == "ignore-imports":            self.ignore_imports = self.linter.config.ignore_imports        elif optname == "ignore-signatures":            self.ignore_signatures = self.linter.config.ignore_signatures</del>     def open(self):         """Init the checkers: reset linesets and statistics information."""         self.linesets = []


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

kwargs: dict[str, Any],         hide_help: bool,         section: str | None,<ins>        metavar: str,</ins>     ) -> None:         super().__init__(             flags=flags, arg_help=arg_help, hide_help=hide_help, section=section


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

self.kwargs = kwargs         """Any additional arguments passed to the action."""        self.metavar = metavar        """The metavar of the argument.        See:        https://docs.python.org/3/library/argparse.html#metavar        """diff --git a/pylint/config/arguments_manager.py b/pylint/config/arguments_manager.py-- a/pylint/config/arguments_manager.py++ b/pylint/config/arguments_manager.py


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

**argument.kwargs,                 action=argument.action,                 help=argument.help,                metavar=argument.metavar,             )         elif isinstance(argument, _ExtendArgument):             section_group.add_argument(diff --git a/pylint/config/utils.py b/pylint/config/utils.py-- a/pylint/config/utils.py++ b/pylint/config/utils.py


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

kwargs=optdict.get("kwargs", {}),             hide_help=optdict.get("hide", False),             section=optdict.get("group", None),<ins>            metavar=optdict.get("metavar", None),</ins>         )     try:         default = optdict["default"]


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

"--output": (True, _set_output),     "--load-plugins": (True, _add_plugins),     "--verbose": (False, _set_verbose_mode),<ins>    "-v": (False, _set_verbose_mode),</ins>     "--enable-all-extensions": (False, _enable_all_extensions), }


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

i = 0     while i < len(args):         argument = args[i]        if not argument.startswith("--"):        if not argument.startswith("-"):             processed_args.append(argument)             i += 1             continuediff --git a/pylint/lint/base_options.py b/pylint/lint/base_options.py-- a/pylint/lint/base_options.py++ b/pylint/lint/base_options.py


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

"help": "In verbose mode, extra non-checker-related info "                 "will be displayed.",                 "hide_from_config_file": True,<ins>                "metavar": "",</ins>             },         ),         (


Question: Argument expected for short verbose option The short option of the option expects an argument. Also, the help message for the option suggests a value should be provided. The long option works ok & doesn't expect an argument: Similar behaviour to the long option.

"help": "Load and enable all available extensions. "                 "Use --list-extensions to see a list all available extensions.",                 "hide_from_config_file": True,<ins>                "metavar": "",</ins>             },         ),         (


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

def __init__(self, linter: PyLinter) -> None:         """Checker instances should have the linter as argument."""<ins>        if getattr(self, "__implements__", None):            warnings.warn(                "Using the __implements__ inheritance pattern for BaseChecker is no "                "longer supported. Child classes should only inherit BaseChecker or any "                "of the other checker types from pylint.checkers.",                DeprecationWarning,            )</ins>         if self.name is not None:             self.name = self.name.lower()         self.linter = linter


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

warnings.filterwarnings("ignore", category=DeprecationWarning)             if isinstance(self, (BaseTokenChecker, BaseRawFileChecker)):                 default_scope = WarningScope.LINE            # TODO: Interfaces: Deprecate looking for implements here # pylint: disable=fixme            # TODO: 3.0: Remove deprecated if-statement # pylint: disable=fixme             elif implements(self, (IRawChecker, ITokenChecker)):                default_scope = WarningScope.LINE                warnings.warn(  # pragma: no cover                    "Checkers should subclass BaseTokenChecker or BaseRawFileChecker"                    "instead of using the __implements__ mechanism. Use of __implements__"                    "will no longer be supported in pylint 3.0",                    DeprecationWarning,                )                default_scope = WarningScope.LINE  # pragma: no cover             else:                 default_scope = WarningScope.NODE         options = {}diff --git a/pylint/interfaces.py b/pylint/interfaces.py-- a/pylint/interfaces.py++ b/pylint/interfaces.py


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

class Interface:     """Base class for interfaces."""     def __init__(self) -> None:        warnings.warn(            "Interface and all of its subclasses have been deprecated "            "and will be removed in pylint 3.0.",            DeprecationWarning,        )     @classmethod     def is_implemented_by(cls, instance):         with warnings.catch_warnings():diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py-- a/pylint/lint/pylinter.py++ b/pylint/lint/pylinter.py


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

"""         walker = ASTWalker(self)         _checkers = self.prepare_checkers()        with warnings.catch_warnings():            warnings.filterwarnings("ignore", category=DeprecationWarning)            tokencheckers = [                c                for c in _checkers        tokencheckers = [            c            for c in _checkers            if isinstance(c, checkers.BaseTokenChecker) and c is not self        ]        # TODO: 3.0: Remove deprecated for-loop # pylint: disable=fixme        for c in _checkers:            with warnings.catch_warnings():                warnings.filterwarnings("ignore", category=DeprecationWarning)                 if (                     interfaces.implements(c, interfaces.ITokenChecker)                    or isinstance(c, checkers.BaseTokenChecker)                )                and c is not self            ]        with warnings.catch_warnings():            warnings.filterwarnings("ignore", category=DeprecationWarning)            rawcheckers = [                c                for c in _checkers                if interfaces.implements(c, interfaces.IRawChecker)                or isinstance(c, checkers.BaseRawFileChecker)            ]                    and c not in tokencheckers                    and c is not self                ):                    tokencheckers.append(c)  # pragma: no cover                    warnings.warn(  # pragma: no cover                        "Checkers should subclass BaseTokenChecker "                        "instead of using the __implements__ mechanism. Use of __implements__ "                        "will no longer be supported in pylint 3.0",                        DeprecationWarning,                    )        rawcheckers = [            c for c in _checkers if isinstance(c, checkers.BaseRawFileChecker)        ]        # TODO: 3.0: Remove deprecated if-statement # pylint: disable=fixme        for c in _checkers:            with warnings.catch_warnings():                warnings.filterwarnings("ignore", category=DeprecationWarning)                if (                    interfaces.implements(c, interfaces.IRawChecker)                    and c not in rawcheckers                ):                    rawcheckers.append(c)  # pragma: no cover                    warnings.warn(  # pragma: no cover                        "Checkers should subclass BaseRawFileChecker "                        "instead of using the __implements__ mechanism. Use of __implements__ "                        "will no longer be supported in pylint 3.0",                        DeprecationWarning,                    )         # notify global begin         for checker in _checkers:             checker.open()diff --git a/pylint/reporters/base_reporter.py b/pylint/reporters/base_reporter.py-- a/pylint/reporters/base_reporter.py++ b/pylint/reporters/base_reporter.py


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

import os import sys<ins>import warnings</ins> from typing import TYPE_CHECKING, TextIO from warnings import warn


Question: Support isinstance checks through ABCMeta for checkers and reporters Currently the PyLinter categorizes checkers through the class attribute. This is not very standard, and is one more barrier for others to write plugins. I propose Changing the interfaces to have a metaclass Change PyLinter to do isinstance checks to categorize checkers/reporters in addition to keeping the old checks

"""Name of the reporter."""      def __init__(self, output: TextIO | None = None) -> None:<ins>        if getattr(self, "__implements__", None):            warnings.warn(                "Using the __implements__ inheritance pattern for BaseReporter is no "                "longer supported. Child classes should only inherit BaseReporter",                DeprecationWarning,            )</ins>         self.linter: PyLinter         self.section = 0         self.out: TextIO = output or sys.stdout


Question: Traceback printed for unrecognized option A traceback is printed when an unrecognized option is passed to pylint. No response The top part of the current output is handy: The traceback I don't think is expected & not user-friendly. A usage tip, for example: No response No response

unrecognized_options.append(opt[1:])     if unrecognized_options:         msg = ", ".join(unrecognized_options)        linter.add_message("unrecognized-option", line=0, args=msg)        raise _UnrecognizedOptionError(options=unrecognized_options)        linter._arg_parser.error(f"Unrecognized option found: {msg}")      # Set the current module to configuration as we don't know where     # the --load-plugins key is coming from


Question: Pylint runs unexpectedly pass if in pylintrc Runs unexpectedly pass in 2.14 if a pylintrc file has . (Default pylintrc files have . 's own config was fixed in to comment it out, but this might bite existing projects.) No response No response

def _confidence_transformer(value: str) -> Sequence[str]:     """Transforms a comma separated string of confidence values."""<ins>    if not value:        return interfaces.CONFIDENCE_LEVEL_NAMES</ins>     values = pylint_utils._check_csv(value)     for confidence in values:         if confidence not in interfaces.CONFIDENCE_LEVEL_NAMES:


Question: How does pylint decide where it should put stat files? I am from the VS Code python extension team, working on building an extension for VS Code using pylint. We have pre-release version out. An issue was reported on the extension that it creates pylint stat files in the project directory. We are not specifically passing anything to change the stat file location (see issue here ). Generally, the stat files go into pre-set directory like %USERPROFILE%/AppData/Local/pylint on windows. What can cause these to be written to the current working directory. We use pass the source code into pylint via stdin, and the only two arguments we use are , . Any clue to debug this would be helpful. I could not find fall back location for the stat files and when would the fallback location be used. We use to run pylint, and we send source to pylint via stdin. Relevant code here:

def _get_pdata_path(     base_name: Path, recurs: int, pylint_home: Path = Path(PYLINT_HOME) ) -> Path:    underscored_name = "_".join(str(p) for p in base_name.parts)    # We strip all characters that can't be used in a filename    # Also strip '/' and '\\' because we want to create a single file, not sub-directories    underscored_name = "_".join(        str(p.replace(":", "_").replace("/", "_").replace("\\", "_"))        for p in base_name.parts    )     return pylint_home / f"{underscored_name}_{recurs}.stats"


Question: Pylint does not respect ignores in mode Pylint does not respect the , , or setting when running in recursive mode. This contradicts the documentation and seriously compromises the usefulness of recursive mode. No response All of these commands give the same output: should be ignored by all of the above commands, because it is in an ignored directory (even the first command with no ignore setting should skip it, since the default value of is . For reference, the docs for the various ignore settings from : No response No response

return any(file_pattern.match(element) for file_pattern in ignore_list_re)  <ins>def _is_ignored_file(    element: str,    ignore_list: list[str],    ignore_list_re: list[Pattern[str]],    ignore_list_paths_re: list[Pattern[str]],) -> bool:    basename = os.path.basename(element)    return (        basename in ignore_list        or _is_in_ignore_list_re(basename, ignore_list_re)        or _is_in_ignore_list_re(element, ignore_list_paths_re)    )</ins> def expand_modules(     files_or_modules: Sequence[str],     ignore_list: list[str],


Question: Pylint does not respect ignores in mode Pylint does not respect the , , or setting when running in recursive mode. This contradicts the documentation and seriously compromises the usefulness of recursive mode. No response All of these commands give the same output: should be ignored by all of the above commands, because it is in an ignored directory (even the first command with no ignore setting should skip it, since the default value of is . For reference, the docs for the various ignore settings from : No response No response

for something in files_or_modules:         basename = os.path.basename(something)        if (            basename in ignore_list            or _is_in_ignore_list_re(os.path.basename(something), ignore_list_re)            or _is_in_ignore_list_re(something, ignore_list_paths_re)        if _is_ignored_file(            something, ignore_list, ignore_list_re, ignore_list_paths_re         ):             continue         module_path = get_python_path(something)diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py-- a/pylint/lint/pylinter.py++ b/pylint/lint/pylinter.py


Question: Pylint does not respect ignores in mode Pylint does not respect the , , or setting when running in recursive mode. This contradicts the documentation and seriously compromises the usefulness of recursive mode. No response All of these commands give the same output: should be ignored by all of the above commands, because it is in an ignored directory (even the first command with no ignore setting should skip it, since the default value of is . For reference, the docs for the various ignore settings from : No response No response

) from pylint.lint.base_options import _make_linter_options from pylint.lint.caching import load_results, save_resultsfrom pylint.lint.expand_modules import expand_modulesfrom pylint.lint.expand_modules import _is_ignored_file, expand_modules from pylint.lint.message_state_handler import _MessageStateHandler from pylint.lint.parallel import check_parallel from pylint.lint.report_functions import (


Question: Pylint does not respect ignores in mode Pylint does not respect the , , or setting when running in recursive mode. This contradicts the documentation and seriously compromises the usefulness of recursive mode. No response All of these commands give the same output: should be ignored by all of the above commands, because it is in an ignored directory (even the first command with no ignore setting should skip it, since the default value of is . For reference, the docs for the various ignore settings from : No response No response

if not msg.may_be_emitted():                 self._msgs_state[msg.msgid] = False     @staticmethod    def _discover_files(files_or_modules: Sequence[str]) -> Iterator[str]:    def _discover_files(self, files_or_modules: Sequence[str]) -> Iterator[str]:         """Discover python modules and packages in sub-directory.          Returns iterator of paths to discovered modules and packages.


Question: Pylint does not respect ignores in mode Pylint does not respect the , , or setting when running in recursive mode. This contradicts the documentation and seriously compromises the usefulness of recursive mode. No response All of these commands give the same output: should be ignored by all of the above commands, because it is in an ignored directory (even the first command with no ignore setting should skip it, since the default value of is . For reference, the docs for the various ignore settings from : No response No response

if any(root.startswith(s) for s in skip_subtrees):                         # Skip subtree of already discovered package.                         continue<ins>                    if _is_ignored_file(                        root,                        self.config.ignore,                        self.config.ignore_patterns,                        self.config.ignore_paths,                    ):                        skip_subtrees.append(root)                        continue</ins>                     if "__init__.py" in files:                         skip_subtrees.append(root)                         yield root


Question: Can't disable bad-option-value code on a computer with a somewhat new pylint (2.4.3 in my example). Get a warning like that I want to ignore, as I'm writing code compatible with python2 and python3. said warning with . a "Bad option value" when other people run their pylint version (example: 2.3.1; and by people, sometimes I mean docker instances ran from Jenkins that I would rather not rebuild or that depend on other people and I can't modify) to disable said error with a global is ignored is ignored To be able to write code that works on several versions of pylint and not having to make sure every computer in the company and every docker container has the same pylint version.

self.process_tokens(tokens)             if self._ignore_file:                 return False            # walk ast to collect line numbers            self.file_state.collect_block_lines(self.msgs_store, node)             # run raw and tokens checkers             for raw_checker in rawcheckers:                 raw_checker.process_module(node)diff --git a/pylint/utils/file_state.py b/pylint/utils/file_state.py-- a/pylint/utils/file_state.py++ b/pylint/utils/file_state.py


Question: Can't disable bad-option-value code on a computer with a somewhat new pylint (2.4.3 in my example). Get a warning like that I want to ignore, as I'm writing code compatible with python2 and python3. said warning with . a "Bad option value" when other people run their pylint version (example: 2.3.1; and by people, sometimes I mean docker instances ran from Jenkins that I would rather not rebuild or that depend on other people and I can't modify) to disable said error with a global is ignored is ignored To be able to write code that works on several versions of pylint and not having to make sure every computer in the company and every docker container has the same pylint version.

self, msgs_store: MessageDefinitionStore, module_node: nodes.Module     ) -> None:         """Walk the AST to collect block level options line numbers."""        warnings.warn(            "'collect_block_lines' has been deprecated and will be removed in pylint 3.0.",            DeprecationWarning,        )         for msg, lines in self._module_msgs_state.items():             self._raw_module_msgs_state[msg] = lines.copy()         orig_state = self._module_msgs_state.copy()         self._module_msgs_state = {}         self._suppression_mapping = {}         self._effective_max_line_number = module_node.tolineno        self._collect_block_lines(msgs_store, module_node, orig_state)        for msgid, lines in orig_state.items():            for msgdef in msgs_store.get_message_definitions(msgid):                self._set_state_on_block_lines(msgs_store, module_node, msgdef, lines)     def _collect_block_lines(    def _set_state_on_block_lines(         self,         msgs_store: MessageDefinitionStore,         node: nodes.NodeNG,        msg_state: MessageStateDict,        msg: MessageDefinition,        msg_state: dict[int, bool],     ) -> None:         """Recursively walk (depth first) AST to collect block level options        line numbers.        line numbers and set the state correctly.         """         for child in node.get_children():            self._collect_block_lines(msgs_store, child, msg_state)            self._set_state_on_block_lines(msgs_store, child, msg, msg_state)         # first child line number used to distinguish between disable         # which are the first child of scoped node with those defined later.         # For instance in the code below:


Question: Can't disable bad-option-value code on a computer with a somewhat new pylint (2.4.3 in my example). Get a warning like that I want to ignore, as I'm writing code compatible with python2 and python3. said warning with . a "Bad option value" when other people run their pylint version (example: 2.3.1; and by people, sometimes I mean docker instances ran from Jenkins that I would rather not rebuild or that depend on other people and I can't modify) to disable said error with a global is ignored is ignored To be able to write code that works on several versions of pylint and not having to make sure every computer in the company and every docker container has the same pylint version.

firstchildlineno = node.body[0].fromlineno         else:             firstchildlineno = node.tolineno        for msgid, lines in msg_state.items():            for msg in msgs_store.get_message_definitions(msgid):                self._set_message_state_in_block(msg, lines, node, firstchildlineno)        self._set_message_state_in_block(msg, msg_state, node, firstchildlineno)      def _set_message_state_in_block(         self,


Question: Can't disable bad-option-value code on a computer with a somewhat new pylint (2.4.3 in my example). Get a warning like that I want to ignore, as I'm writing code compatible with python2 and python3. said warning with . a "Bad option value" when other people run their pylint version (example: 2.3.1; and by people, sometimes I mean docker instances ran from Jenkins that I would rather not rebuild or that depend on other people and I can't modify) to disable said error with a global is ignored is ignored To be able to write code that works on several versions of pylint and not having to make sure every computer in the company and every docker container has the same pylint version.

if lineno > firstchildlineno:                     state = True                 first_, last_ = node.block_range(lineno)                # pylint: disable=useless-suppression                # For block nodes first_ is their definition line. For example, we                # set the state of line zero for a module to allow disabling                # invalid-name for the module. For example:                # 1. # pylint: disable=invalid-name                # 2. ...                # OR                # 1. """Module docstring"""                # 2. # pylint: disable=invalid-name                # 3. ...                #                # But if we already visited line 0 we don't need to set its state again                # 1. # pylint: disable=invalid-name                # 2. # pylint: enable=invalid-name                # 3. ...                # The state should come from line 1, not from line 2                # Therefore, if the 'fromlineno' is already in the states we just start                # with the lineno we were originally visiting.                # pylint: enable=useless-suppression                if (                    first_ == node.fromlineno                    and first_ >= firstchildlineno                    and node.fromlineno in self._module_msgs_state.get(msg.msgid, ())                ):                    first_ = lineno             else:                 first_ = lineno                 last_ = last             for line in range(first_, last_ + 1):                # do not override existing entries                if line in self._module_msgs_state.get(msg.msgid, ()):                # Do not override existing entries. This is especially important                # when parsing the states for a scoped node where some line-disables                # have already been parsed.                if (                    (                        isinstance(node, nodes.Module)                        and node.fromlineno <= line < lineno                    )                    or (                        not isinstance(node, nodes.Module)                        and node.fromlineno < line < lineno                    )                ) and line in self._module_msgs_state.get(msg.msgid, ()):                     continue                 if line in lines:  # state change in the same block                     state = lines[line]                     original_lineno = line                # Update suppression mapping                 if not state:                     self._suppression_mapping[(msg.msgid, line)] = original_lineno                else:                    self._suppression_mapping.pop((msg.msgid, line), None)                # Update message state for respective line                 try:                     self._module_msgs_state[msg.msgid][line] = state                 except KeyError:


Question: Can't disable bad-option-value code on a computer with a somewhat new pylint (2.4.3 in my example). Get a warning like that I want to ignore, as I'm writing code compatible with python2 and python3. said warning with . a "Bad option value" when other people run their pylint version (example: 2.3.1; and by people, sometimes I mean docker instances ran from Jenkins that I would rather not rebuild or that depend on other people and I can't modify) to disable said error with a global is ignored is ignored To be able to write code that works on several versions of pylint and not having to make sure every computer in the company and every docker container has the same pylint version.

def set_msg_status(self, msg: MessageDefinition, line: int, status: bool) -> None:         """Set status (enabled/disable) for a given message at a given line."""         assert line > 0        assert self._module        # TODO: 3.0: Remove unnecessary assertion        assert self._msgs_store        # Expand the status to cover all relevant block lines        self._set_state_on_block_lines(            self._msgs_store, self._module, msg, {line: status}        )        # Store the raw value         try:            self._module_msgs_state[msg.msgid][line] = status            self._raw_module_msgs_state[msg.msgid][line] = status         except KeyError:            self._module_msgs_state[msg.msgid] = {line: status}            self._raw_module_msgs_state[msg.msgid] = {line: status}      def handle_ignored_message(         self, state_scope: Literal[0, 1, 2] | None, msgid: str, line: int | None


Question: Using in CLI silently fail to load the plugin See Warning that load-plugin is not the right argument.

PREPROCESSABLE_OPTIONS: dict[    str, tuple[bool, Callable[[Run, str | None], None]]    str, tuple[bool, Callable[[Run, str | None], None], int] ] = {  # pylint: disable=consider-using-namedtuple-or-dataclass    "--init-hook": (True, _init_hook),    "--rcfile": (True, _set_rcfile),    "--output": (True, _set_output),    "--load-plugins": (True, _add_plugins),    "--verbose": (False, _set_verbose_mode),    "-v": (False, _set_verbose_mode),    "--enable-all-extensions": (False, _enable_all_extensions),    # pylint: disable=wrong-spelling-in-comment    # Argparse by default allows abbreviations. It behaves differently    # if you turn this off, so we also turn it on. We mimick this    # by allowing some abbreviations or incorrect spelling here.    # The integer at the end of the tuple indicates how many letters    # should match, include the '-'. 0 indicates a full match.    #    # Clashes with --init-(import)    "--init-hook": (True, _init_hook, 8),    # Clashes with --r(ecursive)    "--rcfile": (True, _set_rcfile, 4),    # Clashes with --output(-format)    "--output": (True, _set_output, 0),    # Clashes with --lo(ng-help)    "--load-plugins": (True, _add_plugins, 5),    # Clashes with --v(ariable-rgx)    "--verbose": (False, _set_verbose_mode, 4),    "-v": (False, _set_verbose_mode, 2),    # Clashes with --enable    "--enable-all-extensions": (False, _enable_all_extensions, 9), }# pylint: enable=wrong-spelling-in-comment   def _preprocess_options(run: Run, args: Sequence[str]) -> list[str]:


Question: Using in CLI silently fail to load the plugin See Warning that load-plugin is not the right argument.

except ValueError:             option, value = argument, None         if option not in PREPROCESSABLE_OPTIONS:        matched_option = None        for option_name, data in PREPROCESSABLE_OPTIONS.items():            to_match = data[2]            if to_match == 0:                if option == option_name:                    matched_option = option_name            elif option.startswith(option_name[:to_match]):                matched_option = option_name        if matched_option is None:             processed_args.append(argument)             i += 1             continue         takearg, cb = PREPROCESSABLE_OPTIONS[option]        takearg, cb, _ = PREPROCESSABLE_OPTIONS[matched_option]          if takearg and value is None:             i += 1


Question: Running pylint in Kubernetes Pod with --jobs=0 fails I run pylint in multiple parallel stages with Jenkins at a Kubernets agent with . The newly introduced function is called to determine the number of cpus to use and returns 0 in this case. This leads to a crash of pylint because the multiprocessing needs a value 0. I checked the function and found out the following values from the files that are read in above mentioned function: This leads to the calculation then in line which is cast to an and therefore 0 then. No response I expect pylint to not crash if the number of available cpu is misscalculated in this special case. The calculated number should never be 0. A possible solution would be to append a at the end of this line. I'm not sure if the same can happen for the calculation in line though, as I don't know the exact backgrounds of that files. Ubuntu 20.04 Kubernetes Version: v1.18.6 Python 3.9.12 No response

cpu_shares = int(file.read().rstrip())         # For AWS, gives correct value * 1024.         avail_cpu = int(cpu_shares / 1024)<ins>    # In K8s Pods also a fraction of a single core could be available    # As multiprocessing is not able to run only a "fraction" of process    # assume we have 1 CPU available    if avail_cpu == 0:        avail_cpu = 1</ins>     return avail_cpu


Question: --disable ignored when --errors-only specified a python file () with a single line import notfoundpackage --disable=E0401 --errors-only test.py_ reports *** Module test E0401: Unable to import 'notfoundpackage' (import-error) Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00) 11.5

"action": _ErrorsOnlyModeAction,                 "kwargs": {"Run": self},                 "short": "E",                "help": "In error mode, checkers without error messages are "                "disabled and for others, only the ERROR messages are "                "displayed, and no reports are done by default.",                "help": "In error mode, messages with a category besides "                "ERROR or FATAL are suppressed, and no reports are done by default. "                "Error mode is compatible with disabling specific errors. ",                 "hide_from_config_file": True,             },         ),diff --git a/pylint/lint/message_state_handler.py b/pylint/lint/message_state_handler.py-- a/pylint/lint/message_state_handler.py++ b/pylint/lint/message_state_handler.py


Question: --disable ignored when --errors-only specified a python file () with a single line import notfoundpackage --disable=E0401 --errors-only test.py_ reports *** Module test E0401: Unable to import 'notfoundpackage' (import-error) Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00) 11.5

self._register_by_id_managed_msg(msgid, line, is_disabled=False)      def disable_noerror_messages(self) -> None:        for msgcat, msgids in self.linter.msgs_store._msgs_by_category.items():            # enable only messages with 'error' severity and above ('fatal')        """Disable message categories other than `error` and `fatal`."""        for msgcat in self.linter.msgs_store._msgs_by_category:             if msgcat in {"E", "F"}:                for msgid in msgids:                    self.enable(msgid)            else:                for msgid in msgids:                    self.disable(msgid)                continue            self.disable(msgcat)      def list_messages_enabled(self) -> None:         emittable, non_emittable = self.linter.msgs_store.find_emittable_messages()


Question: ignores When running recursively, it seems in my settings in is completely ignored src\gen* should not be checked Windows 10.0. No response

ignore_list_re: list[Pattern[str]],     ignore_list_paths_re: list[Pattern[str]], ) -> bool:<ins>    element = os.path.normpath(element)</ins>     basename = os.path.basename(element)     return (         basename in ignore_list


Question: Linting fails if module contains module of the same name Given multiple files: Which are all empty, running fails: However, if I rename , succeeds: Alternatively, I can also , but that shouldn't be necessary anymore. Running if is present fails while searching for an file. Running if is present should succeed. Result of output: This also has some side-effects in module resolution. For example, if I create another file : With the content: Running will run fine, but will fail. Not just for module a, but for module r as well. Again, if I rename to , will work perfectly.

continue         module_path = get_python_path(something)         additional_search_path = [".", module_path] + path        if os.path.exists(something):            # this is a file or a directory        if os.path.isfile(something) or os.path.exists(            os.path.join(something, "__init__.py")        ):            # this is a file or a directory with an explicit __init__.py             try:                 modname = ".".join(                     modutils.modpath_from_file(something, path=additional_search_path)


Question: Linting fails if module contains module of the same name Given multiple files: Which are all empty, running fails: However, if I rename , succeeds: Alternatively, I can also , but that shouldn't be necessary anymore. Running if is present fails while searching for an file. Running if is present should succeed. Result of output: This also has some side-effects in module resolution. For example, if I create another file : With the content: Running will run fine, but will fail. Not just for module a, but for module r as well. Again, if I rename to , will work perfectly.

)                 if filepath is None:                     continue            except (ImportError, SyntaxError) as ex:                # The SyntaxError is a Python bug and should be                # removed once we move away from imp.find_module: https://bugs.python.org/issue10588            except ImportError as ex:                 errors.append({"key": "fatal", "mod": modname, "ex": ex})                 continue         filepath = os.path.normpath(filepath)


Question: rxg include '\p{Han}' will throw error config rxg in pylintrc with \p{Han} will throw err .pylintrc: not throw error macOS 11.6.7

return version  def _regex_transformer(value: str) -> Pattern[str]:    """Return `re.compile(value)`."""    try:        return re.compile(value)    except re.error as e:        msg = f"Error in provided regular expression: {value} beginning at index {e.pos}: {e.msg}"        raise argparse.ArgumentTypeError(msg) def _regexp_csv_transfomer(value: str) -> Sequence[Pattern[str]]:     """Transforms a comma separated list of regular expressions."""     patterns: list[Pattern[str]] = []     for pattern in _csv_transformer(value):        patterns.append(re.compile(pattern))        patterns.append(_regex_transformer(pattern))     return patterns


Question: rxg include '\p{Han}' will throw error config rxg in pylintrc with \p{Han} will throw err .pylintrc: not throw error macOS 11.6.7

"non_empty_string": _non_empty_string_transformer,     "path": _path_transformer,     "py_version": _py_version_transformer,    "regexp": re.compile,    "regexp": _regex_transformer,     "regexp_csv": _regexp_csv_transfomer,     "regexp_paths_csv": _regexp_paths_csv_transfomer,     "string": pylint_utils._unquote,


Question: removes first item from when running from . This is the line where the first item from is removed. I think there should be a check to ensure that the first item is , or before removing. No response Check if , or before removing the first item from No response No response

if pylint is installed in an editable configuration (as the last item).       https://github.com/PyCQA/pylint/issues/4161     """    sys.path.pop(0)    env_pythonpath = os.environ.get("PYTHONPATH", "")     cwd = os.getcwd()    if sys.path[0] in ("", ".", cwd):        sys.path.pop(0)    env_pythonpath = os.environ.get("PYTHONPATH", "")     if env_pythonpath.startswith(":") and env_pythonpath not in (f":{cwd}", ":."):         sys.path.pop(0)     elif env_pythonpath.endswith(":") and env_pythonpath not in (f"{cwd}:", ".:"):


Question: Using custom braces in message template does not work Have any list of errors: On pylint 1.7 w/ python3.6 - I am able to use this as my message template However, on Python3.9 with Pylint 2.12.2, I get the following: Is this intentional or a bug? No response Expect the dictionary to print out with as the key. No response No response

self._template = template          # Check to see if all parameters in the template are attributes of the Message        arguments = re.findall(r"\{(.+?)(:.*)?\}", template)        arguments = re.findall(r"\{(\w+?)(:.*)?\}", template)         for argument in arguments:             if argument[0] not in MESSAGE_FIELDS:                 warnings.warn(


Question: false positive 'useless-import-alias' error for mypy-compatible explicit re-exports Suppose a package has the following layout: Since the submodules here implement public APIs, imports and re-exports them, expecting users to import them from the public, top-level package, e.g. . Since the implementations of and are complex, they are split into and for better maintainability and separation of concerns. So looks like this: The reason for the aliases here is to be explicit that these imports are for the purpose of re-export (without having to resort to defining , which is error-prone). Without the aliases, popular linters such as will raise an "implicit re-export" error ( -- part of ). However, pylint does not currently understand this usage, and raises "useless-import-alias" errors. Example real-world code triggering pylint false positive errors: No response No "useless-import-alias" errors should be flagged. No response No response_

"help": "Allow wildcard imports from modules that define __all__.",             },         ),<ins>        (            "allow-reexport-from-package",            {                "default": False,                "type": "yn",                "metavar": "<y or n>",                "help": "Allow explicit reexports by alias from a package __init__.",            },        ),</ins>     )      def __init__(self, linter: PyLinter) -> None:


Question: false positive 'useless-import-alias' error for mypy-compatible explicit re-exports Suppose a package has the following layout: Since the submodules here implement public APIs, imports and re-exports them, expecting users to import them from the public, top-level package, e.g. . Since the implementations of and are complex, they are split into and for better maintainability and separation of concerns. So looks like this: The reason for the aliases here is to be explicit that these imports are for the purpose of re-export (without having to resort to defining , which is error-prone). Without the aliases, popular linters such as will raise an "implicit re-export" error ( -- part of ). However, pylint does not currently understand this usage, and raises "useless-import-alias" errors. Example real-world code triggering pylint false positive errors: No response No "useless-import-alias" errors should be flagged. No response No response_

self.linter.stats = self.linter.stats         self.import_graph = defaultdict(set)         self._module_pkg = {}  # mapping of modules to the pkg they belong in<ins>        self._current_module_package = False</ins>         self._excluded_edges: defaultdict[str, set[str]] = defaultdict(set)         self._ignored_modules: Sequence[str] = self.linter.config.ignored_modules         # Build a mapping {'module': 'preferred-module'}