11
11
t = TypeScriptComponent({0})
12
12
"""
13
13
14
+ basic_app_template = """
15
+ from dash import Dash, html, dcc, callback, Input, Output
14
16
15
- def run_pyright (codefile : str ):
17
+ app = Dash()
18
+
19
+ {0}
20
+ app.layout = {1}
21
+
22
+ @callback(Output("out", "children"), Input("btn", "n_clicks"))
23
+ def on_click() -> html.Div:
24
+ return {2}
25
+ """
26
+
27
+ valid_layout = """html.Div([
28
+ html.H2('Valid'),
29
+ 'String in middle',
30
+ 123,
31
+ 404.4,
32
+ dcc.Input(value='', id='in')
33
+ ])
34
+ """
35
+ valid_layout_list = """[
36
+ html.H2('Valid'),
37
+ 'String in middle',
38
+ 123,
39
+ 404.4,
40
+ dcc.Input(value='', id='in')
41
+ ]
42
+ """
43
+ valid_layout_function = """
44
+ def layout() -> html.Div:
45
+ return html.Div(["hello layout"])
46
+
47
+ """
48
+
49
+ invalid_layout = """html.Div([
50
+ {"invalid": "dictionary in children"}
51
+ ])
52
+ """
53
+ # There is not invalid layout for function & list as explicitly typed as Any to avoid special cases.
54
+
55
+ valid_callback = "html.Div('Valid')"
56
+ invalid_callback = "[]"
57
+
58
+
59
+ def run_module (codefile : str , module : str , extra : str = "" ):
16
60
17
61
cmd = shlex .split (
18
- f"pyright { codefile } " ,
62
+ f"{ sys . executable } -m { module } { codefile } { extra } " ,
19
63
posix = sys .platform != "win32" ,
20
64
comments = True ,
21
65
)
@@ -32,17 +76,39 @@ def run_pyright(codefile: str):
32
76
return out .decode (), err .decode (), proc .poll ()
33
77
34
78
35
- def assert_pyright_output (
36
- codefile : str , expected_outputs = tuple (), expected_errors = tuple (), expected_status = 0
79
+ def assert_output (
80
+ codefile : str ,
81
+ code : str ,
82
+ expected_outputs = tuple (),
83
+ expected_errors = tuple (),
84
+ expected_status = 0 ,
85
+ module = "pyright" ,
37
86
):
38
- output , error , status = run_pyright (codefile )
87
+ output , error , status = run_module (codefile , module )
39
88
assert (
40
89
status == expected_status
41
- ), f"Status: { status } \n Output: { output } \n Error: { error } "
90
+ ), f"Status: { status } \n Output: { output } \n Error: { error } \n Code: { code } "
42
91
for ex_out in expected_outputs :
43
- assert ex_out in output , f"Invalid output:\n { output } "
44
- for ex_err in expected_errors :
45
- assert ex_err in error
92
+ assert ex_out in output , f"Invalid output:\n { output } \n \n Code: { code } "
93
+
94
+
95
+ def format_template_and_save (template , filename , * args ):
96
+ formatted = template .format (* args )
97
+ with open (filename , "w" ) as f :
98
+ f .write (formatted )
99
+ return formatted
100
+
101
+
102
+ def expect (status = None , outputs = None , modular = False ):
103
+ data = {}
104
+ if status is not None :
105
+ data ["expected_status" ] = status
106
+ if outputs is not None :
107
+ data ["expected_outputs" ] = outputs
108
+ if modular :
109
+ # The expectations are per module.
110
+ data ["modular" ] = modular
111
+ return data
46
112
47
113
48
114
@pytest .mark .parametrize (
@@ -247,9 +313,28 @@ def assert_pyright_output(
247
313
),
248
314
],
249
315
)
250
- def test_component_typing (arguments , assertions , tmp_path ):
316
+ def test_typi001_component_typing (arguments , assertions , tmp_path ):
251
317
codefile = os .path .join (tmp_path , "code.py" )
252
- with open (codefile , "w" ) as f :
253
- f .write (component_template .format (arguments ))
318
+ code = format_template_and_save (component_template , codefile , arguments )
319
+ assert_output (codefile , code , module = "pyright" , ** assertions )
320
+
254
321
255
- assert_pyright_output (codefile , ** assertions )
322
+ @pytest .mark .parametrize ("typing_module" , ["pyright" , "mypy" ])
323
+ @pytest .mark .parametrize (
324
+ "prelayout, layout, callback_return, assertions" ,
325
+ [
326
+ ("" , valid_layout , valid_callback , expect (status = 0 )),
327
+ ("" , valid_layout_list , valid_callback , expect (status = 0 )),
328
+ (valid_layout_function , "layout" , valid_callback , expect (status = 0 )),
329
+ ("" , valid_layout , invalid_callback , expect (status = 1 )),
330
+ ("" , invalid_layout , valid_callback , expect (status = 1 )),
331
+ ],
332
+ )
333
+ def test_typi002_typing_compliance (
334
+ typing_module , prelayout , layout , callback_return , assertions , tmp_path
335
+ ):
336
+ codefile = os .path .join (tmp_path , "code.py" )
337
+ code = format_template_and_save (
338
+ basic_app_template , codefile , prelayout , layout , callback_return
339
+ )
340
+ assert_output (codefile , code , module = typing_module , ** assertions )
0 commit comments