44# LICENSE file in the root directory of this source tree.
55
66# pyre-unsafe
7+ from __future__ import annotations
78
89import textwrap
910import unittest
1011from pathlib import Path
12+ from typing import cast
1113
1214from ...commands .infer_v2 import (
1315 _create_module_annotations ,
1416 RawInferOutput ,
17+ RawInferOutputDict ,
18+ ModuleAnnotations ,
1519)
1620
1721
22+ PATH = "test.py"
23+
24+
25+ def _raw_infer_output (
26+ data : dict | None ,
27+ ) -> RawInferOutput :
28+ data = data or {}
29+ for category in RawInferOutput .categories :
30+ data [category ] = data .get (category , [])
31+ for annotation in data [category ]:
32+ annotation ["location" ] = {"path" : PATH }
33+ return RawInferOutput (data = cast (RawInferOutputDict , data ))
34+
35+
36+ def _create_test_module_annotations (
37+ data : dict | None ,
38+ complete_only : bool ,
39+ ) -> ModuleAnnotations :
40+ all_module_annotations = _create_module_annotations (
41+ infer_output = _raw_infer_output (data = data ),
42+ complete_only = complete_only ,
43+ )
44+ if len (all_module_annotations ) != 1 :
45+ raise AssertionError ("Expected exactly one module!" )
46+ module_annotations = all_module_annotations [0 ]
47+ assert module_annotations .stubs_path (Path ("code" )) == Path (f"code/{ PATH } i" )
48+ return module_annotations
49+
50+
51+ def _assert_stubs_equal (actual , expected ):
52+ actual = actual .strip ()
53+ expected = textwrap .dedent (expected .rstrip ())
54+ if actual != expected :
55+ print (f"---\n actual\n ---\n { actual } " )
56+ print (f"---\n expected\n ---\n { expected } " )
57+ raise AssertionError ("Stubs not as expected, see stdout" )
58+
59+
1860class StubGenerationTest (unittest .TestCase ):
19- def assert_stubs ( self , data , expected , complete_only = False ) -> None :
20- # auto-generate a bit of boilerplate
21- for category in RawInferOutput . categories :
22- data [ category ] = data . get ( category , [])
23- for annotation in data [ category ]:
24- annotation [ "location" ] = { "path" : "test.py" }
25- all_module_annotations = _create_module_annotations (
26- infer_output = RawInferOutput ( data = data ) ,
61+ def _assert_stubs (
62+ self ,
63+ data : dict ,
64+ expected : str ,
65+ complete_only : bool = False ,
66+ ) -> None :
67+ module_annotations = _create_test_module_annotations (
68+ data = data ,
2769 complete_only = complete_only ,
2870 )
29- self .assertEqual (len (all_module_annotations ), 1 )
30- module_annotations = all_module_annotations [0 ]
31- self .assertEqual (
32- module_annotations .stubs_path (Path ("code" )), Path ("code/test.pyi" )
33- )
34- actual = module_annotations .to_stubs ().strip ()
35- expected = textwrap .dedent (expected .rstrip ())
36- if actual != expected :
37- print (f"---\n actual\n ---\n { actual } " )
38- print (f"---\n expected\n ---\n { expected } " )
39- raise AssertionError ("Stubs not as expected, see stdout" )
71+ actual = module_annotations .to_stubs ()
72+ _assert_stubs_equal (actual , expected )
4073
4174 def test_stubs_defines (self ) -> None :
42- self .assert_stubs (
75+ self ._assert_stubs (
4376 {
4477 "defines" : [
4578 {
4679 "return" : "int" ,
47- "name" : "ret_int" ,
80+ "name" : "test.Test. ret_int" ,
4881 "parent" : "test.Test" ,
4982 "parameters" : [
5083 {"name" : "self" , "annotation" : None , "value" : None }
@@ -61,7 +94,7 @@ def ret_int(self) -> int: ...
6194 """ ,
6295 )
6396
64- self .assert_stubs (
97+ self ._assert_stubs (
6598 {
6699 "defines" : [
67100 {
@@ -80,7 +113,7 @@ async def returns_int() -> int: ...
80113 """ ,
81114 )
82115
83- self .assert_stubs (
116+ self ._assert_stubs (
84117 {
85118 "defines" : [
86119 {
@@ -99,7 +132,7 @@ async def returns_int() -> int: ...
99132 "def with_params(y=7, x: int = 5) -> int: ..." ,
100133 )
101134
102- self .assert_stubs (
135+ self ._assert_stubs (
103136 {
104137 "defines" : [
105138 {
@@ -115,7 +148,7 @@ async def returns_int() -> int: ...
115148 "def returns_string() -> str: ..." ,
116149 )
117150
118- self .assert_stubs (
151+ self ._assert_stubs (
119152 {
120153 "defines" : [
121154 {
@@ -131,7 +164,7 @@ async def returns_int() -> int: ...
131164 "def returns_bool() -> bool: ..." ,
132165 )
133166
134- self .assert_stubs (
167+ self ._assert_stubs (
135168 {
136169 "defines" : [
137170 {
@@ -147,7 +180,7 @@ async def returns_int() -> int: ...
147180 "def returns_float() -> float: ..." ,
148181 )
149182
150- self .assert_stubs (
183+ self ._assert_stubs (
151184 {
152185 "defines" : [
153186 {
@@ -164,7 +197,7 @@ async def returns_int() -> int: ...
164197 "def missing_param_test(x: int = 5): ..." ,
165198 )
166199
167- self .assert_stubs (
200+ self ._assert_stubs (
168201 {
169202 "defines" : [
170203 {
@@ -180,7 +213,7 @@ async def returns_int() -> int: ...
180213 "def another_fun() -> float: ..." ,
181214 )
182215
183- self .assert_stubs (
216+ self ._assert_stubs (
184217 {
185218 "defines" : [
186219 {
@@ -198,7 +231,7 @@ async def returns_int() -> int: ...
198231 "" ,
199232 )
200233
201- self .assert_stubs (
234+ self ._assert_stubs (
202235 {
203236 "defines" : [
204237 {
@@ -216,7 +249,7 @@ async def returns_int() -> int: ...
216249 "" ,
217250 )
218251
219- self .assert_stubs (
252+ self ._assert_stubs (
220253 {
221254 "defines" : [
222255 {
@@ -249,7 +282,7 @@ class Test:
249282 def ret_dict(self) -> Dict[int, str]: ...
250283 """ ,
251284 )
252- self .assert_stubs (
285+ self ._assert_stubs (
253286 {
254287 "defines" : [
255288 {
@@ -285,7 +318,7 @@ def a(self) -> Union[Dict[str, int], str]: ...
285318 )
286319
287320 def test_stubs_attributes_and_globals (self ) -> None :
288- self .assert_stubs (
321+ self ._assert_stubs (
289322 {
290323 "globals" : [{"annotation" : "int" , "name" : "global" , "parent" : None }],
291324 },
@@ -294,7 +327,7 @@ def test_stubs_attributes_and_globals(self) -> None:
294327 """ ,
295328 )
296329
297- self .assert_stubs (
330+ self ._assert_stubs (
298331 {
299332 "attributes" : [
300333 {
@@ -311,7 +344,7 @@ class Test:
311344 )
312345
313346 def test_stubs_with_pathlike (self ) -> None :
314- self .assert_stubs (
347+ self ._assert_stubs (
315348 {
316349 "defines" : [
317350 {
@@ -331,7 +364,7 @@ def test_stubs_with_pathlike(self) -> None:
331364 + " 'os.PathLike[str]', bytes, str]: ..." ,
332365 )
333366
334- self .assert_stubs (
367+ self ._assert_stubs (
335368 {
336369 "defines" : [
337370 {
@@ -348,7 +381,7 @@ def test_stubs_with_pathlike(self) -> None:
348381 },
349382 "def bar(x: int) -> 'os.PathLike[str]': ..." ,
350383 )
351- self .assert_stubs (
384+ self ._assert_stubs (
352385 {
353386 "defines" : [
354387 {
@@ -365,7 +398,7 @@ def test_stubs_with_pathlike(self) -> None:
365398 },
366399 "def bar(x: int) -> os.PathLike[str]: ..." ,
367400 )
368- self .assert_stubs (
401+ self ._assert_stubs (
369402 {
370403 "defines" : [
371404 {
@@ -387,7 +420,7 @@ def test_stubs_with_pathlike(self) -> None:
387420 def bar(x: int) -> Union[os.PathLike[str]]: ...
388421 """ ,
389422 )
390- self .assert_stubs (
423+ self ._assert_stubs (
391424 {
392425 "defines" : [
393426 {
@@ -415,7 +448,7 @@ def test_stubs_complete_only(self) -> None:
415448 """
416449 Make sure we correctly filter out incomplete annotations when desired
417450 """
418- self .assert_stubs (
451+ self ._assert_stubs (
419452 {
420453 "defines" : [
421454 {
@@ -435,7 +468,7 @@ def test_stubs_complete_only(self) -> None:
435468 complete_only = True ,
436469 )
437470
438- self .assert_stubs (
471+ self ._assert_stubs (
439472 {
440473 "defines" : [
441474 {
@@ -454,7 +487,7 @@ def test_stubs_complete_only(self) -> None:
454487 complete_only = True ,
455488 )
456489
457- self .assert_stubs (
490+ self ._assert_stubs (
458491 {
459492 "defines" : [
460493 {
@@ -474,7 +507,7 @@ def test_stubs_complete_only(self) -> None:
474507 complete_only = True ,
475508 )
476509
477- self .assert_stubs (
510+ self ._assert_stubs (
478511 {
479512 "defines" : [
480513 {
@@ -498,13 +531,13 @@ def test_stubs_no_typing_import(self) -> None:
498531 """
499532 Make sure we don't spuriously import from typing
500533
501- NOTE: this logic is almost certainly incomplete - if another function
534+ NOTE: This logic is almost certainly incomplete - if another function
502535 in the same module used typing.Union, we would produce incorrect stubs.
503536
504537 We should determine whether it is truly necessary to import from typing,
505538 because doing it correctly in edge cases is nontrivial.
506539 """
507- self .assert_stubs (
540+ self ._assert_stubs (
508541 {
509542 "defines" : [
510543 {
0 commit comments