summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2018-09-26 08:20:39 -0500
committerJason Madden <jamadden@gmail.com>2018-09-26 08:20:39 -0500
commita8bb58e35a3b71e0da4baab8cec5d3e55c054e90 (patch)
treef735854016ba00bcce1d1da4077ac3e3fa4d4a8b
parent13ffadc2f097bc463a597f577fc932ced13fa3b7 (diff)
downloadzope-configuration-a8bb58e35a3b71e0da4baab8cec5d3e55c054e90.tar.gz
Stop catching and wrapping BaseException in config and xmlconfig.py
Add new tests for this.
-rw-r--r--CHANGES.rst5
-rw-r--r--src/zope/configuration/config.py10
-rw-r--r--src/zope/configuration/tests/test_config.py18
-rw-r--r--src/zope/configuration/tests/test_xmlconfig.py138
-rw-r--r--src/zope/configuration/xmlconfig.py18
5 files changed, 107 insertions, 82 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index eb5e594..00e185a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -52,6 +52,11 @@ Changes
``ConfigurationExecutionError``. See `issue 10
<https://github.com/zopefoundation/zope.configuration/issues/10>`_.
+- Stop catching ``BaseException`` and wrapping it in either
+ ``ConfigurationExecutionError`` or ``ZopeXMLConfigurationError``.
+ ``SystemExit`` and ``KeyboardInterrupt`` were always allowed to
+ propagate; now ``GeneratorExit`` and custom subclasses of
+ ``BaseException`` are also allowed te propagate.
4.1.0 (2017-04-26)
------------------
diff --git a/src/zope/configuration/config.py b/src/zope/configuration/config.py
index 61c37a8..265a528 100644
--- a/src/zope/configuration/config.py
+++ b/src/zope/configuration/config.py
@@ -333,13 +333,15 @@ class ConfigurationMachine(ConfigurationAdapterRegistry, ConfigurationContext):
includepath = ()
info = ''
- #: These exceptions are allowed to be raised from `execute_actions`
- #: without being re-wrapped into a `ConfigurationExecutionError`.
+ #: These `Exception` subclasses are allowed to be raised from `execute_actions`
+ #: without being re-wrapped into a `ConfigurationExecutionError`. (`BaseException`
+ #: instances are never wrapped.)
+ #:
#: Users of instances of this class may modify this before calling `execute_actions`
#: if they need to propagate specific exceptions.
#:
#: .. versionadded:: 4.2.0
- pass_through_exceptions = (KeyboardInterrupt, SystemExit)
+ pass_through_exceptions = ()
def __init__(self):
super(ConfigurationMachine, self).__init__()
@@ -390,7 +392,7 @@ class ConfigurationMachine(ConfigurationAdapterRegistry, ConfigurationContext):
callable(*args, **kw)
except pass_through_exceptions:
raise
- except:
+ except Exception:
t, v, tb = sys.exc_info()
try:
reraise(ConfigurationExecutionError(t, v, info),
diff --git a/src/zope/configuration/tests/test_config.py b/src/zope/configuration/tests/test_config.py
index 42e7e2b..4bd5930 100644
--- a/src/zope/configuration/tests/test_config.py
+++ b/src/zope/configuration/tests/test_config.py
@@ -770,11 +770,11 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext,
self.assertEqual(str(exc.exception.evalue), "XXX")
self.assertEqual(exc.exception.info, "INFO")
- def _check_execute_actions_w_errors_wo_testing(self, ex_kind):
+ def _check_execute_actions_w_errors_wo_testing(self, ex_kind, cm=None):
ex = ex_kind('XXX')
def _err(*args, **kw):
raise ex
- cm = self._makeOne()
+ cm = cm if cm is not None else self._makeOne()
cm.info = 'INFO'
cm.action(None, _err)
with self.assertRaises(ex_kind) as exc:
@@ -790,6 +790,20 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext,
# It gets passed through as-is
self._check_execute_actions_w_errors_wo_testing(KeyboardInterrupt)
+ def test_execute_actions_w_errors_wo_testing_BaseException(self):
+ # It gets passed through as-is
+ class Bex(BaseException):
+ pass
+ self._check_execute_actions_w_errors_wo_testing(Bex)
+
+ def test_execute_actions_w_errors_custom(self):
+ # It gets passed through as-is, if we ask it to
+ class Ex(Exception):
+ pass
+ cm = self._makeOne()
+ cm.pass_through_exceptions += (Ex,)
+ self._check_execute_actions_w_errors_wo_testing(Ex, cm)
+
def test_keyword_handling(self):
# This is really an integraiton test.
from zope.configuration.config import metans
diff --git a/src/zope/configuration/tests/test_xmlconfig.py b/src/zope/configuration/tests/test_xmlconfig.py
index beafd98..e75a8f0 100644
--- a/src/zope/configuration/tests/test_xmlconfig.py
+++ b/src/zope/configuration/tests/test_xmlconfig.py
@@ -156,42 +156,62 @@ class ConfigurationHandlerTests(unittest.TestCase):
})
self.assertEqual(handler.ignore_depth, 2)
- def test_startElementNS_context_begin_raises_wo_testing(self):
- from zope.configuration.xmlconfig import ZopeXMLConfigurationError
+ def _check_elementNS_context_raises(self, raises, catches,
+ testing=False,
+ meth='endElementNS',
+ meth_args=((NS, FOO), FOO)):
class ErrorContext(FauxContext):
- def begin(self, *args):
- raise AttributeError("xxx")
+ def end(self, *args):
+ raise raises("xxx")
+ begin = end
+ class Info(object):
+ _line = _col = None
+ def end(self, line, col):
+ self._line, self._col = line, col
context = ErrorContext()
+ info = Info()
+ context.setInfo(info)
locator = FauxLocator('tests//sample.zcml', 1, 1)
- handler = self._makeOne(context)
+ handler = self._makeOne(context, testing)
handler.setDocumentLocator(locator)
- with self.assertRaises(ZopeXMLConfigurationError) as exc:
- handler.startElementNS(
- (NS, FOO),
- FOO,
- {(XXX, SPLAT): SPLATV,
- (None, A): AVALUE,
- (None, B): BVALUE,
- })
- self.assertEqual(exc.exception.info.file, 'tests//sample.zcml')
- self.assertEqual(exc.exception.info.line, 1)
- self.assertEqual(exc.exception.info.column, 1)
+ locator.line, locator.column = 7, 16
+ meth = getattr(handler, meth)
+ with self.assertRaises(catches) as exc:
+ meth(*meth_args)
+ return exc.exception, info
+
+ def _check_startElementNS_context_begin_raises(self, raises, catches, testing=False):
+ return self._check_elementNS_context_raises(
+ raises, catches, testing,
+ meth='startElementNS',
+ meth_args=((NS, FOO),
+ FOO,
+ {(XXX, SPLAT): SPLATV,
+ (None, A): AVALUE,
+ (None, B): BVALUE,
+ })
+ )
+
+ def test_startElementNS_context_begin_raises_wo_testing(self):
+ from zope.configuration.xmlconfig import ZopeXMLConfigurationError
+ raised, _ = self._check_startElementNS_context_begin_raises(AttributeError,
+ ZopeXMLConfigurationError)
+ info = raised.info
+ self.assertEqual(info.file, 'tests//sample.zcml')
+ self.assertEqual(info.line, 7)
+ self.assertEqual(info.column, 16)
def test_startElementNS_context_begin_raises_w_testing(self):
- class ErrorContext(FauxContext):
- def begin(self, *args):
- raise AttributeError("xxx")
- context = ErrorContext()
- locator = FauxLocator('tests//sample.zcml', 1, 1)
- handler = self._makeOne(context, True)
- handler.setDocumentLocator(locator)
- with self.assertRaises(AttributeError):
- handler.startElementNS(
- (NS, FOO), FOO,
- {(XXX, SPLAT): SPLATV,
- (None, A): AVALUE,
- (None, B): BVALUE,
- })
+ self._check_startElementNS_context_begin_raises(AttributeError,
+ AttributeError,
+ True)
+
+ def test_startElementNS_context_begin_raises_BaseException(self):
+ class Bex(BaseException):
+ pass
+ self._check_startElementNS_context_begin_raises(Bex,
+ Bex)
+
def test_startElementNS_normal(self):
# Integration test of startElementNS / endElementNS pair.
@@ -222,47 +242,31 @@ class ConfigurationHandlerTests(unittest.TestCase):
handler.endElementNS((NS, FOO), FOO)
self.assertEqual(handler.ignore_depth, 0)
+ def _check_endElementNS_context_end_raises(self, raises, catches, testing=False):
+ return self._check_elementNS_context_raises(raises, catches, testing)
+
def test_endElementNS_context_end_raises_wo_testing(self):
from zope.configuration.xmlconfig import ZopeXMLConfigurationError
- class ErrorContext(FauxContext):
- def end(self):
- raise AttributeError("xxx")
- class Info(object):
- _line = _col = None
- def end(self, line, col):
- self._line, self._col = line, col
- context = ErrorContext()
- info = Info()
- context.setInfo(info)
- locator = FauxLocator('tests//sample.zcml', 1, 1)
- handler = self._makeOne(context)
- handler.setDocumentLocator(locator)
- locator.line, locator.column = 7, 16
- with self.assertRaises(ZopeXMLConfigurationError) as exc:
- handler.endElementNS((NS, FOO), FOO)
- self.assertTrue(exc.exception.info is context.info)
- self.assertEqual(exc.exception.info._line, 7)
- self.assertEqual(exc.exception.info._col, 16)
+
+ raised, info = self._check_endElementNS_context_end_raises(AttributeError,
+ ZopeXMLConfigurationError)
+
+ self.assertIs(raised.info, info)
+ self.assertEqual(raised.info._line, 7)
+ self.assertEqual(raised.info._col, 16)
def test_endElementNS_context_end_raises_w_testing(self):
- class ErrorContext(FauxContext):
- def end(self):
- raise AttributeError("xxx")
- class Info(object):
- _line = _col = None
- def end(self, line, col):
- self._line, self._col = line, col
- context = ErrorContext()
- info = Info()
- context.setInfo(info)
- locator = FauxLocator('tests//sample.zcml', 1, 1)
- handler = self._makeOne(context, True)
- handler.setDocumentLocator(locator)
- locator.line, locator.column = 7, 16
- with self.assertRaises(AttributeError):
- handler.endElementNS((NS, FOO), FOO)
- self.assertEqual(context.info._line, 7)
- self.assertEqual(context.info._col, 16)
+ _, info = self._check_endElementNS_context_end_raises(AttributeError,
+ AttributeError,
+ True)
+ self.assertEqual(info._line, 7)
+ self.assertEqual(info._col, 16)
+
+ def test_endElementNS_context_end_raises_BaseException(self):
+ class Bex(BaseException):
+ pass
+ self._check_endElementNS_context_end_raises(Bex,
+ Bex)
def test_evaluateCondition_w_have_no_args(self):
context = FauxContext()
diff --git a/src/zope/configuration/xmlconfig.py b/src/zope/configuration/xmlconfig.py
index d33cd69..24cdcac 100644
--- a/src/zope/configuration/xmlconfig.py
+++ b/src/zope/configuration/xmlconfig.py
@@ -162,7 +162,11 @@ class ConfigurationHandler(ContentHandler):
def __init__(self, context, testing=False):
self.context = context
- self.testing = testing
+ # We use this in an `except:` clause. For backwards
+ # compatibility, ever though this attribute isn't documented,
+ # we keep it in an attribute named 'testing' which can be interpreted
+ # as a boolean
+ self.testing = BaseException if testing else ()
self.ignore_depth = 0
def setDocumentLocator(self, locator):
@@ -201,11 +205,9 @@ class ConfigurationHandler(ContentHandler):
try:
self.context.begin(name, data, info)
- except (KeyboardInterrupt, SystemExit): # pragma: no cover
+ except self.testing:
raise
- except:
- if self.testing:
- raise
+ except Exception:
reraise(ZopeXMLConfigurationError(info,
sys.exc_info()[0],
sys.exc_info()[1]),
@@ -269,11 +271,9 @@ class ConfigurationHandler(ContentHandler):
try:
self.context.end()
- except (KeyboardInterrupt, SystemExit): # pragma: no cover
+ except self.testing:
raise
- except:
- if self.testing:
- raise
+ except Exception:
reraise(ZopeXMLConfigurationError(info,
sys.exc_info()[0],
sys.exc_info()[1]),