Skip to content

Commit 5b85ecc

Browse files
DanielNoordPierre-Sassoulas
authored andcommitted
Suppress OSError in config file discovery (#7423)
1 parent 262723a commit 5b85ecc

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

doc/whatsnew/fragments/7169.bugfix

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Don't crash on ``OSError`` in config file discovery.
2+
3+
Closes #7169

pylint/config/find_default_config_files.py

+42-10
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,26 @@ def _cfg_has_config(path: Path | str) -> bool:
3939
return any(section.startswith("pylint.") for section in parser.sections())
4040

4141

42-
def find_default_config_files() -> Iterator[Path]:
43-
"""Find all possible config files."""
42+
def _yield_default_files() -> Iterator[Path]:
43+
"""Iterate over the default config file names and see if they exist."""
4444
for config_name in CONFIG_NAMES:
45-
if config_name.is_file():
46-
if config_name.suffix == ".toml" and not _toml_has_config(config_name):
47-
continue
48-
if config_name.suffix == ".cfg" and not _cfg_has_config(config_name):
49-
continue
45+
try:
46+
if config_name.is_file():
47+
if config_name.suffix == ".toml" and not _toml_has_config(config_name):
48+
continue
49+
if config_name.suffix == ".cfg" and not _cfg_has_config(config_name):
50+
continue
51+
52+
yield config_name.resolve()
53+
except OSError:
54+
pass
55+
5056

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

71+
72+
def _find_config_in_home_or_environment() -> Iterator[Path]:
73+
"""Find a config file in the specified environment var or the home directory."""
6274
if "PYLINTRC" in os.environ and Path(os.environ["PYLINTRC"]).exists():
6375
if Path(os.environ["PYLINTRC"]).is_file():
6476
yield Path(os.environ["PYLINTRC"]).resolve()
@@ -68,16 +80,36 @@ def find_default_config_files() -> Iterator[Path]:
6880
except RuntimeError:
6981
# If the home directory does not exist a RuntimeError will be raised
7082
user_home = None
83+
7184
if user_home is not None and str(user_home) not in ("~", "/root"):
7285
home_rc = user_home / ".pylintrc"
7386
if home_rc.is_file():
7487
yield home_rc.resolve()
88+
7589
home_rc = user_home / ".config" / "pylintrc"
7690
if home_rc.is_file():
7791
yield home_rc.resolve()
7892

79-
if os.path.isfile("/etc/pylintrc"):
80-
yield Path("/etc/pylintrc").resolve()
93+
94+
def find_default_config_files() -> Iterator[Path]:
95+
"""Find all possible config files."""
96+
yield from _yield_default_files()
97+
98+
try:
99+
yield from _find_project_config()
100+
except OSError:
101+
pass
102+
103+
try:
104+
yield from _find_config_in_home_or_environment()
105+
except OSError:
106+
pass
107+
108+
try:
109+
if os.path.isfile("/etc/pylintrc"):
110+
yield Path("/etc/pylintrc").resolve()
111+
except OSError:
112+
pass
81113

82114

83115
def find_pylintrc() -> str | None:

tests/config/test_find_default_config_files.py

+9
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,12 @@ def test_non_existent_home() -> None:
253253
assert not list(config.find_default_config_files())
254254

255255
os.chdir(current_dir)
256+
257+
258+
def test_permission_error() -> None:
259+
"""Test that we handle PermissionError correctly in find_default_config_files.
260+
261+
Reported in https://github.com/PyCQA/pylint/issues/7169.
262+
"""
263+
with mock.patch("pathlib.Path.is_file", side_effect=PermissionError):
264+
list(config.find_default_config_files())

0 commit comments

Comments
 (0)