Skip to content

Fix crash when the user ask for --version and pylintrc is malformed #3581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pylint/__pkginfo__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
# pylint: disable=redefined-builtin,invalid-name
"""pylint packaging information"""


from os.path import join

# For an official release, use dev_version = None
Expand Down
8 changes: 4 additions & 4 deletions pylint/config/option_manager_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ def _patch_optparse():
class OptionsManagerMixIn:
"""Handle configuration from both a configuration file and command line options"""

def __init__(self, usage, config_file=None, version=None):
def __init__(self, usage, config_file=None):
self.config_file = config_file
self.reset_parsers(usage, version=version)
self.reset_parsers(usage)
# list of registered options providers
self.options_providers = []
# dictionary associating option name to checker
Expand All @@ -68,13 +68,13 @@ def __init__(self, usage, config_file=None, version=None):
# verbosity
self._maxlevel = 0

def reset_parsers(self, usage="", version=None):
def reset_parsers(self, usage=""):
# configuration file parser
self.cfgfile_parser = configparser.ConfigParser(
inline_comment_prefixes=("#", ";")
)
# command line parser
self.cmdline_parser = OptionParser(Option, usage=usage, version=version)
self.cmdline_parser = OptionParser(Option, usage=usage)
self.cmdline_parser.options_manager = self
self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS)

Expand Down
12 changes: 12 additions & 0 deletions pylint/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING

import re
import sys

from astroid.__pkginfo__ import version as astroid_version
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we grab it directly from __pkginfo__ as that is the source of truth for the version?

Copy link
Member Author

@Pierre-Sassoulas Pierre-Sassoulas May 5, 2020

Choose a reason for hiding this comment

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

Putting this version in __pgfinfo__ creates a 10+ links circular import error. I originally put it there :(

Copy link
Member Author

Choose a reason for hiding this comment

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

We can't because in __pkginfo__ we're defining the dependencies for the setup.py so astroid is not installed yet. We could do it if we put the dependencies in the setup.py/pyproject.toml directly


from pylint.__pkginfo__ import version as pylint_version

# Allow stopping after the first semicolon/hash encountered,
# so that an option can be continued with the reasons
Expand Down Expand Up @@ -39,3 +44,10 @@
class WarningScope:
LINE = "line-based-msg"
NODE = "node-based-msg"


full_version = "pylint %s\nastroid %s\nPython %s" % (
pylint_version,
astroid_version,
sys.version,
)
8 changes: 0 additions & 8 deletions pylint/lint/pylinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@

import astroid
from astroid import modutils
from astroid.__pkginfo__ import version as astroid_version
from astroid.builder import AstroidBuilder

from pylint import checkers, config, exceptions, interfaces, reporters
from pylint.__pkginfo__ import version
from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES
from pylint.lint.check_parallel import check_parallel
from pylint.lint.report_functions import (
Expand Down Expand Up @@ -448,16 +446,10 @@ def __init__(self, options=(), reporter=None, option_groups=(), pylintrc=None):
"disable-msg": self.disable,
"enable-msg": self.enable,
}
full_version = "pylint %s\nastroid %s\nPython %s" % (
version,
astroid_version,
sys.version,
)
MessagesHandlerMixIn.__init__(self)
reporters.ReportsHandlerMixIn.__init__(self)
super().__init__(
usage=__doc__,
version=full_version,
config_file=pylintrc or next(config.find_default_config_files(), None),
)
checkers.BaseTokenChecker.__init__(self)
Expand Down
10 changes: 10 additions & 0 deletions pylint/lint/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import warnings

from pylint import __pkginfo__, config, extensions, interfaces
from pylint.constants import full_version
from pylint.lint.pylinter import PyLinter
from pylint.lint.utils import ArgumentPreprocessingError, preprocess_options
from pylint.utils import utils
Expand Down Expand Up @@ -74,13 +75,15 @@ def __init__(
self, args, reporter=None, exit=True, do_exit=UNUSED_PARAM_SENTINEL,
): # pylint: disable=redefined-builtin
self._rcfile = None
self._version_asked = False
self._plugins = []
self.verbose = None
try:
preprocess_options(
args,
{
# option: (callback, takearg)
"version": (self.version_asked, False),
"init-hook": (cb_init_hook, True),
"rcfile": (self.cb_set_rcfile, True),
"load-plugins": (self.cb_add_plugins, True),
Expand Down Expand Up @@ -251,6 +254,9 @@ def __init__(
pylintrc=self._rcfile,
)
# register standard checkers
if self._version_asked:
print(full_version)
sys.exit(0)
linter.load_default_plugins()
# load command line plugins
linter.load_plugin_modules(self._plugins)
Expand Down Expand Up @@ -358,6 +364,10 @@ def __init__(
sys.exit(0)
sys.exit(self.linter.msg_status)

def version_asked(self, _, __):
"""callback for version (i.e. before option parsing)"""
self._version_asked = True

def cb_set_rcfile(self, name, value):
"""callback for option preprocessing (i.e. before option parsing)"""
self._rcfile = value
Expand Down