Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commited164d7

Browse files
committed
gh-119842: Honor PyOS_InputHook in the new REPL
Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
1 parent5152120 commited164d7

File tree

8 files changed

+144
-11
lines changed

8 files changed

+144
-11
lines changed

‎Lib/_pyrepl/console.py‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
ifTYPE_CHECKING:
3535
fromtypingimportIO
36+
fromtypingimportCallable
3637

3738

3839
@dataclass
@@ -134,8 +135,15 @@ def getpending(self) -> Event:
134135
...
135136

136137
@abstractmethod
137-
defwait(self)->None:
138-
"""Wait for an event."""
138+
defwait(self,timeout:float|None)->bool:
139+
"""Wait for an event. The return value is True if an event is
140+
available, False if the timeout has been reached. If timeout is
141+
None, wait forever. The timeout is in milliseconds."""
142+
...
143+
144+
@property
145+
definput_hook(self)->Callable[[],int]:
146+
"""Returns the current input hook."""
139147
...
140148

141149
@abstractmethod

‎Lib/_pyrepl/reader.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,15 @@ def handle1(self, block: bool = True) -> bool:
644644
self.dirty=True
645645

646646
whileTrue:
647-
event=self.console.get_event(block)
647+
input_hook=self.console.input_hook
648+
ifinput_hook:
649+
input_hook()
650+
# We use the same timeout as in readline.c: 100ms
651+
whilenotself.console.wait(100):
652+
input_hook()
653+
event=self.console.get_event(block=False)
654+
else:
655+
event=self.console.get_event(block)
648656
ifnotevent:# can only happen if we're not blocking
649657
returnFalse
650658

‎Lib/_pyrepl/unix_console.py‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,12 @@ def __init__(self):
118118

119119
defregister(self,fd,flag):
120120
self.fd=fd
121-
122-
defpoll(self):# note: a 'timeout' argument would be *milliseconds*
123-
r,w,e=select.select([self.fd], [], [])
121+
# note: The 'timeout' argument is received as *milliseconds*
122+
defpoll(self,timeout:float|None=None):
123+
iftimeoutisNone:
124+
r,w,e=select.select([self.fd], [], [])
125+
else:
126+
r,w,e=select.select([self.fd], [], [],timeout/1000)
124127
returnr
125128

126129
poll=MinimalPoll# type: ignore[assignment]
@@ -385,11 +388,11 @@ def get_event(self, block: bool = True) -> Event | None:
385388
break
386389
returnself.event_queue.get()
387390

388-
defwait(self):
391+
defwait(self,timeout:float|None=None)->bool:
389392
"""
390393
Wait for events on the console.
391394
"""
392-
self.pollob.poll()
395+
returnbool(self.pollob.poll(timeout))
393396

394397
defset_cursor_vis(self,visible):
395398
"""
@@ -527,6 +530,15 @@ def clear(self):
527530
self.__posxy=0,0
528531
self.screen= []
529532

533+
@property
534+
definput_hook(self):
535+
try:
536+
importposix
537+
exceptImportError:
538+
returnNone
539+
ifposix._is_inputhook_installed():
540+
returnposix._inputhook
541+
530542
def__enable_bracketed_paste(self)->None:
531543
os.write(self.output_fd,b"\x1b[?2004h")
532544

‎Lib/_pyrepl/windows_console.py‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
frommultiprocessingimportValue
2424
importos
2525
importsys
26+
importtime
27+
importmsvcrt
2628

2729
fromabcimportABC,abstractmethod
2830
fromcollectionsimportdeque
@@ -202,6 +204,15 @@ def refresh(self, screen: list[str], c_xy: tuple[int, int]) -> None:
202204
self.screen=screen
203205
self.move_cursor(cx,cy)
204206

207+
@property
208+
definput_hook(self):
209+
try:
210+
importnt
211+
exceptImportError:
212+
returnNone
213+
ifnt._is_inputhook_installed():
214+
returnnt._inputhook
215+
205216
def__write_changed_line(
206217
self,y:int,oldline:str,newline:str,px_coord:int
207218
)->None:
@@ -460,9 +471,16 @@ def getpending(self) -> Event:
460471
processed."""
461472
returnEvent("key","",b"")
462473

463-
defwait(self)->None:
474+
defwait(self,timeout:float|None)->bool:
464475
"""Wait for an event."""
465-
raiseNotImplementedError("No wait support")
476+
# Poor man's Windows select loop
477+
start_time=time.time()
478+
whileTrue:
479+
ifmsvcrt.kbhit():
480+
returnTrue
481+
iftimeoutandtime.time()-start_time>timeout:
482+
returnFalse
483+
time.sleep(0.01)
466484

467485
defrepaint(self)->None:
468486
raiseNotImplementedError("No repaint support")

‎Lib/test/test_pyrepl/test_reader.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
importitertools
22
importfunctools
33
fromunittestimportTestCase
4+
fromunittest.mockimportMagicMock,patch
45

56
from .supportimporthandle_all_events,handle_events_narrow_console,code_to_events,prepare_reader
7+
fromtest.supportimportimport_helper
68
from_pyrepl.consoleimportEvent
79

810

@@ -176,3 +178,18 @@ def test_newline_within_block_trailing_whitespace(self):
176178
)
177179
self.assert_screen_equals(reader,expected)
178180
self.assertTrue(reader.finished)
181+
182+
deftest_input_hook_is_called_if_set(self):
183+
input_hook=MagicMock()
184+
def_prepare_console(events):
185+
console=MagicMock()
186+
console.get_event.side_effect=events
187+
console.height=100
188+
console.width=80
189+
console.input_hook=input_hook
190+
returnconsole
191+
192+
events=code_to_events("a")
193+
reader,_=handle_all_events(events,prepare_console=_prepare_console)
194+
195+
self.assertEqual(len(input_hook.mock_calls),4)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Honor:c:func:`PyOS_InputHook` in the new REPL. Patch by Pablo Galindo

‎Modules/clinic/posixmodule.c.h‎

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Modules/posixmodule.c‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16726,6 +16726,37 @@ os__supports_virtual_terminal_impl(PyObject *module)
1672616726
}
1672716727
#endif
1672816728

16729+
/*[clinic input]
16730+
os._inputhook
16731+
16732+
Calls PyOS_CallInputHook droppong the GIL first
16733+
[clinic start generated code]*/
16734+
16735+
staticPyObject*
16736+
os__inputhook_impl(PyObject*module)
16737+
/*[clinic end generated code: output=525aca4ef3c6149f input=fc531701930d064f]*/
16738+
{
16739+
intresult=0;
16740+
if (PyOS_InputHook) {
16741+
Py_BEGIN_ALLOW_THREADS;
16742+
result=PyOS_InputHook();
16743+
Py_END_ALLOW_THREADS;
16744+
}
16745+
returnPyLong_FromLong(result);
16746+
}
16747+
16748+
/*[clinic input]
16749+
os._is_inputhook_installed
16750+
16751+
Checks if PyOS_CallInputHook is set
16752+
[clinic start generated code]*/
16753+
16754+
staticPyObject*
16755+
os__is_inputhook_installed_impl(PyObject*module)
16756+
/*[clinic end generated code: output=3b3eab4f672c689a input=ff177c9938dd76d8]*/
16757+
{
16758+
returnPyBool_FromLong(PyOS_InputHook!=NULL);
16759+
}
1672916760

1673016761
staticPyMethodDefposix_methods[]= {
1673116762

@@ -16939,6 +16970,8 @@ static PyMethodDef posix_methods[] = {
1693916970
OS__PATH_LEXISTS_METHODDEF
1694016971

1694116972
OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
16973+
OS__INPUTHOOK_METHODDEF
16974+
OS__IS_INPUTHOOK_INSTALLED_METHODDEF
1694216975
{NULL,NULL}/* Sentinel */
1694316976
};
1694416977

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp