Skip to content

Commit 1229be3

Browse files
Merge branch 'jam' of https://github.com/marcothephoenix65/313mypy into jam
2 parents 9c2c16e + 92c0cdb commit 1229be3

3 files changed

Lines changed: 85 additions & 83 deletions

File tree

mypy/installtypes.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
def normalize_distribution_name(name: str) -> str:
2222
return _DIST_NORMALIZE_RE.sub("-", name).lower()
2323

24-
DIST_TO_MODULE_NAME: dict[str, str] = {
24+
25+
DIST_TO_MODULE_NAME: dict[str, str] = { # FIX
2526
"python-dateutil": "dateutil",
2627
"pyyaml": "yaml",
2728
"python-xlib": "Xlib",
@@ -68,14 +69,28 @@ def resolve_stub_packages_from_lock(locked: Mapping[str, str | None]) -> list[st
6869
known_stubs.update(namespace_packages.values())
6970

7071
stubs: set[str] = set()
72+
# FIX
73+
# for dist_name in locked:
74+
# if dist_name.startswith("types-"):
75+
# continue
76+
# candidates = {
77+
# dist_name,
78+
# dist_name.replace("-", "_"),
79+
# }
80+
81+
# for module_name in candidates:
82+
# stub = stub_distribution_name(module_name)
83+
# if stub:
84+
# stubs.add(stub)
85+
# typeshed_name = f"types-{dist_name}"
86+
# if typeshed_name in known_stubs:
87+
# stubs.add(typeshed_name)
88+
# return sorted(stubs)
7189
for dist_name in locked:
7290
if dist_name.startswith("types-"):
7391
continue
7492

75-
candidates = {
76-
dist_name,
77-
dist_name.replace("-", "_"),
78-
}
93+
candidates = {dist_name, dist_name.replace("-", "_")}
7994

8095
mapped_module = DIST_TO_MODULE_NAME.get(dist_name)
8196
if mapped_module is not None:
@@ -98,4 +113,4 @@ def make_runtime_constraints(locked: Mapping[str, str | None]) -> list[str]:
98113
for name, version in sorted(locked.items()):
99114
if version:
100115
constraints.append(f"{name}=={version}")
101-
return constraints
116+
return constraints

mypy/main.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
from mypy.errors import CompileError
3131
from mypy.find_sources import InvalidSourceList, create_source_list
3232
from mypy.fscache import FileSystemCache
33-
from mypy.installtypes import make_runtime_constraints, read_locked_packages, resolve_stub_packages_from_lock
33+
from mypy.installtypes import (
34+
make_runtime_constraints,
35+
read_locked_packages,
36+
resolve_stub_packages_from_lock,
37+
)
3438
from mypy.modulefinder import (
3539
BuildSource,
3640
FindModuleCache,
@@ -136,11 +140,7 @@ def main(
136140
if options.install_types_from_pylock is not None and not os.path.isfile(
137141
options.install_types_from_pylock
138142
):
139-
fail(
140-
f"error: Can't find lock file '{options.install_types_from_pylock}'",
141-
stderr,
142-
options,
143-
)
143+
fail(f"error: Can't find lock file '{options.install_types_from_pylock}'", stderr, options)
144144

145145
if options.install_types and not options.incremental:
146146
fail(

mypy/test/testinstalltypes.py

Lines changed: 58 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,20 @@
44
import tempfile
55
import textwrap
66
import unittest
7-
import sys
8-
from unittest.mock import MagicMock, patch
9-
from mypy.options import Options
10-
from mypy.util import FancyFormatter
11-
7+
from types import SimpleNamespace # ADDED
8+
from unittest.mock import patch # ADDED
129

1310
from mypy.installtypes import (
1411
make_runtime_constraints,
1512
read_locked_packages,
1613
resolve_stub_packages_from_lock,
1714
)
18-
from mypy.main import install_types
15+
from mypy.main import install_types # ADDED
1916

2017

2118
class TestInstallTypesFromPylock(unittest.TestCase):
2219
def test_read_locked_packages(self) -> None:
23-
content = textwrap.dedent(
24-
"""
20+
content = textwrap.dedent("""
2521
[[package]]
2622
name = "requests"
2723
version = "2.32.3"
@@ -33,8 +29,7 @@ def test_read_locked_packages(self) -> None:
3329
[[package]]
3430
name = "types-requests"
3531
version = "2.32.0"
36-
"""
37-
)
32+
""")
3833
with tempfile.NamedTemporaryFile("w", suffix=".toml", delete=False, encoding="utf-8") as f:
3934
f.write(content)
4035
path = f.name
@@ -91,27 +86,24 @@ def test_read_locked_packages_empty_file(self) -> None:
9186
assert locked == {}
9287

9388
def test_resolve_stub_packages_from_lock(self) -> None:
94-
locked = {
95-
"requests": "2.32.3",
96-
"python-dateutil": "2.9.0",
97-
"types-requests": "2.32.0",
98-
}
89+
locked = {"requests": "2.32.3", "python-dateutil": "2.9.0", "types-requests": "2.32.0"}
9990
stubs = resolve_stub_packages_from_lock(locked)
91+
# requests already worked before fix because distribution name == module name.
10092
assert "types-requests" in stubs
101-
assert "types-python-dateutil" in stubs
10293

103-
#TEST: checks explicit distribution->module mapping
94+
# FIX: Before my fix, this failed because the lock file used the distribution name
95+
# "python-dateutil" but stubinfo.py knows the module/import name "dateutil".
96+
# After adding the explicit distribution->module mapping, it should resolve.
97+
assert "types-python-dateutil" in stubs # FIX
98+
99+
# TEST: checks explicit distribution->module mapping
104100
def test_resolve_stub_packages_from_lock_handles_distribution_module_mismatch(self) -> None:
105-
locked = {
106-
"python-dateutil": "2.9.0",
107-
}
101+
locked = {"python-dateutil": "2.9.0"}
108102
stubs = resolve_stub_packages_from_lock(locked)
109103
assert "types-python-dateutil" in stubs
110-
104+
111105
def test_resolve_stub_packages_skips_types_packages(self) -> None:
112-
locked = {
113-
"types-requests": "2.32.0",
114-
}
106+
locked = {"types-requests": "2.32.0"}
115107
stubs = resolve_stub_packages_from_lock(locked)
116108
# Should not produce "types-types-requests"
117109
assert "types-types-requests" not in stubs
@@ -131,11 +123,7 @@ def test_resolve_stub_packages_pyyaml_mapping(self) -> None:
131123
assert "types-PyYAML" in stubs
132124

133125
def test_make_runtime_constraints(self) -> None:
134-
locked = {
135-
"requests": "2.32.3",
136-
"python-dateutil": "2.9.0",
137-
"no-version": None,
138-
}
126+
locked = {"requests": "2.32.3", "python-dateutil": "2.9.0", "no-version": None}
139127
constraints = make_runtime_constraints(locked)
140128
assert constraints == ["python-dateutil==2.9.0", "requests==2.32.3"]
141129

@@ -146,50 +134,49 @@ def test_make_runtime_constraints_skips_none_versions(self) -> None:
146134
assert "python-dateutil==2.9.0" in constraints
147135

148136
def test_make_runtime_constraints_empty(self) -> None:
149-
locked: dict[str, str | None] = {}
137+
locked = {}
150138
assert make_runtime_constraints(locked) == []
151139

152140
def test_make_runtime_constraints_is_sorted(self) -> None:
153141
locked = {"zebra-lib": "1.0", "alpha-lib": "2.0"}
154142
constraints = make_runtime_constraints(locked)
155143
assert constraints == sorted(constraints)
156144

157-
#TEST: integrations tests
145+
146+
# FIX: stub/mock object that pretends to be a formatter so tests don’t crash.
147+
class DummyFormatter:
148+
def style(self, text: str, *args: object, **kwargs: object) -> str:
149+
return text
150+
151+
152+
# TEST: integrations tests
158153
class TestInstallTypesFromPylockIntegration(unittest.TestCase):
159-
def make_options(self) -> Options:
160-
options = Options()
161-
options.python_executable = "python"
162-
options.cache_dir = "unused"
163-
return options
164-
def make_formatter(self) -> FancyFormatter:
165-
return FancyFormatter(sys.stdout, sys.stderr, False)
154+
def make_options(self) -> SimpleNamespace:
155+
return SimpleNamespace(python_executable="python", cache_dir="unused")
166156

167157
@patch("mypy.main.subprocess.run")
168-
def test_install_types_builds_correct_pip_command(self, mock_run: MagicMock) -> None:
169-
content = textwrap.dedent(
170-
"""
158+
def test_install_types_builds_correct_pip_command(self, mock_run) -> None:
159+
content = textwrap.dedent("""
171160
[[package]]
172161
name = "requests"
173162
version = "2.32.3"
174163
175164
[[package]]
176165
name = "python-dateutil"
177166
version = "2.9.0"
178-
"""
179-
)
167+
""")
180168

181-
with tempfile.NamedTemporaryFile(
182-
"w", suffix=".toml", delete=False, encoding="utf-8"
183-
) as f:
169+
with tempfile.NamedTemporaryFile("w", suffix=".toml", delete=False, encoding="utf-8") as f:
184170
f.write(content)
185171
path = f.name
186172

187173
try:
188174
options = self.make_options()
189-
formatter = self.make_formatter()
175+
formatter = DummyFormatter() # FIX
190176

191177
result = install_types(
192-
formatter=formatter,
178+
# formatter=None,
179+
formatter=formatter, # FIX
193180
options=options,
194181
non_interactive=True,
195182
pylock_path=path,
@@ -208,34 +195,38 @@ def test_install_types_builds_correct_pip_command(self, mock_run: MagicMock) ->
208195
self.assertIn("--constraint", cmd)
209196

210197
# Stub packages should be installed
198+
# requests already resolved before the fix.
211199
self.assertIn("types-requests", cmd)
200+
201+
# FIX: Before the fix, this was missing from the pip command because
202+
# resolve_stub_packages_from_lock only tried "python-dateutil" and
203+
# "python_dateutil", but stubinfo.py maps "dateutil" -> "types-python-dateutil".
204+
# After adding the explicit distribution->module mapping, install_types()
205+
# should include the correct stub package in the pip command.
212206
self.assertIn("types-python-dateutil", cmd)
213207

214208
finally:
215209
os.unlink(path)
216210

217211
@patch("mypy.main.subprocess.run")
218-
def test_no_stubs_found_skips_install(self, mock_run: MagicMock) -> None:
219-
content = textwrap.dedent(
220-
"""
212+
def test_no_stubs_found_skips_install(self, mock_run) -> None:
213+
content = textwrap.dedent("""
221214
[[package]]
222215
name = "unknown-lib"
223216
version = "1.0.0"
224-
"""
225-
)
217+
""")
226218

227-
with tempfile.NamedTemporaryFile(
228-
"w", suffix=".toml", delete=False, encoding="utf-8"
229-
) as f:
219+
with tempfile.NamedTemporaryFile("w", suffix=".toml", delete=False, encoding="utf-8") as f:
230220
f.write(content)
231221
path = f.name
232222

233223
try:
234224
options = self.make_options()
235-
formatter = self.make_formatter()
225+
formatter = DummyFormatter() # FIX
236226

237227
result = install_types(
238-
formatter=formatter,
228+
# formatter=None,
229+
formatter=formatter, # FIX
239230
options=options,
240231
non_interactive=True,
241232
pylock_path=path,
@@ -248,14 +239,12 @@ def test_no_stubs_found_skips_install(self, mock_run: MagicMock) -> None:
248239
os.unlink(path)
249240

250241
@patch("mypy.main.subprocess.run")
251-
def test_constraint_file_cleaned_up_after_success(self, mock_run: MagicMock) -> None:
252-
content = textwrap.dedent(
253-
"""
242+
def test_constraint_file_cleaned_up_after_success(self, mock_run) -> None:
243+
content = textwrap.dedent("""
254244
[[package]]
255245
name = "requests"
256246
version = "2.32.3"
257-
"""
258-
)
247+
""")
259248
with tempfile.NamedTemporaryFile("w", suffix=".toml", delete=False, encoding="utf-8") as f:
260249
f.write(content)
261250
path = f.name
@@ -270,7 +259,7 @@ def capture_cmd(cmd: list[str], **kwargs: object) -> None:
270259

271260
try:
272261
install_types(
273-
formatter=self.make_formatter(),
262+
formatter=DummyFormatter(),
274263
options=self.make_options(),
275264
non_interactive=True,
276265
pylock_path=path,
@@ -285,14 +274,12 @@ def capture_cmd(cmd: list[str], **kwargs: object) -> None:
285274
)
286275

287276
@patch("mypy.main.subprocess.run")
288-
def test_constraint_file_cleaned_up_even_if_subprocess_fails(self, mock_run: MagicMock) -> None:
289-
content = textwrap.dedent(
290-
"""
277+
def test_constraint_file_cleaned_up_even_if_subprocess_fails(self, mock_run) -> None:
278+
content = textwrap.dedent("""
291279
[[package]]
292280
name = "requests"
293281
version = "2.32.3"
294-
"""
295-
)
282+
""")
296283
with tempfile.NamedTemporaryFile("w", suffix=".toml", delete=False, encoding="utf-8") as f:
297284
f.write(content)
298285
path = f.name
@@ -309,7 +296,7 @@ def capture_and_raise(cmd: list[str], **kwargs: object) -> None:
309296
try:
310297
with self.assertRaises(RuntimeError):
311298
install_types(
312-
formatter=self.make_formatter(),
299+
formatter=DummyFormatter(),
313300
options=self.make_options(),
314301
non_interactive=True,
315302
pylock_path=path,
@@ -321,4 +308,4 @@ def capture_and_raise(cmd: list[str], **kwargs: object) -> None:
321308
self.assertFalse(
322309
os.path.exists(captured[0]),
323310
"Temp constraint file should be deleted even when subprocess raises",
324-
)
311+
)

0 commit comments

Comments
 (0)