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

Skip to content

Commit 40ce22e

Browse files
Issue #15539: Fix a number of bugs in Tools/scripts/pindent.py.
Now pindent.py works with a "with" statement. pindent.py no longer produces improper indentation. pindent.py now works with continued lines broken after "class" or "def" keywords and with continuations at the start of line. Added regression tests for pindent.py. Modernized pindent.py.
2 parents 5a4b03d + 6840a54 commit 40ce22e

3 files changed

Lines changed: 392 additions & 105 deletions

File tree

Lib/test/test_tools.py

Lines changed: 325 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
import importlib.machinery
1010
import unittest
1111
from unittest import mock
12+
import shutil
13+
import subprocess
1214
import sysconfig
1315
import tempfile
16+
import textwrap
1417
from test import support
15-
from test.script_helper import assert_python_ok
18+
from test.script_helper import assert_python_ok, temp_dir
1619

1720
if not sysconfig.is_python_build():
1821
# XXX some installers do contain the tools, should we detect that
@@ -36,6 +39,327 @@ def test_help(self):
3639
self.assertGreater(err, b'')
3740

3841

42+
class PindentTests(unittest.TestCase):
43+
script = os.path.join(scriptsdir, 'pindent.py')
44+
45+
def assertFileEqual(self, fn1, fn2):
46+
with open(fn1) as f1, open(fn2) as f2:
47+
self.assertEqual(f1.readlines(), f2.readlines())
48+
49+
def pindent(self, source, *args):
50+
with subprocess.Popen(
51+
(sys.executable, self.script) + args,
52+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
53+
universal_newlines=True) as proc:
54+
out, err = proc.communicate(source)
55+
self.assertIsNone(err)
56+
return out
57+
58+
def lstriplines(self, data):
59+
return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n'
60+
61+
def test_selftest(self):
62+
with temp_dir() as directory:
63+
data_path = os.path.join(directory, '_test.py')
64+
with open(self.script) as f:
65+
closed = f.read()
66+
with open(data_path, 'w') as f:
67+
f.write(closed)
68+
69+
rc, out, err = assert_python_ok(self.script, '-d', data_path)
70+
self.assertEqual(out, b'')
71+
self.assertEqual(err, b'')
72+
backup = data_path + '~'
73+
self.assertTrue(os.path.exists(backup))
74+
with open(backup) as f:
75+
self.assertEqual(f.read(), closed)
76+
with open(data_path) as f:
77+
clean = f.read()
78+
compile(clean, '_test.py', 'exec')
79+
self.assertEqual(self.pindent(clean, '-c'), closed)
80+
self.assertEqual(self.pindent(closed, '-d'), clean)
81+
82+
rc, out, err = assert_python_ok(self.script, '-c', data_path)
83+
self.assertEqual(out, b'')
84+
self.assertEqual(err, b'')
85+
with open(backup) as f:
86+
self.assertEqual(f.read(), clean)
87+
with open(data_path) as f:
88+
self.assertEqual(f.read(), closed)
89+
90+
broken = self.lstriplines(closed)
91+
with open(data_path, 'w') as f:
92+
f.write(broken)
93+
rc, out, err = assert_python_ok(self.script, '-r', data_path)
94+
self.assertEqual(out, b'')
95+
self.assertEqual(err, b'')
96+
with open(backup) as f:
97+
self.assertEqual(f.read(), broken)
98+
with open(data_path) as f:
99+
indented = f.read()
100+
compile(indented, '_test.py', 'exec')
101+
self.assertEqual(self.pindent(broken, '-r'), indented)
102+
103+
def pindent_test(self, clean, closed):
104+
self.assertEqual(self.pindent(clean, '-c'), closed)
105+
self.assertEqual(self.pindent(closed, '-d'), clean)
106+
broken = self.lstriplines(closed)
107+
self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed)
108+
109+
def test_statements(self):
110+
clean = textwrap.dedent("""\
111+
if a:
112+
pass
113+
114+
if a:
115+
pass
116+
else:
117+
pass
118+
119+
if a:
120+
pass
121+
elif:
122+
pass
123+
else:
124+
pass
125+
126+
while a:
127+
break
128+
129+
while a:
130+
break
131+
else:
132+
pass
133+
134+
for i in a:
135+
break
136+
137+
for i in a:
138+
break
139+
else:
140+
pass
141+
142+
try:
143+
pass
144+
finally:
145+
pass
146+
147+
try:
148+
pass
149+
except TypeError:
150+
pass
151+
except ValueError:
152+
pass
153+
else:
154+
pass
155+
156+
try:
157+
pass
158+
except TypeError:
159+
pass
160+
except ValueError:
161+
pass
162+
finally:
163+
pass
164+
165+
with a:
166+
pass
167+
168+
class A:
169+
pass
170+
171+
def f():
172+
pass
173+
""")
174+
175+
closed = textwrap.dedent("""\
176+
if a:
177+
pass
178+
# end if
179+
180+
if a:
181+
pass
182+
else:
183+
pass
184+
# end if
185+
186+
if a:
187+
pass
188+
elif:
189+
pass
190+
else:
191+
pass
192+
# end if
193+
194+
while a:
195+
break
196+
# end while
197+
198+
while a:
199+
break
200+
else:
201+
pass
202+
# end while
203+
204+
for i in a:
205+
break
206+
# end for
207+
208+
for i in a:
209+
break
210+
else:
211+
pass
212+
# end for
213+
214+
try:
215+
pass
216+
finally:
217+
pass
218+
# end try
219+
220+
try:
221+
pass
222+
except TypeError:
223+
pass
224+
except ValueError:
225+
pass
226+
else:
227+
pass
228+
# end try
229+
230+
try:
231+
pass
232+
except TypeError:
233+
pass
234+
except ValueError:
235+
pass
236+
finally:
237+
pass
238+
# end try
239+
240+
with a:
241+
pass
242+
# end with
243+
244+
class A:
245+
pass
246+
# end class A
247+
248+
def f():
249+
pass
250+
# end def f
251+
""")
252+
self.pindent_test(clean, closed)
253+
254+
def test_multilevel(self):
255+
clean = textwrap.dedent("""\
256+
def foobar(a, b):
257+
if a == b:
258+
a = a+1
259+
elif a < b:
260+
b = b-1
261+
if b > a: a = a-1
262+
else:
263+
print 'oops!'
264+
""")
265+
closed = textwrap.dedent("""\
266+
def foobar(a, b):
267+
if a == b:
268+
a = a+1
269+
elif a < b:
270+
b = b-1
271+
if b > a: a = a-1
272+
# end if
273+
else:
274+
print 'oops!'
275+
# end if
276+
# end def foobar
277+
""")
278+
self.pindent_test(clean, closed)
279+
280+
def test_preserve_indents(self):
281+
clean = textwrap.dedent("""\
282+
if a:
283+
if b:
284+
pass
285+
""")
286+
closed = textwrap.dedent("""\
287+
if a:
288+
if b:
289+
pass
290+
# end if
291+
# end if
292+
""")
293+
self.assertEqual(self.pindent(clean, '-c'), closed)
294+
self.assertEqual(self.pindent(closed, '-d'), clean)
295+
broken = self.lstriplines(closed)
296+
self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed)
297+
clean = textwrap.dedent("""\
298+
if a:
299+
\tif b:
300+
\t\tpass
301+
""")
302+
closed = textwrap.dedent("""\
303+
if a:
304+
\tif b:
305+
\t\tpass
306+
\t# end if
307+
# end if
308+
""")
309+
self.assertEqual(self.pindent(clean, '-c'), closed)
310+
self.assertEqual(self.pindent(closed, '-d'), clean)
311+
broken = self.lstriplines(closed)
312+
self.assertEqual(self.pindent(broken, '-r'), closed)
313+
314+
def test_escaped_newline(self):
315+
clean = textwrap.dedent("""\
316+
class\\
317+
\\
318+
A:
319+
def\
320+
\\
321+
f:
322+
pass
323+
""")
324+
closed = textwrap.dedent("""\
325+
class\\
326+
\\
327+
A:
328+
def\
329+
\\
330+
f:
331+
pass
332+
# end def f
333+
# end class A
334+
""")
335+
self.assertEqual(self.pindent(clean, '-c'), closed)
336+
self.assertEqual(self.pindent(closed, '-d'), clean)
337+
338+
def test_empty_line(self):
339+
clean = textwrap.dedent("""\
340+
if a:
341+
342+
pass
343+
""")
344+
closed = textwrap.dedent("""\
345+
if a:
346+
347+
pass
348+
# end if
349+
""")
350+
self.pindent_test(clean, closed)
351+
352+
def test_oneline(self):
353+
clean = textwrap.dedent("""\
354+
if a: pass
355+
""")
356+
closed = textwrap.dedent("""\
357+
if a: pass
358+
# end if
359+
""")
360+
self.pindent_test(clean, closed)
361+
362+
39363
class TestSundryScripts(unittest.TestCase):
40364
# At least make sure the rest don't have syntax errors. When tests are
41365
# added for a script it should be added to the whitelist below.

Misc/NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ Library
424424
Tests
425425
-----
426426

427+
- Issue #15539: Added regression tests for Tools/scripts/pindent.py.
428+
427429
- Issue #16925: test_configparser now works with unittest test discovery.
428430
Patch by Zachary Ware.
429431

@@ -571,6 +573,11 @@ Documentation
571573
Tools/Demos
572574
-----------
573575

576+
- Issue #15539: Fix a number of bugs in Tools/scripts/pindent.py. Now
577+
pindent.py works with a "with" statement. pindent.py no longer produces
578+
improper indentation. pindent.py now works with continued lines broken after
579+
"class" or "def" keywords and with continuations at the start of line.
580+
574581
- Issue #15378: Fix Tools/unicode/comparecodecs.py. Patch by Serhiy Storchaka.
575582

576583

0 commit comments

Comments
 (0)