teststubtest.py 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038
  1. from __future__ import annotations
  2. import contextlib
  3. import inspect
  4. import io
  5. import os
  6. import re
  7. import sys
  8. import tempfile
  9. import textwrap
  10. import unittest
  11. from typing import Any, Callable, Iterator
  12. import mypy.stubtest
  13. from mypy.stubtest import parse_options, test_stubs
  14. from mypy.test.data import root_dir
  15. @contextlib.contextmanager
  16. def use_tmp_dir(mod_name: str) -> Iterator[str]:
  17. current = os.getcwd()
  18. current_syspath = sys.path.copy()
  19. with tempfile.TemporaryDirectory() as tmp:
  20. try:
  21. os.chdir(tmp)
  22. if sys.path[0] != tmp:
  23. sys.path.insert(0, tmp)
  24. yield tmp
  25. finally:
  26. sys.path = current_syspath.copy()
  27. if mod_name in sys.modules:
  28. del sys.modules[mod_name]
  29. os.chdir(current)
  30. TEST_MODULE_NAME = "test_module"
  31. stubtest_typing_stub = """
  32. Any = object()
  33. class _SpecialForm:
  34. def __getitem__(self, typeargs: Any) -> object: ...
  35. Callable: _SpecialForm = ...
  36. Generic: _SpecialForm = ...
  37. Protocol: _SpecialForm = ...
  38. Union: _SpecialForm = ...
  39. class TypeVar:
  40. def __init__(self, name, covariant: bool = ..., contravariant: bool = ...) -> None: ...
  41. class ParamSpec:
  42. def __init__(self, name: str) -> None: ...
  43. AnyStr = TypeVar("AnyStr", str, bytes)
  44. _T = TypeVar("_T")
  45. _T_co = TypeVar("_T_co", covariant=True)
  46. _K = TypeVar("_K")
  47. _V = TypeVar("_V")
  48. _S = TypeVar("_S", contravariant=True)
  49. _R = TypeVar("_R", covariant=True)
  50. class Coroutine(Generic[_T_co, _S, _R]): ...
  51. class Iterable(Generic[_T_co]): ...
  52. class Mapping(Generic[_K, _V]): ...
  53. class Match(Generic[AnyStr]): ...
  54. class Sequence(Iterable[_T_co]): ...
  55. class Tuple(Sequence[_T_co]): ...
  56. def overload(func: _T) -> _T: ...
  57. """
  58. stubtest_builtins_stub = """
  59. from typing import Generic, Mapping, Sequence, TypeVar, overload
  60. T = TypeVar('T')
  61. T_co = TypeVar('T_co', covariant=True)
  62. KT = TypeVar('KT')
  63. VT = TypeVar('VT')
  64. class object:
  65. __module__: str
  66. def __init__(self) -> None: pass
  67. class type: ...
  68. class tuple(Sequence[T_co], Generic[T_co]): ...
  69. class dict(Mapping[KT, VT]): ...
  70. class function: pass
  71. class ellipsis: pass
  72. class int: ...
  73. class float: ...
  74. class bool(int): ...
  75. class str: ...
  76. class bytes: ...
  77. class list(Sequence[T]): ...
  78. def property(f: T) -> T: ...
  79. def classmethod(f: T) -> T: ...
  80. def staticmethod(f: T) -> T: ...
  81. """
  82. def run_stubtest(
  83. stub: str, runtime: str, options: list[str], config_file: str | None = None
  84. ) -> str:
  85. with use_tmp_dir(TEST_MODULE_NAME) as tmp_dir:
  86. with open("builtins.pyi", "w") as f:
  87. f.write(stubtest_builtins_stub)
  88. with open("typing.pyi", "w") as f:
  89. f.write(stubtest_typing_stub)
  90. with open(f"{TEST_MODULE_NAME}.pyi", "w") as f:
  91. f.write(stub)
  92. with open(f"{TEST_MODULE_NAME}.py", "w") as f:
  93. f.write(runtime)
  94. if config_file:
  95. with open(f"{TEST_MODULE_NAME}_config.ini", "w") as f:
  96. f.write(config_file)
  97. options = options + ["--mypy-config-file", f"{TEST_MODULE_NAME}_config.ini"]
  98. output = io.StringIO()
  99. with contextlib.redirect_stdout(output):
  100. test_stubs(parse_options([TEST_MODULE_NAME] + options), use_builtins_fixtures=True)
  101. return remove_color_code(
  102. output.getvalue()
  103. # remove cwd as it's not available from outside
  104. .replace(os.path.realpath(tmp_dir) + os.sep, "").replace(tmp_dir + os.sep, "")
  105. )
  106. class Case:
  107. def __init__(self, stub: str, runtime: str, error: str | None):
  108. self.stub = stub
  109. self.runtime = runtime
  110. self.error = error
  111. def collect_cases(fn: Callable[..., Iterator[Case]]) -> Callable[..., None]:
  112. """run_stubtest used to be slow, so we used this decorator to combine cases.
  113. If you're reading this and bored, feel free to refactor this and make it more like
  114. other mypy tests.
  115. """
  116. def test(*args: Any, **kwargs: Any) -> None:
  117. cases = list(fn(*args, **kwargs))
  118. expected_errors = set()
  119. for c in cases:
  120. if c.error is None:
  121. continue
  122. expected_error = c.error
  123. if expected_error == "":
  124. expected_error = TEST_MODULE_NAME
  125. elif not expected_error.startswith(f"{TEST_MODULE_NAME}."):
  126. expected_error = f"{TEST_MODULE_NAME}.{expected_error}"
  127. assert expected_error not in expected_errors, (
  128. "collect_cases merges cases into a single stubtest invocation; we already "
  129. "expect an error for {}".format(expected_error)
  130. )
  131. expected_errors.add(expected_error)
  132. output = run_stubtest(
  133. stub="\n\n".join(textwrap.dedent(c.stub.lstrip("\n")) for c in cases),
  134. runtime="\n\n".join(textwrap.dedent(c.runtime.lstrip("\n")) for c in cases),
  135. options=["--generate-allowlist"],
  136. )
  137. actual_errors = set(output.splitlines())
  138. assert actual_errors == expected_errors, output
  139. return test
  140. class StubtestUnit(unittest.TestCase):
  141. @collect_cases
  142. def test_basic_good(self) -> Iterator[Case]:
  143. yield Case(
  144. stub="def f(number: int, text: str) -> None: ...",
  145. runtime="def f(number, text): pass",
  146. error=None,
  147. )
  148. yield Case(
  149. stub="""
  150. class X:
  151. def f(self, number: int, text: str) -> None: ...
  152. """,
  153. runtime="""
  154. class X:
  155. def f(self, number, text): pass
  156. """,
  157. error=None,
  158. )
  159. @collect_cases
  160. def test_types(self) -> Iterator[Case]:
  161. yield Case(
  162. stub="def mistyped_class() -> None: ...",
  163. runtime="class mistyped_class: pass",
  164. error="mistyped_class",
  165. )
  166. yield Case(
  167. stub="class mistyped_fn: ...", runtime="def mistyped_fn(): pass", error="mistyped_fn"
  168. )
  169. yield Case(
  170. stub="""
  171. class X:
  172. def mistyped_var(self) -> int: ...
  173. """,
  174. runtime="""
  175. class X:
  176. mistyped_var = 1
  177. """,
  178. error="X.mistyped_var",
  179. )
  180. @collect_cases
  181. def test_coroutines(self) -> Iterator[Case]:
  182. yield Case(stub="def bar() -> int: ...", runtime="async def bar(): return 5", error="bar")
  183. # Don't error for this one -- we get false positives otherwise
  184. yield Case(stub="async def foo() -> int: ...", runtime="def foo(): return 5", error=None)
  185. yield Case(stub="def baz() -> int: ...", runtime="def baz(): return 5", error=None)
  186. yield Case(
  187. stub="async def bingo() -> int: ...", runtime="async def bingo(): return 5", error=None
  188. )
  189. @collect_cases
  190. def test_arg_name(self) -> Iterator[Case]:
  191. yield Case(
  192. stub="def bad(number: int, text: str) -> None: ...",
  193. runtime="def bad(num, text) -> None: pass",
  194. error="bad",
  195. )
  196. yield Case(
  197. stub="def good_posonly(__number: int, text: str) -> None: ...",
  198. runtime="def good_posonly(num, /, text): pass",
  199. error=None,
  200. )
  201. yield Case(
  202. stub="def bad_posonly(__number: int, text: str) -> None: ...",
  203. runtime="def bad_posonly(flag, /, text): pass",
  204. error="bad_posonly",
  205. )
  206. yield Case(
  207. stub="""
  208. class BadMethod:
  209. def f(self, number: int, text: str) -> None: ...
  210. """,
  211. runtime="""
  212. class BadMethod:
  213. def f(self, n, text): pass
  214. """,
  215. error="BadMethod.f",
  216. )
  217. yield Case(
  218. stub="""
  219. class GoodDunder:
  220. def __exit__(self, t, v, tb) -> None: ...
  221. """,
  222. runtime="""
  223. class GoodDunder:
  224. def __exit__(self, exc_type, exc_val, exc_tb): pass
  225. """,
  226. error=None,
  227. )
  228. @collect_cases
  229. def test_arg_kind(self) -> Iterator[Case]:
  230. yield Case(
  231. stub="def runtime_kwonly(number: int, text: str) -> None: ...",
  232. runtime="def runtime_kwonly(number, *, text): pass",
  233. error="runtime_kwonly",
  234. )
  235. yield Case(
  236. stub="def stub_kwonly(number: int, *, text: str) -> None: ...",
  237. runtime="def stub_kwonly(number, text): pass",
  238. error="stub_kwonly",
  239. )
  240. yield Case(
  241. stub="def stub_posonly(__number: int, text: str) -> None: ...",
  242. runtime="def stub_posonly(number, text): pass",
  243. error="stub_posonly",
  244. )
  245. yield Case(
  246. stub="def good_posonly(__number: int, text: str) -> None: ...",
  247. runtime="def good_posonly(number, /, text): pass",
  248. error=None,
  249. )
  250. yield Case(
  251. stub="def runtime_posonly(number: int, text: str) -> None: ...",
  252. runtime="def runtime_posonly(number, /, text): pass",
  253. error="runtime_posonly",
  254. )
  255. yield Case(
  256. stub="def stub_posonly_570(number: int, /, text: str) -> None: ...",
  257. runtime="def stub_posonly_570(number, text): pass",
  258. error="stub_posonly_570",
  259. )
  260. @collect_cases
  261. def test_default_presence(self) -> Iterator[Case]:
  262. yield Case(
  263. stub="def f1(text: str = ...) -> None: ...",
  264. runtime="def f1(text = 'asdf'): pass",
  265. error=None,
  266. )
  267. yield Case(
  268. stub="def f2(text: str = ...) -> None: ...", runtime="def f2(text): pass", error="f2"
  269. )
  270. yield Case(
  271. stub="def f3(text: str) -> None: ...",
  272. runtime="def f3(text = 'asdf'): pass",
  273. error="f3",
  274. )
  275. yield Case(
  276. stub="def f4(text: str = ...) -> None: ...",
  277. runtime="def f4(text = None): pass",
  278. error="f4",
  279. )
  280. yield Case(
  281. stub="def f5(data: bytes = ...) -> None: ...",
  282. runtime="def f5(data = 'asdf'): pass",
  283. error="f5",
  284. )
  285. yield Case(
  286. stub="""
  287. from typing import TypeVar
  288. _T = TypeVar("_T", bound=str)
  289. def f6(text: _T = ...) -> None: ...
  290. """,
  291. runtime="def f6(text = None): pass",
  292. error="f6",
  293. )
  294. @collect_cases
  295. def test_default_value(self) -> Iterator[Case]:
  296. yield Case(
  297. stub="def f1(text: str = 'x') -> None: ...",
  298. runtime="def f1(text = 'y'): pass",
  299. error="f1",
  300. )
  301. yield Case(
  302. stub='def f2(text: bytes = b"x\'") -> None: ...',
  303. runtime='def f2(text = b"x\'"): pass',
  304. error=None,
  305. )
  306. yield Case(
  307. stub='def f3(text: bytes = b"y\'") -> None: ...',
  308. runtime='def f3(text = b"x\'"): pass',
  309. error="f3",
  310. )
  311. yield Case(
  312. stub="def f4(text: object = 1) -> None: ...",
  313. runtime="def f4(text = 1.0): pass",
  314. error="f4",
  315. )
  316. yield Case(
  317. stub="def f5(text: object = True) -> None: ...",
  318. runtime="def f5(text = 1): pass",
  319. error="f5",
  320. )
  321. yield Case(
  322. stub="def f6(text: object = True) -> None: ...",
  323. runtime="def f6(text = True): pass",
  324. error=None,
  325. )
  326. yield Case(
  327. stub="def f7(text: object = not True) -> None: ...",
  328. runtime="def f7(text = False): pass",
  329. error=None,
  330. )
  331. yield Case(
  332. stub="def f8(text: object = not True) -> None: ...",
  333. runtime="def f8(text = True): pass",
  334. error="f8",
  335. )
  336. yield Case(
  337. stub="def f9(text: object = {1: 2}) -> None: ...",
  338. runtime="def f9(text = {1: 3}): pass",
  339. error="f9",
  340. )
  341. yield Case(
  342. stub="def f10(text: object = [1, 2]) -> None: ...",
  343. runtime="def f10(text = [1, 2]): pass",
  344. error=None,
  345. )
  346. @collect_cases
  347. def test_static_class_method(self) -> Iterator[Case]:
  348. yield Case(
  349. stub="""
  350. class Good:
  351. @classmethod
  352. def f(cls, number: int, text: str) -> None: ...
  353. """,
  354. runtime="""
  355. class Good:
  356. @classmethod
  357. def f(cls, number, text): pass
  358. """,
  359. error=None,
  360. )
  361. yield Case(
  362. stub="""
  363. class Bad1:
  364. def f(cls, number: int, text: str) -> None: ...
  365. """,
  366. runtime="""
  367. class Bad1:
  368. @classmethod
  369. def f(cls, number, text): pass
  370. """,
  371. error="Bad1.f",
  372. )
  373. yield Case(
  374. stub="""
  375. class Bad2:
  376. @classmethod
  377. def f(cls, number: int, text: str) -> None: ...
  378. """,
  379. runtime="""
  380. class Bad2:
  381. @staticmethod
  382. def f(self, number, text): pass
  383. """,
  384. error="Bad2.f",
  385. )
  386. yield Case(
  387. stub="""
  388. class Bad3:
  389. @staticmethod
  390. def f(cls, number: int, text: str) -> None: ...
  391. """,
  392. runtime="""
  393. class Bad3:
  394. @classmethod
  395. def f(self, number, text): pass
  396. """,
  397. error="Bad3.f",
  398. )
  399. yield Case(
  400. stub="""
  401. class GoodNew:
  402. def __new__(cls, *args, **kwargs): ...
  403. """,
  404. runtime="""
  405. class GoodNew:
  406. def __new__(cls, *args, **kwargs): pass
  407. """,
  408. error=None,
  409. )
  410. @collect_cases
  411. def test_arg_mismatch(self) -> Iterator[Case]:
  412. yield Case(
  413. stub="def f1(a, *, b, c) -> None: ...", runtime="def f1(a, *, b, c): pass", error=None
  414. )
  415. yield Case(
  416. stub="def f2(a, *, b) -> None: ...", runtime="def f2(a, *, b, c): pass", error="f2"
  417. )
  418. yield Case(
  419. stub="def f3(a, *, b, c) -> None: ...", runtime="def f3(a, *, b): pass", error="f3"
  420. )
  421. yield Case(
  422. stub="def f4(a, *, b, c) -> None: ...", runtime="def f4(a, b, *, c): pass", error="f4"
  423. )
  424. yield Case(
  425. stub="def f5(a, b, *, c) -> None: ...", runtime="def f5(a, *, b, c): pass", error="f5"
  426. )
  427. @collect_cases
  428. def test_varargs_varkwargs(self) -> Iterator[Case]:
  429. yield Case(
  430. stub="def f1(*args, **kwargs) -> None: ...",
  431. runtime="def f1(*args, **kwargs): pass",
  432. error=None,
  433. )
  434. yield Case(
  435. stub="def f2(*args, **kwargs) -> None: ...",
  436. runtime="def f2(**kwargs): pass",
  437. error="f2",
  438. )
  439. yield Case(
  440. stub="def g1(a, b, c, d) -> None: ...", runtime="def g1(a, *args): pass", error=None
  441. )
  442. yield Case(
  443. stub="def g2(a, b, c, d, *args) -> None: ...", runtime="def g2(a): pass", error="g2"
  444. )
  445. yield Case(
  446. stub="def g3(a, b, c, d, *args) -> None: ...",
  447. runtime="def g3(a, *args): pass",
  448. error=None,
  449. )
  450. yield Case(
  451. stub="def h1(a) -> None: ...", runtime="def h1(a, b, c, d, *args): pass", error="h1"
  452. )
  453. yield Case(
  454. stub="def h2(a, *args) -> None: ...", runtime="def h2(a, b, c, d): pass", error="h2"
  455. )
  456. yield Case(
  457. stub="def h3(a, *args) -> None: ...",
  458. runtime="def h3(a, b, c, d, *args): pass",
  459. error="h3",
  460. )
  461. yield Case(
  462. stub="def j1(a: int, *args) -> None: ...", runtime="def j1(a): pass", error="j1"
  463. )
  464. yield Case(
  465. stub="def j2(a: int) -> None: ...", runtime="def j2(a, *args): pass", error="j2"
  466. )
  467. yield Case(
  468. stub="def j3(a, b, c) -> None: ...", runtime="def j3(a, *args, c): pass", error="j3"
  469. )
  470. yield Case(stub="def k1(a, **kwargs) -> None: ...", runtime="def k1(a): pass", error="k1")
  471. yield Case(
  472. # In theory an error, but led to worse results in practice
  473. stub="def k2(a) -> None: ...",
  474. runtime="def k2(a, **kwargs): pass",
  475. error=None,
  476. )
  477. yield Case(
  478. stub="def k3(a, b) -> None: ...", runtime="def k3(a, **kwargs): pass", error="k3"
  479. )
  480. yield Case(
  481. stub="def k4(a, *, b) -> None: ...", runtime="def k4(a, **kwargs): pass", error=None
  482. )
  483. yield Case(
  484. stub="def k5(a, *, b) -> None: ...",
  485. runtime="def k5(a, *, b, c, **kwargs): pass",
  486. error="k5",
  487. )
  488. yield Case(
  489. stub="def k6(a, *, b, **kwargs) -> None: ...",
  490. runtime="def k6(a, *, b, c, **kwargs): pass",
  491. error="k6",
  492. )
  493. @collect_cases
  494. def test_overload(self) -> Iterator[Case]:
  495. yield Case(
  496. stub="""
  497. from typing import overload
  498. @overload
  499. def f1(a: int, *, c: int = ...) -> int: ...
  500. @overload
  501. def f1(a: int, b: int, c: int = ...) -> str: ...
  502. """,
  503. runtime="def f1(a, b = 0, c = 0): pass",
  504. error=None,
  505. )
  506. yield Case(
  507. stub="""
  508. @overload
  509. def f2(a: int, *, c: int = ...) -> int: ...
  510. @overload
  511. def f2(a: int, b: int, c: int = ...) -> str: ...
  512. """,
  513. runtime="def f2(a, b, c = 0): pass",
  514. error="f2",
  515. )
  516. yield Case(
  517. stub="""
  518. @overload
  519. def f3(a: int) -> int: ...
  520. @overload
  521. def f3(a: int, b: str) -> str: ...
  522. """,
  523. runtime="def f3(a, b = None): pass",
  524. error="f3",
  525. )
  526. yield Case(
  527. stub="""
  528. @overload
  529. def f4(a: int, *args, b: int, **kwargs) -> int: ...
  530. @overload
  531. def f4(a: str, *args, b: int, **kwargs) -> str: ...
  532. """,
  533. runtime="def f4(a, *args, b, **kwargs): pass",
  534. error=None,
  535. )
  536. yield Case(
  537. stub="""
  538. @overload
  539. def f5(__a: int) -> int: ...
  540. @overload
  541. def f5(__b: str) -> str: ...
  542. """,
  543. runtime="def f5(x, /): pass",
  544. error=None,
  545. )
  546. @collect_cases
  547. def test_property(self) -> Iterator[Case]:
  548. yield Case(
  549. stub="""
  550. class Good:
  551. @property
  552. def read_only_attr(self) -> int: ...
  553. """,
  554. runtime="""
  555. class Good:
  556. @property
  557. def read_only_attr(self): return 1
  558. """,
  559. error=None,
  560. )
  561. yield Case(
  562. stub="""
  563. class Bad:
  564. @property
  565. def f(self) -> int: ...
  566. """,
  567. runtime="""
  568. class Bad:
  569. def f(self) -> int: return 1
  570. """,
  571. error="Bad.f",
  572. )
  573. yield Case(
  574. stub="""
  575. class GoodReadOnly:
  576. @property
  577. def f(self) -> int: ...
  578. """,
  579. runtime="""
  580. class GoodReadOnly:
  581. f = 1
  582. """,
  583. error=None,
  584. )
  585. yield Case(
  586. stub="""
  587. class BadReadOnly:
  588. @property
  589. def f(self) -> str: ...
  590. """,
  591. runtime="""
  592. class BadReadOnly:
  593. f = 1
  594. """,
  595. error="BadReadOnly.f",
  596. )
  597. yield Case(
  598. stub="""
  599. class Y:
  600. @property
  601. def read_only_attr(self) -> int: ...
  602. @read_only_attr.setter
  603. def read_only_attr(self, val: int) -> None: ...
  604. """,
  605. runtime="""
  606. class Y:
  607. @property
  608. def read_only_attr(self): return 5
  609. """,
  610. error="Y.read_only_attr",
  611. )
  612. yield Case(
  613. stub="""
  614. class Z:
  615. @property
  616. def read_write_attr(self) -> int: ...
  617. @read_write_attr.setter
  618. def read_write_attr(self, val: int) -> None: ...
  619. """,
  620. runtime="""
  621. class Z:
  622. @property
  623. def read_write_attr(self): return self._val
  624. @read_write_attr.setter
  625. def read_write_attr(self, val): self._val = val
  626. """,
  627. error=None,
  628. )
  629. yield Case(
  630. stub="""
  631. class FineAndDandy:
  632. @property
  633. def attr(self) -> int: ...
  634. """,
  635. runtime="""
  636. class _EvilDescriptor:
  637. def __get__(self, instance, ownerclass=None):
  638. if instance is None:
  639. raise AttributeError('no')
  640. return 42
  641. def __set__(self, instance, value):
  642. raise AttributeError('no')
  643. class FineAndDandy:
  644. attr = _EvilDescriptor()
  645. """,
  646. error=None,
  647. )
  648. @collect_cases
  649. def test_var(self) -> Iterator[Case]:
  650. yield Case(stub="x1: int", runtime="x1 = 5", error=None)
  651. yield Case(stub="x2: str", runtime="x2 = 5", error="x2")
  652. yield Case("from typing import Tuple", "", None) # dummy case
  653. yield Case(
  654. stub="""
  655. x3: Tuple[int, int]
  656. """,
  657. runtime="x3 = (1, 3)",
  658. error=None,
  659. )
  660. yield Case(
  661. stub="""
  662. x4: Tuple[int, int]
  663. """,
  664. runtime="x4 = (1, 3, 5)",
  665. error="x4",
  666. )
  667. yield Case(stub="x5: int", runtime="def x5(a, b): pass", error="x5")
  668. yield Case(
  669. stub="def foo(a: int, b: int) -> None: ...\nx6 = foo",
  670. runtime="def foo(a, b): pass\ndef x6(c, d): pass",
  671. error="x6",
  672. )
  673. yield Case(
  674. stub="""
  675. class X:
  676. f: int
  677. """,
  678. runtime="""
  679. class X:
  680. def __init__(self):
  681. self.f = "asdf"
  682. """,
  683. error=None,
  684. )
  685. yield Case(
  686. stub="""
  687. class Y:
  688. read_only_attr: int
  689. """,
  690. runtime="""
  691. class Y:
  692. @property
  693. def read_only_attr(self): return 5
  694. """,
  695. error="Y.read_only_attr",
  696. )
  697. yield Case(
  698. stub="""
  699. class Z:
  700. read_write_attr: int
  701. """,
  702. runtime="""
  703. class Z:
  704. @property
  705. def read_write_attr(self): return self._val
  706. @read_write_attr.setter
  707. def read_write_attr(self, val): self._val = val
  708. """,
  709. error=None,
  710. )
  711. @collect_cases
  712. def test_type_alias(self) -> Iterator[Case]:
  713. yield Case(
  714. stub="""
  715. import collections.abc
  716. import re
  717. import typing
  718. from typing import Callable, Dict, Generic, Iterable, List, Match, Tuple, TypeVar, Union
  719. """,
  720. runtime="""
  721. import collections.abc
  722. import re
  723. from typing import Callable, Dict, Generic, Iterable, List, Match, Tuple, TypeVar, Union
  724. """,
  725. error=None,
  726. )
  727. yield Case(
  728. stub="""
  729. class X:
  730. def f(self) -> None: ...
  731. Y = X
  732. """,
  733. runtime="""
  734. class X:
  735. def f(self) -> None: ...
  736. class Y: ...
  737. """,
  738. error="Y.f",
  739. )
  740. yield Case(stub="A = Tuple[int, str]", runtime="A = (int, str)", error="A")
  741. # Error if an alias isn't present at runtime...
  742. yield Case(stub="B = str", runtime="", error="B")
  743. # ... but only if the alias isn't private
  744. yield Case(stub="_C = int", runtime="", error=None)
  745. yield Case(
  746. stub="""
  747. D = tuple[str, str]
  748. E = Tuple[int, int, int]
  749. F = Tuple[str, int]
  750. """,
  751. runtime="""
  752. D = Tuple[str, str]
  753. E = Tuple[int, int, int]
  754. F = List[str]
  755. """,
  756. error="F",
  757. )
  758. yield Case(
  759. stub="""
  760. G = str | int
  761. H = Union[str, bool]
  762. I = str | int
  763. """,
  764. runtime="""
  765. G = Union[str, int]
  766. H = Union[str, bool]
  767. I = str
  768. """,
  769. error="I",
  770. )
  771. yield Case(
  772. stub="""
  773. K = dict[str, str]
  774. L = Dict[int, int]
  775. KK = collections.abc.Iterable[str]
  776. LL = typing.Iterable[str]
  777. """,
  778. runtime="""
  779. K = Dict[str, str]
  780. L = Dict[int, int]
  781. KK = Iterable[str]
  782. LL = Iterable[str]
  783. """,
  784. error=None,
  785. )
  786. yield Case(
  787. stub="""
  788. _T = TypeVar("_T")
  789. class _Spam(Generic[_T]):
  790. def foo(self) -> None: ...
  791. IntFood = _Spam[int]
  792. """,
  793. runtime="""
  794. _T = TypeVar("_T")
  795. class _Bacon(Generic[_T]):
  796. def foo(self, arg): pass
  797. IntFood = _Bacon[int]
  798. """,
  799. error="IntFood.foo",
  800. )
  801. yield Case(stub="StrList = list[str]", runtime="StrList = ['foo', 'bar']", error="StrList")
  802. yield Case(
  803. stub="""
  804. N = typing.Callable[[str], bool]
  805. O = collections.abc.Callable[[int], str]
  806. P = typing.Callable[[str], bool]
  807. """,
  808. runtime="""
  809. N = Callable[[str], bool]
  810. O = Callable[[int], str]
  811. P = int
  812. """,
  813. error="P",
  814. )
  815. yield Case(
  816. stub="""
  817. class Foo:
  818. class Bar: ...
  819. BarAlias = Foo.Bar
  820. """,
  821. runtime="""
  822. class Foo:
  823. class Bar: pass
  824. BarAlias = Foo.Bar
  825. """,
  826. error=None,
  827. )
  828. yield Case(
  829. stub="""
  830. from io import StringIO
  831. StringIOAlias = StringIO
  832. """,
  833. runtime="""
  834. from _io import StringIO
  835. StringIOAlias = StringIO
  836. """,
  837. error=None,
  838. )
  839. yield Case(stub="M = Match[str]", runtime="M = Match[str]", error=None)
  840. yield Case(
  841. stub="""
  842. class Baz:
  843. def fizz(self) -> None: ...
  844. BazAlias = Baz
  845. """,
  846. runtime="""
  847. class Baz:
  848. def fizz(self): pass
  849. BazAlias = Baz
  850. Baz.__name__ = Baz.__qualname__ = Baz.__module__ = "New"
  851. """,
  852. error=None,
  853. )
  854. yield Case(
  855. stub="""
  856. class FooBar:
  857. __module__: None # type: ignore
  858. def fizz(self) -> None: ...
  859. FooBarAlias = FooBar
  860. """,
  861. runtime="""
  862. class FooBar:
  863. def fizz(self): pass
  864. FooBarAlias = FooBar
  865. FooBar.__module__ = None
  866. """,
  867. error=None,
  868. )
  869. if sys.version_info >= (3, 10):
  870. yield Case(
  871. stub="""
  872. Q = Dict[str, str]
  873. R = dict[int, int]
  874. S = Tuple[int, int]
  875. T = tuple[str, str]
  876. U = int | str
  877. V = Union[int, str]
  878. W = typing.Callable[[str], bool]
  879. Z = collections.abc.Callable[[str], bool]
  880. QQ = typing.Iterable[str]
  881. RR = collections.abc.Iterable[str]
  882. MM = typing.Match[str]
  883. MMM = re.Match[str]
  884. """,
  885. runtime="""
  886. Q = dict[str, str]
  887. R = dict[int, int]
  888. S = tuple[int, int]
  889. T = tuple[str, str]
  890. U = int | str
  891. V = int | str
  892. W = collections.abc.Callable[[str], bool]
  893. Z = collections.abc.Callable[[str], bool]
  894. QQ = collections.abc.Iterable[str]
  895. RR = collections.abc.Iterable[str]
  896. MM = re.Match[str]
  897. MMM = re.Match[str]
  898. """,
  899. error=None,
  900. )
  901. @collect_cases
  902. def test_enum(self) -> Iterator[Case]:
  903. yield Case(
  904. stub="""
  905. import enum
  906. class X(enum.Enum):
  907. a: int
  908. b: str
  909. c: str
  910. """,
  911. runtime="""
  912. import enum
  913. class X(enum.Enum):
  914. a = 1
  915. b = "asdf"
  916. c = 2
  917. """,
  918. error="X.c",
  919. )
  920. @collect_cases
  921. def test_decorator(self) -> Iterator[Case]:
  922. yield Case(
  923. stub="""
  924. from typing import Any, Callable
  925. def decorator(f: Callable[[], int]) -> Callable[..., Any]: ...
  926. @decorator
  927. def f() -> Any: ...
  928. """,
  929. runtime="""
  930. def decorator(f): return f
  931. @decorator
  932. def f(): return 3
  933. """,
  934. error=None,
  935. )
  936. @collect_cases
  937. def test_all_at_runtime_not_stub(self) -> Iterator[Case]:
  938. yield Case(
  939. stub="Z: int",
  940. runtime="""
  941. __all__ = []
  942. Z = 5""",
  943. error=None,
  944. )
  945. @collect_cases
  946. def test_all_in_stub_not_at_runtime(self) -> Iterator[Case]:
  947. yield Case(stub="__all__ = ()", runtime="", error="__all__")
  948. @collect_cases
  949. def test_all_in_stub_different_to_all_at_runtime(self) -> Iterator[Case]:
  950. # We *should* emit an error with the module name itself + __all__,
  951. # if the stub *does* define __all__,
  952. # but the stub's __all__ is inconsistent with the runtime's __all__
  953. yield Case(
  954. stub="""
  955. __all__ = ['foo']
  956. foo: str
  957. """,
  958. runtime="""
  959. __all__ = []
  960. foo = 'foo'
  961. """,
  962. error="__all__",
  963. )
  964. @collect_cases
  965. def test_missing(self) -> Iterator[Case]:
  966. yield Case(stub="x = 5", runtime="", error="x")
  967. yield Case(stub="def f(): ...", runtime="", error="f")
  968. yield Case(stub="class X: ...", runtime="", error="X")
  969. yield Case(
  970. stub="""
  971. from typing import overload
  972. @overload
  973. def h(x: int): ...
  974. @overload
  975. def h(x: str): ...
  976. """,
  977. runtime="",
  978. error="h",
  979. )
  980. yield Case(stub="", runtime="__all__ = []", error=None) # dummy case
  981. yield Case(stub="", runtime="__all__ += ['y']\ny = 5", error="y")
  982. yield Case(stub="", runtime="__all__ += ['g']\ndef g(): pass", error="g")
  983. # Here we should only check that runtime has B, since the stub explicitly re-exports it
  984. yield Case(
  985. stub="from mystery import A, B as B, C as D # type: ignore", runtime="", error="B"
  986. )
  987. yield Case(
  988. stub="class Y: ...",
  989. runtime="__all__ += ['Y']\nclass Y:\n def __or__(self, other): return self|other",
  990. error="Y.__or__",
  991. )
  992. yield Case(
  993. stub="class Z: ...",
  994. runtime="__all__ += ['Z']\nclass Z:\n def __reduce__(self): return (Z,)",
  995. error=None,
  996. )
  997. @collect_cases
  998. def test_missing_no_runtime_all(self) -> Iterator[Case]:
  999. yield Case(stub="", runtime="import sys", error=None)
  1000. yield Case(stub="", runtime="def g(): ...", error="g")
  1001. yield Case(stub="", runtime="CONSTANT = 0", error="CONSTANT")
  1002. yield Case(stub="", runtime="import re; constant = re.compile('foo')", error="constant")
  1003. yield Case(stub="", runtime="from json.scanner import NUMBER_RE", error=None)
  1004. yield Case(stub="", runtime="from string import ascii_letters", error=None)
  1005. @collect_cases
  1006. def test_non_public_1(self) -> Iterator[Case]:
  1007. yield Case(
  1008. stub="__all__: list[str]", runtime="", error=f"{TEST_MODULE_NAME}.__all__"
  1009. ) # dummy case
  1010. yield Case(stub="_f: int", runtime="def _f(): ...", error="_f")
  1011. @collect_cases
  1012. def test_non_public_2(self) -> Iterator[Case]:
  1013. yield Case(stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None)
  1014. yield Case(stub="f: int", runtime="def f(): ...", error="f")
  1015. yield Case(stub="g: int", runtime="def g(): ...", error="g")
  1016. @collect_cases
  1017. def test_dunders(self) -> Iterator[Case]:
  1018. yield Case(
  1019. stub="class A:\n def __init__(self, a: int, b: int) -> None: ...",
  1020. runtime="class A:\n def __init__(self, a, bx): pass",
  1021. error="A.__init__",
  1022. )
  1023. yield Case(
  1024. stub="class B:\n def __call__(self, c: int, d: int) -> None: ...",
  1025. runtime="class B:\n def __call__(self, c, dx): pass",
  1026. error="B.__call__",
  1027. )
  1028. yield Case(
  1029. stub=(
  1030. "class C:\n"
  1031. " def __init_subclass__(\n"
  1032. " cls, e: int = ..., **kwargs: int\n"
  1033. " ) -> None: ...\n"
  1034. ),
  1035. runtime="class C:\n def __init_subclass__(cls, e=1, **kwargs): pass",
  1036. error=None,
  1037. )
  1038. if sys.version_info >= (3, 9):
  1039. yield Case(
  1040. stub="class D:\n def __class_getitem__(cls, type: type) -> type: ...",
  1041. runtime="class D:\n def __class_getitem__(cls, type): ...",
  1042. error=None,
  1043. )
  1044. @collect_cases
  1045. def test_not_subclassable(self) -> Iterator[Case]:
  1046. yield Case(
  1047. stub="class CanBeSubclassed: ...", runtime="class CanBeSubclassed: ...", error=None
  1048. )
  1049. yield Case(
  1050. stub="class CannotBeSubclassed:\n def __init_subclass__(cls) -> None: ...",
  1051. runtime="class CannotBeSubclassed:\n def __init_subclass__(cls): raise TypeError",
  1052. error="CannotBeSubclassed",
  1053. )
  1054. @collect_cases
  1055. def test_has_runtime_final_decorator(self) -> Iterator[Case]:
  1056. yield Case(
  1057. stub="from typing_extensions import final",
  1058. runtime="""
  1059. import functools
  1060. from typing_extensions import final
  1061. """,
  1062. error=None,
  1063. )
  1064. yield Case(
  1065. stub="""
  1066. @final
  1067. class A: ...
  1068. """,
  1069. runtime="""
  1070. @final
  1071. class A: ...
  1072. """,
  1073. error=None,
  1074. )
  1075. yield Case( # Runtime can miss `@final` decorator
  1076. stub="""
  1077. @final
  1078. class B: ...
  1079. """,
  1080. runtime="""
  1081. class B: ...
  1082. """,
  1083. error=None,
  1084. )
  1085. yield Case( # Stub cannot miss `@final` decorator
  1086. stub="""
  1087. class C: ...
  1088. """,
  1089. runtime="""
  1090. @final
  1091. class C: ...
  1092. """,
  1093. error="C",
  1094. )
  1095. yield Case(
  1096. stub="""
  1097. class D:
  1098. @final
  1099. def foo(self) -> None: ...
  1100. @final
  1101. @staticmethod
  1102. def bar() -> None: ...
  1103. @staticmethod
  1104. @final
  1105. def bar2() -> None: ...
  1106. @final
  1107. @classmethod
  1108. def baz(cls) -> None: ...
  1109. @classmethod
  1110. @final
  1111. def baz2(cls) -> None: ...
  1112. @property
  1113. @final
  1114. def eggs(self) -> int: ...
  1115. @final
  1116. @property
  1117. def eggs2(self) -> int: ...
  1118. @final
  1119. def ham(self, obj: int) -> int: ...
  1120. """,
  1121. runtime="""
  1122. class D:
  1123. @final
  1124. def foo(self): pass
  1125. @final
  1126. @staticmethod
  1127. def bar(): pass
  1128. @staticmethod
  1129. @final
  1130. def bar2(): pass
  1131. @final
  1132. @classmethod
  1133. def baz(cls): pass
  1134. @classmethod
  1135. @final
  1136. def baz2(cls): pass
  1137. @property
  1138. @final
  1139. def eggs(self): return 42
  1140. @final
  1141. @property
  1142. def eggs2(self): pass
  1143. @final
  1144. @functools.lru_cache()
  1145. def ham(self, obj): return obj * 2
  1146. """,
  1147. error=None,
  1148. )
  1149. # Stub methods are allowed to have @final even if the runtime doesn't...
  1150. yield Case(
  1151. stub="""
  1152. class E:
  1153. @final
  1154. def foo(self) -> None: ...
  1155. @final
  1156. @staticmethod
  1157. def bar() -> None: ...
  1158. @staticmethod
  1159. @final
  1160. def bar2() -> None: ...
  1161. @final
  1162. @classmethod
  1163. def baz(cls) -> None: ...
  1164. @classmethod
  1165. @final
  1166. def baz2(cls) -> None: ...
  1167. @property
  1168. @final
  1169. def eggs(self) -> int: ...
  1170. @final
  1171. @property
  1172. def eggs2(self) -> int: ...
  1173. @final
  1174. def ham(self, obj: int) -> int: ...
  1175. """,
  1176. runtime="""
  1177. class E:
  1178. def foo(self): pass
  1179. @staticmethod
  1180. def bar(): pass
  1181. @staticmethod
  1182. def bar2(): pass
  1183. @classmethod
  1184. def baz(cls): pass
  1185. @classmethod
  1186. def baz2(cls): pass
  1187. @property
  1188. def eggs(self): return 42
  1189. @property
  1190. def eggs2(self): return 42
  1191. @functools.lru_cache()
  1192. def ham(self, obj): return obj * 2
  1193. """,
  1194. error=None,
  1195. )
  1196. # ...But if the runtime has @final, the stub must have it as well
  1197. yield Case(
  1198. stub="""
  1199. class F:
  1200. def foo(self) -> None: ...
  1201. """,
  1202. runtime="""
  1203. class F:
  1204. @final
  1205. def foo(self): pass
  1206. """,
  1207. error="F.foo",
  1208. )
  1209. yield Case(
  1210. stub="""
  1211. class G:
  1212. @staticmethod
  1213. def foo() -> None: ...
  1214. """,
  1215. runtime="""
  1216. class G:
  1217. @final
  1218. @staticmethod
  1219. def foo(): pass
  1220. """,
  1221. error="G.foo",
  1222. )
  1223. yield Case(
  1224. stub="""
  1225. class H:
  1226. @staticmethod
  1227. def foo() -> None: ...
  1228. """,
  1229. runtime="""
  1230. class H:
  1231. @staticmethod
  1232. @final
  1233. def foo(): pass
  1234. """,
  1235. error="H.foo",
  1236. )
  1237. yield Case(
  1238. stub="""
  1239. class I:
  1240. @classmethod
  1241. def foo(cls) -> None: ...
  1242. """,
  1243. runtime="""
  1244. class I:
  1245. @final
  1246. @classmethod
  1247. def foo(cls): pass
  1248. """,
  1249. error="I.foo",
  1250. )
  1251. yield Case(
  1252. stub="""
  1253. class J:
  1254. @classmethod
  1255. def foo(cls) -> None: ...
  1256. """,
  1257. runtime="""
  1258. class J:
  1259. @classmethod
  1260. @final
  1261. def foo(cls): pass
  1262. """,
  1263. error="J.foo",
  1264. )
  1265. yield Case(
  1266. stub="""
  1267. class K:
  1268. @property
  1269. def foo(self) -> int: ...
  1270. """,
  1271. runtime="""
  1272. class K:
  1273. @property
  1274. @final
  1275. def foo(self): return 42
  1276. """,
  1277. error="K.foo",
  1278. )
  1279. # This test wouldn't pass,
  1280. # because the runtime can't set __final__ on instances of builtins.property,
  1281. # so stubtest has non way of knowing that the runtime was decorated with @final:
  1282. #
  1283. # yield Case(
  1284. # stub="""
  1285. # class K2:
  1286. # @property
  1287. # def foo(self) -> int: ...
  1288. # """,
  1289. # runtime="""
  1290. # class K2:
  1291. # @final
  1292. # @property
  1293. # def foo(self): return 42
  1294. # """,
  1295. # error="K2.foo",
  1296. # )
  1297. yield Case(
  1298. stub="""
  1299. class L:
  1300. def foo(self, obj: int) -> int: ...
  1301. """,
  1302. runtime="""
  1303. class L:
  1304. @final
  1305. @functools.lru_cache()
  1306. def foo(self, obj): return obj * 2
  1307. """,
  1308. error="L.foo",
  1309. )
  1310. @collect_cases
  1311. def test_name_mangling(self) -> Iterator[Case]:
  1312. yield Case(
  1313. stub="""
  1314. class X:
  1315. def __mangle_good(self, text: str) -> None: ...
  1316. def __mangle_bad(self, number: int) -> None: ...
  1317. """,
  1318. runtime="""
  1319. class X:
  1320. def __mangle_good(self, text): pass
  1321. def __mangle_bad(self, text): pass
  1322. """,
  1323. error="X.__mangle_bad",
  1324. )
  1325. yield Case(
  1326. stub="""
  1327. class Klass:
  1328. class __Mangled1:
  1329. class __Mangled2:
  1330. def __mangle_good(self, text: str) -> None: ...
  1331. def __mangle_bad(self, number: int) -> None: ...
  1332. """,
  1333. runtime="""
  1334. class Klass:
  1335. class __Mangled1:
  1336. class __Mangled2:
  1337. def __mangle_good(self, text): pass
  1338. def __mangle_bad(self, text): pass
  1339. """,
  1340. error="Klass.__Mangled1.__Mangled2.__mangle_bad",
  1341. )
  1342. yield Case(
  1343. stub="""
  1344. class __Dunder__:
  1345. def __mangle_good(self, text: str) -> None: ...
  1346. def __mangle_bad(self, number: int) -> None: ...
  1347. """,
  1348. runtime="""
  1349. class __Dunder__:
  1350. def __mangle_good(self, text): pass
  1351. def __mangle_bad(self, text): pass
  1352. """,
  1353. error="__Dunder__.__mangle_bad",
  1354. )
  1355. yield Case(
  1356. stub="""
  1357. class _Private:
  1358. def __mangle_good(self, text: str) -> None: ...
  1359. def __mangle_bad(self, number: int) -> None: ...
  1360. """,
  1361. runtime="""
  1362. class _Private:
  1363. def __mangle_good(self, text): pass
  1364. def __mangle_bad(self, text): pass
  1365. """,
  1366. error="_Private.__mangle_bad",
  1367. )
  1368. @collect_cases
  1369. def test_mro(self) -> Iterator[Case]:
  1370. yield Case(
  1371. stub="""
  1372. class A:
  1373. def foo(self, x: int) -> None: ...
  1374. class B(A):
  1375. pass
  1376. class C(A):
  1377. pass
  1378. """,
  1379. runtime="""
  1380. class A:
  1381. def foo(self, x: int) -> None: ...
  1382. class B(A):
  1383. def foo(self, x: int) -> None: ...
  1384. class C(A):
  1385. def foo(self, y: int) -> None: ...
  1386. """,
  1387. error="C.foo",
  1388. )
  1389. yield Case(
  1390. stub="""
  1391. class X: ...
  1392. """,
  1393. runtime="""
  1394. class X:
  1395. def __init__(self, x): pass
  1396. """,
  1397. error="X.__init__",
  1398. )
  1399. @collect_cases
  1400. def test_good_literal(self) -> Iterator[Case]:
  1401. yield Case(
  1402. stub=r"""
  1403. from typing_extensions import Literal
  1404. import enum
  1405. class Color(enum.Enum):
  1406. RED: int
  1407. NUM: Literal[1]
  1408. CHAR: Literal['a']
  1409. FLAG: Literal[True]
  1410. NON: Literal[None]
  1411. BYT1: Literal[b'abc']
  1412. BYT2: Literal[b'\x90']
  1413. ENUM: Literal[Color.RED]
  1414. """,
  1415. runtime=r"""
  1416. import enum
  1417. class Color(enum.Enum):
  1418. RED = 3
  1419. NUM = 1
  1420. CHAR = 'a'
  1421. NON = None
  1422. FLAG = True
  1423. BYT1 = b"abc"
  1424. BYT2 = b'\x90'
  1425. ENUM = Color.RED
  1426. """,
  1427. error=None,
  1428. )
  1429. @collect_cases
  1430. def test_bad_literal(self) -> Iterator[Case]:
  1431. yield Case("from typing_extensions import Literal", "", None) # dummy case
  1432. yield Case(
  1433. stub="INT_FLOAT_MISMATCH: Literal[1]",
  1434. runtime="INT_FLOAT_MISMATCH = 1.0",
  1435. error="INT_FLOAT_MISMATCH",
  1436. )
  1437. yield Case(stub="WRONG_INT: Literal[1]", runtime="WRONG_INT = 2", error="WRONG_INT")
  1438. yield Case(stub="WRONG_STR: Literal['a']", runtime="WRONG_STR = 'b'", error="WRONG_STR")
  1439. yield Case(
  1440. stub="BYTES_STR_MISMATCH: Literal[b'value']",
  1441. runtime="BYTES_STR_MISMATCH = 'value'",
  1442. error="BYTES_STR_MISMATCH",
  1443. )
  1444. yield Case(
  1445. stub="STR_BYTES_MISMATCH: Literal['value']",
  1446. runtime="STR_BYTES_MISMATCH = b'value'",
  1447. error="STR_BYTES_MISMATCH",
  1448. )
  1449. yield Case(
  1450. stub="WRONG_BYTES: Literal[b'abc']",
  1451. runtime="WRONG_BYTES = b'xyz'",
  1452. error="WRONG_BYTES",
  1453. )
  1454. yield Case(
  1455. stub="WRONG_BOOL_1: Literal[True]",
  1456. runtime="WRONG_BOOL_1 = False",
  1457. error="WRONG_BOOL_1",
  1458. )
  1459. yield Case(
  1460. stub="WRONG_BOOL_2: Literal[False]",
  1461. runtime="WRONG_BOOL_2 = True",
  1462. error="WRONG_BOOL_2",
  1463. )
  1464. @collect_cases
  1465. def test_special_subtype(self) -> Iterator[Case]:
  1466. yield Case(
  1467. stub="""
  1468. b1: bool
  1469. b2: bool
  1470. b3: bool
  1471. """,
  1472. runtime="""
  1473. b1 = 0
  1474. b2 = 1
  1475. b3 = 2
  1476. """,
  1477. error="b3",
  1478. )
  1479. yield Case(
  1480. stub="""
  1481. from typing_extensions import TypedDict
  1482. class _Options(TypedDict):
  1483. a: str
  1484. b: int
  1485. opt1: _Options
  1486. opt2: _Options
  1487. opt3: _Options
  1488. """,
  1489. runtime="""
  1490. opt1 = {"a": "3.", "b": 14}
  1491. opt2 = {"some": "stuff"} # false negative
  1492. opt3 = 0
  1493. """,
  1494. error="opt3",
  1495. )
  1496. @collect_cases
  1497. def test_runtime_typing_objects(self) -> Iterator[Case]:
  1498. yield Case(
  1499. stub="from typing_extensions import Protocol, TypedDict",
  1500. runtime="from typing_extensions import Protocol, TypedDict",
  1501. error=None,
  1502. )
  1503. yield Case(
  1504. stub="""
  1505. class X(Protocol):
  1506. bar: int
  1507. def foo(self, x: int, y: bytes = ...) -> str: ...
  1508. """,
  1509. runtime="""
  1510. class X(Protocol):
  1511. bar: int
  1512. def foo(self, x: int, y: bytes = ...) -> str: ...
  1513. """,
  1514. error=None,
  1515. )
  1516. yield Case(
  1517. stub="""
  1518. class Y(TypedDict):
  1519. a: int
  1520. """,
  1521. runtime="""
  1522. class Y(TypedDict):
  1523. a: int
  1524. """,
  1525. error=None,
  1526. )
  1527. @collect_cases
  1528. def test_type_var(self) -> Iterator[Case]:
  1529. yield Case(
  1530. stub="from typing import TypeVar", runtime="from typing import TypeVar", error=None
  1531. )
  1532. yield Case(stub="A = TypeVar('A')", runtime="A = TypeVar('A')", error=None)
  1533. yield Case(stub="B = TypeVar('B')", runtime="B = 5", error="B")
  1534. if sys.version_info >= (3, 10):
  1535. yield Case(
  1536. stub="from typing import ParamSpec",
  1537. runtime="from typing import ParamSpec",
  1538. error=None,
  1539. )
  1540. yield Case(stub="C = ParamSpec('C')", runtime="C = ParamSpec('C')", error=None)
  1541. @collect_cases
  1542. def test_metaclass_match(self) -> Iterator[Case]:
  1543. yield Case(stub="class Meta(type): ...", runtime="class Meta(type): ...", error=None)
  1544. yield Case(stub="class A0: ...", runtime="class A0: ...", error=None)
  1545. yield Case(
  1546. stub="class A1(metaclass=Meta): ...",
  1547. runtime="class A1(metaclass=Meta): ...",
  1548. error=None,
  1549. )
  1550. yield Case(stub="class A2: ...", runtime="class A2(metaclass=Meta): ...", error="A2")
  1551. yield Case(stub="class A3(metaclass=Meta): ...", runtime="class A3: ...", error="A3")
  1552. # Explicit `type` metaclass can always be added in any part:
  1553. yield Case(
  1554. stub="class T1(metaclass=type): ...",
  1555. runtime="class T1(metaclass=type): ...",
  1556. error=None,
  1557. )
  1558. yield Case(stub="class T2: ...", runtime="class T2(metaclass=type): ...", error=None)
  1559. yield Case(stub="class T3(metaclass=type): ...", runtime="class T3: ...", error=None)
  1560. # Explicit check that `_protected` names are also supported:
  1561. yield Case(stub="class _P1(type): ...", runtime="class _P1(type): ...", error=None)
  1562. yield Case(stub="class P2: ...", runtime="class P2(metaclass=_P1): ...", error="P2")
  1563. # With inheritance:
  1564. yield Case(
  1565. stub="""
  1566. class I1(metaclass=Meta): ...
  1567. class S1(I1): ...
  1568. """,
  1569. runtime="""
  1570. class I1(metaclass=Meta): ...
  1571. class S1(I1): ...
  1572. """,
  1573. error=None,
  1574. )
  1575. yield Case(
  1576. stub="""
  1577. class I2(metaclass=Meta): ...
  1578. class S2: ... # missing inheritance
  1579. """,
  1580. runtime="""
  1581. class I2(metaclass=Meta): ...
  1582. class S2(I2): ...
  1583. """,
  1584. error="S2",
  1585. )
  1586. @collect_cases
  1587. def test_metaclass_abcmeta(self) -> Iterator[Case]:
  1588. # Handling abstract metaclasses is special:
  1589. yield Case(stub="from abc import ABCMeta", runtime="from abc import ABCMeta", error=None)
  1590. yield Case(
  1591. stub="class A1(metaclass=ABCMeta): ...",
  1592. runtime="class A1(metaclass=ABCMeta): ...",
  1593. error=None,
  1594. )
  1595. # Stubs cannot miss abstract metaclass:
  1596. yield Case(stub="class A2: ...", runtime="class A2(metaclass=ABCMeta): ...", error="A2")
  1597. # But, stubs can add extra abstract metaclass, this might be a typing hack:
  1598. yield Case(stub="class A3(metaclass=ABCMeta): ...", runtime="class A3: ...", error=None)
  1599. @collect_cases
  1600. def test_abstract_methods(self) -> Iterator[Case]:
  1601. yield Case(
  1602. stub="""
  1603. from abc import abstractmethod
  1604. from typing import overload
  1605. """,
  1606. runtime="from abc import abstractmethod",
  1607. error=None,
  1608. )
  1609. yield Case(
  1610. stub="""
  1611. class A1:
  1612. def some(self) -> None: ...
  1613. """,
  1614. runtime="""
  1615. class A1:
  1616. @abstractmethod
  1617. def some(self) -> None: ...
  1618. """,
  1619. error="A1.some",
  1620. )
  1621. yield Case(
  1622. stub="""
  1623. class A2:
  1624. @abstractmethod
  1625. def some(self) -> None: ...
  1626. """,
  1627. runtime="""
  1628. class A2:
  1629. @abstractmethod
  1630. def some(self) -> None: ...
  1631. """,
  1632. error=None,
  1633. )
  1634. yield Case(
  1635. stub="""
  1636. class A3:
  1637. @overload
  1638. def some(self, other: int) -> str: ...
  1639. @overload
  1640. def some(self, other: str) -> int: ...
  1641. """,
  1642. runtime="""
  1643. class A3:
  1644. @abstractmethod
  1645. def some(self, other) -> None: ...
  1646. """,
  1647. error="A3.some",
  1648. )
  1649. yield Case(
  1650. stub="""
  1651. class A4:
  1652. @overload
  1653. @abstractmethod
  1654. def some(self, other: int) -> str: ...
  1655. @overload
  1656. @abstractmethod
  1657. def some(self, other: str) -> int: ...
  1658. """,
  1659. runtime="""
  1660. class A4:
  1661. @abstractmethod
  1662. def some(self, other) -> None: ...
  1663. """,
  1664. error=None,
  1665. )
  1666. yield Case(
  1667. stub="""
  1668. class A5:
  1669. @abstractmethod
  1670. @overload
  1671. def some(self, other: int) -> str: ...
  1672. @abstractmethod
  1673. @overload
  1674. def some(self, other: str) -> int: ...
  1675. """,
  1676. runtime="""
  1677. class A5:
  1678. @abstractmethod
  1679. def some(self, other) -> None: ...
  1680. """,
  1681. error=None,
  1682. )
  1683. # Runtime can miss `@abstractmethod`:
  1684. yield Case(
  1685. stub="""
  1686. class A6:
  1687. @abstractmethod
  1688. def some(self) -> None: ...
  1689. """,
  1690. runtime="""
  1691. class A6:
  1692. def some(self) -> None: ...
  1693. """,
  1694. error=None,
  1695. )
  1696. @collect_cases
  1697. def test_abstract_properties(self) -> Iterator[Case]:
  1698. # TODO: test abstract properties with setters
  1699. yield Case(
  1700. stub="from abc import abstractmethod",
  1701. runtime="from abc import abstractmethod",
  1702. error=None,
  1703. )
  1704. # Ensure that `@property` also can be abstract:
  1705. yield Case(
  1706. stub="""
  1707. class AP1:
  1708. @property
  1709. def some(self) -> int: ...
  1710. """,
  1711. runtime="""
  1712. class AP1:
  1713. @property
  1714. @abstractmethod
  1715. def some(self) -> int: ...
  1716. """,
  1717. error="AP1.some",
  1718. )
  1719. yield Case(
  1720. stub="""
  1721. class AP1_2:
  1722. def some(self) -> int: ... # missing `@property` decorator
  1723. """,
  1724. runtime="""
  1725. class AP1_2:
  1726. @property
  1727. @abstractmethod
  1728. def some(self) -> int: ...
  1729. """,
  1730. error="AP1_2.some",
  1731. )
  1732. yield Case(
  1733. stub="""
  1734. class AP2:
  1735. @property
  1736. @abstractmethod
  1737. def some(self) -> int: ...
  1738. """,
  1739. runtime="""
  1740. class AP2:
  1741. @property
  1742. @abstractmethod
  1743. def some(self) -> int: ...
  1744. """,
  1745. error=None,
  1746. )
  1747. # Runtime can miss `@abstractmethod`:
  1748. yield Case(
  1749. stub="""
  1750. class AP3:
  1751. @property
  1752. @abstractmethod
  1753. def some(self) -> int: ...
  1754. """,
  1755. runtime="""
  1756. class AP3:
  1757. @property
  1758. def some(self) -> int: ...
  1759. """,
  1760. error=None,
  1761. )
  1762. def remove_color_code(s: str) -> str:
  1763. return re.sub("\\x1b.*?m", "", s) # this works!
  1764. class StubtestMiscUnit(unittest.TestCase):
  1765. def test_output(self) -> None:
  1766. output = run_stubtest(
  1767. stub="def bad(number: int, text: str) -> None: ...",
  1768. runtime="def bad(num, text): pass",
  1769. options=[],
  1770. )
  1771. expected = (
  1772. f'error: {TEST_MODULE_NAME}.bad is inconsistent, stub argument "number" differs '
  1773. 'from runtime argument "num"\n'
  1774. f"Stub: in file {TEST_MODULE_NAME}.pyi:1\n"
  1775. "def (number: builtins.int, text: builtins.str)\n"
  1776. f"Runtime: in file {TEST_MODULE_NAME}.py:1\ndef (num, text)\n\n"
  1777. "Found 1 error (checked 1 module)\n"
  1778. )
  1779. assert output == expected
  1780. output = run_stubtest(
  1781. stub="def bad(number: int, text: str) -> None: ...",
  1782. runtime="def bad(num, text): pass",
  1783. options=["--concise"],
  1784. )
  1785. expected = (
  1786. "{}.bad is inconsistent, "
  1787. 'stub argument "number" differs from runtime argument "num"\n'.format(TEST_MODULE_NAME)
  1788. )
  1789. assert output == expected
  1790. def test_ignore_flags(self) -> None:
  1791. output = run_stubtest(
  1792. stub="", runtime="__all__ = ['f']\ndef f(): pass", options=["--ignore-missing-stub"]
  1793. )
  1794. assert output == "Success: no issues found in 1 module\n"
  1795. output = run_stubtest(stub="", runtime="def f(): pass", options=["--ignore-missing-stub"])
  1796. assert output == "Success: no issues found in 1 module\n"
  1797. output = run_stubtest(
  1798. stub="def f(__a): ...", runtime="def f(a): pass", options=["--ignore-positional-only"]
  1799. )
  1800. assert output == "Success: no issues found in 1 module\n"
  1801. def test_allowlist(self) -> None:
  1802. # Can't use this as a context because Windows
  1803. allowlist = tempfile.NamedTemporaryFile(mode="w+", delete=False)
  1804. try:
  1805. with allowlist:
  1806. allowlist.write(f"{TEST_MODULE_NAME}.bad # comment\n# comment")
  1807. output = run_stubtest(
  1808. stub="def bad(number: int, text: str) -> None: ...",
  1809. runtime="def bad(asdf, text): pass",
  1810. options=["--allowlist", allowlist.name],
  1811. )
  1812. assert output == "Success: no issues found in 1 module\n"
  1813. # test unused entry detection
  1814. output = run_stubtest(stub="", runtime="", options=["--allowlist", allowlist.name])
  1815. assert output == (
  1816. f"note: unused allowlist entry {TEST_MODULE_NAME}.bad\n"
  1817. "Found 1 error (checked 1 module)\n"
  1818. )
  1819. output = run_stubtest(
  1820. stub="",
  1821. runtime="",
  1822. options=["--allowlist", allowlist.name, "--ignore-unused-allowlist"],
  1823. )
  1824. assert output == "Success: no issues found in 1 module\n"
  1825. # test regex matching
  1826. with open(allowlist.name, mode="w+") as f:
  1827. f.write(f"{TEST_MODULE_NAME}.b.*\n")
  1828. f.write("(unused_missing)?\n")
  1829. f.write("unused.*\n")
  1830. output = run_stubtest(
  1831. stub=textwrap.dedent(
  1832. """
  1833. def good() -> None: ...
  1834. def bad(number: int) -> None: ...
  1835. def also_bad(number: int) -> None: ...
  1836. """.lstrip(
  1837. "\n"
  1838. )
  1839. ),
  1840. runtime=textwrap.dedent(
  1841. """
  1842. def good(): pass
  1843. def bad(asdf): pass
  1844. def also_bad(asdf): pass
  1845. """.lstrip(
  1846. "\n"
  1847. )
  1848. ),
  1849. options=["--allowlist", allowlist.name, "--generate-allowlist"],
  1850. )
  1851. assert output == (
  1852. f"note: unused allowlist entry unused.*\n" f"{TEST_MODULE_NAME}.also_bad\n"
  1853. )
  1854. finally:
  1855. os.unlink(allowlist.name)
  1856. def test_mypy_build(self) -> None:
  1857. output = run_stubtest(stub="+", runtime="", options=[])
  1858. assert output == (
  1859. "error: not checking stubs due to failed mypy compile:\n{}.pyi:1: "
  1860. "error: invalid syntax [syntax]\n".format(TEST_MODULE_NAME)
  1861. )
  1862. output = run_stubtest(stub="def f(): ...\ndef f(): ...", runtime="", options=[])
  1863. assert output == (
  1864. "error: not checking stubs due to mypy build errors:\n{}.pyi:2: "
  1865. 'error: Name "f" already defined on line 1 [no-redef]\n'.format(TEST_MODULE_NAME)
  1866. )
  1867. def test_missing_stubs(self) -> None:
  1868. output = io.StringIO()
  1869. with contextlib.redirect_stdout(output):
  1870. test_stubs(parse_options(["not_a_module"]))
  1871. assert remove_color_code(output.getvalue()) == (
  1872. "error: not_a_module failed to find stubs\n"
  1873. "Stub:\nMISSING\nRuntime:\nN/A\n\n"
  1874. "Found 1 error (checked 1 module)\n"
  1875. )
  1876. def test_only_py(self) -> None:
  1877. # in this case, stubtest will check the py against itself
  1878. # this is useful to support packages with a mix of stubs and inline types
  1879. with use_tmp_dir(TEST_MODULE_NAME):
  1880. with open(f"{TEST_MODULE_NAME}.py", "w") as f:
  1881. f.write("a = 1")
  1882. output = io.StringIO()
  1883. with contextlib.redirect_stdout(output):
  1884. test_stubs(parse_options([TEST_MODULE_NAME]))
  1885. output_str = remove_color_code(output.getvalue())
  1886. assert output_str == "Success: no issues found in 1 module\n"
  1887. def test_get_typeshed_stdlib_modules(self) -> None:
  1888. stdlib = mypy.stubtest.get_typeshed_stdlib_modules(None, (3, 7))
  1889. assert "builtins" in stdlib
  1890. assert "os" in stdlib
  1891. assert "os.path" in stdlib
  1892. assert "asyncio" in stdlib
  1893. assert "graphlib" not in stdlib
  1894. assert "formatter" in stdlib
  1895. assert "contextvars" in stdlib # 3.7+
  1896. assert "importlib.metadata" not in stdlib
  1897. stdlib = mypy.stubtest.get_typeshed_stdlib_modules(None, (3, 10))
  1898. assert "graphlib" in stdlib
  1899. assert "formatter" not in stdlib
  1900. assert "importlib.metadata" in stdlib
  1901. def test_signature(self) -> None:
  1902. def f(a: int, b: int, *, c: int, d: int = 0, **kwargs: Any) -> None:
  1903. pass
  1904. assert (
  1905. str(mypy.stubtest.Signature.from_inspect_signature(inspect.signature(f)))
  1906. == "def (a, b, *, c, d = ..., **kwargs)"
  1907. )
  1908. def test_config_file(self) -> None:
  1909. runtime = "temp = 5\n"
  1910. stub = "from decimal import Decimal\ntemp: Decimal\n"
  1911. config_file = f"[mypy]\nplugins={root_dir}/test-data/unit/plugins/decimal_to_int.py\n"
  1912. output = run_stubtest(stub=stub, runtime=runtime, options=[])
  1913. assert output == (
  1914. f"error: {TEST_MODULE_NAME}.temp variable differs from runtime type Literal[5]\n"
  1915. f"Stub: in file {TEST_MODULE_NAME}.pyi:2\n_decimal.Decimal\nRuntime:\n5\n\n"
  1916. "Found 1 error (checked 1 module)\n"
  1917. )
  1918. output = run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file)
  1919. assert output == "Success: no issues found in 1 module\n"
  1920. def test_no_modules(self) -> None:
  1921. output = io.StringIO()
  1922. with contextlib.redirect_stdout(output):
  1923. test_stubs(parse_options([]))
  1924. assert remove_color_code(output.getvalue()) == "error: no modules to check\n"
  1925. def test_module_and_typeshed(self) -> None:
  1926. output = io.StringIO()
  1927. with contextlib.redirect_stdout(output):
  1928. test_stubs(parse_options(["--check-typeshed", "some_module"]))
  1929. assert remove_color_code(output.getvalue()) == (
  1930. "error: cannot pass both --check-typeshed and a list of modules\n"
  1931. )