Skip to content
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

Add a function to search for pyproject.toml in a project root #16965

Merged
merged 3 commits into from
Jan 16, 2025
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
34 changes: 33 additions & 1 deletion mypy/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,41 @@
# 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
"""

def is_root(current_dir: str) -> bool:
parent = os.path.join(current_dir, os.path.pardir)
return os.path.samefile(current_dir, parent) or any(
os.path.isdir(os.path.join(current_dir, cvs_root)) for cvs_root in (".git", ".hg")
)

# Preserve the original behavior, returning PYPROJECT_FILE if exists
if os.path.isfile(PYPROJECT_FILE) or is_root(os.path.curdir):
return PYPROJECT_FILE

# And iterate over the tree
current_dir = os.path.pardir
while not is_root(current_dir):
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)
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"):
Expand Down
35 changes: 35 additions & 0 deletions test-data/unit/cmdline.pyproject.test
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,38 @@ Neither is this!
description = "Factory ⸻ A code generator 🏭"
\[tool.mypy]
[file x.py]

[case testSearchRecursively]
# cmd: mypy x.py
[file ../pyproject.toml]
\[tool.mypy]
\[tool.mypy.overrides]
module = "x"
disallow_untyped_defs = false
[file x.py]
pass
[out]
../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 testSearchRecursivelyStopsGit]
# cmd: mypy x.py
[file .git/test]
[file ../pyproject.toml]
\[tool.mypy]
\[tool.mypy.overrides]
module = "x"
disallow_untyped_defs = false
[file x.py]
i: int = 0

[case testSearchRecursivelyStopsHg]
# cmd: mypy x.py
[file .hg/test]
[file ../pyproject.toml]
\[tool.mypy]
\[tool.mypy.overrides]
module = "x"
disallow_untyped_defs = false
[file x.py]
i: int = 0
Loading