diff --git a/.travis.yml b/.travis.yml
index c5d1671..bddb890 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,9 +15,11 @@ matrix:
install:
- pip install -U pip setuptools
- pip install -U coverage coveralls
+ - pip install -U flake8
- pip install -U -e .[test]
script:
- coverage run -m zope.testrunner --test-path=.
+ - find setup.py ZConfig -name '*.py' | xargs flake8 --isolated
notifications:
email: false
after_success:
diff --git a/ZConfig/__init__.py b/ZConfig/__init__.py
index deba14e..19634d4 100644
--- a/ZConfig/__init__.py
+++ b/ZConfig/__init__.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -33,13 +33,17 @@
"""
__docformat__ = "reStructuredText"
-version_info = (3, 0)
-__version__ = ".".join([str(n) for n in version_info])
+from ZConfig._compat import TextIO
+import ZConfig.loader
-from ZConfig.loader import loadConfig, loadConfigFile
-from ZConfig.loader import loadSchema, loadSchemaFile
+loadConfigFile = ZConfig.loader.loadConfigFile
+loadSchemaFile = ZConfig.loader.loadSchemaFile
+loadConfig = ZConfig.loader.loadConfig
+loadSchema = ZConfig.loader.loadSchema
-from ZConfig._compat import TextIO
+
+version_info = (3, 0)
+__version__ = ".".join([str(n) for n in version_info])
class ConfigurationError(Exception):
@@ -48,8 +52,8 @@ class ConfigurationError(Exception):
All instances provide a ``message`` attribute that describes
the specific error, and a ``url`` attribute that gives the URL
of the resource the error was located in, or ``None``.
- """
+ """
# The 'message' attribute was deprecated for BaseException with
# Python 2.6; here we create descriptor properties to continue using it
@@ -214,12 +218,14 @@ def __init__(self, source, name, url=None, lineno=None):
def configureLoggers(text):
"""Configure one or more loggers from configuration text."""
- schema = loadSchemaFile(TextIO("""
+
+ schema = ZConfig.loader.loadSchemaFile(TextIO("""
"""))
- for factory in loadConfigFile(schema, TextIO(text))[0].loggers:
+ config, _ = ZConfig.loader.loadConfigFile(schema, TextIO(text))
+ for factory in config.loggers:
factory()
diff --git a/ZConfig/_compat.py b/ZConfig/_compat.py
index c0068fd..c377e35 100644
--- a/ZConfig/_compat.py
+++ b/ZConfig/_compat.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2016 Zope Foundation and Contributors.
+# Copyright (c) 2016, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -12,28 +12,36 @@
#
##############################################################################
+from io import StringIO
+from io import BytesIO
+import abc
import sys
+
PY3 = sys.version_info[0] >= 3
# Native string object IO
if str is not bytes:
from io import StringIO as NStringIO
string_types = str
+ text_type = str
+ have_unicode = False
else:
# Python 2
from io import BytesIO as NStringIO
- string_types = str, unicode
+ string_types = str, unicode # noqa: F821
+ text_type = string_types[1] # avoid direct reference!
+ have_unicode = True
+
NStringIO = NStringIO
-from io import StringIO
-from io import BytesIO
def TextIO(text):
- "Return StringIO or BytesIO as appropriate"
+ """Return StringIO or BytesIO as appropriate"""
return BytesIO(text) if isinstance(text, bytes) else StringIO(text)
+
try:
import urllib2
except ImportError:
@@ -58,24 +66,23 @@ def TextIO(text):
urlparse = urlparse
-if PY3: # pragma: no cover
+
+if PY3: # pragma: no cover
import builtins
exec_ = getattr(builtins, "exec")
- text_type = str
binary_type = bytes
maxsize = sys.maxsize
- def reraise(tp, value, tb=None): #pragma NO COVER
+ def reraise(tp, value, tb=None): # pragma NO COVER
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
-else: # pragma: no cover
- text_type = unicode
+else: # pragma: no cover
binary_type = bytes
maxsize = sys.maxint
- def exec_(code, globs=None, locs=None): #pragma NO COVER
+ def exec_(code, globs=None, locs=None): # pragma NO COVER
"""Execute code in a namespace."""
if globs is None:
frame = sys._getframe(1)
@@ -93,9 +100,9 @@ def exec_(code, globs=None, locs=None): #pragma NO COVER
def raise_with_same_tb(exception):
- "Raise an exception having the current traceback (if there is one)"
- reraise(type(exception), exception, sys.exc_info()[2])
+ """Raise an exception having the current traceback (if there is one)"""
+ reraise(type(exception), exception, sys.exc_info()[2])
+
-import abc
# workaround the metaclass diff in Py2/Py3
AbstractBaseClass = abc.ABCMeta('AbstractBaseClass', (object,), {})
diff --git a/ZConfig/_schema_utils.py b/ZConfig/_schema_utils.py
index ec3b707..d134614 100755
--- a/ZConfig/_schema_utils.py
+++ b/ZConfig/_schema_utils.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2017 Zope Corporation and Contributors.
+# Copyright (c) 2017, 2018 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -39,6 +39,9 @@
from ZConfig.info import AbstractType
+MARKER = object()
+
+
class _VisitorBuilder(object):
def __init__(self):
@@ -50,7 +53,6 @@ def dec(func):
return func
return dec
-MARKER = object()
class AbstractSchemaFormatter(AbstractBaseClass):
@@ -134,27 +136,30 @@ def body(self):
class AbstractSchemaPrinter(AbstractBaseClass):
-
- def __init__(self, schema, stream=None, allowed_names=(), excluded_names=()):
+ def __init__(self, schema, stream=None,
+ allowed_names=(), excluded_names=()):
self.schema = schema
stream = stream or sys.stdout
self._explained = set()
self._seen_typenames = set()
self.fmt = self._schema_formatter(schema, stream)
-
def _make_predicate(names):
names = {x.lower() for x in names}
+
def predicate(name_info):
name, _ = name_info
return name and name.lower() in names
+
return predicate
def _make_filter(names, filt):
iter_all = self._iter_schema_items
pred = _make_predicate(names)
+
def it():
return filt(pred, iter_all())
+
return it
if allowed_names:
@@ -162,7 +167,8 @@ def it():
if excluded_names:
excluded_names = {x.lower() for x in excluded_names}
- self._iter_schema_items = _make_filter(excluded_names, ifilterfalse)
+ self._iter_schema_items = _make_filter(excluded_names,
+ ifilterfalse)
self._included = lambda st: st.name not in excluded_names
@abstractmethod
@@ -173,7 +179,7 @@ def _included(self, st):
return True
def _explain(self, st):
- if st.name in self._explained: # pragma: no cover
+ if st.name in self._explained: # pragma: no cover
return
self._explained.add(st.name)
@@ -192,14 +198,14 @@ def _iter_schema_items(self):
def everything():
return itertools.chain(self.schema.itertypes(),
self.schema)
- # The abstract types tend to be the most important. Since
- # we only document a concrete type the first time we find it,
- # and we can find extensions of abstract types beneath
- # the abstract type which is itself buried under a concrete section,
- # all the different permutations would be only documented once under
- # that section. By exposing these first, they get documented at the top-level,
- # and each concrete section that uses the abstract type gets a reference
- # to it.
+ # The abstract types tend to be the most important. Since we
+ # only document a concrete type the first time we find it, and
+ # we can find extensions of abstract types beneath the abstract
+ # type which is itself buried under a concrete section, all the
+ # different permutations would be only documented once under
+ # that section. By exposing these first, they get documented at
+ # the top-level, and each concrete section that uses the
+ # abstract type gets a reference to it.
def abstract_sections(base):
for name, info in base:
@@ -219,7 +225,7 @@ def printSchema(self):
self.buildSchema()
def buildSchema(self):
- seen = set() # prevent duplicates at the top-level
+ seen = set() # prevent duplicates at the top-level
# as we find multiple abstract types
with self.fmt.body():
with self.fmt.item_list():
@@ -258,14 +264,14 @@ def _visit_SectionType(self, name, info):
with self.fmt.item_list():
for sub in info:
- self.visit(*sub) # pragma: no cover
-
+ self.visit(*sub) # pragma: no cover
@TypeVisitor(SectionInfo)
def _visit_SectionInfo(self, name, info):
st = info.sectiontype
if st.isabstract():
- with self.fmt.describing(info.description, lambda: self._explain(st)):
+ with self.fmt.describing(info.description,
+ lambda: self._explain(st)):
self.fmt.abstract_name(st.name)
self.fmt.concrete_name(info.name)
@@ -283,7 +289,8 @@ def _visit_SectionInfo(self, name, info):
@TypeVisitor(AbstractType)
def _visit_AbstractType(self, name, info):
- with self.fmt.describing(info.description, lambda: self._explain(info)):
+ with self.fmt.describing(info.description,
+ lambda: self._explain(info)):
self.fmt.abstract_name(info.name)
def _visit_default(self, name, info):
@@ -305,8 +312,9 @@ def load_schema(schema, package, package_file):
if not package:
schema_reader = argparse.FileType('r')(schema)
else:
- schema_template = "" % (
- schema, package_file or 'component.xml')
+ schema_template = (
+ ""
+ % (schema, package_file or 'component.xml'))
from ZConfig._compat import TextIO
schema_reader = TextIO(schema_template)
diff --git a/ZConfig/cfgparser.py b/ZConfig/cfgparser.py
index d9337f7..d20e141 100644
--- a/ZConfig/cfgparser.py
+++ b/ZConfig/cfgparser.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -13,12 +13,26 @@
##############################################################################
"""Configuration parser."""
+import re
+
import ZConfig
import ZConfig.url
from ZConfig.substitution import isname, substitute
from ZConfig._compat import raise_with_same_tb
+
+# _name_re does not allow "(" or ")" for historical reasons. Though
+# the restriction could be lifted, there seems no need to do so.
+_name_re = r"[^\s()]+"
+_keyvalue_rx = re.compile(r"(?P%s)\s*(?P[^\s].*)?$"
+ % _name_re)
+_section_start_rx = re.compile(r"(?P%s)"
+ r"(?:\s+(?P%s))?"
+ r"$"
+ % (_name_re, _name_re))
+
+
class ZConfigParser(object):
__slots__ = ('resource', 'context', 'lineno',
@@ -172,21 +186,7 @@ def error(self, message):
ZConfig.ConfigurationSyntaxError(
message, self.url, self.lineno))
-
def _normalize_case(self, string):
# This method is factored out solely to allow subclasses to modify
# the behavior of the parser.
return string.lower()
-
-
-import re
-# _name_re does not allow "(" or ")" for historical reasons. Though
-# the restriction could be lifted, there seems no need to do so.
-_name_re = r"[^\s()]+"
-_keyvalue_rx = re.compile(r"(?P%s)\s*(?P[^\s].*)?$"
- % _name_re)
-_section_start_rx = re.compile(r"(?P%s)"
- r"(?:\s+(?P%s))?"
- r"$"
- % (_name_re, _name_re))
-del re
diff --git a/ZConfig/cmdline.py b/ZConfig/cmdline.py
index 084f613..74c0a48 100644
--- a/ZConfig/cmdline.py
+++ b/ZConfig/cmdline.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2003 Zope Foundation and Contributors.
+# Copyright (c) 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -22,6 +22,7 @@ class from the :mod:`ZConfig.loader` module. This provides support for
Each setting is given by a value specifier string, as described by
:meth:`ExtendedConfigLoader.addOption`.
+
"""
import ZConfig
@@ -30,6 +31,7 @@ class from the :mod:`ZConfig.loader` module. This provides support for
from ZConfig._compat import raise_with_same_tb
+
class ExtendedConfigLoader(ZConfig.loader.ConfigLoader):
"""A :class:`~.ConfigLoader` subclass that adds support for
command-line overrides.
@@ -153,7 +155,7 @@ def get_section_info(self, type_, name):
bk = self.basic_key(s, pos)
if name and self._normalize_case(s) == name:
L.append((optpath[1:], val, pos))
- elif bk == type_: # pragma: no cover
+ elif bk == type_: # pragma: no cover
L.append((optpath[1:], val, pos))
else:
R.append(item)
@@ -206,6 +208,7 @@ def finish(self):
self.finish_optionbag()
return ZConfig.matcher.SectionMatcher.finish(self)
+
class ExtendedSchemaMatcher(MatcherMixin, ZConfig.matcher.SchemaMatcher):
def finish(self):
self.finish_optionbag()
diff --git a/ZConfig/components/basic/mapping.py b/ZConfig/components/basic/mapping.py
index e30c289..6122406 100644
--- a/ZConfig/components/basic/mapping.py
+++ b/ZConfig/components/basic/mapping.py
@@ -14,5 +14,6 @@
"""Python datatype for the ZConfig.components.basic.mapping section type."""
+
def mapping(section):
return section.mapping
diff --git a/ZConfig/components/basic/tests/test_mapping.py b/ZConfig/components/basic/tests/test_mapping.py
index 85e0890..63bf27c 100644
--- a/ZConfig/components/basic/tests/test_mapping.py
+++ b/ZConfig/components/basic/tests/test_mapping.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2003 Zope Foundation and Contributors.
+# Copyright (c) 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -13,7 +13,8 @@
##############################################################################
"""Tests of the 'basic' section types provided as part of
-ZConfig.components.basic."""
+ZConfig.components.basic.
+"""
import ZConfig.tests.support
import unittest
@@ -42,8 +43,8 @@
'''
-class BasicSectionTypeTestCase(
- ZConfig.tests.support.TestHelper, unittest.TestCase):
+class BasicSectionTypeTestCase(ZConfig.tests.support.TestHelper,
+ unittest.TestCase):
schema = None
@@ -87,5 +88,6 @@ def test_derived_dict(self):
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
diff --git a/ZConfig/components/logger/datatypes.py b/ZConfig/components/logger/datatypes.py
index 8f7ff37..d521430 100644
--- a/ZConfig/components/logger/datatypes.py
+++ b/ZConfig/components/logger/datatypes.py
@@ -28,6 +28,7 @@
"notset": 0,
}
+
def logging_level(value):
s = str(value).lower()
if s in _logging_levels:
diff --git a/ZConfig/components/logger/factory.py b/ZConfig/components/logger/factory.py
index dfe57b5..ce4b813 100644
--- a/ZConfig/components/logger/factory.py
+++ b/ZConfig/components/logger/factory.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -12,12 +12,14 @@
#
##############################################################################
-_marker = object()
-
from abc import abstractmethod
from ZConfig._compat import AbstractBaseClass
+
+_marker = object()
+
+
class Factory(AbstractBaseClass):
"""Generic wrapper for instance construction.
@@ -27,7 +29,9 @@ class Factory(AbstractBaseClass):
The instance is created using the factory's create() method, which
must be overriden by subclasses.
+
"""
+
def __init__(self):
self.instance = _marker
diff --git a/ZConfig/components/logger/handlers.py b/ZConfig/components/logger/handlers.py
index 1c05f70..4b9c2e8 100644
--- a/ZConfig/components/logger/handlers.py
+++ b/ZConfig/components/logger/handlers.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2003 Zope Foundation and Contributors.
+# Copyright (c) 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -20,6 +20,7 @@
from ZConfig.components.logger.factory import Factory
+
_log_format_variables = {
'name': '',
'levelno': '3',
@@ -37,6 +38,7 @@
'process': 1,
}
+
def log_format(value):
value = ctrl_char_insert(value)
try:
@@ -48,14 +50,17 @@ def log_format(value):
raise ValueError('Invalid log format string %s' % value)
return value
+
_control_char_rewrites = {r'\n': '\n', r'\t': '\t', r'\b': '\b',
r'\f': '\f', r'\r': '\r'}.items()
+
def ctrl_char_insert(value):
for pattern, replacement in _control_char_rewrites:
value = value.replace(pattern, replacement)
return value
+
def resolve(name):
"""Given a dotted name, returns an object imported from a Python module."""
name = name.split('.')
@@ -70,7 +75,9 @@ def resolve(name):
found = getattr(found, n)
return found
+
class HandlerFactory(Factory):
+
def __init__(self, section):
Factory.__init__(self)
self.section = section
@@ -90,10 +97,12 @@ def create(self):
logger.setLevel(self.section.level)
return logger
- def getLevel(self): # pragma: no cover Is this used?
+ def getLevel(self): # pragma: no cover Is this used?
return self.section.level
+
class FileHandlerFactory(HandlerFactory):
+
def create_loghandler(self):
from ZConfig.components.logger import loghandler
path = self.section.path
@@ -130,6 +139,7 @@ def create_loghandler(self):
handler = loghandler.FileHandler(path)
return handler
+
_syslog_facilities = {
"auth": 1,
"authpriv": 1,
@@ -153,6 +163,7 @@ def create_loghandler(self):
"local7": 1,
}
+
def syslog_facility(value):
value = value.lower()
if value not in _syslog_facilities:
@@ -160,17 +171,22 @@ def syslog_facility(value):
raise ValueError("Syslog facility must be one of " + ", ".join(L))
return value
+
class SyslogHandlerFactory(HandlerFactory):
+
def create_loghandler(self):
from ZConfig.components.logger import loghandler
return loghandler.SysLogHandler(self.section.address.address,
self.section.facility)
+
class Win32EventLogFactory(HandlerFactory):
+
def create_loghandler(self):
from ZConfig.components.logger import loghandler
return loghandler.Win32EventLogHandler(self.section.appname)
+
def http_handler_url(value):
scheme, netloc, path, param, query, fragment = urlparse.urlparse(value)
if scheme != 'http':
@@ -191,6 +207,7 @@ def http_handler_url(value):
q.append(fragment)
return (netloc, path + ''.join(q))
+
def get_or_post(value):
value = value.upper()
if value not in ('GET', 'POST'):
@@ -198,13 +215,17 @@ def get_or_post(value):
+ repr(value))
return value
+
class HTTPHandlerFactory(HandlerFactory):
+
def create_loghandler(self):
from ZConfig.components.logger import loghandler
host, selector = self.section.url
return loghandler.HTTPHandler(host, selector, self.section.method)
+
class SMTPHandlerFactory(HandlerFactory):
+
def create_loghandler(self):
from ZConfig.components.logger import loghandler
host, port = self.section.smtp_server
diff --git a/ZConfig/components/logger/logger.py b/ZConfig/components/logger/logger.py
index e786692..9cb2a12 100644
--- a/ZConfig/components/logger/logger.py
+++ b/ZConfig/components/logger/logger.py
@@ -25,6 +25,7 @@ class LoggerFactoryBase(Factory):
to allow the app time to set an effective user). An instance of
this wrapper is a callable which, when called, returns a logger
object.
+
"""
def __init__(self, section):
@@ -55,6 +56,7 @@ def getLowestHandlerLevel(self):
If all handlers and the logger itself have level==NOTSET, this
returns NOTSET.
+
"""
import logging
lowest = self.level
@@ -74,6 +76,7 @@ def reopen(self):
factory directly; handlers for child loggers are not affected.
(This can be considered a bug, but is sufficient at the
moment.)
+
"""
logger = self()
for handler in logger.handlers:
diff --git a/ZConfig/components/logger/loghandler.py b/ZConfig/components/logger/loghandler.py
index 2d9c6bd..2652b28 100644
--- a/ZConfig/components/logger/loghandler.py
+++ b/ZConfig/components/logger/loghandler.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2001 Zope Foundation and Contributors.
+# Copyright (c) 2001, 2018 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -13,29 +13,25 @@
"""Handlers which can plug into a PEP 282 logger."""
+import logging
+import logging.handlers
import os
-
import weakref
-from logging import Handler, StreamHandler
-from logging.handlers import RotatingFileHandler as _RotatingFileHandler
-from logging.handlers import TimedRotatingFileHandler \
- as _TimedRotatingFileHandler
-from logging.handlers import SysLogHandler, BufferingHandler
-from logging.handlers import HTTPHandler, SMTPHandler
-from logging.handlers import NTEventLogHandler as Win32EventLogHandler
+from ZConfig._compat import maxsize
-# Export these, they're used in handlers.py
-SysLogHandler = SysLogHandler
-HTTPHandler = HTTPHandler
-SMTPHandler = SMTPHandler
-Win32EventLogHandler = Win32EventLogHandler
-from ZConfig._compat import maxsize
+# Export these, they're used in handlers.py
+StreamHandler = logging.StreamHandler
+SysLogHandler = logging.handlers.SysLogHandler
+HTTPHandler = logging.handlers.HTTPHandler
+SMTPHandler = logging.handlers.SMTPHandler
+Win32EventLogHandler = logging.handlers.NTEventLogHandler
_reopenable_handlers = []
+
def closeFiles():
"""Reopen all logfiles managed by ZConfig configuration."""
while _reopenable_handlers:
@@ -44,6 +40,7 @@ def closeFiles():
if h is not None:
h.close()
+
def reopenFiles():
"""Reopen all logfiles managed by ZConfig configuration."""
for wr in _reopenable_handlers[:]:
@@ -56,6 +53,7 @@ def reopenFiles():
else:
h.reopen()
+
def _remove_from_reopenable(wr):
try:
_reopenable_handlers.remove(wr)
@@ -63,7 +61,7 @@ def _remove_from_reopenable(wr):
pass
-class FileHandler(StreamHandler):
+class FileHandler(logging.StreamHandler):
"""File handler which supports reopening of logs.
Re-opening should be used instead of the 'rollover' feature of
@@ -72,7 +70,7 @@ class FileHandler(StreamHandler):
def __init__(self, filename, mode="a"):
filename = os.path.abspath(filename)
- StreamHandler.__init__(self, open(filename, mode))
+ logging.StreamHandler.__init__(self, open(filename, mode))
self.baseFilename = filename
self.mode = mode
self._wr = weakref.ref(self, _remove_from_reopenable)
@@ -85,8 +83,8 @@ def close(self):
# StreamHandler.close() isn't called. This seems the best
# compromise. :-(
try:
- StreamHandler.close(self)
- except KeyError: # pragma: no cover
+ logging.StreamHandler.close(self)
+ except KeyError: # pragma: no cover
pass
_remove_from_reopenable(self._wr)
@@ -103,11 +101,12 @@ class Win32FileHandler(FileHandler):
"""File-based log handler for Windows that supports an additional 'rotate'
method. reopen() is generally useless since Windows cannot do a move on
an open file.
+
"""
+
def rotate(self, rotateFilename=None):
if not rotateFilename:
rotateFilename = self.baseFilename + ".last"
- error = None
self.close()
try:
os.rename(self.baseFilename, rotateFilename)
@@ -116,42 +115,44 @@ def rotate(self, rotateFilename=None):
self.stream = open(self.baseFilename, self.mode)
+
if os.name == "nt":
# Make it the default for Windows - we install a 'reopen' handler that
# tries to rotate the logfile.
FileHandler = Win32FileHandler
-class RotatingFileHandler(_RotatingFileHandler):
+class RotatingFileHandler(logging.handlers.RotatingFileHandler):
def __init__(self, *args, **kw):
- _RotatingFileHandler.__init__(self, *args, **kw)
+ logging.handlers.RotatingFileHandler.__init__(self, *args, **kw)
self._wr = weakref.ref(self, _remove_from_reopenable)
_reopenable_handlers.append(self._wr)
def close(self):
- _RotatingFileHandler.close(self)
+ logging.handlers.RotatingFileHandler.close(self)
_remove_from_reopenable(self._wr)
def reopen(self):
self.doRollover()
-class TimedRotatingFileHandler(_TimedRotatingFileHandler):
+
+class TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self, *args, **kw):
- _TimedRotatingFileHandler.__init__(self, *args, **kw)
+ logging.handlers.TimedRotatingFileHandler.__init__(self, *args, **kw)
self._wr = weakref.ref(self, _remove_from_reopenable)
_reopenable_handlers.append(self._wr)
def close(self):
- _TimedRotatingFileHandler.close(self)
+ logging.handlers.TimedRotatingFileHandler.close(self)
_remove_from_reopenable(self._wr)
def reopen(self):
self.doRollover()
-class NullHandler(Handler):
+class NullHandler(logging.Handler):
"""Handler that does nothing."""
def emit(self, record):
@@ -161,7 +162,7 @@ def handle(self, record):
pass
-class StartupHandler(BufferingHandler):
+class StartupHandler(logging.handlers.BufferingHandler):
"""Handler which stores messages in a buffer until later.
This is useful at startup before we can know that we can safely
@@ -169,7 +170,7 @@ class StartupHandler(BufferingHandler):
"""
def __init__(self):
- BufferingHandler.__init__(self, maxsize)
+ logging.handlers.BufferingHandler.__init__(self, maxsize)
def shouldFlush(self, record):
return False
diff --git a/ZConfig/components/logger/tests/test_logger.py b/ZConfig/components/logger/tests/test_logger.py
index b90c110..ced3b66 100644
--- a/ZConfig/components/logger/tests/test_logger.py
+++ b/ZConfig/components/logger/tests/test_logger.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -76,7 +76,7 @@ def tearDown(self):
for h in self._old_logger.handlers:
self._old_logger.removeHandler(h)
for h in self._old_handlers:
- self._old_logger.addHandler(h) # pragma: no cover
+ self._old_logger.addHandler(h) # pragma: no cover
self._old_logger.setLevel(self._old_level)
while self._created:
@@ -212,7 +212,7 @@ def test_with_timed_rotating_logfile(self):
self.assertEqual(logfile.level, logging.DEBUG)
self.assertEqual(logfile.backupCount, 11)
self.assertEqual(logfile.interval, 86400*3)
- self.assertTrue(isinstance(logfile, loghandler.TimedRotatingFileHandler))
+ self.assertIsInstance(logfile, loghandler.TimedRotatingFileHandler)
logger.removeHandler(logfile)
logfile.close()
@@ -258,7 +258,6 @@ def test_with_timed_rotating_logfile_and_size_should_fail(self):
" \n"
"" % fn)
-
def test_with_rotating_logfile_and_STD_should_fail(self):
for path in ('STDERR', 'STDOUT'):
for param in ('old-files 10', 'max-size 5mb'):
@@ -274,7 +273,6 @@ def test_with_rotating_logfile_and_STD_should_fail(self):
" \n"
"" % (path, param))
-
def check_standard_stream(self, name):
old_stream = getattr(sys, name)
conf = self.get_config("""
@@ -333,10 +331,10 @@ def test_with_syslog(self):
syslog = logger.handlers[0]
self.assertEqual(syslog.level, logging.ERROR)
self.assertTrue(isinstance(syslog, loghandler.SysLogHandler))
- syslog.close() # avoid ResourceWarning
+ syslog.close() # avoid ResourceWarning
try:
- syslog.socket.close() # ResourceWarning under 3.2
- except socket.SocketError: # pragma: no cover
+ syslog.socket.close() # ResourceWarning under 3.2
+ except socket.SocketError: # pragma: no cover
pass
def test_with_http_logger_localhost(self):
@@ -686,6 +684,7 @@ def test_filehandler_reopen_thread_safety(self):
self.assertEqual(calls, ["acquire", "release"])
+
class TestFunctions(TestHelper, unittest.TestCase):
def test_log_format_bad(self):
@@ -727,9 +726,12 @@ def test_http_handler_url(self):
def test_close_files(self):
class F(object):
closed = 0
+
def close(self):
self.closed += 1
+
f = F()
+
def wr():
return f
@@ -788,8 +790,10 @@ def test_buffer(self):
self.assertEqual(maxsize, handler.capacity)
records = []
+
def handle(record):
records.append(record)
+
handle.handle = handle
handler.flushBufferTo(handle)
@@ -801,6 +805,7 @@ def handle(record):
del handle.handle
+
def test_logger_convenience_function_and_ommiting_name_to_get_root_logger():
"""
@@ -853,11 +858,13 @@ def test_logger_convenience_function_and_ommiting_name_to_get_root_logger():
"""
+
def test_suite():
return unittest.TestSuite([
unittest.defaultTestLoader.loadTestsFromName(__name__),
doctest.DocTestSuite()
])
+
if __name__ == '__main__':
unittest.main(defaultTest="test_suite")
diff --git a/ZConfig/datatypes.py b/ZConfig/datatypes.py
index aa55766..1d3c051 100644
--- a/ZConfig/datatypes.py
+++ b/ZConfig/datatypes.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -27,6 +27,7 @@
input value is not acceptable. :exc:`ValueError` is the preferred
exception for disallowed inputs, but any other exception will be
properly propagated.
+
"""
import os
@@ -34,14 +35,10 @@
import sys
import datetime
-try:
- unicode
-except NameError:
- # Python 3
- have_unicode = False
+from ZConfig._compat import have_unicode, text_type, PY3
+
+if PY3:
from functools import reduce
-else:
- have_unicode = True
class MemoizedConversion(object):
@@ -51,6 +48,7 @@ class MemoizedConversion(object):
at a later time; failed conversions are not cached in any way, since
it is difficult to raise a meaningful exception providing
information about the specific failure.
+
"""
def __init__(self, conversion):
@@ -75,6 +73,7 @@ class RangeCheckedConversion(object):
not ``None``, are the inclusive endpoints of the allowed range.
Values returned by *conversion* which lay outside the range
described by *min* and *max* cause :exc:`ValueError` to be raised.
+
"""
def __init__(self, conversion, min=None, max=None):
@@ -132,6 +131,7 @@ def check_locale(value):
class BasicKeyConversion(RegularExpressionConversion):
+
def __init__(self):
RegularExpressionConversion.__init__(self, "[a-zA-Z][-._a-zA-Z0-9]*")
@@ -141,15 +141,17 @@ def __call__(self, value):
class ASCIIConversion(RegularExpressionConversion):
+
def __call__(self, value):
value = RegularExpressionConversion.__call__(self, value)
- if have_unicode and isinstance(value, unicode):
+ if have_unicode and isinstance(value, text_type):
value = value.encode("ascii")
return value
_ident_re = "[_a-zA-Z][_a-zA-Z0-9]*"
+
class IdentifierConversion(ASCIIConversion):
reason = "not a valid Python identifier"
@@ -220,7 +222,7 @@ def __call__(self, s):
# last part is not the port number
host = s
p = None
- if p: # else leave port at None
+ if p: # else leave port at None
port = port_number(p)
host = host.lower()
else:
@@ -244,6 +246,7 @@ def __call__(self, s):
inet_connection_address = InetAddress("127.0.0.1")
inet_binding_address = InetAddress("")
+
class SocketAddress(object):
# Parsing results in family and address
# Family can be AF_UNIX (for addresses that are path names)
@@ -253,6 +256,7 @@ class SocketAddress(object):
# Notice that no DNS lookup is performed, so if the host
# is a DNS name, DNS lookup may end up with either IPv4 or
# IPv6 addresses, or both
+
def __init__(self, s):
import socket
if "/" in s or s.find(os.sep) >= 0:
@@ -267,11 +271,13 @@ def __init__(self, s):
def _parse_address(self, s):
return inet_address(s)
+
class SocketBindingAddress(SocketAddress):
def _parse_address(self, s):
return inet_binding_address(s)
+
class SocketConnectionAddress(SocketAddress):
def _parse_address(self, s):
@@ -288,13 +294,13 @@ def __init__(self):
# We allow underscores in hostnames although this is considered
# illegal according to RFC1034.
# Addition: IPv6 addresses are now also accepted
- expr = (r"(^(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])$)" #ipaddr cont'd
- r"|([A-Za-z_][-A-Za-z0-9_.]*[-A-Za-z0-9_])" # or hostname
- r"|([0-9A-Fa-f:.]+:[0-9A-Fa-f:.]*)" # or superset of IPv6 addresses
- # (requiring at least one colon)
+ expr = (r"(^(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." # ipaddr
+ r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." # ipaddr cont'd
+ r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." # ipaddr cont'd
+ r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])$)" # ipaddr cont'd
+ r"|([A-Za-z_][-A-Za-z0-9_.]*[-A-Za-z0-9_])" # or hostname
+ # or superset of IPv6 addresses (requiring at least one colon)
+ r"|([0-9A-Fa-f:.]+:[0-9A-Fa-f:.]*)"
)
RegularExpressionConversion.__init__(self, expr)
@@ -310,24 +316,28 @@ def __call__(self, value):
raise ValueError('%r is not a valid IPv6 address' % value)
return result
+
def existing_directory(v):
nv = os.path.expanduser(v)
if os.path.isdir(nv):
return nv
raise ValueError('%s is not an existing directory' % v)
+
def existing_path(v):
nv = os.path.expanduser(v)
if os.path.exists(nv):
return nv
raise ValueError('%s is not an existing path' % v)
+
def existing_file(v):
nv = os.path.expanduser(v)
if os.path.exists(nv):
return nv
raise ValueError('%s is not an existing file' % v)
+
def existing_dirpath(v):
nv = os.path.expanduser(v)
dirname = os.path.dirname(nv)
@@ -348,10 +358,12 @@ def __init__(self, d, default=1):
self._d = d
self._default = default
# all keys must be the same size
+
def check(a, b):
if len(a) != len(b):
raise ValueError("suffix length mismatch")
return a
+
self._keysz = len(reduce(check, d))
def __call__(self, v):
@@ -418,8 +430,8 @@ def timedelta(s):
"socket-address": SocketAddress,
"socket-binding-address": SocketBindingAddress,
"socket-connection-address": SocketConnectionAddress,
- "ipaddr-or-hostname":IpaddrOrHostname(),
- "existing-directory":existing_directory,
+ "ipaddr-or-hostname": IpaddrOrHostname(),
+ "existing-directory": existing_directory,
"existing-path": existing_path,
"existing-file": existing_file,
"existing-dirpath": existing_dirpath,
@@ -442,7 +454,9 @@ class Registry(object):
If given, *stock* should be a mapping which defines the "built-in"
data types for the registry; if omitted or ``None``, the standard
set of data types is used (see :ref:`standard-datatypes`).
+
"""
+
def __init__(self, stock=None):
if stock is None:
stock = stock_datatypes.copy()
@@ -459,7 +473,7 @@ def find_name(self, conversion):
return k
# If they followed the rules, we shouldn't get here.
- return str(conversion) # pragma: no cover
+ return str(conversion) # pragma: no cover
def get(self, name):
"""Return the type conversion routine for *name*.
@@ -470,6 +484,7 @@ def get(self, name):
registered, this method uses the :meth:`search` method to load
the conversion function. This is the only method the rest of
:mod:`ZConfig` requires.
+
"""
if '.' not in name:
if self._basic_key is None:
@@ -493,6 +508,7 @@ def register(self, name, conversion):
If *name* is already registered or provided as a stock data
type, :exc:`ValueError` is raised (this includes the case when
*name* was found using the :meth:`search` method).
+
"""
if name in self._stock:
raise ValueError("datatype name conflicts with built-in type: "
@@ -509,8 +525,9 @@ def search(self, name):
for the name by dynamically importing the containing module
and extracting the value of the name. The name must refer to a
usable conversion function.
+
"""
- if not "." in name:
+ if "." not in name:
raise ValueError("unloadable datatype name: " + repr(name))
components = name.split('.')
start = components[0]
diff --git a/ZConfig/info.py b/ZConfig/info.py
index 26962a5..525d12b 100644
--- a/ZConfig/info.py
+++ b/ZConfig/info.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -22,6 +22,7 @@
from ZConfig._compat import AbstractBaseClass
+
@total_ordering
class UnboundedThing(object):
__slots__ = ()
@@ -34,9 +35,10 @@ def __gt__(self, other):
def __eq__(self, other):
return isinstance(other, self.__class__)
- def __repr__(self): # pragma: no cover
+ def __repr__(self): # pragma: no cover
return ""
+
Unbounded = UnboundedThing()
@@ -64,8 +66,10 @@ class BaseInfo(object):
def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
attribute):
- assert maxOccurs is not None, "Use Unbounded for an upper bound, not None"
- assert minOccurs is not None, "Use 0 for a lower bound, not None"
+ assert maxOccurs is not None, (
+ "Use Unbounded for an upper bound, not None")
+ assert minOccurs is not None, (
+ "Use 0 for a lower bound, not None")
if maxOccurs < 1:
raise ZConfig.SchemaError(
@@ -403,7 +407,7 @@ def getsectioninfo(self, type_, name):
if st.isabstract():
try:
st = st.getsubtype(type_)
- except ZConfig.ConfigurationError: # pragma: no cover
+ except ZConfig.ConfigurationError: # pragma: no cover
raise ZConfig.ConfigurationError(
"section type %s not allowed for name %s"
% (repr(type_), repr(key)))
@@ -420,19 +424,19 @@ def getsectioninfo(self, type_, name):
return info
elif info.sectiontype.isabstract():
st = info.sectiontype
- if st.name == type_: # pragma: no cover
+ if st.name == type_: # pragma: no cover
raise ZConfig.ConfigurationError(
"cannot define section with an abstract type")
try:
st = st.getsubtype(type_)
- except ZConfig.ConfigurationError: # pragma: no cover
+ except ZConfig.ConfigurationError: # pragma: no cover
# not this one; maybe a different one
pass
else:
return info
raise ZConfig.ConfigurationError(
- "no matching section defined for type='%s', name='%s'" % (
- type_, name))
+ "no matching section defined for type='%s', name='%s'"
+ % (type_, name))
def isabstract(self):
return False
@@ -470,7 +474,7 @@ def getunusedtypes(self):
alltypes.remove(n)
if self.name and self.name in alltypes:
# Not clear we can get here
- alltypes.remove(self.name) # pragma: no cover.
+ alltypes.remove(self.name) # pragma: no cover.
return alltypes
def createSectionType(self, name, keytype, valuetype, datatype):
diff --git a/ZConfig/loader.py b/ZConfig/loader.py
index dfa2bbc..aa371bc 100644
--- a/ZConfig/loader.py
+++ b/ZConfig/loader.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -214,7 +214,7 @@ def openResource(self, url):
except urllib2.URLError as e:
# urllib2.URLError has a particularly hostile str(), so we
# generally don't want to pass it along to the user.
- self._raise_open_error(url, e.reason) # pragma: no cover
+ self._raise_open_error(url, e.reason) # pragma: no cover
except (IOError, OSError) as e:
# Python 2.1 raises a different error from Python 2.2+,
# so we catch both to make sure we detect the situation.
@@ -371,7 +371,7 @@ def loadResource(self, resource):
def schemaComponentSource(self, package, filename):
parts = package.split(".")
- if not parts: # pragma: no cover. can we even get here?
+ if not parts: # pragma: no cover. can we even get here?
raise ZConfig.SchemaError(
"illegal schema component name: " + repr(package))
if "" in parts:
@@ -401,8 +401,8 @@ class ConfigLoader(BaseLoader):
conform to the schema *schema*. The ``load*()`` methods
return a tuple consisting of the configuration object and a
composite handler.
- """
+ """
def __init__(self, schema):
if schema.isabstract():
diff --git a/ZConfig/matcher.py b/ZConfig/matcher.py
index 2482478..ab4ee09 100644
--- a/ZConfig/matcher.py
+++ b/ZConfig/matcher.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -55,7 +55,7 @@ def addSection(self, type_, name, sectvalue):
v.append(sectvalue)
elif v is None:
self._values[attr] = sectvalue
- else: # pragma: no cover
+ else: # pragma: no cover
raise ZConfig.ConfigurationError(
"too many instances of %s section" % repr(ci.sectiontype.name))
@@ -76,7 +76,7 @@ def addValue(self, key, value, position):
raise ZConfig.ConfigurationError(
repr(key) + " is not a known key name")
k, ci = arbkey_info
- if ci.issection(): # pragma: no cover
+ if ci.issection(): # pragma: no cover
if ci.name:
extra = " in %s sections" % repr(self.type.name)
else:
@@ -90,15 +90,15 @@ def addValue(self, key, value, position):
v = self._values[attr]
if v is None:
if k == '+':
- v = {} # pragma: no cover
+ v = {} # pragma: no cover
elif ismulti:
- v = [] # pragma: no cover
+ v = [] # pragma: no cover
self._values[attr] = v
elif not ismulti:
if k != '+':
raise ZConfig.ConfigurationError(
repr(key) + " does not support multiple values")
- elif len(v) == ci.maxOccurs: # pragma: no cover
+ elif len(v) == ci.maxOccurs: # pragma: no cover
# This code may be impossible to hit. Previously it would
# have raised a NameError because it used an unbound
# local.
@@ -113,7 +113,7 @@ def addValue(self, key, value, position):
else:
v[realkey] = [value]
else:
- if realkey in v: # pragma: no cover
+ if realkey in v: # pragma: no cover
raise ZConfig.ConfigurationError(
"too many values for " + repr(key))
v[realkey] = value
@@ -155,7 +155,7 @@ def finish(self):
raise ZConfig.ConfigurationError(
"no values for %s; %s required" % (key, ci.minOccurs))
else:
- v = values[attr] = default[:] # pragma: no cover
+ v = values[attr] = default[:] # pragma: no cover
if ci.ismulti():
if not v:
default = ci.getdefault()
@@ -169,7 +169,7 @@ def finish(self):
% (key, len(v), ci.minOccurs))
if v is None and not ci.issection():
if ci.ismulti():
- v = ci.getdefault()[:] # pragma: no cover
+ v = ci.getdefault()[:] # pragma: no cover
else:
v = ci.getdefault()
values[attr] = v
@@ -282,12 +282,12 @@ def __repr__(self):
return "<%s for %s %s>" % (clsname, self._matcher.type.name, name)
def __str__(self):
- l = []
+ lst = []
attrnames = sorted([s for s in self.__dict__ if s[0] != "_"])
for k in attrnames:
v = getattr(self, k)
- l.append('%-40s: %s' % (k, v))
- return '\n'.join(l)
+ lst.append('%-40s: %s' % (k, v))
+ return '\n'.join(lst)
def getSectionName(self):
return self._name
diff --git a/ZConfig/schema.py b/ZConfig/schema.py
index 3a6b2e9..03e40d6 100644
--- a/ZConfig/schema.py
+++ b/ZConfig/schema.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
+# Copyright (c) 2002, 2003, 2018 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -26,6 +26,7 @@
BLANK = u''
+
def parseResource(resource, loader):
parser = SchemaParser(loader, resource.url)
xml.sax.parse(resource.file, parser)
@@ -54,7 +55,8 @@ class BaseParser(xml.sax.ContentHandler):
"description": ["key", "section", "multikey", "multisection",
"sectiontype", "abstracttype",
"schema", "component"],
- "example": ["schema", "sectiontype", "key", "multikey", "section", "multisection"],
+ "example": ["schema", "sectiontype", "key", "multikey",
+ "section", "multisection"],
"metadefault": ["key", "section", "multikey", "multisection"],
"default": ["key", "multikey"],
"import": ["schema", "component"],
@@ -101,17 +103,17 @@ def startElement(self, name, attrs):
# self._schema is assigned to in self.start_<_top_level>, so
# most of the checks for it being None are just extra precaution.
if name == self._top_level:
- if self._schema is not None: # pragma: no cover
+ if self._schema is not None: # pragma: no cover
self.error("schema element improperly nested")
getattr(self, "start_" + name)(attrs)
elif name in self._handled_tags:
- if self._schema is None: # pragma: no cover
+ if self._schema is None: # pragma: no cover
self.error(name + " element outside of schema")
getattr(self, "start_" + name)(attrs)
elif name in self._cdata_tags:
- if self._schema is None: # pragma: no cover
+ if self._schema is None: # pragma: no cover
self.error(name + " element outside of schema")
- if self._cdata is not None: # pragma: no cover
+ if self._cdata is not None: # pragma: no cover
# this should be handled by the earlier nesting check
self.error(name + " element improperly nested")
self._cdata = []
@@ -137,7 +139,7 @@ def endElement(self, name):
getattr(self, "characters_" + name)(data)
def endDocument(self):
- if self._schema is None: # pragma: no cover
+ if self._schema is None: # pragma: no cover
# this would have to be a broken subclass
self.error("no %s found" % self._top_level)
@@ -148,7 +150,7 @@ def get_position(self):
return (self._locator.getLineNumber(),
self._locator.getColumnNumber(),
(self._locator.getSystemId() or self._url))
- return None, None, self._url # pragma: no cover
+ return None, None, self._url # pragma: no cover
def get_handler(self, attrs):
v = attrs.get("handler")
@@ -235,7 +237,7 @@ def get_key_info(self, attrs, element):
any_name, name, attribute = self.get_name_info(attrs, element)
if any_name == '*':
self.error(element + " may not specify '*' for name")
- if not name and any_name != '+': # pragma: no cover
+ if not name and any_name != '+': # pragma: no cover
# Can we even get here?
self.error(element + " name may not be omitted or empty")
datatype = self.get_datatype(attrs, "datatype", "string")
@@ -365,7 +367,7 @@ def start_section(self, attrs):
handler = self.get_handler(attrs)
minOccurs = 1 if self.get_required(attrs) else 0
any_name, name, attribute = self.get_name_info(attrs, "section", "*")
- if any_name and not attribute: # pragma: no cover
+ if any_name and not attribute: # pragma: no cover
# It seems like this is handled by get_name_info.
self.error(
"attribute must be specified if section name is '*' or '+'")
@@ -380,7 +382,8 @@ def end_section(self):
def start_multisection(self, attrs):
sectiontype = self.get_sectiontype(attrs)
minOccurs, maxOccurs = self.get_ordinality(attrs)
- any_name, name, attribute = self.get_name_info(attrs, "multisection", "*")
+ any_name, name, attribute = self.get_name_info(
+ attrs, "multisection", "*")
if any_name not in ("*", "+"):
self.error("multisection must specify '*' or '+' for the name")
handler = self.get_handler(attrs)
@@ -431,7 +434,8 @@ def start_multikey(self, attrs):
name, datatype, handler, attribute = self.get_key_info(attrs,
"multikey")
minOccurs, maxOccurs = self.get_ordinality(attrs)
- key = info.MultiKeyInfo(name, datatype, minOccurs, maxOccurs, handler, attribute)
+ key = info.MultiKeyInfo(name, datatype, minOccurs, maxOccurs,
+ handler, attribute)
self._stack[-1].addkey(key)
self._stack.append(key)
@@ -598,7 +602,7 @@ def end_component(self):
self.pop_prefix()
def _check_not_toplevel(self, what):
- if not self._stack: # pragma: no cover
+ if not self._stack: # pragma: no cover
# we can't get here because the elements that call
# this function have specified _allowed_parents that are
# checked first
diff --git a/ZConfig/schema2html.py b/ZConfig/schema2html.py
index 99eb8e1..07ef522 100755
--- a/ZConfig/schema2html.py
+++ b/ZConfig/schema2html.py
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2003 Zope Corporation and Contributors.
+# Copyright (c) 2003, 2018 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -11,7 +11,6 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-from __future__ import print_function
import argparse
from contextlib import contextmanager
@@ -28,6 +27,7 @@
from ZConfig._schema_utils import load_schema
from ZConfig.sphinx import RstSchemaPrinter
+
class HtmlSchemaFormatter(AbstractSchemaFormatter):
def esc(self, x):
@@ -85,10 +85,12 @@ def body(self):
yield
self.write('