diff --git a/mypy/config_parser.py b/mypy/config_parser.py index afda41ad58822..a6bf021000c1a 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -229,28 +229,6 @@ def split_commas(value: str) -> list[str]: ) -def _find_pyproject() -> list[str]: - """Search for file pyproject.toml in the parent directories recursively. - - It resolves symlinks, so if there is any symlink up in the tree, it does not respect them - """ - # We start from the parent dir, since 'pyproject.toml' is already parsed - current_dir = os.path.abspath(os.path.join(os.path.curdir, os.path.pardir)) - is_root = False - while not is_root: - for pyproject_name in defaults.PYPROJECT_CONFIG_FILES: - config_file = os.path.join(current_dir, pyproject_name) - if os.path.isfile(config_file): - return [os.path.abspath(config_file)] - parent = os.path.abspath(os.path.join(current_dir, os.path.pardir)) - is_root = current_dir == parent or any( - os.path.isdir(os.path.join(current_dir, cvs_root)) for cvs_root in (".git", ".hg") - ) - current_dir = parent - - return [] - - def parse_config_file( options: Options, set_strict_flags: Callable[[], None], @@ -270,9 +248,7 @@ def parse_config_file( if filename is not None: config_files: tuple[str, ...] = (filename,) else: - config_files_iter: Iterable[str] = map( - os.path.expanduser, defaults.CONFIG_FILES + _find_pyproject() - ) + config_files_iter: Iterable[str] = map(os.path.expanduser, defaults.CONFIG_FILES) config_files = tuple(config_files_iter) config_parser = configparser.RawConfigParser() diff --git a/mypy/defaults.py b/mypy/defaults.py index 2bbae23d7e2d8..3ec689e548ec0 100644 --- a/mypy/defaults.py +++ b/mypy/defaults.py @@ -12,9 +12,33 @@ # mypy, at least version PYTHON3_VERSION is needed. PYTHON3_VERSION_MIN: Final = (3, 8) # Keep in sync with typeshed's python support + +def find_pyproject() -> str: + """Search for file pyproject.toml in the parent directories recursively. + + It resolves symlinks, so if there is any symlink up in the tree, it does not respect them + + If the file is not found until the root of FS or repository, PYPROJECT_FILE is used + """ + current_dir = os.path.curdir + is_root = False + while not is_root: + config_file = os.path.join(current_dir, PYPROJECT_FILE) + if os.path.isfile(config_file): + return config_file + parent = os.path.join(current_dir, os.path.pardir) + is_root = os.path.samefile(current_dir, parent) or any( + os.path.isdir(os.path.join(current_dir, cvs_root)) for cvs_root in (".git", ".hg") + ) + current_dir = parent + + return PYPROJECT_FILE + + CACHE_DIR: Final = ".mypy_cache" CONFIG_FILE: Final = ["mypy.ini", ".mypy.ini"] -PYPROJECT_CONFIG_FILES: Final = ["pyproject.toml"] +PYPROJECT_FILE: Final = "pyproject.toml" +PYPROJECT_CONFIG_FILES: Final = [find_pyproject()] SHARED_CONFIG_FILES: Final = ["setup.cfg"] USER_CONFIG_FILES: Final = ["~/.config/mypy/config", "~/.mypy.ini"] if os.environ.get("XDG_CONFIG_HOME"): diff --git a/test-data/unit/cmdline.pyproject.test b/test-data/unit/cmdline.pyproject.test index 831bce2eb63d1..7150737a7661a 100644 --- a/test-data/unit/cmdline.pyproject.test +++ b/test-data/unit/cmdline.pyproject.test @@ -28,7 +28,7 @@ def f(a): def g(a: int) -> int: return f(a) [out] -pyproject.toml: tool.mypy.overrides sections must be an array. Please make sure you are using double brackets like so: [[tool.mypy.overrides]] +./pyproject.toml: tool.mypy.overrides sections must be an array. Please make sure you are using double brackets like so: [[tool.mypy.overrides]] == Return code: 0 [case testNoModuleInOverridePyprojectTOML] @@ -43,7 +43,7 @@ def f(a): def g(a: int) -> int: return f(a) [out] -pyproject.toml: toml config file contains a [[tool.mypy.overrides]] section, but no module to override was specified. +./pyproject.toml: toml config file contains a [[tool.mypy.overrides]] section, but no module to override was specified. == Return code: 0 [case testInvalidModuleInOverridePyprojectTOML] @@ -59,7 +59,7 @@ def f(a): def g(a: int) -> int: return f(a) [out] -pyproject.toml: toml config file contains a [[tool.mypy.overrides]] section with a module value that is not a string or a list of strings +./pyproject.toml: toml config file contains a [[tool.mypy.overrides]] section with a module value that is not a string or a list of strings == Return code: 0 [case testConflictingModuleInOverridesPyprojectTOML] @@ -78,7 +78,7 @@ def f(a): def g(a: int) -> int: return f(a) [out] -pyproject.toml: toml config file contains [[tool.mypy.overrides]] sections with conflicting values. Module 'x' has two different values for 'disallow_untyped_defs' +./pyproject.toml: toml config file contains [[tool.mypy.overrides]] sections with conflicting values. Module 'x' has two different values for 'disallow_untyped_defs' == Return code: 0 [case testMultilineLiteralExcludePyprojectTOML]