| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- # For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
- # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
- from __future__ import annotations
- import sys
- import warnings
- from glob import glob
- from itertools import chain
- from pathlib import Path
- from typing import TYPE_CHECKING
- from pylint import reporters
- from pylint.config.config_file_parser import _ConfigurationFileParser
- from pylint.config.exceptions import (
- ArgumentPreprocessingError,
- _UnrecognizedOptionError,
- )
- from pylint.utils import utils
- if TYPE_CHECKING:
- from pylint.lint import PyLinter
- def _config_initialization( # pylint: disable=too-many-statements
- linter: PyLinter,
- args_list: list[str],
- reporter: reporters.BaseReporter | reporters.MultiReporter | None = None,
- config_file: None | str | Path = None,
- verbose_mode: bool = False,
- ) -> list[str]:
- """Parse all available options, read config files and command line arguments and
- set options accordingly.
- """
- linter.verbose = verbose_mode
- config_file = Path(config_file) if config_file else None
- # Set the current module to the configuration file
- # to allow raising messages on the configuration file.
- linter.set_current_module(str(config_file) if config_file else "")
- # Read the configuration file
- config_file_parser = _ConfigurationFileParser(verbose_mode, linter)
- try:
- config_data, config_args = config_file_parser.parse_config_file(
- file_path=config_file
- )
- except OSError as ex:
- print(ex, file=sys.stderr)
- sys.exit(32)
- # Order --enable=all or --disable=all to come first.
- config_args = _order_all_first(config_args, joined=False)
- # Run init hook, if present, before loading plugins
- 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:
- linter.load_plugin_modules(utils._splitstrip(config_data["load-plugins"]))
- unrecognized_options_message = None
- # First we parse any options from a configuration file
- try:
- linter._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:
- linter.set_reporter(reporter)
- # Set the current module to the command line
- # to allow raising messages on it
- linter.set_current_module("Command line")
- # 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 = linter._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:
- linter._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:
- linter.set_current_module(str(config_file) if config_file else "")
- linter.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 linter.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",
- )
- linter._emit_stashed_messages()
- # Set the current module to configuration as we don't know where
- # the --load-plugins key is coming from
- linter.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.
- linter.load_plugin_configuration()
- # Now that plugins are loaded, get list of all fail_on messages, and
- # enable them
- linter.enable_fail_on_messages()
- # Now that fail_on messages are enabled, pass them to colorized reporter
- linter.pass_fail_on_config_to_color_reporter()
- linter._parse_error_mode()
- # Link the base Namespace object on the current directory
- linter._directory_namespaces[Path().resolve()] = (linter.config, {})
- # parsed_args_list should now only be a list of inputs to lint.
- # All other options have been removed from the list.
- return list(
- chain.from_iterable(
- # NOTE: 'or [arg]' is needed in the case the input file or directory does
- # not exist and 'glob(arg)' cannot find anything. Without this we would
- # not be able to output the fatal import error for this module later on,
- # as it would get silently ignored.
- glob(arg, recursive=True) or [arg]
- for arg in parsed_args_list
- )
- )
- def _order_all_first(config_args: list[str], *, joined: bool) -> list[str]:
- """Reorder config_args such that --enable=all or --disable=all comes first.
- Raise if both are given.
- If joined is True, expect args in the form '--enable=all,for-any-all'.
- If joined is False, expect args in the form '--enable', 'all,for-any-all'.
- """
- indexes_to_prepend = []
- all_action = ""
- for i, arg in enumerate(config_args):
- if joined and arg.startswith(("--enable=", "--disable=")):
- value = arg.split("=")[1]
- elif arg in {"--enable", "--disable"}:
- value = config_args[i + 1]
- else:
- continue
- if "all" not in (msg.strip() for msg in value.split(",")):
- continue
- arg = arg.split("=")[0]
- if all_action and (arg != all_action):
- raise ArgumentPreprocessingError(
- "--enable=all and --disable=all are incompatible."
- )
- all_action = arg
- indexes_to_prepend.append(i)
- if not joined:
- indexes_to_prepend.append(i + 1)
- returned_args = []
- for i in indexes_to_prepend:
- returned_args.append(config_args[i])
- for i, arg in enumerate(config_args):
- if i in indexes_to_prepend:
- continue
- returned_args.append(arg)
- return returned_args
|