Skip to content

Commit 8d588b8

Browse files
Felixoidx612skm
authored andcommitted
Add a function to search for pyproject.toml in a project root (python#16965)
Here's a solution to fix python#10613. The tests are covered. It adds the functionality of searching `pyproject.toml` recursively from the current directory up to a project root (directory with either `.git` or `.hg`) to `mypy`
1 parent 79c1a86 commit 8d588b8

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

mypy/defaults.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,41 @@
1212
# mypy, at least version PYTHON3_VERSION is needed.
1313
PYTHON3_VERSION_MIN: Final = (3, 8) # Keep in sync with typeshed's python support
1414

15+
16+
def find_pyproject() -> str:
17+
"""Search for file pyproject.toml in the parent directories recursively.
18+
19+
It resolves symlinks, so if there is any symlink up in the tree, it does not respect them
20+
21+
If the file is not found until the root of FS or repository, PYPROJECT_FILE is used
22+
"""
23+
24+
def is_root(current_dir: str) -> bool:
25+
parent = os.path.join(current_dir, os.path.pardir)
26+
return os.path.samefile(current_dir, parent) or any(
27+
os.path.isdir(os.path.join(current_dir, cvs_root)) for cvs_root in (".git", ".hg")
28+
)
29+
30+
# Preserve the original behavior, returning PYPROJECT_FILE if exists
31+
if os.path.isfile(PYPROJECT_FILE) or is_root(os.path.curdir):
32+
return PYPROJECT_FILE
33+
34+
# And iterate over the tree
35+
current_dir = os.path.pardir
36+
while not is_root(current_dir):
37+
config_file = os.path.join(current_dir, PYPROJECT_FILE)
38+
if os.path.isfile(config_file):
39+
return config_file
40+
parent = os.path.join(current_dir, os.path.pardir)
41+
current_dir = parent
42+
43+
return PYPROJECT_FILE
44+
45+
1546
CACHE_DIR: Final = ".mypy_cache"
1647
CONFIG_FILE: Final = ["mypy.ini", ".mypy.ini"]
17-
PYPROJECT_CONFIG_FILES: Final = ["pyproject.toml"]
48+
PYPROJECT_FILE: Final = "pyproject.toml"
49+
PYPROJECT_CONFIG_FILES: Final = [find_pyproject()]
1850
SHARED_CONFIG_FILES: Final = ["setup.cfg"]
1951
USER_CONFIG_FILES: Final = ["~/.config/mypy/config", "~/.mypy.ini"]
2052
if os.environ.get("XDG_CONFIG_HOME"):

test-data/unit/cmdline.pyproject.test

+35
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,38 @@ Neither is this!
133133
description = "Factory ⸻ A code generator 🏭"
134134
\[tool.mypy]
135135
[file x.py]
136+
137+
[case testSearchRecursively]
138+
# cmd: mypy x.py
139+
[file ../pyproject.toml]
140+
\[tool.mypy]
141+
\[tool.mypy.overrides]
142+
module = "x"
143+
disallow_untyped_defs = false
144+
[file x.py]
145+
pass
146+
[out]
147+
../pyproject.toml: tool.mypy.overrides sections must be an array. Please make sure you are using double brackets like so: [[tool.mypy.overrides]]
148+
== Return code: 0
149+
150+
[case testSearchRecursivelyStopsGit]
151+
# cmd: mypy x.py
152+
[file .git/test]
153+
[file ../pyproject.toml]
154+
\[tool.mypy]
155+
\[tool.mypy.overrides]
156+
module = "x"
157+
disallow_untyped_defs = false
158+
[file x.py]
159+
i: int = 0
160+
161+
[case testSearchRecursivelyStopsHg]
162+
# cmd: mypy x.py
163+
[file .hg/test]
164+
[file ../pyproject.toml]
165+
\[tool.mypy]
166+
\[tool.mypy.overrides]
167+
module = "x"
168+
disallow_untyped_defs = false
169+
[file x.py]
170+
i: int = 0

0 commit comments

Comments
 (0)