Skip to content

Commit

Permalink
Suppress OSError in config file discovery (pylint-dev#7423)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielNoord authored and Pierre-Sassoulas committed Sep 6, 2022
1 parent 7848356 commit bf1cbd6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 10 deletions.
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/7169.bugfix
@@ -0,0 +1,3 @@
Don't crash on ``OSError`` in config file discovery.

Closes #7169
52 changes: 42 additions & 10 deletions pylint/config/find_default_config_files.py
Expand Up @@ -39,17 +39,26 @@ def _cfg_has_config(path: Path | str) -> bool:
return any(section.startswith("pylint.") for section in parser.sections())


def find_default_config_files() -> Iterator[Path]:
"""Find all possible config files."""
def _yield_default_files() -> Iterator[Path]:
"""Iterate over the default config file names and see if they exist."""
for config_name in CONFIG_NAMES:
if config_name.is_file():
if config_name.suffix == ".toml" and not _toml_has_config(config_name):
continue
if config_name.suffix == ".cfg" and not _cfg_has_config(config_name):
continue
try:
if config_name.is_file():
if config_name.suffix == ".toml" and not _toml_has_config(config_name):
continue
if config_name.suffix == ".cfg" and not _cfg_has_config(config_name):
continue

yield config_name.resolve()
except OSError:
pass


yield config_name.resolve()
def _find_project_config() -> Iterator[Path]:
"""Traverse up the directory tree to find a config file.
Stop if no '__init__' is found and thus we are no longer in a package.
"""
if Path("__init__.py").is_file():
curdir = Path(os.getcwd()).resolve()
while (curdir / "__init__.py").is_file():
Expand All @@ -59,6 +68,9 @@ def find_default_config_files() -> Iterator[Path]:
if rc_path.is_file():
yield rc_path.resolve()


def _find_config_in_home_or_environment() -> Iterator[Path]:
"""Find a config file in the specified environment var or the home directory."""
if "PYLINTRC" in os.environ and Path(os.environ["PYLINTRC"]).exists():
if Path(os.environ["PYLINTRC"]).is_file():
yield Path(os.environ["PYLINTRC"]).resolve()
Expand All @@ -68,16 +80,36 @@ def find_default_config_files() -> Iterator[Path]:
except RuntimeError:
# If the home directory does not exist a RuntimeError will be raised
user_home = None

if user_home is not None and str(user_home) not in ("~", "/root"):
home_rc = user_home / ".pylintrc"
if home_rc.is_file():
yield home_rc.resolve()

home_rc = user_home / ".config" / "pylintrc"
if home_rc.is_file():
yield home_rc.resolve()

if os.path.isfile("/etc/pylintrc"):
yield Path("/etc/pylintrc").resolve()

def find_default_config_files() -> Iterator[Path]:
"""Find all possible config files."""
yield from _yield_default_files()

try:
yield from _find_project_config()
except OSError:
pass

try:
yield from _find_config_in_home_or_environment()
except OSError:
pass

try:
if os.path.isfile("/etc/pylintrc"):
yield Path("/etc/pylintrc").resolve()
except OSError:
pass


def find_pylintrc() -> str | None:
Expand Down
9 changes: 9 additions & 0 deletions tests/config/test_find_default_config_files.py
Expand Up @@ -253,3 +253,12 @@ def test_non_existent_home() -> None:
assert not list(config.find_default_config_files())

os.chdir(current_dir)


def test_permission_error() -> None:
"""Test that we handle PermissionError correctly in find_default_config_files.
Reported in https://github.com/PyCQA/pylint/issues/7169.
"""
with mock.patch("pathlib.Path.is_file", side_effect=PermissionError):
list(config.find_default_config_files())

0 comments on commit bf1cbd6

Please sign in to comment.