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

Commit7d111da

Browse files
saucoideambv
andauthored
gh-121610: pyrepl - handle extending blocks when multi-statement blocks are pasted (GH-121757)
console.compile with the "single" param throws an exception whenthere are multiple statements, never allowing to adding newlinesto a pasted code block (gh-121610)This add a few extra checks to allow extending when in an indentedblock, and tests for a few examplesCo-authored-by: Łukasz Langa <lukasz@langa.pl>
1 parent2b1b689 commit7d111da

File tree

2 files changed

+123
-11
lines changed

2 files changed

+123
-11
lines changed

‎Lib/_pyrepl/simple_interact.py‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import_sitebuiltins
2929
importlinecache
30+
importfunctools
3031
importsys
3132
importcode
3233

@@ -78,6 +79,25 @@ def _clear_screen():
7879
}
7980

8081

82+
def_more_lines(console:code.InteractiveConsole,unicodetext:str)->bool:
83+
# ooh, look at the hack:
84+
src=_strip_final_indent(unicodetext)
85+
try:
86+
code=console.compile(src,"<stdin>","single")
87+
except (OverflowError,SyntaxError,ValueError):
88+
lines=src.splitlines(keepends=True)
89+
iflen(lines)==1:
90+
returnFalse
91+
92+
last_line=lines[-1]
93+
was_indented=last_line.startswith((" ","\t"))
94+
not_empty=last_line.strip()!=""
95+
incomplete=notlast_line.endswith("\n")
96+
return (was_indentedornot_empty)andincomplete
97+
else:
98+
returncodeisNone
99+
100+
81101
defrun_multiline_interactive_console(
82102
console:code.InteractiveConsole,
83103
*,
@@ -88,6 +108,7 @@ def run_multiline_interactive_console(
88108
iffuture_flags:
89109
console.compile.compiler.flags|=future_flags
90110

111+
more_lines=functools.partial(_more_lines,console)
91112
input_n=0
92113

93114
defmaybe_run_command(statement:str)->bool:
@@ -113,16 +134,6 @@ def maybe_run_command(statement: str) -> bool:
113134

114135
returnFalse
115136

116-
defmore_lines(unicodetext:str)->bool:
117-
# ooh, look at the hack:
118-
src=_strip_final_indent(unicodetext)
119-
try:
120-
code=console.compile(src,"<stdin>","single")
121-
except (OverflowError,SyntaxError,ValueError):
122-
returnFalse
123-
else:
124-
returncodeisNone
125-
126137
while1:
127138
try:
128139
try:

‎Lib/test/test_pyrepl/test_interact.py‎

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
fromtest.supportimportforce_not_colorized
88

99
from_pyrepl.consoleimportInteractiveColoredConsole
10-
10+
from_pyrepl.simple_interactimport_more_lines
1111

1212
classTestSimpleInteract(unittest.TestCase):
1313
deftest_multiple_statements(self):
@@ -111,3 +111,104 @@ def test_no_active_future(self):
111111
result=console.runsource(source)
112112
self.assertFalse(result)
113113
self.assertEqual(f.getvalue(),"{'x': <class 'int'>}\n")
114+
115+
116+
classTestMoreLines(unittest.TestCase):
117+
deftest_invalid_syntax_single_line(self):
118+
namespace= {}
119+
code="if foo"
120+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
121+
self.assertFalse(_more_lines(console,code))
122+
123+
deftest_empty_line(self):
124+
namespace= {}
125+
code=""
126+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
127+
self.assertFalse(_more_lines(console,code))
128+
129+
deftest_valid_single_statement(self):
130+
namespace= {}
131+
code="foo = 1"
132+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
133+
self.assertFalse(_more_lines(console,code))
134+
135+
deftest_multiline_single_assignment(self):
136+
namespace= {}
137+
code=dedent("""\
138+
foo = [
139+
1,
140+
2,
141+
3,
142+
]""")
143+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
144+
self.assertFalse(_more_lines(console,code))
145+
146+
deftest_multiline_single_block(self):
147+
namespace= {}
148+
code=dedent("""\
149+
def foo():
150+
'''docs'''
151+
152+
return 1""")
153+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
154+
self.assertTrue(_more_lines(console,code))
155+
156+
deftest_multiple_statements_single_line(self):
157+
namespace= {}
158+
code="foo = 1;bar = 2"
159+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
160+
self.assertFalse(_more_lines(console,code))
161+
162+
deftest_multiple_statements(self):
163+
namespace= {}
164+
code=dedent("""\
165+
import time
166+
167+
foo = 1""")
168+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
169+
self.assertTrue(_more_lines(console,code))
170+
171+
deftest_multiple_blocks(self):
172+
namespace= {}
173+
code=dedent("""\
174+
from dataclasses import dataclass
175+
176+
@dataclass
177+
class Point:
178+
x: float
179+
y: float""")
180+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
181+
self.assertTrue(_more_lines(console,code))
182+
183+
deftest_multiple_blocks_empty_newline(self):
184+
namespace= {}
185+
code=dedent("""\
186+
from dataclasses import dataclass
187+
188+
@dataclass
189+
class Point:
190+
x: float
191+
y: float
192+
""")
193+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
194+
self.assertFalse(_more_lines(console,code))
195+
196+
deftest_multiple_blocks_indented_newline(self):
197+
namespace= {}
198+
code= (
199+
"from dataclasses import dataclass\n"
200+
"\n"
201+
"@dataclass\n"
202+
"class Point:\n"
203+
" x: float\n"
204+
" y: float\n"
205+
" "
206+
)
207+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
208+
self.assertFalse(_more_lines(console,code))
209+
210+
deftest_incomplete_statement(self):
211+
namespace= {}
212+
code="if foo:"
213+
console=InteractiveColoredConsole(namespace,filename="<stdin>")
214+
self.assertTrue(_more_lines(console,code))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp