Merge ~cjwatson/launchpad:py3-services-print-function into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 17231a0a841aa8396865973f6044310063080618
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:py3-services-print-function
Merge into: launchpad:master
Diff against target: 544 lines (+76/-59)
18 files modified
lib/lp/services/doc/collection.txt (+2/-2)
lib/lp/services/doc/limitedlist.txt (+1/-1)
lib/lp/services/doc/looptuner.txt (+13/-13)
lib/lp/services/doc/orderingcheck.txt (+1/-1)
lib/lp/services/doc/pidfile.txt (+12/-12)
lib/lp/services/doc/propertycache.txt (+2/-2)
lib/lp/services/doc/sprites.txt (+6/-6)
lib/lp/services/doc/tarfile_helpers.txt (+6/-6)
lib/lp/services/features/__init__.py (+1/-1)
lib/lp/services/fields/doc/uri-field.txt (+2/-2)
lib/lp/services/job/celeryconfig.py (+3/-1)
lib/lp/services/librarianserver/tests/test_doc.py (+2/-1)
lib/lp/services/sitesearch/tests/data/blog.launchpad.net-feed.xml (+2/-2)
lib/lp/services/spriteutils.py (+9/-4)
lib/lp/services/tests/test_doc.py (+9/-2)
lib/lp/services/tests/test_helpers.py (+2/-0)
lib/lp/services/webservice/tests/test_wadllib.py (+2/-2)
utilities/lsconf.py (+1/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+398840@code.launchpad.net

Commit message

Convert the rest of lp.services to print_function

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Self-approving, since this is just more of the same.

I think this is in fact the last of the print() conversions, aside from a few scattered references in docstrings and commented-out code and the like.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/services/doc/collection.txt b/lib/lp/services/doc/collection.txt
2index 87bf99f..5d2408c 100644
3--- a/lib/lp/services/doc/collection.txt
4+++ b/lib/lp/services/doc/collection.txt
5@@ -42,12 +42,12 @@ yet until you invoke the "select" method, which returns a Storm result
6 set.
7
8 >>> collection = KumquatCollection()
9- >>> print list(collection.select().order_by(Kumquat.id))
10+ >>> print(list(collection.select().order_by(Kumquat.id)))
11 [Kumquat-1, Kumquat-2]
12
13 Actually, select() is just shorthand for select(Kumquat).
14
15- >>> print list(collection.select(Kumquat).order_by(Kumquat.id))
16+ >>> print(list(collection.select(Kumquat).order_by(Kumquat.id)))
17 [Kumquat-1, Kumquat-2]
18
19 You can also query individual columns.
20diff --git a/lib/lp/services/doc/limitedlist.txt b/lib/lp/services/doc/limitedlist.txt
21index 10f1fed..e8bdf08 100644
22--- a/lib/lp/services/doc/limitedlist.txt
23+++ b/lib/lp/services/doc/limitedlist.txt
24@@ -22,7 +22,7 @@ We can optionally specify the initial content of the sequence. Note that
25 only the last N elements of the second parameter are stored, where N is
26 the given maximum size of the LimitedList.
27
28- >>> LimitedList(3, (0, 'one', 2, 3))
29+ >>> LimitedList(3, (0, six.ensure_str('one'), 2, 3))
30 <LimitedList(3, ['one', 2, 3])>
31
32 If the initial content has more elements than the given maximum length,
33diff --git a/lib/lp/services/doc/looptuner.txt b/lib/lp/services/doc/looptuner.txt
34index 8c83471..56bb62b 100644
35--- a/lib/lp/services/doc/looptuner.txt
36+++ b/lib/lp/services/doc/looptuner.txt
37@@ -52,7 +52,7 @@ architectures, compilers used for the Python interpreter, etc.
38 >>> goal_seconds = 10.0
39 >>> def print_change(last_chunk_size, new_chunk_size):
40 ... if last_chunk_size is None:
41- ... print "start"
42+ ... print("start")
43 ... return
44 ... change = "same"
45 ... if new_chunk_size > last_chunk_size:
46@@ -61,7 +61,7 @@ architectures, compilers used for the Python interpreter, etc.
47 ... change = "decreased"
48 ... ratio = new_chunk_size / last_chunk_size
49 ... order_of_magnitude = math.log10(ratio)
50- ... print "%s (%.1f)" % (change, order_of_magnitude)
51+ ... print("%s (%.1f)" % (change, order_of_magnitude))
52
53 >>> @implementer(ITunableLoop)
54 ... class PlannedLoop:
55@@ -74,7 +74,7 @@ architectures, compilers used for the Python interpreter, etc.
56 ... def isDone(self):
57 ... done = self.iteration >= len(self.timings)
58 ... if done:
59- ... print "done"
60+ ... print("done")
61 ... return done
62 ...
63 ... def __call__(self, chunk_size):
64@@ -197,7 +197,7 @@ This variant of the LoopTuner simulates an overridable cost function:
65 ... def isDone(self):
66 ... done = (self.iteration >= self.counter)
67 ... if done:
68- ... print "done"
69+ ... print("done")
70 ... return done
71 ...
72 ... def __call__(self, chunk_size):
73@@ -379,9 +379,9 @@ but still print out what would happen.
74 >>> class CooldownTuner(LoopTuner):
75 ... def _coolDown(self, bedtime):
76 ... if self.cooldown_time is None or self.cooldown_time <= 0.0:
77- ... print "No cooldown"
78+ ... print("No cooldown")
79 ... else:
80- ... print "Cooldown for %.1f seconds." % self.cooldown_time
81+ ... print("Cooldown for %.1f seconds." % self.cooldown_time)
82 ... return bedtime
83
84 SimpleLoop is a loop that does a constant number of iterations, regardless
85@@ -397,11 +397,11 @@ of the actual run-time.
86 ... def isDone(self):
87 ... done = (self.iteration >= self.total_iterations)
88 ... if done:
89- ... print "done"
90+ ... print("done")
91 ... return done
92 ...
93 ... def __call__(self, chunk_size):
94- ... print "Processing %d items." % (chunk_size)
95+ ... print("Processing %d items." % (chunk_size))
96 ... self.iteration += 1
97
98 Aim for a low goal_seconds (to reduce test runtime), and only 3 iterations.
99@@ -427,7 +427,7 @@ returns time after sleep is done.
100 >>> cooldown_loop = LoopTuner(body, goal_seconds, cooldown_time=0.2)
101 >>> old_time = time.time()
102 >>> new_time = cooldown_loop._coolDown(old_time)
103- >>> print new_time > old_time
104+ >>> print(new_time > old_time)
105 True
106
107 If no cooldown_time is specified, there's no sleep, and exactly the same
108@@ -436,7 +436,7 @@ time is returned.
109 >>> no_cooldown_loop = LoopTuner(body, goal_seconds, cooldown_time=None)
110 >>> old_time = time.time()
111 >>> new_time = no_cooldown_loop._coolDown(old_time)
112- >>> print new_time == old_time
113+ >>> print(new_time == old_time)
114 True
115
116 == Abort Timeout ==
117@@ -454,7 +454,7 @@ than this timeout, it is aborted and a INFO logged.
118 start
119 same (0.0)
120 same (0.0)
121- >>> print logger.getLogBufferAndClear()
122+ >>> print(logger.getLogBufferAndClear())
123 INFO Task aborted after 20 seconds.
124
125
126@@ -466,7 +466,7 @@ the isDone() method, and __del__ is fragile and can never be relied on.
127
128 >>> class PlannedLoopWithCleanup(PlannedLoop):
129 ... def cleanUp(self):
130- ... print 'clean up'
131+ ... print('clean up')
132
133 >>> body = PlannedLoopWithCleanup([])
134 >>> loop = TestTuner(body, goal_seconds, 100)
135@@ -481,6 +481,6 @@ the isDone() method, and __del__ is fragile and can never be relied on.
136 same (0.0)
137 same (0.0)
138 clean up
139- >>> print logger.getLogBufferAndClear()
140+ >>> print(logger.getLogBufferAndClear())
141 INFO Task aborted after 20 seconds.
142
143diff --git a/lib/lp/services/doc/orderingcheck.txt b/lib/lp/services/doc/orderingcheck.txt
144index fe9294f..209b6e0 100644
145--- a/lib/lp/services/doc/orderingcheck.txt
146+++ b/lib/lp/services/doc/orderingcheck.txt
147@@ -75,7 +75,7 @@ ordering, override the "fail" method.
148
149 >>> def alternative_fail(item):
150 ... """Don't raise an error, just print a message."""
151- ... print "Item %s was out of sequence." % item
152+ ... print("Item %s was out of sequence." % item)
153
154 >>> checker = OrderingCheck(key=sort_key)
155 >>> checker.fail = alternative_fail
156diff --git a/lib/lp/services/doc/pidfile.txt b/lib/lp/services/doc/pidfile.txt
157index d0a1728..672d68c 100644
158--- a/lib/lp/services/doc/pidfile.txt
159+++ b/lib/lp/services/doc/pidfile.txt
160@@ -32,8 +32,8 @@ You can pass in your own config instance to use.
161 ... class canonical:
162 ... pid_dir = '/var/tmp'
163 ... instance_name = 'blah'
164- >>> pidfile_path('beans', MyConfig)
165- '/var/tmp/blah-beans.pid'
166+ >>> print(pidfile_path('beans', MyConfig))
167+ /var/tmp/blah-beans.pid
168
169 This basic mechanism supports the other three functions.
170
171@@ -93,24 +93,24 @@ we'll need them again later.
172 ... return real_pid
173 ... time.sleep(0.1)
174 ... else:
175- ... print 'Error: pid file was not created'
176+ ... print('Error: pid file was not created')
177 ...
178 >>> def stop(pid, sig):
179 ... os.kill(pid, sig)
180 ... os.waitpid(pid, 0)
181 ... if not os.path.exists(pidfile_path('nuts')):
182- ... print 'Stopped successfully'
183+ ... print('Stopped successfully')
184 ... else:
185 ... try:
186 ... # Is it still here at all?
187 ... os.kill(pid, 0)
188 ... except OSError as e:
189 ... if e.errno == errno.ESRCH:
190- ... print 'Error: pid file was not removed'
191+ ... print('Error: pid file was not removed')
192 ... else:
193 ... raise
194 ... else:
195- ... print 'Error: process did not exit'
196+ ... print('Error: process did not exit')
197 ...
198
199 Here's our example. We start, and then stop with SIGINT.
200@@ -165,7 +165,7 @@ continuing as normal.
201 True
202 >>> stop(new_pid, signal.SIGTERM)
203 Stopped successfully
204- >>> print get_pid('nuts')
205+ >>> print(get_pid('nuts'))
206 None
207
208
209@@ -197,11 +197,11 @@ You can also pass in your own config instance.
210 ... pid_dir = '/var/tmp'
211 ... instance_name = 'blah'
212 >>> path = pidfile_path('beans', MyConfig)
213- >>> path
214- '/var/tmp/blah-beans.pid'
215+ >>> print(path)
216+ /var/tmp/blah-beans.pid
217 >>> file = open(path, 'w')
218 >>> try:
219- ... print >> file, 72
220+ ... print(72, file=file)
221 ... finally:
222 ... file.close()
223 >>> get_pid('beans', MyConfig)
224@@ -218,7 +218,7 @@ if you are overriding the default SIGTERM signal handler.
225 >>> path = pidfile_path('legumes')
226 >>> file = open(path, 'w')
227 >>> try:
228- ... print >> file, os.getpid()
229+ ... print(os.getpid(), file=file)
230 ... finally:
231 ... file.close()
232 >>> remove_pidfile('legumes')
233@@ -240,7 +240,7 @@ need to match the current process's pid.
234
235 >>> file = open(path, 'w')
236 >>> try:
237- ... print >> file, os.getpid() + 1
238+ ... print(os.getpid() + 1, file=file)
239 ... finally:
240 ... file.close()
241 >>> remove_pidfile('pits', MyConfig)
242diff --git a/lib/lp/services/doc/propertycache.txt b/lib/lp/services/doc/propertycache.txt
243index 4930b01..d8af5ff 100644
244--- a/lib/lp/services/doc/propertycache.txt
245+++ b/lib/lp/services/doc/propertycache.txt
246@@ -140,8 +140,8 @@ as "a_in_cache" in the cache.
247
248 >>> isinstance(Foo.a, CachedProperty)
249 True
250- >>> Foo.a.name
251- 'a_in_cache'
252+ >>> print(Foo.a.name)
253+ a_in_cache
254 >>> Foo.a.populate
255 <function ...a at 0x...>
256
257diff --git a/lib/lp/services/doc/sprites.txt b/lib/lp/services/doc/sprites.txt
258index ccdfcea..8c8d692 100644
259--- a/lib/lp/services/doc/sprites.txt
260+++ b/lib/lp/services/doc/sprites.txt
261@@ -75,7 +75,7 @@ is currently zero.
262 >>> sprite_util.combineImages(icing)
263 >>> sprite_util.savePNG(new_png_file.name)
264 >>> image = Image.open(new_png_file.name)
265- >>> print image.size
266+ >>> print(image.size)
267 (14, 55)
268
269 The height will increase when the margin is increased.
270@@ -84,7 +84,7 @@ The height will increase when the margin is increased.
271 >>> sprite_util.combineImages(icing)
272 >>> sprite_util.savePNG(new_png_file.name)
273 >>> image = Image.open(new_png_file.name)
274- >>> print image.size
275+ >>> print(image.size)
276 (14, 455)
277
278
279@@ -96,7 +96,7 @@ image file. This allows the css file to be regenerated when the template
280 changes without requiring the combined image file to be recreated.
281
282 >>> sprite_util.savePositioning(new_positioning_file.name)
283- >>> print new_positioning_file.read()
284+ >>> print(new_positioning_file.read())
285 /*...
286 {
287 "../images/add.png": [
288@@ -115,13 +115,13 @@ changes without requiring the combined image file to be recreated.
289
290 The positions attribute can be cleared and loaded from the file.
291
292- >>> print pretty(sprite_util.positions)
293+ >>> print(pretty(sprite_util.positions))
294 {'../images/add.png': (0, -114),
295 '../images/blue-bar.png': (0, -342),
296 '../images/edit.png': (0, -228)}
297 >>> sprite_util.positions = None
298 >>> sprite_util.loadPositioning(new_positioning_file.name)
299- >>> print pretty(sprite_util.positions)
300+ >>> print(pretty(sprite_util.positions))
301 {'../images/add.png': [0, -114],
302 '../images/blue-bar.png': [0, -342],
303 '../images/edit.png': [0, -228]}
304@@ -138,7 +138,7 @@ referenced /@@/add.png, which was only added once to the combined file.
305 is not group1.png, since its sprite-ref is "group2".
306
307 >>> sprite_util.saveConvertedCSS(new_css_file.name, 'group1.png')
308- >>> print new_css_file.read()
309+ >>> print(new_css_file.read())
310 /*...
311 .add {
312 background-image: url(group1.png);
313diff --git a/lib/lp/services/doc/tarfile_helpers.txt b/lib/lp/services/doc/tarfile_helpers.txt
314index 9748d38..59b809f 100644
315--- a/lib/lp/services/doc/tarfile_helpers.txt
316+++ b/lib/lp/services/doc/tarfile_helpers.txt
317@@ -23,15 +23,15 @@ output we will get.
318 ... file = tar.extractfile(member)
319 ...
320 ... if file is not None:
321- ... print format % (
322- ... member.name, six.ensure_text(file.read()))
323+ ... print(format % (
324+ ... member.name, six.ensure_text(file.read())))
325 ... else:
326- ... print format % (member.name, '')
327+ ... print(format % (member.name, ''))
328 ... elif member.type == tarfile.SYMTYPE:
329- ... print format % (
330- ... member.name, "<link to %s>" % member.linkname)
331+ ... print(format % (
332+ ... member.name, "<link to %s>" % member.linkname))
333 ... elif member.type == tarfile.DIRTYPE:
334- ... print format % (member.name, "<directory>")
335+ ... print(format % (member.name, "<directory>"))
336
337 # Start off by creating a blank archive.
338 # We'll need a filehandle to store it in.
339diff --git a/lib/lp/services/features/__init__.py b/lib/lp/services/features/__init__.py
340index 6604472..7ee4895 100644
341--- a/lib/lp/services/features/__init__.py
342+++ b/lib/lp/services/features/__init__.py
343@@ -123,7 +123,7 @@ and if you want to use the value ::
344
345 value = features.getFeatureFlag('example_flag.enabled')
346 if value:
347- print value
348+ print(value)
349
350 Checking flags without access to the database
351 =============================================
352diff --git a/lib/lp/services/fields/doc/uri-field.txt b/lib/lp/services/fields/doc/uri-field.txt
353index f4c9c00..bd8ff8c 100644
354--- a/lib/lp/services/fields/doc/uri-field.txt
355+++ b/lib/lp/services/fields/doc/uri-field.txt
356@@ -170,7 +170,7 @@ URIs with an authority but a blank path get canonicalised to a path of
357 None is an acceptable value for a URI field.
358
359 >>> field = URIField(__name__='foo', title=u'Foo')
360- >>> print field.normalize(None)
361+ >>> print(field.normalize(None))
362 None
363
364
365@@ -196,7 +196,7 @@ This widget is registered as an input widget:
366 >>> field = IURIFieldTest['field'].bind(context)
367 >>> request = LaunchpadTestRequest()
368 >>> widget = getMultiAdapter((field, request), IInputWidget)
369- >>> print widget
370+ >>> print(widget)
371 <lp.app.widgets.textwidgets.URIWidget object at ...>
372
373 Multiple values will cause an UnexpectedFormData exception:
374diff --git a/lib/lp/services/job/celeryconfig.py b/lib/lp/services/job/celeryconfig.py
375index b830826..dcc931e 100644
376--- a/lib/lp/services/job/celeryconfig.py
377+++ b/lib/lp/services/job/celeryconfig.py
378@@ -1,6 +1,8 @@
379 # Copyright 2012-2019 Canonical Ltd. This software is licensed under the
380 # GNU Affero General Public License version 3 (see the file LICENSE).
381
382+from __future__ import absolute_import, print_function
383+
384 from datetime import timedelta
385 import sys
386
387@@ -118,5 +120,5 @@ def configure(argv):
388 try:
389 globals().update(configure(getattr(sys, 'argv', [''])))
390 except ConfigurationError as error:
391- print >>sys.stderr, error
392+ print(error, file=sys.stderr)
393 sys.exit(1)
394diff --git a/lib/lp/services/librarianserver/tests/test_doc.py b/lib/lp/services/librarianserver/tests/test_doc.py
395index 6a9ed9c..613acf3 100644
396--- a/lib/lp/services/librarianserver/tests/test_doc.py
397+++ b/lib/lp/services/librarianserver/tests/test_doc.py
398@@ -150,4 +150,5 @@ special = {
399
400
401 def test_suite():
402- return build_test_suite(here, special)
403+ return build_test_suite(
404+ here, special, setUp=lambda test: setUp(future=True))
405diff --git a/lib/lp/services/sitesearch/tests/data/blog.launchpad.net-feed.xml b/lib/lp/services/sitesearch/tests/data/blog.launchpad.net-feed.xml
406index 562dd87..93dd442 100644
407--- a/lib/lp/services/sitesearch/tests/data/blog.launchpad.net-feed.xml
408+++ b/lib/lp/services/sitesearch/tests/data/blog.launchpad.net-feed.xml
409@@ -65,13 +65,13 @@
410 <p>Don&#8217;t do this:</p>
411 <pre>
412 if bug.person is not None:
413- print bug.person.name
414+ print(bug.person.name)
415 </pre>
416 <p>instead</p>
417 <pre>
418 p = bug.person
419 if p is not None:
420- print p.name
421+ print(p.name)
422 </pre>
423 <p>In the first case, the client may fetch the Person object twice. (We may fix this in future.)</p>
424 ]]></content:encoded>
425diff --git a/lib/lp/services/spriteutils.py b/lib/lp/services/spriteutils.py
426index 21ccddb..826e36a 100644
427--- a/lib/lp/services/spriteutils.py
428+++ b/lib/lp/services/spriteutils.py
429@@ -6,6 +6,8 @@
430
431 """Library to create sprites."""
432
433+from __future__ import absolute_import, print_function
434+
435 __metaclass__ = type
436
437 __all__ = [
438@@ -160,8 +162,10 @@ class SpriteUtil:
439 try:
440 sprite_images[sprite['filename']] = Image.open(abs_filename)
441 except IOError:
442- print >> sys.stderr, "Error opening '%s' for %s css rule" % (
443- abs_filename, sprite['rule'].selectorText)
444+ print(
445+ "Error opening '%s' for %s css rule" % (
446+ abs_filename, sprite['rule'].selectorText),
447+ file=sys.stderr)
448 raise
449 width, height = sprite_images[sprite['filename']].size
450 max_sprite_width = max(width, max_sprite_width)
451@@ -194,8 +198,9 @@ class SpriteUtil:
452 position[0] = x_position
453 combined_image.paste(sprite_image, tuple(position))
454 except:
455- print >> sys.stderr, (
456- "Error with image file %s" % sprite['filename'])
457+ print(
458+ "Error with image file %s" % sprite['filename'],
459+ file=sys.stderr)
460 raise
461 # This is the position of the combined image on an HTML
462 # element. Therefore, it subtracts the position of the
463diff --git a/lib/lp/services/tests/test_doc.py b/lib/lp/services/tests/test_doc.py
464index 5a4a7a1..d15b126 100644
465--- a/lib/lp/services/tests/test_doc.py
466+++ b/lib/lp/services/tests/test_doc.py
467@@ -9,7 +9,11 @@ import os
468
469 from lp.services.testing import build_test_suite
470 from lp.testing.layers import BaseLayer
471-from lp.testing.systemdocs import LayeredDocFileSuite
472+from lp.testing.systemdocs import (
473+ LayeredDocFileSuite,
474+ setGlobs,
475+ setUp,
476+ )
477
478
479 here = os.path.dirname(os.path.realpath(__file__))
480@@ -18,12 +22,15 @@ here = os.path.dirname(os.path.realpath(__file__))
481 special = {
482 'limitedlist.txt': LayeredDocFileSuite(
483 '../doc/limitedlist.txt',
484+ setUp=lambda test: setGlobs(test, future=True),
485 layer=BaseLayer),
486 'propertycache.txt': LayeredDocFileSuite(
487 '../doc/propertycache.txt',
488+ setUp=lambda test: setGlobs(test, future=True),
489 layer=BaseLayer),
490 }
491
492
493 def test_suite():
494- return build_test_suite(here, special)
495+ return build_test_suite(
496+ here, special, setUp=lambda test: setUp(test, future=True))
497diff --git a/lib/lp/services/tests/test_helpers.py b/lib/lp/services/tests/test_helpers.py
498index 4a1aa84..b0383dc 100644
499--- a/lib/lp/services/tests/test_helpers.py
500+++ b/lib/lp/services/tests/test_helpers.py
501@@ -1,6 +1,8 @@
502 # Copyright 2009-2018 Canonical Ltd. This software is licensed under the
503 # GNU Affero General Public License version 3 (see the file LICENSE).
504
505+from __future__ import absolute_import, print_function
506+
507 from doctest import DocTestSuite
508 from textwrap import dedent
509 import unittest
510diff --git a/lib/lp/services/webservice/tests/test_wadllib.py b/lib/lp/services/webservice/tests/test_wadllib.py
511index 10a7238..07134b4 100644
512--- a/lib/lp/services/webservice/tests/test_wadllib.py
513+++ b/lib/lp/services/webservice/tests/test_wadllib.py
514@@ -8,7 +8,7 @@ from __future__ import absolute_import, print_function
515 __metaclass__ = type
516 __all__ = ['test_suite']
517
518-
519+import __future__
520 import os
521 import unittest
522
523@@ -23,7 +23,7 @@ topdir = os.path.dirname(wadllib.__file__)
524
525 def setUp(test):
526 for future_item in 'absolute_import', 'print_function':
527- test.globs[future_item] = getattr(globals(), future_item)
528+ test.globs[future_item] = getattr(__future__, future_item)
529
530
531 def test_suite():
532diff --git a/utilities/lsconf.py b/utilities/lsconf.py
533index c6306d7..8eab198 100755
534--- a/utilities/lsconf.py
535+++ b/utilities/lsconf.py
536@@ -82,7 +82,7 @@ class Configuration:
537 continue
538 if count > 0:
539 # Separate sections by a blank line, or two when verbose.
540- print
541+ print()
542 print('[%s]' % section.name)
543 if verbose and section.optional:
544 print('# This section is optional.\n')

Subscribers

People subscribed via source and target branches

to status/vote changes: