Skip to content

Commit

Permalink
Adaptation for Pylint >=3
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrunner committed Oct 6, 2024
1 parent 50f9b34 commit 5097b66
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 12 deletions.
7 changes: 5 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion prospector/profiles/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def _load_content_package(name):
file_names = (
["prospector.yaml", "prospector.yml"]
if len(name_split) == 1
else [f"{name_split[1]}.yaml", f"{name_split[1]}.yaml"]
else [f"{name_split[1]}.yaml", f"{name_split[1]}.yml"]
)

data = None
Expand Down
4 changes: 2 additions & 2 deletions prospector/tools/pylint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def _prospector_configure(self, prospector_config, linter: ProspectorLinter):
continue
for option in checker.options:
if option[0] in options:
checker.set_option(option[0], options[option[0]])
checker._arguments_manager.set_option(option[0], options[option[0]])

# The warnings about disabling warnings are useful for figuring out
# with other tools to suppress messages from. For example, an unused
Expand Down Expand Up @@ -167,7 +167,7 @@ def _get_pylint_check_paths(self, found_files: FileFinder) -> List[Path]:
def _get_pylint_configuration(
self, check_paths: List[Path], linter: ProspectorLinter, prospector_config, pylint_options
):
self._args = linter.load_command_line_configuration(str(path) for path in check_paths)
self._args = check_paths
linter.load_default_plugins()

config_messages = self._prospector_configure(prospector_config, linter)
Expand Down
107 changes: 102 additions & 5 deletions prospector/tools/pylint/linter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import sys
import warnings
from pathlib import Path

from packaging import version as packaging_version
from pylint import version as pylint_version
from pylint.config.config_file_parser import _ConfigurationFileParser
from pylint.config.config_initialization import _order_all_first
from pylint.config.exceptions import _UnrecognizedOptionError
from pylint.lint import PyLinter
from pylint.utils import _splitstrip
from pylint.utils import _splitstrip, utils


class ProspectorLinter(PyLinter):
Expand All @@ -12,13 +17,105 @@ def __init__(self, found_files, *args, **kwargs):
# set up the standard PyLint linter
PyLinter.__init__(self, *args, **kwargs)

# get the base from https://github.com/pylint-dev/pylint/blob/main/pylint/config/config_initialization.py#L26
def config_from_file(self, config_file=None):
"""Will return `True` if plugins have been loaded. For pylint>=1.5. Else `False`."""
self.read_config_file(config_file)
if self.cfgfile_parser.has_option("MASTER", "load-plugins"):
plugins = _splitstrip(self.cfgfile_parser.get("MASTER", "load-plugins"))
config_file_parser = _ConfigurationFileParser(False, self)
config_data, config_args = config_file_parser.parse_config_file(file_path=config_file)
if config_data.get("MASTER", {}).get("load-plugins"):
plugins = _splitstrip(config_data["MASTER"]["load-plugins"])
self.load_plugin_modules(plugins)
self.load_config_file()

config_args = _order_all_first(config_args, joined=False)

if "init-hook" in config_data:
exec(utils._unquote(config_data["init-hook"])) # pylint: disable=exec-used

# Load plugins if specified in the config file
if "load-plugins" in config_data:
self.load_plugin_modules(utils._splitstrip(config_data["load-plugins"]))

unrecognized_options_message = None
# First we parse any options from a configuration file
try:
self._parse_configuration_file(config_args)
except _UnrecognizedOptionError as exc:
unrecognized_options_message = ", ".join(exc.options)

# Then, if a custom reporter is provided as argument, it may be overridden
# by file parameters, so we re-set it here. We do this before command line
# parsing, so it's still overridable by command line options
# if reporter:
# self.set_reporter(reporter)

# Set the current module to the command line
# to allow raising messages on it
self.set_current_module(config_file)

# Now we parse any options from the command line, so they can override
# the configuration file
# args_list = _order_all_first(args_list, joined=True)
# parsed_args_list = self._parse_command_line_configuration(args_list)

# Remove the positional arguments separator from the list of arguments if it exists
# try:
# parsed_args_list.remove("--")
# except ValueError:
# pass

# Check if there are any options that we do not recognize
unrecognized_options: list[str] = []
# for opt in parsed_args_list:
# if opt.startswith("--"):
# unrecognized_options.append(opt[2:])
# elif opt.startswith("-"):
# unrecognized_options.append(opt[1:])
if unrecognized_options:
msg = ", ".join(unrecognized_options)
try:
self._arg_parser.error(f"Unrecognized option found: {msg}")
except SystemExit:
sys.exit(32)

# Now that config file and command line options have been loaded
# with all disables, it is safe to emit messages
if unrecognized_options_message is not None:
self.set_current_module(str(config_file) if config_file else "")
self.add_message("unrecognized-option", args=unrecognized_options_message, line=0)

# TODO: Change this to be checked only when upgrading the configuration
for exc_name in self.config.overgeneral_exceptions:
if "." not in exc_name:
warnings.warn_explicit(
f"'{exc_name}' is not a proper value for the 'overgeneral-exceptions' option. "
f"Use fully qualified name (maybe 'builtins.{exc_name}' ?) instead. "
"This will cease to be checked at runtime when the configuration "
"upgrader is released.",
category=UserWarning,
filename="pylint: Command line or configuration file",
lineno=1,
module="pylint",
)

self._emit_stashed_messages()

# Set the current module to configuration as we don't know where
# the --load-plugins key is coming from
self.set_current_module("Command line or configuration file")

# We have loaded configuration from config file and command line. Now, we can
# load plugin specific configuration.
self.load_plugin_configuration()

# Now that plugins are loaded, get list of all fail_on messages, and
# enable them
self.enable_fail_on_messages()

self._parse_error_mode()

# Link the base Namespace object on the current directory
self._directory_namespaces[Path().resolve()] = (self.config, {})

return True

def _expand_files(self, modules):
Expand Down
4 changes: 2 additions & 2 deletions tests/tools/pylint/test_pylint_tool.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from pathlib import Path
from pathlib import Path, PosixPath
from typing import Tuple
from unittest import TestCase
from unittest.mock import patch
Expand Down Expand Up @@ -75,7 +75,7 @@ def test_absolute_path_is_computed_correctly(self):
found_files = _get_test_files("testpath/testfile.py")
pylint_tool.configure(config, found_files)
self.assertNotEqual(pylint_tool._args, [os.path.join(*root_sep_split)])
self.assertEqual(pylint_tool._args, [os.path.join(*root_os_split)])
self.assertEqual(pylint_tool._args, [PosixPath(os.path.join(*root_os_split))])

def test_wont_throw_false_positive_relative_beyond_top_level(self):
with patch("os.getcwd", return_value=os.path.realpath("tests/tools/pylint/testpath/")):
Expand Down

0 comments on commit 5097b66

Please sign in to comment.