Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d4aa4c8

Browse files
author
michaelj094
committed
fix: Removing leading indentation #15089
1 parent 4d71bcf commit d4aa4c8

2 files changed

Lines changed: 72 additions & 5 deletions

File tree

IPython/core/inputtransformer2.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,58 @@ class PromptStripper:
6767
If any prompt is found on the first two lines,
6868
prompts will be stripped from the rest of the block.
6969
"""
70-
def __init__(self, prompt_re, initial_re=None):
70+
def __init__(self, prompt_re, initial_re=None, *, doctest=False):
7171
self.prompt_re = prompt_re
7272
self.initial_re = initial_re or prompt_re
73+
self.doctest = doctest
74+
if doctest:
75+
# Doctest/xdoctest prompts may be indented (e.g. " >>>").
76+
# We only treat "..." as a continuation prompt when the same pasted
77+
# block contains at least one ">>>" line, to avoid ambiguity with the
78+
# Python Ellipsis literal.
79+
self._doctest_initial_re = re.compile(r'^\s*>>>')
80+
self._doctest_ps1_re = re.compile(r'^\s*>>>\s?')
81+
self._doctest_ps2_re = re.compile(r'^\s*\.\.\.\s?')
7382

7483
def _strip(self, lines):
7584
return [self.prompt_re.sub('', l, count=1) for l in lines]
7685

7786
def __call__(self, lines):
7887
if not lines:
7988
return lines
89+
90+
if self.doctest:
91+
if not any(self._doctest_initial_re.match(l) for l in lines):
92+
return lines
93+
94+
stripped_any = False
95+
out_lines = []
96+
for l in lines:
97+
if self._doctest_ps1_re.match(l):
98+
new_l = self._doctest_ps1_re.sub('', l, count=1)
99+
elif self._doctest_ps2_re.match(l):
100+
new_l = self._doctest_ps2_re.sub('', l, count=1)
101+
else:
102+
new_l = l
103+
stripped_any = stripped_any or (new_l != l)
104+
out_lines.append(new_l)
105+
106+
if not stripped_any:
107+
return out_lines
108+
109+
# Only dedent when we actually stripped doctest prompts, so we don't
110+
# change the indentation semantics of normal pastes.
111+
return dedent(''.join(out_lines)).splitlines(keepends=True)
112+
80113
if self.initial_re.match(lines[0]) or \
81114
(len(lines) > 1 and self.prompt_re.match(lines[1])):
82115
return self._strip(lines)
83116
return lines
84117

85118
classic_prompt = PromptStripper(
86119
prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
87-
initial_re=re.compile(r'^>>>( |$)')
120+
initial_re=re.compile(r'^>>>( |$)'),
121+
doctest=True,
88122
)
89123

90124
ipython_prompt = PromptStripper(

tests/test_inputtransformer2_line.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,47 @@ def test_cell_magic():
4646
""",
4747
"""\
4848
for a in range(5):
49-
print(a)
50-
print(a ** 2)
49+
... print(a)
50+
... print(a ** 2)
51+
""",
52+
)
53+
54+
CLASSIC_PROMPT_DEDENT_SINGLE_LINE = (
55+
">>> print(1)\n",
56+
"print(1)\n",
57+
)
58+
59+
CLASSIC_PROMPT_DEDENT_LEADING_WS = (
60+
" >>> print(1)\n",
61+
"print(1)\n",
62+
)
63+
64+
CLASSIC_PROMPT_MULTILINE_DOCTEST = (
65+
"""\
66+
>>> for i in range(2):
67+
... print(i)
68+
""",
69+
"""\
70+
for i in range(2):
71+
print(i)
5172
""",
5273
)
5374

75+
CLASSIC_PROMPT_STANDALONE_CONTINUATION = (
76+
"... print(1)\n",
77+
"... print(1)\n",
78+
)
79+
5480

5581
def test_classic_prompt():
56-
for sample, expected in [CLASSIC_PROMPT, CLASSIC_PROMPT_L2]:
82+
for sample, expected in [
83+
CLASSIC_PROMPT,
84+
CLASSIC_PROMPT_L2,
85+
CLASSIC_PROMPT_DEDENT_SINGLE_LINE,
86+
CLASSIC_PROMPT_DEDENT_LEADING_WS,
87+
CLASSIC_PROMPT_MULTILINE_DOCTEST,
88+
CLASSIC_PROMPT_STANDALONE_CONTINUATION,
89+
]:
5790
assert ipt2.classic_prompt(
5891
sample.splitlines(keepends=True)
5992
) == expected.splitlines(keepends=True)

0 commit comments

Comments
 (0)