4
4
5
5
import time
6
6
from io import StringIO
7
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING , Protocol
8
8
9
9
import pytest
10
10
13
13
from sphinx .testing .util import SphinxTestApp
14
14
15
15
if TYPE_CHECKING :
16
- from collections .abc import Callable
17
16
from pathlib import Path
18
17
from typing import Any
19
18
20
19
warnfile = StringIO ()
21
20
22
21
23
- def setup_module ():
22
+ def setup_module () -> None :
24
23
disable_colour ()
25
24
26
25
26
+ class _MockTermInput (Protocol ):
27
+ """Protocol for mocking term_input in quickstart."""
28
+
29
+ def __call__ (self , prompt : str ) -> str :
30
+ """Mock input function that returns a string based on the prompt."""
31
+
32
+
27
33
def mock_input (
28
34
answers : dict [str , str ], needanswer : bool = False
29
- ) -> Callable [[ str ], str ] :
35
+ ) -> _MockTermInput :
30
36
called = set ()
31
37
32
38
def input_ (prompt : str ) -> str :
@@ -45,10 +51,16 @@ def input_(prompt: str) -> str:
45
51
return input_
46
52
47
53
48
- real_input : Callable [[str ], str ] = input
54
+ def _real_input_but_allow_named_args_in_hint (* args : str , ** kwargs : str ) -> str :
55
+ """A wrapper for the real input function to allow named arguments in the type hint."""
56
+ assert not kwargs , 'Named arguments are not allowed in input()'
57
+ return input (* args )
58
+
49
59
60
+ real_input : _MockTermInput = _real_input_but_allow_named_args_in_hint
50
61
51
- def teardown_module ():
62
+
63
+ def teardown_module () -> None :
52
64
qs .term_input = real_input
53
65
enable_colour ()
54
66
@@ -61,7 +73,7 @@ def test_do_prompt() -> None:
61
73
'Q5' : 'no' ,
62
74
'Q6' : 'foo' ,
63
75
}
64
- qs .term_input = mock_input (answers ) # type: ignore[assignment]
76
+ qs .term_input = mock_input (answers )
65
77
66
78
assert qs .do_prompt ('Q1' , default = 'v1' ) == 'v1'
67
79
assert qs .do_prompt ('Q3' , default = 'v3_default' ) == 'v3'
@@ -79,7 +91,7 @@ def test_do_prompt_inputstrip() -> None:
79
91
'Q3' : 'N' ,
80
92
'Q4' : 'N ' ,
81
93
}
82
- qs .term_input = mock_input (answers ) # type: ignore[assignment]
94
+ qs .term_input = mock_input (answers )
83
95
84
96
assert qs .do_prompt ('Q1' ) == 'Y'
85
97
assert qs .do_prompt ('Q2' ) == 'Yes'
@@ -91,12 +103,12 @@ def test_do_prompt_with_nonascii() -> None:
91
103
answers = {
92
104
'Q1' : '\u30c9 \u30a4 \u30c4 ' ,
93
105
}
94
- qs .term_input = mock_input (answers ) # type: ignore[assignment]
106
+ qs .term_input = mock_input (answers )
95
107
result = qs .do_prompt ('Q1' , default = '\u65e5 \u672c ' )
96
108
assert result == '\u30c9 \u30a4 \u30c4 '
97
109
98
110
99
- def test_quickstart_defaults (tmp_path ) :
111
+ def test_quickstart_defaults (tmp_path : Path ) -> None :
100
112
answers = {
101
113
'Root path' : str (tmp_path ),
102
114
'Project name' : 'Sphinx Test' ,
@@ -127,7 +139,7 @@ def test_quickstart_defaults(tmp_path):
127
139
assert (tmp_path / 'make.bat' ).is_file ()
128
140
129
141
130
- def test_quickstart_all_answers (tmp_path ) :
142
+ def test_quickstart_all_answers (tmp_path : Path ) -> None :
131
143
answers = {
132
144
'Root path' : str (tmp_path ),
133
145
'Separate source and build' : 'y' ,
@@ -185,7 +197,7 @@ def test_quickstart_all_answers(tmp_path):
185
197
assert (tmp_path / 'source' / 'contents.txt' ).is_file ()
186
198
187
199
188
- def test_generated_files_eol (tmp_path ) :
200
+ def test_generated_files_eol (tmp_path : Path ) -> None :
189
201
answers = {
190
202
'Root path' : str (tmp_path ),
191
203
'Project name' : 'Sphinx Test' ,
@@ -205,7 +217,7 @@ def assert_eol(filename: Path, eol: str) -> None:
205
217
assert_eol (tmp_path / 'Makefile' , '\n ' )
206
218
207
219
208
- def test_quickstart_and_build (tmp_path ) :
220
+ def test_quickstart_and_build (tmp_path : Path ) -> None :
209
221
answers = {
210
222
'Root path' : str (tmp_path ),
211
223
'Project name' : 'Fullwidth characters: \u30c9 \u30a4 \u30c4 ' ,
@@ -224,7 +236,7 @@ def test_quickstart_and_build(tmp_path):
224
236
assert not warnings
225
237
226
238
227
- def test_default_filename (tmp_path ) :
239
+ def test_default_filename (tmp_path : Path ) -> None :
228
240
answers = {
229
241
'Root path' : str (tmp_path ),
230
242
'Project name' : '\u30c9 \u30a4 \u30c4 ' , # Fullwidth characters only
@@ -242,7 +254,7 @@ def test_default_filename(tmp_path):
242
254
exec (conffile .read_text (encoding = 'utf8' ), ns ) # NoQA: S102
243
255
244
256
245
- def test_extensions (tmp_path ) :
257
+ def test_extensions (tmp_path : Path ) -> None :
246
258
qs .main ([
247
259
'-q' ,
248
260
'-p' ,
@@ -261,7 +273,7 @@ def test_extensions(tmp_path):
261
273
assert ns ['extensions' ] == ['foo' , 'bar' , 'baz' ]
262
274
263
275
264
- def test_exits_when_existing_confpy (monkeypatch ) :
276
+ def test_exits_when_existing_confpy (monkeypatch : pytest . MonkeyPatch ) -> None :
265
277
# The code detects existing conf.py with path.is_file()
266
278
# so we mock it as True with pytest's monkeypatch
267
279
monkeypatch .setattr ('os.path.isfile' , lambda path : True )
0 commit comments