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

Skip to content

Commit 6840a54

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.
1 parent 4050792 commit 6840a54

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
@@ -8,10 +8,13 @@
88
import sys
99
import imp
1010
import unittest
11+
import shutil
12+
import subprocess
1113
import sysconfig
1214
import tempfile
15+
import textwrap
1316
from test import support
14-
from test.script_helper import assert_python_ok
17+
from test.script_helper import assert_python_ok, temp_dir
1518

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

3740

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

773+
- Issue #15539: Added regression tests for Tools/scripts/pindent.py.
774+
773775
- Issue #15324: Fix regrtest parsing of --fromfile, --match, and --randomize
774776
options.
775777

@@ -951,6 +953,11 @@ Documentation
951953
Tools/Demos
952954
-----------
953955

956+
- Issue #15539: Fix a number of bugs in Tools/scripts/pindent.py. Now
957+
pindent.py works with a "with" statement. pindent.py no longer produces
958+
improper indentation. pindent.py now works with continued lines broken after
959+
"class" or "def" keywords and with continuations at the start of line.
960+
954961
- Issue #15378: Fix Tools/unicode/comparecodecs.py. Patch by Serhiy Storchaka.
955962

956963
- Issue #14695: Fix missing support for starred assignments in

0 commit comments

Comments
 (0)