Merge lp:~logan/ubuntu/quantal/zconfig/new-upstream into lp:ubuntu/quantal/zconfig

Proposed by Logan Rosen
Status: Merged
Merged at revision: 9
Proposed branch: lp:~logan/ubuntu/quantal/zconfig/new-upstream
Merge into: lp:ubuntu/quantal/zconfig
Diff against target: 1219 lines (+557/-189)
24 files modified
NEWS.txt (+26/-0)
PKG-INFO (+28/-2)
ZConfig.egg-info/PKG-INFO (+28/-2)
ZConfig/cfgparser.py (+2/-1)
ZConfig/components/basic/tests/test_mapping.py (+4/-3)
ZConfig/components/logger/loghandler.py (+6/-2)
ZConfig/components/logger/tests/test_logger.py (+112/-93)
ZConfig/datatypes.py (+37/-6)
ZConfig/tests/support.py (+4/-2)
ZConfig/tests/test_cfgimports.py (+2/-1)
ZConfig/tests/test_cmdline.py (+4/-4)
ZConfig/tests/test_config.py (+3/-1)
ZConfig/tests/test_cookbook.py (+2/-3)
ZConfig/tests/test_datatypes.py (+12/-1)
ZConfig/tests/test_loader.py (+2/-2)
ZConfig/tests/test_readme.py (+12/-10)
ZConfig/tests/test_schema.py (+2/-2)
ZConfig/tests/test_schemaless.py (+1/-4)
bootstrap.py (+237/-29)
buildout.cfg (+8/-3)
debian/changelog (+7/-0)
debian/control (+1/-1)
doc/zconfig.tex (+7/-5)
setup.py (+10/-12)
To merge this branch: bzr merge lp:~logan/ubuntu/quantal/zconfig/new-upstream
Reviewer Review Type Date Requested Status
Barry Warsaw (community) Approve
Ubuntu branches Pending
Review via email: mp+115046@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :

Looks good, thanks! I will sponsor it. Please submit a bug in Debian for them to update to the latest version, and then create a bug in Launchpad that links to it. This way, we can resync to Debian when the new version is available there.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.txt'
2--- NEWS.txt 2011-03-24 18:29:45 +0000
3+++ NEWS.txt 2012-07-15 23:54:18 +0000
4@@ -3,6 +3,32 @@
5 ==========================
6
7
8+ZConfig 2.9.3 (2012-06-25)
9+--------------------------
10+
11+- Fixed: port values of 0 weren't allowed. Port 0 is used to request
12+ an ephemeral port.
13+
14+ZConfig 2.9.2 (2012-02-11)
15+--------------------------
16+
17+- Adjust test classes to avoid base classes being considered separate
18+ test cases by (at least) the "nose" test runner.
19+
20+
21+ZConfig 2.9.1 (2012-02-11)
22+--------------------------
23+
24+- Make FileHandler.reopen thread safe.
25+
26+
27+ZConfig 2.9.0 (2011-03-22)
28+--------------------------
29+
30+- Allow identical redefinition of ``%define`` names.
31+- Added support for IPv6 addresses.
32+
33+
34 ZConfig 2.8.0 (2010-04-13)
35 --------------------------
36
37
38=== modified file 'PKG-INFO'
39--- PKG-INFO 2011-03-24 18:29:45 +0000
40+++ PKG-INFO 2012-07-15 23:54:18 +0000
41@@ -1,6 +1,6 @@
42 Metadata-Version: 1.0
43 Name: ZConfig
44-Version: 2.8.0
45+Version: 2.9.3
46 Summary: Structured Configuration Library
47 Home-page: http://www.zope.org/Members/fdrake/zconfig/
48 Author: Zope Foundation and Contributors
49@@ -107,6 +107,32 @@
50 ==========================
51
52
53+ ZConfig 2.9.3 (2012-06-25)
54+ --------------------------
55+
56+ - Fixed: port values of 0 weren't allowed. Port 0 is used to request
57+ an ephemeral port.
58+
59+ ZConfig 2.9.2 (2012-02-11)
60+ --------------------------
61+
62+ - Adjust test classes to avoid base classes being considered separate
63+ test cases by (at least) the "nose" test runner.
64+
65+
66+ ZConfig 2.9.1 (2012-02-11)
67+ --------------------------
68+
69+ - Make FileHandler.reopen thread safe.
70+
71+
72+ ZConfig 2.9.0 (2011-03-22)
73+ --------------------------
74+
75+ - Allow identical redefinition of ``%define`` names.
76+ - Added support for IPv6 addresses.
77+
78+
79 ZConfig 2.8.0 (2010-04-13)
80 --------------------------
81
82@@ -320,4 +346,4 @@
83 Classifier: Programming Language :: Python :: 2.4
84 Classifier: Programming Language :: Python :: 2.5
85 Classifier: Programming Language :: Python :: 2.6
86-Classifier: Topic :: Software Development :: Libraries :: Python Modules
87+Classifier: Programming Language :: Python :: 2.7
88
89=== modified file 'ZConfig.egg-info/PKG-INFO'
90--- ZConfig.egg-info/PKG-INFO 2011-03-24 18:29:45 +0000
91+++ ZConfig.egg-info/PKG-INFO 2012-07-15 23:54:18 +0000
92@@ -1,6 +1,6 @@
93 Metadata-Version: 1.0
94 Name: ZConfig
95-Version: 2.8.0
96+Version: 2.9.3
97 Summary: Structured Configuration Library
98 Home-page: http://www.zope.org/Members/fdrake/zconfig/
99 Author: Zope Foundation and Contributors
100@@ -107,6 +107,32 @@
101 ==========================
102
103
104+ ZConfig 2.9.3 (2012-06-25)
105+ --------------------------
106+
107+ - Fixed: port values of 0 weren't allowed. Port 0 is used to request
108+ an ephemeral port.
109+
110+ ZConfig 2.9.2 (2012-02-11)
111+ --------------------------
112+
113+ - Adjust test classes to avoid base classes being considered separate
114+ test cases by (at least) the "nose" test runner.
115+
116+
117+ ZConfig 2.9.1 (2012-02-11)
118+ --------------------------
119+
120+ - Make FileHandler.reopen thread safe.
121+
122+
123+ ZConfig 2.9.0 (2011-03-22)
124+ --------------------------
125+
126+ - Allow identical redefinition of ``%define`` names.
127+ - Added support for IPv6 addresses.
128+
129+
130 ZConfig 2.8.0 (2010-04-13)
131 --------------------------
132
133@@ -320,4 +346,4 @@
134 Classifier: Programming Language :: Python :: 2.4
135 Classifier: Programming Language :: Python :: 2.5
136 Classifier: Programming Language :: Python :: 2.6
137-Classifier: Topic :: Software Development :: Libraries :: Python Modules
138+Classifier: Programming Language :: Python :: 2.7
139
140=== modified file 'ZConfig/cfgparser.py'
141--- ZConfig/cfgparser.py 2011-03-24 18:29:45 +0000
142+++ ZConfig/cfgparser.py 2012-07-15 23:54:18 +0000
143@@ -160,7 +160,8 @@
144 if len(parts) == 2:
145 defvalue = parts[1]
146 if self.defines.has_key(defname):
147- self.error("cannot redefine " + `defname`)
148+ if self.defines[defname] != defvalue:
149+ self.error("cannot redefine " + `defname`)
150 if not isname(defname):
151 self.error("not a substitution legal name: " + `defname`)
152 self.defines[defname] = self.replace(defvalue)
153
154=== modified file 'ZConfig/components/basic/tests/test_mapping.py'
155--- ZConfig/components/basic/tests/test_mapping.py 2011-03-24 18:29:45 +0000
156+++ ZConfig/components/basic/tests/test_mapping.py 2012-07-15 23:54:18 +0000
157@@ -15,10 +15,9 @@
158 """Tests of the 'basic' section types provided as part of
159 ZConfig.components.basic."""
160
161+import ZConfig.tests.support
162 import unittest
163
164-from ZConfig.tests import support
165-
166
167 SIMPLE_SCHEMA = '''\
168 <schema>
169@@ -43,7 +42,9 @@
170 '''
171
172
173-class BasicSectionTypeTestCase(support.TestBase):
174+class BasicSectionTypeTestCase(
175+ ZConfig.tests.support.TestHelper, unittest.TestCase):
176+
177 schema = None
178
179 def setUp(self):
180
181=== modified file 'ZConfig/components/logger/loghandler.py'
182--- ZConfig/components/logger/loghandler.py 2011-03-24 18:29:45 +0000
183+++ ZConfig/components/logger/loghandler.py 2012-07-15 23:54:18 +0000
184@@ -84,8 +84,12 @@
185 _remove_from_reopenable(self._wr)
186
187 def reopen(self):
188- self.stream.close()
189- self.stream = open(self.baseFilename, self.mode)
190+ self.acquire()
191+ try:
192+ self.stream.close()
193+ self.stream = open(self.baseFilename, self.mode)
194+ finally:
195+ self.release()
196
197
198 class Win32FileHandler(FileHandler):
199
200=== modified file 'ZConfig/components/logger/tests/test_logger.py'
201--- ZConfig/components/logger/tests/test_logger.py 2011-03-24 18:29:45 +0000
202+++ ZConfig/components/logger/tests/test_logger.py 2012-07-15 23:54:18 +0000
203@@ -41,7 +41,10 @@
204 return sio.getvalue() + "... Don't panic!"
205
206
207-class LoggingTestBase(unittest.TestCase):
208+class LoggingTestHelper:
209+
210+ # Not derived from unittest.TestCase; some test runners seem to
211+ # think that means this class contains tests.
212
213 # XXX This tries to save and restore the state of logging around
214 # the test. Somewhat surgical; there may be a better way.
215@@ -100,7 +103,7 @@
216 return conf
217
218
219-class TestConfig(LoggingTestBase):
220+class TestConfig(LoggingTestHelper, unittest.TestCase):
221
222 _schematext = """
223 <schema>
224@@ -404,10 +407,12 @@
225 return logger
226
227
228-class TestReopeningLogfilesBase(LoggingTestBase):
229+class TestReopeningRotatingLogfiles(LoggingTestHelper, unittest.TestCase):
230
231 # These tests should not be run on Windows.
232
233+ handler_factory = loghandler.RotatingFileHandler
234+
235 _schematext = """
236 <schema>
237 <import package='ZConfig.components.logger'/>
238@@ -415,6 +420,40 @@
239 </schema>
240 """
241
242+ _sampleconfig_template = """
243+ <logger>
244+ name foo.bar
245+ <logfile>
246+ path %(path0)s
247+ level debug
248+ max-size 1mb
249+ old-files 10
250+ </logfile>
251+ <logfile>
252+ path %(path1)s
253+ level info
254+ max-size 1mb
255+ old-files 3
256+ </logfile>
257+ <logfile>
258+ path %(path1)s
259+ level info
260+ when D
261+ old-files 3
262+ </logfile>
263+ </logger>
264+
265+ <logger>
266+ name bar.foo
267+ <logfile>
268+ path %(path2)s
269+ level info
270+ max-size 10mb
271+ old-files 10
272+ </logfile>
273+ </logger>
274+ """
275+
276 def test_filehandler_reopen(self):
277
278 def mkrecord(msg):
279@@ -458,7 +497,59 @@
280 self.assert_("message 4" in text2)
281 self.assert_("message 5" in text3)
282
283-class TestReopeningLogfiles(TestReopeningLogfilesBase):
284+ def test_logfile_reopening(self):
285+ #
286+ # This test only applies to the simple logfile reopening; it
287+ # doesn't work the same way as the rotating logfile handler.
288+ #
289+ paths = self.mktemp(), self.mktemp(), self.mktemp()
290+ d = {
291+ "path0": paths[0],
292+ "path1": paths[1],
293+ "path2": paths[2],
294+ }
295+ text = self._sampleconfig_template % d
296+ conf = self.get_config(text)
297+ self.assertEqual(len(conf.loggers), 2)
298+ # Build the loggers from the configuration, and write to them:
299+ conf.loggers[0]().info("message 1")
300+ conf.loggers[1]().info("message 2")
301+ #
302+ # We expect this to re-open the original filenames, so we'll
303+ # have six files instead of three.
304+ #
305+ loghandler.reopenFiles()
306+ #
307+ # Write to them again:
308+ conf.loggers[0]().info("message 3")
309+ conf.loggers[1]().info("message 4")
310+ #
311+ # We expect this to re-open the original filenames, so we'll
312+ # have nine files instead of six.
313+ #
314+ loghandler.reopenFiles()
315+ #
316+ # Write to them again:
317+ conf.loggers[0]().info("message 5")
318+ conf.loggers[1]().info("message 6")
319+ #
320+ # We should now have all nine files:
321+ for fn in paths:
322+ fn1 = fn + ".1"
323+ fn2 = fn + ".2"
324+ self.assert_(os.path.isfile(fn), "%r must exist" % fn)
325+ self.assert_(os.path.isfile(fn1), "%r must exist" % fn1)
326+ self.assert_(os.path.isfile(fn2), "%r must exist" % fn2)
327+ #
328+ # Clean up:
329+ for logger in conf.loggers:
330+ logger = logger()
331+ for handler in logger.handlers[:]:
332+ logger.removeHandler(handler)
333+ handler.close()
334+
335+
336+class TestReopeningLogfiles(TestReopeningRotatingLogfiles):
337
338 handler_factory = loghandler.FileHandler
339
340@@ -537,95 +628,23 @@
341 logger.removeHandler(handler)
342 handler.close()
343
344-
345-class TestReopeningRotatingLogfiles(TestReopeningLogfilesBase):
346-
347- _sampleconfig_template = """
348- <logger>
349- name foo.bar
350- <logfile>
351- path %(path0)s
352- level debug
353- max-size 1mb
354- old-files 10
355- </logfile>
356- <logfile>
357- path %(path1)s
358- level info
359- max-size 1mb
360- old-files 3
361- </logfile>
362- <logfile>
363- path %(path1)s
364- level info
365- when D
366- old-files 3
367- </logfile>
368- </logger>
369-
370- <logger>
371- name bar.foo
372- <logfile>
373- path %(path2)s
374- level info
375- max-size 10mb
376- old-files 10
377- </logfile>
378- </logger>
379- """
380-
381- handler_factory = loghandler.RotatingFileHandler
382-
383- def test_logfile_reopening(self):
384- #
385- # This test only applies to the simple logfile reopening; it
386- # doesn't work the same way as the rotating logfile handler.
387- #
388- paths = self.mktemp(), self.mktemp(), self.mktemp()
389- d = {
390- "path0": paths[0],
391- "path1": paths[1],
392- "path2": paths[2],
393- }
394- text = self._sampleconfig_template % d
395- conf = self.get_config(text)
396- self.assertEqual(len(conf.loggers), 2)
397- # Build the loggers from the configuration, and write to them:
398- conf.loggers[0]().info("message 1")
399- conf.loggers[1]().info("message 2")
400- #
401- # We expect this to re-open the original filenames, so we'll
402- # have six files instead of three.
403- #
404- loghandler.reopenFiles()
405- #
406- # Write to them again:
407- conf.loggers[0]().info("message 3")
408- conf.loggers[1]().info("message 4")
409- #
410- # We expect this to re-open the original filenames, so we'll
411- # have nine files instead of six.
412- #
413- loghandler.reopenFiles()
414- #
415- # Write to them again:
416- conf.loggers[0]().info("message 5")
417- conf.loggers[1]().info("message 6")
418- #
419- # We should now have all nine files:
420- for fn in paths:
421- fn1 = fn + ".1"
422- fn2 = fn + ".2"
423- self.assert_(os.path.isfile(fn), "%r must exist" % fn)
424- self.assert_(os.path.isfile(fn1), "%r must exist" % fn1)
425- self.assert_(os.path.isfile(fn2), "%r must exist" % fn2)
426- #
427- # Clean up:
428- for logger in conf.loggers:
429- logger = logger()
430- for handler in logger.handlers[:]:
431- logger.removeHandler(handler)
432- handler.close()
433+ def test_filehandler_reopen_thread_safety(self):
434+ # The reopen method needs to do locking to avoid a race condition
435+ # with emit calls. For simplicity we replace the "acquire" and
436+ # "release" methods with dummies that record calls to them.
437+
438+ fn = self.mktemp()
439+ h = self.handler_factory(fn)
440+
441+ calls = []
442+ h.acquire = lambda: calls.append("acquire")
443+ h.release = lambda: calls.append("release")
444+
445+ h.reopen()
446+ h.close()
447+
448+ self.assertEqual(calls, ["acquire", "release"])
449+
450
451 def test_logger_convenience_function_and_ommiting_name_to_get_root_logger():
452 """
453
454=== modified file 'ZConfig/datatypes.py'
455--- ZConfig/datatypes.py 2011-03-24 18:29:45 +0000
456+++ ZConfig/datatypes.py 2012-07-15 23:54:18 +0000
457@@ -164,7 +164,7 @@
458 return s.split()
459
460
461-port_number = RangeCheckedConversion(integer, min=1, max=0xffff).__call__
462+port_number = RangeCheckedConversion(integer, min=0, max=0xffff).__call__
463
464
465 class InetAddress:
466@@ -177,9 +177,17 @@
467 host = ''
468 port = None
469 if ":" in s:
470- host, s = s.split(":", 1)
471- if s:
472- port = port_number(s)
473+ host, p = s.rsplit(":", 1)
474+ if host.startswith('[') and host.endswith(']'):
475+ # [IPv6]:port
476+ host = host[1:-1]
477+ elif ':' in host:
478+ # Unbracketed IPv6 address;
479+ # last part is not the port number
480+ host = s
481+ p = None
482+ if p: # else leave port at None
483+ port = port_number(p)
484 host = host.lower()
485 else:
486 try:
487@@ -203,6 +211,14 @@
488 inet_binding_address = InetAddress("")
489
490 class SocketAddress:
491+ # Parsing results in family and address
492+ # Family can be AF_UNIX (for addresses that are path names)
493+ # or AF_INET6 (for inet addresses with colons in them)
494+ # or AF_INET (for all other inet addresses);
495+ # An inet address is a (host, port) pair
496+ # Notice that no DNS lookup is performed, so if the host
497+ # is a DNS name, DNS lookup may end up with either IPv4 or
498+ # IPv6 addresses, or both
499 def __init__(self, s):
500 import socket
501 if "/" in s or s.find(os.sep) >= 0:
502@@ -211,6 +227,8 @@
503 else:
504 self.family = socket.AF_INET
505 self.address = self._parse_address(s)
506+ if ':' in self.address[0]:
507+ self.family = socket.AF_INET6
508
509 def _parse_address(self, s):
510 return inet_address(s)
511@@ -237,15 +255,28 @@
512 # IP address regex from the Perl Cookbook, Recipe 6.23 (revised ed.)
513 # We allow underscores in hostnames although this is considered
514 # illegal according to RFC1034.
515+ # Addition: IPv6 addresses are now also accepted
516 expr = (r"(^(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr
517 r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
518 r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
519 r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])$)" #ipaddr cont'd
520- r"|([A-Za-z_][-A-Za-z0-9_.]*[-A-Za-z0-9_])") # or hostname
521+ r"|([A-Za-z_][-A-Za-z0-9_.]*[-A-Za-z0-9_])" # or hostname
522+ r"|([0-9A-Fa-f:.]+:[0-9A-Fa-f:.]*)" # or superset of IPv6 addresses
523+ # (requiring at least one colon)
524+ )
525 RegularExpressionConversion.__init__(self, expr)
526
527 def __call__(self, value):
528- return RegularExpressionConversion.__call__(self, value).lower()
529+ result = RegularExpressionConversion.__call__(self, value).lower()
530+ # Use C library to validate IPv6 addresses, in particular wrt.
531+ # number of colons and number of digits per group
532+ if ':' in result:
533+ import socket
534+ try:
535+ socket.inet_pton(socket.AF_INET6, result)
536+ except socket.error:
537+ raise ValueError('%r is not a valid IPv6 address' % value)
538+ return result
539
540 def existing_directory(v):
541 nv = os.path.expanduser(v)
542
543=== modified file 'ZConfig/tests/support.py'
544--- ZConfig/tests/support.py 2011-03-24 18:29:45 +0000
545+++ ZConfig/tests/support.py 2012-07-15 23:54:18 +0000
546@@ -16,7 +16,6 @@
547
548 import os
549 import StringIO
550-import unittest
551 import urllib
552
553 import ZConfig
554@@ -35,9 +34,12 @@
555 CONFIG_BASE = "file://%s/" % urllib.pathname2url(d)
556
557
558-class TestBase(unittest.TestCase):
559+class TestHelper:
560 """Utility methods which can be used with the schema support."""
561
562+ # Not derived from unittest.TestCase; some test runners seem to
563+ # think that means this class contains tests.
564+
565 def load_both(self, schema_url, conf_url):
566 schema = self.load_schema(schema_url)
567 conf = self.load_config(schema, conf_url)
568
569=== modified file 'ZConfig/tests/test_cfgimports.py'
570--- ZConfig/tests/test_cfgimports.py 2011-03-24 18:29:45 +0000
571+++ ZConfig/tests/test_cfgimports.py 2012-07-15 23:54:18 +0000
572@@ -24,7 +24,8 @@
573 import ZConfig.tests.support
574
575
576-class TestImportFromConfiguration(ZConfig.tests.support.TestBase):
577+class TestImportFromConfiguration(
578+ ZConfig.tests.support.TestHelper, unittest.TestCase):
579
580 def test_simple_import(self):
581 schema = self.load_schema_text("<schema/>")
582
583=== modified file 'ZConfig/tests/test_cmdline.py'
584--- ZConfig/tests/test_cmdline.py 2011-03-24 18:29:45 +0000
585+++ ZConfig/tests/test_cmdline.py 2012-07-15 23:54:18 +0000
586@@ -17,12 +17,12 @@
587 import unittest
588
589 import ZConfig
590+import ZConfig.tests.support
591
592 from ZConfig.cmdline import ExtendedConfigLoader
593-from ZConfig.tests.support import TestBase
594-
595-
596-class CommandLineTest(TestBase):
597+
598+
599+class CommandLineTest(ZConfig.tests.support.TestHelper, unittest.TestCase):
600
601 def create_config_loader(self, schema):
602 loader = ExtendedConfigLoader(schema)
603
604=== modified file 'ZConfig/tests/test_config.py'
605--- ZConfig/tests/test_config.py 2011-03-24 18:29:45 +0000
606+++ ZConfig/tests/test_config.py 2012-07-15 23:54:18 +0000
607@@ -133,7 +133,9 @@
608 self.assertRaises(ZConfig.ConfigurationSyntaxError,
609 self.loadtext, "%define abc-def\n")
610 self.assertRaises(ZConfig.ConfigurationSyntaxError,
611- self.loadtext, "%define a value\n%define a value\n")
612+ self.loadtext, "%define a value\n%define a other\n")
613+ # doesn't raise if value is equal
614+ self.loadtext("%define a value\n%define a value\n")
615
616 def test_fragment_ident_disallowed(self):
617 self.assertRaises(ZConfig.ConfigurationError,
618
619=== modified file 'ZConfig/tests/test_cookbook.py'
620--- ZConfig/tests/test_cookbook.py 2011-03-24 18:29:45 +0000
621+++ ZConfig/tests/test_cookbook.py 2012-07-15 23:54:18 +0000
622@@ -20,10 +20,9 @@
623
624 """
625
626+import ZConfig.tests.support
627 import unittest
628
629-from ZConfig.tests.support import TestBase
630-
631
632 def basic_key_mapping_password_to_passwd(key):
633 # Lower-case the key since that's what basic-key does:
634@@ -37,7 +36,7 @@
635 return section
636
637
638-class CookbookTestCase(TestBase):
639+class CookbookTestCase(ZConfig.tests.support.TestHelper, unittest.TestCase):
640
641 def test_rewriting_key_names(self):
642 schema = self.load_schema_text("""
643
644=== modified file 'ZConfig/tests/test_datatypes.py'
645--- ZConfig/tests/test_datatypes.py 2011-03-24 18:29:45 +0000
646+++ ZConfig/tests/test_datatypes.py 2012-07-15 23:54:18 +0000
647@@ -183,9 +183,12 @@
648 eq = self.assertEqual
649 defhost = ZConfig.datatypes.DEFAULT_HOST
650 eq(convert("Host.Example.Com:80"), ("host.example.com", 80))
651+ eq(convert("Host.Example.Com:0"), ("host.example.com", 0))
652 eq(convert(":80"), (defhost, 80))
653 eq(convert("80"), (defhost, 80))
654+ eq(convert("[::1]:80"), ("::1", 80))
655 eq(convert("host.EXAMPLE.com"), ("host.example.com", None))
656+ eq(convert("2001::ABCD"), ("2001::abcd", None))
657 self.assertRaises(ValueError, convert, "40 # foo")
658
659 def test_datatype_inet_binding_address(self):
660@@ -245,7 +248,7 @@
661 raises = self.assertRaises
662
663 raises(ValueError, convert, '-1')
664- raises(ValueError, convert, '0')
665+ eq(convert('0'), 0)
666 eq(convert('1'), 1)
667 eq(convert('80'), 80)
668 eq(convert('1023'), 1023)
669@@ -258,6 +261,7 @@
670 convert = self.types.get("socket-address")
671 eq = self.assertEqual
672 AF_INET = socket.AF_INET
673+ AF_INET6 = socket.AF_INET6
674 defhost = ZConfig.datatypes.DEFAULT_HOST
675
676 def check(value, family, address, self=self, convert=convert):
677@@ -269,6 +273,8 @@
678 check(":80", AF_INET, (defhost, 80))
679 check("80", AF_INET, (defhost, 80))
680 check("host.EXAMPLE.com", AF_INET, ("host.example.com",None))
681+ check("::1", AF_INET6,("::1", None))
682+ check("[::]:80", AF_INET6,("::", 80))
683 a1 = convert("/tmp/var/@345.4")
684 a2 = convert("/tmp/var/@345.4:80")
685 self.assertEqual(a1.address, "/tmp/var/@345.4")
686@@ -291,11 +297,16 @@
687 eq(convert('HOSTNAME.COM'), 'hostname.com')
688 eq(convert('WWW.HOSTNAME.COM'), 'www.hostname.com')
689 eq(convert('127.0.0.1'), '127.0.0.1')
690+ eq(convert('::1'), '::1')
691+ eq(convert('2001:DB8:1234:4567:89AB:cdef:0:1'), '2001:db8:1234:4567:89ab:cdef:0:1')
692+ eq(convert('2001:DB8:1234:4567::10.11.12.13'), '2001:db8:1234:4567::10.11.12.13')
693 raises(ValueError, convert, '1hostnamewithleadingnumeric')
694 raises(ValueError, convert, '255.255')
695 raises(ValueError, convert, '12345678')
696 raises(ValueError, convert, '999.999.999.999')
697 raises(ValueError, convert, 'a!badhostname')
698+ raises(ValueError, convert, '2001:DB8:0123:4567:89AB:cdef:0:1:2')
699+ raises(ValueError, convert, '2001:DB8:0123:4567::10.11.12.13.14')
700
701 def test_existing_directory(self):
702 convert = self.types.get('existing-directory')
703
704=== modified file 'ZConfig/tests/test_loader.py'
705--- ZConfig/tests/test_loader.py 2011-03-24 18:29:45 +0000
706+++ ZConfig/tests/test_loader.py 2012-07-15 23:54:18 +0000
707@@ -25,7 +25,7 @@
708 import ZConfig.loader
709 import ZConfig.url
710
711-from ZConfig.tests.support import CONFIG_BASE, TestBase
712+from ZConfig.tests.support import CONFIG_BASE, TestHelper
713
714
715 try:
716@@ -37,7 +37,7 @@
717 LIBRARY_DIR = os.path.join(os.path.dirname(myfile), "library")
718
719
720-class LoaderTestCase(TestBase):
721+class LoaderTestCase(TestHelper, unittest.TestCase):
722
723 def test_schema_caching(self):
724 loader = ZConfig.loader.SchemaLoader()
725
726=== modified file 'ZConfig/tests/test_readme.py'
727--- ZConfig/tests/test_readme.py 2011-03-24 18:29:45 +0000
728+++ ZConfig/tests/test_readme.py 2012-07-15 23:54:18 +0000
729@@ -11,16 +11,17 @@
730 # FOR A PARTICULAR PURPOSE.
731 #
732 ##############################################################################
733-import logging,os,unittest
734-from zope.testing.doctest import DocFileSuite, REPORT_NDIFF,ELLIPSIS
735-
736-options = REPORT_NDIFF|ELLIPSIS
737+import doctest
738+import logging
739+
740+
741+options = doctest.REPORT_NDIFF | doctest.ELLIPSIS
742
743 old = {}
744 def setUp(test):
745 global old
746- logger=logging.getLogger()
747- old['level']=logger.level
748+ logger = logging.getLogger()
749+ old['level'] = logger.level
750 old['handlers'] = logger.handlers[:]
751
752 def tearDown(test):
753@@ -29,7 +30,8 @@
754 logger.handlers = old['handlers']
755
756 def test_suite():
757- return unittest.TestSuite((
758- DocFileSuite('../../README.txt', optionflags=options,
759- setUp=setUp,tearDown=tearDown),
760- ))
761+ return doctest.DocFileSuite(
762+ '../../README.txt',
763+ optionflags=options,
764+ setUp=setUp, tearDown=tearDown,
765+ )
766
767=== modified file 'ZConfig/tests/test_schema.py'
768--- ZConfig/tests/test_schema.py 2011-03-24 18:29:45 +0000
769+++ ZConfig/tests/test_schema.py 2012-07-15 23:54:18 +0000
770@@ -17,7 +17,7 @@
771
772 import ZConfig
773
774-from ZConfig.tests.support import TestBase, CONFIG_BASE
775+from ZConfig.tests.support import TestHelper, CONFIG_BASE
776
777
778 def uppercase(value):
779@@ -40,7 +40,7 @@
780 return L
781
782
783-class SchemaTestCase(TestBase):
784+class SchemaTestCase(TestHelper, unittest.TestCase):
785 """Tests of the basic schema support itself."""
786
787 def test_minimal_schema(self):
788
789=== modified file 'ZConfig/tests/test_schemaless.py'
790--- ZConfig/tests/test_schemaless.py 2011-03-24 18:29:45 +0000
791+++ ZConfig/tests/test_schemaless.py 2012-07-15 23:54:18 +0000
792@@ -17,10 +17,7 @@
793 """
794 __docformat__ = "reStructuredText"
795
796-try:
797- from zope.testing import doctest
798-except ImportError:
799- import doctest
800+import doctest
801
802
803 def test_suite():
804
805=== modified file 'bootstrap.py'
806--- bootstrap.py 2011-03-24 18:29:45 +0000
807+++ bootstrap.py 2012-07-15 23:54:18 +0000
808@@ -16,37 +16,245 @@
809 Simply run this script in a directory containing a buildout.cfg.
810 The script accepts buildout command-line options, so you can
811 use the -c option to specify an alternate configuration file.
812-
813-$Id: bootstrap.py 72703 2007-02-20 11:49:26Z jim $
814 """
815
816-import os, shutil, sys, tempfile, urllib2
817-
818-tmpeggs = tempfile.mkdtemp()
819-
820-ez = {}
821-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
822- ).read() in ez
823-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
824-
825-import pkg_resources
826-
827-cmd = 'from setuptools.command.easy_install import main; main()'
828+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
829+from optparse import OptionParser
830+
831 if sys.platform == 'win32':
832- cmd = '"%s"' % cmd # work around spawn lamosity on windows
833-
834+ def quote(c):
835+ if ' ' in c:
836+ return '"%s"' % c # work around spawn lamosity on windows
837+ else:
838+ return c
839+else:
840+ quote = str
841+
842+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
843+stdout, stderr = subprocess.Popen(
844+ [sys.executable, '-Sc',
845+ 'try:\n'
846+ ' import ConfigParser\n'
847+ 'except ImportError:\n'
848+ ' print 1\n'
849+ 'else:\n'
850+ ' print 0\n'],
851+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
852+has_broken_dash_S = bool(int(stdout.strip()))
853+
854+# In order to be more robust in the face of system Pythons, we want to
855+# run without site-packages loaded. This is somewhat tricky, in
856+# particular because Python 2.6's distutils imports site, so starting
857+# with the -S flag is not sufficient. However, we'll start with that:
858+if not has_broken_dash_S and 'site' in sys.modules:
859+ # We will restart with python -S.
860+ args = sys.argv[:]
861+ args[0:0] = [sys.executable, '-S']
862+ args = map(quote, args)
863+ os.execv(sys.executable, args)
864+# Now we are running with -S. We'll get the clean sys.path, import site
865+# because distutils will do it later, and then reset the path and clean
866+# out any namespace packages from site-packages that might have been
867+# loaded by .pth files.
868+clean_path = sys.path[:]
869+import site
870+sys.path[:] = clean_path
871+for k, v in sys.modules.items():
872+ if k in ('setuptools', 'pkg_resources') or (
873+ hasattr(v, '__path__') and
874+ len(v.__path__)==1 and
875+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
876+ # This is a namespace package. Remove it.
877+ sys.modules.pop(k)
878+
879+is_jython = sys.platform.startswith('java')
880+
881+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
882+distribute_source = 'http://python-distribute.org/distribute_setup.py'
883+
884+# parsing arguments
885+def normalize_to_url(option, opt_str, value, parser):
886+ if value:
887+ if '://' not in value: # It doesn't smell like a URL.
888+ value = 'file://%s' % (
889+ urllib.pathname2url(
890+ os.path.abspath(os.path.expanduser(value))),)
891+ if opt_str == '--download-base' and not value.endswith('/'):
892+ # Download base needs a trailing slash to make the world happy.
893+ value += '/'
894+ else:
895+ value = None
896+ name = opt_str[2:].replace('-', '_')
897+ setattr(parser.values, name, value)
898+
899+usage = '''\
900+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
901+
902+Bootstraps a buildout-based project.
903+
904+Simply run this script in a directory containing a buildout.cfg, using the
905+Python that you want bin/buildout to use.
906+
907+Note that by using --setup-source and --download-base to point to
908+local resources, you can keep this script from going over the network.
909+'''
910+
911+parser = OptionParser(usage=usage)
912+parser.add_option("-v", "--version", dest="version",
913+ help="use a specific zc.buildout version")
914+parser.add_option("-d", "--distribute",
915+ action="store_true", dest="use_distribute", default=False,
916+ help="Use Distribute rather than Setuptools.")
917+parser.add_option("--setup-source", action="callback", dest="setup_source",
918+ callback=normalize_to_url, nargs=1, type="string",
919+ help=("Specify a URL or file location for the setup file. "
920+ "If you use Setuptools, this will default to " +
921+ setuptools_source + "; if you use Distribute, this "
922+ "will default to " + distribute_source +"."))
923+parser.add_option("--download-base", action="callback", dest="download_base",
924+ callback=normalize_to_url, nargs=1, type="string",
925+ help=("Specify a URL or directory for downloading "
926+ "zc.buildout and either Setuptools or Distribute. "
927+ "Defaults to PyPI."))
928+parser.add_option("--eggs",
929+ help=("Specify a directory for storing eggs. Defaults to "
930+ "a temporary directory that is deleted when the "
931+ "bootstrap script completes."))
932+parser.add_option("-t", "--accept-buildout-test-releases",
933+ dest='accept_buildout_test_releases',
934+ action="store_true", default=False,
935+ help=("Normally, if you do not specify a --version, the "
936+ "bootstrap script and buildout gets the newest "
937+ "*final* versions of zc.buildout and its recipes and "
938+ "extensions for you. If you use this flag, "
939+ "bootstrap and buildout will get the newest releases "
940+ "even if they are alphas or betas."))
941+parser.add_option("-c", None, action="store", dest="config_file",
942+ help=("Specify the path to the buildout configuration "
943+ "file to be used."))
944+
945+options, args = parser.parse_args()
946+
947+# if -c was provided, we push it back into args for buildout's main function
948+if options.config_file is not None:
949+ args += ['-c', options.config_file]
950+
951+if options.eggs:
952+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
953+else:
954+ eggs_dir = tempfile.mkdtemp()
955+
956+if options.setup_source is None:
957+ if options.use_distribute:
958+ options.setup_source = distribute_source
959+ else:
960+ options.setup_source = setuptools_source
961+
962+if options.accept_buildout_test_releases:
963+ args.append('buildout:accept-buildout-test-releases=true')
964+args.append('bootstrap')
965+
966+try:
967+ import pkg_resources
968+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
969+ if not hasattr(pkg_resources, '_distribute'):
970+ raise ImportError
971+except ImportError:
972+ ez_code = urllib2.urlopen(
973+ options.setup_source).read().replace('\r\n', '\n')
974+ ez = {}
975+ exec ez_code in ez
976+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
977+ if options.download_base:
978+ setup_args['download_base'] = options.download_base
979+ if options.use_distribute:
980+ setup_args['no_fake'] = True
981+ ez['use_setuptools'](**setup_args)
982+ if 'pkg_resources' in sys.modules:
983+ reload(sys.modules['pkg_resources'])
984+ import pkg_resources
985+ # This does not (always?) update the default working set. We will
986+ # do it.
987+ for path in sys.path:
988+ if path not in pkg_resources.working_set.entries:
989+ pkg_resources.working_set.add_entry(path)
990+
991+cmd = [quote(sys.executable),
992+ '-c',
993+ quote('from setuptools.command.easy_install import main; main()'),
994+ '-mqNxd',
995+ quote(eggs_dir)]
996+
997+if not has_broken_dash_S:
998+ cmd.insert(1, '-S')
999+
1000+find_links = options.download_base
1001+if not find_links:
1002+ find_links = os.environ.get('bootstrap-testing-find-links')
1003+if find_links:
1004+ cmd.extend(['-f', quote(find_links)])
1005+
1006+if options.use_distribute:
1007+ setup_requirement = 'distribute'
1008+else:
1009+ setup_requirement = 'setuptools'
1010 ws = pkg_resources.working_set
1011-assert os.spawnle(
1012- os.P_WAIT, sys.executable, sys.executable,
1013- '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
1014- dict(os.environ,
1015- PYTHONPATH=
1016- ws.find(pkg_resources.Requirement.parse('setuptools')).location
1017- ),
1018- ) == 0
1019-
1020-ws.add_entry(tmpeggs)
1021-ws.require('zc.buildout')
1022+setup_requirement_path = ws.find(
1023+ pkg_resources.Requirement.parse(setup_requirement)).location
1024+env = dict(
1025+ os.environ,
1026+ PYTHONPATH=setup_requirement_path)
1027+
1028+requirement = 'zc.buildout'
1029+version = options.version
1030+if version is None and not options.accept_buildout_test_releases:
1031+ # Figure out the most recent final version of zc.buildout.
1032+ import setuptools.package_index
1033+ _final_parts = '*final-', '*final'
1034+ def _final_version(parsed_version):
1035+ for part in parsed_version:
1036+ if (part[:1] == '*') and (part not in _final_parts):
1037+ return False
1038+ return True
1039+ index = setuptools.package_index.PackageIndex(
1040+ search_path=[setup_requirement_path])
1041+ if find_links:
1042+ index.add_find_links((find_links,))
1043+ req = pkg_resources.Requirement.parse(requirement)
1044+ if index.obtain(req) is not None:
1045+ best = []
1046+ bestv = None
1047+ for dist in index[req.project_name]:
1048+ distv = dist.parsed_version
1049+ if _final_version(distv):
1050+ if bestv is None or distv > bestv:
1051+ best = [dist]
1052+ bestv = distv
1053+ elif distv == bestv:
1054+ best.append(dist)
1055+ if best:
1056+ best.sort()
1057+ version = best[-1].version
1058+if version:
1059+ requirement = '=='.join((requirement, version))
1060+cmd.append(requirement)
1061+
1062+if is_jython:
1063+ import subprocess
1064+ exitcode = subprocess.Popen(cmd, env=env).wait()
1065+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
1066+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
1067+if exitcode != 0:
1068+ sys.stdout.flush()
1069+ sys.stderr.flush()
1070+ print ("An error occurred when trying to install zc.buildout. "
1071+ "Look above this message for any errors that "
1072+ "were output by easy_install.")
1073+ sys.exit(exitcode)
1074+
1075+ws.add_entry(eggs_dir)
1076+ws.require(requirement)
1077 import zc.buildout.buildout
1078-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
1079-shutil.rmtree(tmpeggs)
1080+zc.buildout.buildout.main(args)
1081+if not options.eggs: # clean up temporary egg directory
1082+ shutil.rmtree(eggs_dir)
1083
1084=== modified file 'buildout.cfg'
1085--- buildout.cfg 2009-06-18 17:30:22 +0000
1086+++ buildout.cfg 2012-07-15 23:54:18 +0000
1087@@ -1,9 +1,14 @@
1088 [buildout]
1089 develop = .
1090-find-links = http://download.zope.org/distribution/
1091-parts = test
1092+parts = nosetests test
1093+prefer-final = true
1094+
1095+[nosetests]
1096+recipe = zc.recipe.egg
1097+eggs = nose
1098+scripts = nosetests
1099
1100 [test]
1101 recipe = zc.recipe.testrunner
1102 eggs = ZConfig
1103-defaults = '--exit-with-status -1'.split()
1104+defaults = ['-1']
1105
1106=== modified file 'debian/changelog'
1107--- debian/changelog 2011-12-31 08:17:16 +0000
1108+++ debian/changelog 2012-07-15 23:54:18 +0000
1109@@ -1,3 +1,10 @@
1110+zconfig (2.9.3-0ubuntu1) quantal; urgency=low
1111+
1112+ * New upstream release.
1113+ * Bump Standards-Version to 3.9.3.
1114+
1115+ -- Logan Rosen <logatronico@gmail.com> Sun, 15 Jul 2012 19:48:02 -0400
1116+
1117 zconfig (2.8.0-1build1) precise; urgency=low
1118
1119 * Rebuild to drop python2.6 dependencies.
1120
1121=== modified file 'debian/control'
1122--- debian/control 2011-05-06 22:36:13 +0000
1123+++ debian/control 2012-07-15 23:54:18 +0000
1124@@ -8,7 +8,7 @@
1125 python-all (>= 2.6.6-3~),
1126 python-setuptools,
1127 python-van.pydeb (>= 1.3.0-4)
1128-Standards-Version: 3.9.2
1129+Standards-Version: 3.9.3
1130 X-Python-Version: >= 2.4
1131 Homepage: http://www.zope.org/Members/fdrake/zconfig
1132 Vcs-Svn: svn://svn.debian.org/pkg-zope/zconfig/trunk
1133
1134=== modified file 'doc/zconfig.tex'
1135--- doc/zconfig.tex 2011-03-24 18:29:45 +0000
1136+++ doc/zconfig.tex 2012-07-15 23:54:18 +0000
1137@@ -272,9 +272,8 @@
1138 pairs.
1139
1140 Names must be defined before they are used, and may not be
1141-re-defined. All resources being parsed as part of a configuration
1142-share a single namespace for defined names. This means that resources
1143-which may be included more than once should not define any names.
1144+re-defined with a different value. All resources being parsed as part of
1145+a configuration share a single namespace for defined names.
1146
1147 References to defined names from configuration values use the syntax
1148 described for the \refmodule{ZConfig.substitution} module.
1149@@ -906,7 +905,9 @@
1150 will be returned for \var{hostname}. The default host is
1151 \code{localhost} on Windows and the empty string on all other
1152 platforms. If the port is omitted, \code{None} will be returned for
1153- \var{port}.
1154+ \var{port}. IPv6 addresses can be specified in colon-separated notation;
1155+ if both host and port need to be specified, the bracketed form
1156+ (\code{[addr]:port}) must be used.
1157
1158 \term{\datatype{inet-binding-address}}
1159 An Internet address expressed as a \code{(\var{hostname},
1160@@ -932,7 +933,8 @@
1161 Validates a valid IP address or hostname. If the first
1162 character is a digit, the value is assumed to be an IP
1163 address. If the first character is not a digit, the value
1164- is assumed to be a hostname. Hostnames are converted to lower
1165+ is assumed to be a hostname. Strings containing colons are
1166+ considered IPv6 address. Hostnames are converted to lower
1167 case.
1168
1169 \term{\datatype{locale}}
1170
1171=== modified file 'setup.py'
1172--- setup.py 2011-03-24 18:29:45 +0000
1173+++ setup.py 2012-07-15 23:54:18 +0000
1174@@ -4,23 +4,21 @@
1175 def alltests():
1176 import os
1177 import sys
1178- from unittest import TestSuite
1179- # use the zope.testing testrunner machinery to find all the
1180+ import unittest
1181+ # use the zope.testrunner machinery to find all the
1182 # test suites we've put under ourselves
1183- from zope.testing.testrunner import get_options
1184- from zope.testing.testrunner import find_suites
1185- from zope.testing.testrunner import configure_logging
1186- configure_logging()
1187+ import zope.testrunner.find
1188+ import zope.testrunner.options
1189 here = os.path.abspath(os.path.dirname(sys.argv[0]))
1190 args = sys.argv[:]
1191 defaults = ["--test-path", here]
1192- options = get_options(args, defaults)
1193- suites = list(find_suites(options))
1194- return TestSuite(suites)
1195+ options = zope.testrunner.options.get_options(args, defaults)
1196+ suites = list(zope.testrunner.find.find_suites(options))
1197+ return unittest.TestSuite(suites)
1198
1199 options = dict(
1200 name="ZConfig",
1201- version="2.8.0",
1202+ version="2.9.3",
1203 author="Fred L. Drake, Jr.",
1204 author_email="fred@zope.com",
1205 maintainer="Zope Foundation and Contributors",
1206@@ -53,12 +51,12 @@
1207 "Programming Language :: Python :: 2.4",
1208 "Programming Language :: Python :: 2.5",
1209 "Programming Language :: Python :: 2.6",
1210- "Topic :: Software Development :: Libraries :: Python Modules",
1211+ "Programming Language :: Python :: 2.7",
1212 ],
1213 # Support for 'setup.py test' when setuptools is available:
1214 test_suite="__main__.alltests",
1215 tests_require=[
1216- "zope.testing",
1217+ "zope.testrunner",
1218 ],
1219 )
1220

Subscribers

People subscribed via source and target branches

to all changes: