diff --git a/src/flake8/options/config.py b/src/flake8/options/config.py index 9756e7d..f5c93ce 100644 --- a/src/flake8/options/config.py +++ b/src/flake8/options/config.py @@ -14,7 +14,18 @@ from flake8.options.manager import OptionManager LOG = logging.getLogger(__name__) +def _stat_key(s: str) -> Tuple[int, int]: + # same as what's used by samefile / samestat + st = os.stat(s) + return st.st_ino, st.st_dev + + def _find_config_file(path: str) -> Optional[str]: + # on windows if the homedir isn't detected this returns back `~` + home = os.path.expanduser("~") + home_stat = _stat_key(home) if home != "~" else None + + dir_stat = _stat_key(path) cfg = configparser.RawConfigParser() while True: for candidate in ("setup.cfg", "tox.ini", ".flake8"): @@ -29,10 +40,12 @@ def _find_config_file(path: str) -> Optional[str]: return cfg_path new_path = os.path.dirname(path) - if new_path == path: + new_dir_stat = _stat_key(new_path) + if new_dir_stat == dir_stat or new_dir_stat == home_stat: break else: path = new_path + dir_stat = new_dir_stat # did not find any configuration file return None diff --git a/tests/unit/test_options_config.py b/tests/unit/test_options_config.py index 02dd218..7a7c4f7 100644 --- a/tests/unit/test_options_config.py +++ b/tests/unit/test_options_config.py @@ -1,4 +1,6 @@ import configparser +import os.path +from unittest import mock import pytest @@ -66,6 +68,16 @@ def test_find_config_searches_upwards(tmp_path): assert config._find_config_file(str(subdir)) == str(expected) +def test_find_config_ignores_homedir(tmp_path): + subdir = tmp_path.joinpath("d") + subdir.mkdir() + + tmp_path.joinpath(".flake8").write_text("[flake8]") + + with mock.patch.object(os.path, "expanduser", return_value=str(tmp_path)): + assert config._find_config_file(str(subdir)) is None + + def test_load_config_config_specified_skips_discovery(tmpdir): tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n") custom_cfg = tmpdir.join("custom.cfg")