Skip to content

Commit e540b66

Browse files
stroxlerfacebook-github-bot
authored andcommitted
Infer: clean up code style
Summary: Improve the style of infer_v2 code and tests: - add a type alias for the raw `json.loads` output from ocaml - extract some helper functions, stick underscores in front of most function names - extract the logic for injecting `location.path` and handling null data into a helper function for readability - adjust comments Reviewed By: pradeep90 Differential Revision: D28935185 fbshipit-source-id: 3c605b037467cb832bc084550937381581781251
1 parent 967659f commit e540b66

File tree

2 files changed

+84
-47
lines changed

2 files changed

+84
-47
lines changed

client/commands/infer_v2.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
from collections import defaultdict
1313
from dataclasses import dataclass
1414
from pathlib import Path
15-
from typing import cast, Dict, Optional, Sequence
15+
from typing import cast, Dict, List, Optional, Sequence
1616

1717
from typing_extensions import Final
18+
from typing_extensions import TypeAlias
1819

1920
from .. import command_arguments, log
2021
from ..analysis_directory import AnalysisDirectory, resolve_analysis_directory
@@ -31,14 +32,17 @@ def _sanitize_name(name: str) -> str:
3132
return name.split(".")[-1]
3233

3334

35+
RawInferOutputDict: TypeAlias = Dict[str, List[Dict[str, object]]]
36+
37+
3438
class RawInferOutput:
3539
"""
3640
Class encapsulating the raw json output from infer.
3741
3842
This is converted into a list[ModuleAnnotation] to produce stubs.
3943
"""
4044

41-
def __init__(self, data: dict[str, list[dict[str, object]]]) -> None:
45+
def __init__(self, data: RawInferOutputDict) -> None:
4246
self.data = data
4347

4448
categories: Sequence[str] = ["globals", "attributes", "defines"]

client/commands/tests/infer_v2_test.py

Lines changed: 78 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,80 @@
44
# LICENSE file in the root directory of this source tree.
55

66
# pyre-unsafe
7+
from __future__ import annotations
78

89
import textwrap
910
import unittest
1011
from pathlib import Path
12+
from typing import cast
1113

1214
from ...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"---\nactual\n---\n{actual}")
56+
print(f"---\nexpected\n---\n{expected}")
57+
raise AssertionError("Stubs not as expected, see stdout")
58+
59+
1860
class 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"---\nactual\n---\n{actual}")
38-
print(f"---\nexpected\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

Comments
 (0)