Skip to content

Commit 55564ff

Browse files
Type curtsies.py
1 parent b1aa263 commit 55564ff

File tree

10 files changed

+141
-71
lines changed

10 files changed

+141
-71
lines changed

.github/workflows/lint.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,4 @@ jobs:
4242
pip install types-backports types-requests types-setuptools types-toml types-pygments
4343
- name: Check with mypy
4444
# for now only run on a few files to avoid slipping backward
45-
run: mypy bpython/autocomplete.py
45+
run: mypy bpython/autocomplete.py bpython/args.py bpython/config.py bpython/curtsies.py

bpython/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222
# THE SOFTWARE.
2323

24+
# To gradually migrate to mypy we aren't setting these globally yet
25+
# mypy: disallow_untyped_defs=True
26+
# mypy: disallow_untyped_calls=True
27+
2428
import os
2529
import sys
2630
import locale

bpython/curtsies.py

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# To gradually migrate to mypy we aren't setting these globally yet
2+
# mypy: disallow_untyped_defs=True
3+
# mypy: disallow_untyped_calls=True
4+
5+
import argparse
6+
import code
17
import collections
28
import logging
39
import sys
@@ -16,11 +22,43 @@
1622
from .repl import extract_exit_value
1723
from .translations import _
1824

25+
from typing import (
26+
Any,
27+
Dict,
28+
List,
29+
Callable,
30+
Union,
31+
Sequence,
32+
Tuple,
33+
Optional,
34+
Generator,
35+
)
36+
from typing_extensions import Literal, Protocol
37+
1938
logger = logging.getLogger(__name__)
2039

2140

41+
class SupportsEventGeneration(Protocol):
42+
def send(
43+
self, timeout: Union[float, None]
44+
) -> Union[str, curtsies.events.Event, None]:
45+
...
46+
47+
def __iter__(self) -> SupportsEventGeneration:
48+
...
49+
50+
def __next__(self) -> Union[str, curtsies.events.Event, None]:
51+
...
52+
53+
2254
class FullCurtsiesRepl(BaseRepl):
23-
def __init__(self, config, locals_, banner, interp=None) -> None:
55+
def __init__(
56+
self,
57+
config: Config,
58+
locals_: Optional[Dict[str, Any]],
59+
banner: Optional[str],
60+
interp: code.InteractiveInterpreter = None,
61+
) -> None:
2462
self.input_generator = curtsies.input.Input(
2563
keynames="curtsies", sigint_event=True, paste_threshold=None
2664
)
@@ -32,13 +70,13 @@ def __init__(self, config, locals_, banner, interp=None) -> None:
3270
extra_bytes_callback=self.input_generator.unget_bytes,
3371
)
3472

35-
self._request_refresh_callback = self.input_generator.event_trigger(
36-
events.RefreshRequestEvent
37-
)
38-
self._schedule_refresh_callback = (
39-
self.input_generator.scheduled_event_trigger(
40-
events.ScheduledRefreshRequestEvent
41-
)
73+
self._request_refresh_callback: Callable[
74+
[], None
75+
] = self.input_generator.event_trigger(events.RefreshRequestEvent)
76+
self._schedule_refresh_callback: Callable[
77+
[float], None
78+
] = self.input_generator.scheduled_event_trigger(
79+
events.ScheduledRefreshRequestEvent
4280
)
4381
self._request_reload_callback = (
4482
self.input_generator.threadsafe_event_trigger(events.ReloadEvent)
@@ -61,40 +99,42 @@ def __init__(self, config, locals_, banner, interp=None) -> None:
6199
orig_tcattrs=self.input_generator.original_stty,
62100
)
63101

64-
def _request_refresh(self):
102+
def _request_refresh(self) -> None:
65103
return self._request_refresh_callback()
66104

67-
def _schedule_refresh(self, when="now"):
105+
def _schedule_refresh(self, when: float) -> None:
68106
return self._schedule_refresh_callback(when)
69107

70-
def _request_reload(self, files_modified=("?",)):
108+
def _request_reload(self, files_modified: Sequence[str] = ("?",)) -> None:
71109
return self._request_reload_callback(files_modified)
72110

73-
def interrupting_refresh(self):
111+
def interrupting_refresh(self) -> None:
74112
return self._interrupting_refresh_callback()
75113

76-
def request_undo(self, n=1):
114+
def request_undo(self, n: int = 1) -> None:
77115
return self._request_undo_callback(n=n)
78116

79-
def get_term_hw(self):
117+
def get_term_hw(self) -> Tuple[int, int]:
80118
return self.window.get_term_hw()
81119

82-
def get_cursor_vertical_diff(self):
120+
def get_cursor_vertical_diff(self) -> int:
83121
return self.window.get_cursor_vertical_diff()
84122

85-
def get_top_usable_line(self):
123+
def get_top_usable_line(self) -> int:
86124
return self.window.top_usable_row
87125

88-
def on_suspend(self):
126+
def on_suspend(self) -> None:
89127
self.window.__exit__(None, None, None)
90128
self.input_generator.__exit__(None, None, None)
91129

92-
def after_suspend(self):
130+
def after_suspend(self) -> None:
93131
self.input_generator.__enter__()
94132
self.window.__enter__()
95133
self.interrupting_refresh()
96134

97-
def process_event_and_paint(self, e):
135+
def process_event_and_paint(
136+
self, e: Union[str, curtsies.events.Event, None]
137+
) -> None:
98138
"""If None is passed in, just paint the screen"""
99139
try:
100140
if e is not None:
@@ -112,7 +152,11 @@ def process_event_and_paint(self, e):
112152
scrolled = self.window.render_to_terminal(array, cursor_pos)
113153
self.scroll_offset += scrolled
114154

115-
def mainloop(self, interactive=True, paste=None):
155+
def mainloop(
156+
self,
157+
interactive: bool = True,
158+
paste: Optional[curtsies.events.PasteEvent] = None,
159+
) -> None:
116160
if interactive:
117161
# Add custom help command
118162
# TODO: add methods to run the code
@@ -137,14 +181,19 @@ def mainloop(self, interactive=True, paste=None):
137181
self.process_event_and_paint(e)
138182

139183

140-
def main(args=None, locals_=None, banner=None, welcome_message=None):
184+
def main(
185+
args: List[str] = None,
186+
locals_: Dict[str, Any] = None,
187+
banner: str = None,
188+
welcome_message: str = None,
189+
) -> Any:
141190
"""
142191
banner is displayed directly after the version information.
143192
welcome_message is passed on to Repl and displayed in the statusbar.
144193
"""
145194
translations.init()
146195

147-
def curtsies_arguments(parser):
196+
def curtsies_arguments(parser: argparse._ArgumentGroup) -> None:
148197
parser.add_argument(
149198
"--paste",
150199
"-p",
@@ -163,10 +212,10 @@ def curtsies_arguments(parser):
163212

164213
interp = None
165214
paste = None
215+
exit_value: Tuple[Any, ...] = ()
166216
if exec_args:
167217
if not options:
168218
raise ValueError("don't pass in exec_args without options")
169-
exit_value = ()
170219
if options.paste:
171220
paste = curtsies.events.PasteEvent()
172221
encoding = inspection.get_encoding_file(exec_args[0])
@@ -196,16 +245,20 @@ def curtsies_arguments(parser):
196245
with repl.window as win:
197246
with repl:
198247
repl.height, repl.width = win.t.height, win.t.width
199-
exit_value = repl.mainloop(True, paste)
248+
repl.mainloop(True, paste)
200249
except (SystemExitFromCodeRunner, SystemExit) as e:
201250
exit_value = e.args
202251
return extract_exit_value(exit_value)
203252

204253

205-
def _combined_events(event_provider, paste_threshold):
254+
def _combined_events(
255+
event_provider: SupportsEventGeneration, paste_threshold: int
256+
) -> Generator[
257+
Union[str, curtsies.events.Event, None], Union[float, None], None
258+
]:
206259
"""Combines consecutive keypress events into paste events."""
207260
timeout = yield "nonsense_event" # so send can be used immediately
208-
queue = collections.deque()
261+
queue: collections.deque = collections.deque()
209262
while True:
210263
e = event_provider.send(timeout)
211264
if isinstance(e, curtsies.events.Event):
@@ -230,7 +283,9 @@ def _combined_events(event_provider, paste_threshold):
230283
timeout = yield queue.popleft()
231284

232285

233-
def combined_events(event_provider, paste_threshold=3):
286+
def combined_events(
287+
event_provider: SupportsEventGeneration, paste_threshold: int = 3
288+
) -> SupportsEventGeneration:
234289
g = _combined_events(event_provider, paste_threshold)
235290
next(g)
236291
return g

bpython/curtsiesfrontend/interaction.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import greenlet
22
import time
3+
from typing import Optional
34
from curtsies import events
45

56
from ..translations import _
@@ -78,7 +79,7 @@ def _check_for_expired_message(self):
7879
):
7980
self._message = ""
8081

81-
def process_event(self, e):
82+
def process_event(self, e) -> None:
8283
"""Returns True if shutting down"""
8384
assert self.in_prompt or self.in_confirm or self.waiting_for_refresh
8485
if isinstance(e, RefreshRequestEvent):

bpython/curtsiesfrontend/interpreter.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sys
2+
from typing import Any, Dict
23

34
from pygments.token import Generic, Token, Keyword, Name, Comment, String
45
from pygments.token import Error, Literal, Number, Operator, Punctuation
@@ -59,7 +60,7 @@ def format(self, tokensource, outfile):
5960

6061

6162
class Interp(ReplInterpreter):
62-
def __init__(self, locals=None, encoding=None):
63+
def __init__(self, locals: Dict[str, Any] = None, encoding=None):
6364
"""Constructor.
6465
6566
We include an argument for the outfile to pass to the formatter for it
@@ -75,7 +76,7 @@ def write(err_line):
7576
Accepts FmtStrs so interpreters can output them"""
7677
sys.stderr.write(str(err_line))
7778

78-
self.write = write
79+
self.write = write # type: ignore
7980
self.outfile = self
8081

8182
def writetb(self, lines):

0 commit comments

Comments
 (0)