summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jason+github@nextthought.com>2017-09-11 09:25:01 -0500
committerGitHub <noreply@github.com>2017-09-11 09:25:01 -0500
commit009f4299cfdb22d871cad3c8fcedd97f4b5680ad (patch)
treec1e3247cb68507bdce169a17766091bd59c535f4
parenta19b95f381047bf1b957c2b83cb9cf0f42897cbb (diff)
parentaac82c40249095ec98afca4e88332e1db1790470 (diff)
downloadzope-security-009f4299cfdb22d871cad3c8fcedd97f4b5680ad.tar.gz
Merge pull request #36 from zopefoundation/issue8
Fix ZOPE_WATCH_CHECKERS in pure-Python mode
-rw-r--r--.travis.yml6
-rw-r--r--CHANGES.rst3
-rw-r--r--docs/conf.py34
-rw-r--r--src/zope/security/checker.py55
-rw-r--r--src/zope/security/tests/__init__.py18
-rw-r--r--src/zope/security/tests/test_checker.py48
-rw-r--r--src/zope/security/tests/test_decorator.py11
-rw-r--r--src/zope/security/tests/test_location.py20
-rw-r--r--tox.ini9
9 files changed, 142 insertions, 62 deletions
diff --git a/.travis.yml b/.travis.yml
index c38e00c..76848c2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,9 +9,11 @@ matrix:
- python: pypy
- python: pypy3
- python: 2.7
- env: PURE_PYTHON=1
+ env:
+ - PURE_PYTHON=1
+ - ZOPE_WATCH_CHECKERS=1
- python: 3.4
- env: PURE_PYTHON=1
+ env: ZOPE_WATCH_CHECKERS=1
install:
- pip install -U pip setuptools
- pip install -U coveralls coverage
diff --git a/CHANGES.rst b/CHANGES.rst
index ab5790b..450fc34 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -35,6 +35,9 @@ Changes
- Respect ``PURE_PYTHON`` at runtime. See `issue 33
<https://github.com/zopefoundation/zope.security/issues/33>`_.
+- Fix watching checkers (``ZOPE_WATCH_CHECKERS=1``) in pure-Python
+ mode. See `issue 8 <https://github.com/zopefoundation/zope.security/issues/8>`_.
+
4.1.1 (2017-05-17)
------------------
diff --git a/docs/conf.py b/docs/conf.py
index 2bcdf49..caabf00 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -11,8 +11,16 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import os
+import sys
+import pkg_resources
+sys.path.append(os.path.abspath('../src'))
+rqmt = pkg_resources.require('zope.security')[0]
+
+# We can't have ZOPE_WATCH_CHECKERS set because it interferes
+# with doctests
+os.environ['ZOPE_WATCH_CHECKERS'] = '0'
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -28,6 +36,7 @@ import sys, os
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
+ 'sphinx.ext.extlinks',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
'repoze.sphinx.autointerface',
@@ -54,9 +63,9 @@ copyright = u'2012, Zope Foundation Contributors <zope-dev@zope.org>'
# built documents.
#
# The short X.Y version.
-version = '4.0'
+version = '%s.%s' % tuple(map(int, rqmt.version.split('.')[:2]))
# The full version, including alpha/beta/rc tags.
-release = '4.0dev'
+release = rqmt.version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -249,4 +258,21 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'http://docs.python.org/': None}
+intersphinx_mapping = {
+ 'https://docs.python.org/': None,
+ 'https://zopeinterface.readthedocs.io/en/latest': None,
+ 'https://zopeproxy.readthedocs.io/en/latest': None,
+ 'https://zopeschema.readthedocs.io/en/latest': None,
+}
+
+extlinks = {'issue': ('https://github.com/zopefoundation/zope.datetime/issues/%s',
+ 'issue #'),
+ 'pr': ('https://github.com/zopefoundation/zope.datetime/pull/%s',
+ 'pull request #')}
+
+autodoc_default_flags = [
+ 'members',
+ 'show-inheritance',
+]
+autoclass_content = 'both'
+autodoc_member_order = 'bysource'
diff --git a/src/zope/security/checker.py b/src/zope/security/checker.py
index 238f748..575d16d 100644
--- a/src/zope/security/checker.py
+++ b/src/zope/security/checker.py
@@ -55,17 +55,17 @@ from zope.security.proxy import getChecker
try:
from zope.exceptions import DuplicationError
-except ImportError: #pragma NO COVER
+except ImportError: # pragma: no cover
class DuplicationError(Exception):
"""A duplicate registration was attempted"""
-if os.environ.get('ZOPE_WATCH_CHECKERS'): #pragma NO COVER
+WATCH_CHECKERS = 0
+
+if os.environ.get('ZOPE_WATCH_CHECKERS'):
try:
WATCH_CHECKERS = int(os.environ.get('ZOPE_WATCH_CHECKERS'))
except ValueError:
WATCH_CHECKERS = 1
-else:
- WATCH_CHECKERS = 0
def ProxyFactory(object, checker=None):
@@ -256,19 +256,19 @@ class TracebackSupplement(object):
cls = self.obj.__class__
if hasattr(cls, "__module__"):
s = "%s.%s" % (cls.__module__, cls.__name__)
- else: #pragma NO COVER XXX
+ else: # pragma: no cover XXX
s = str(cls.__name__)
result.append(" - class: " + s)
- except: #pragma NO COVER XXX
+ except: # pragma: no cover XXX
pass
try:
cls = type(self.obj)
if hasattr(cls, "__module__"):
s = "%s.%s" % (cls.__module__, cls.__name__)
- else: #pragma NO COVER XXX
+ else: # pragma: no cover XXX
s = str(cls.__name__)
result.append(" - type: " + s)
- except: #pragma NO COVER XXX
+ except: # pragma: no cover XXX
pass
return "\n".join(result)
@@ -282,7 +282,7 @@ class Global(object):
"""
def __init__(self, name, module=None):
- if module is None: #pragma NO COVER XXX
+ if module is None: # pragma: no cover XXX
module = sys._getframe(1).f_locals['__name__']
self.__name__ = name
@@ -395,6 +395,7 @@ def selectCheckerPy(object):
while not isinstance(checker, Checker):
checker = checker(object)
+
if checker is NoProxy or checker is None:
return None
@@ -443,7 +444,7 @@ _c_available = not PURE_PYTHON
if _c_available:
try:
import zope.security._zope_security_checker
- except (ImportError, AttributeError): #pragma NO COVER PyPy / PURE_PYTHON
+ except (ImportError, AttributeError): # pragma: no cover PyPy / PURE_PYTHON
_c_available = False
if _c_available:
@@ -479,6 +480,7 @@ class CombinedChecker(Checker):
Checker.__init__(self,
checker1.get_permissions,
checker1.set_permissions)
+
self._checker2 = checker2
def check(self, object, name):
@@ -580,11 +582,24 @@ class CheckerLoggingMixin(object):
raise
-if WATCH_CHECKERS: #pragma NO COVER
- class Checker(CheckerLoggingMixin, Checker):
- verbosity = WATCH_CHECKERS
- class CombinedChecker(CheckerLoggingMixin, CombinedChecker):
- verbosity = WATCH_CHECKERS
+# We have to be careful with the order of inheritance
+# here. See https://github.com/zopefoundation/zope.security/issues/8
+class WatchingChecker(CheckerLoggingMixin, Checker):
+ verbosity = WATCH_CHECKERS
+class WatchingCombinedChecker(CombinedChecker, WatchingChecker):
+ verbosity = WATCH_CHECKERS
+
+if WATCH_CHECKERS: # pragma: no cover
+ # When we make these the default, we also need to be sure
+ # to update the _defaultChecker's type (if it's not the C
+ # extension) so that selectCheckerPy can properly recognize
+ # it as a Checker.
+ # See https://github.com/zopefoundation/zope.security/issues/8
+ Checker = WatchingChecker
+ CombinedChecker = WatchingCombinedChecker
+
+ if not _c_available:
+ _defaultChecker.__class__ = Checker
def _instanceChecker(inst):
return _checkers.get(inst.__class__, _defaultChecker)
@@ -658,7 +673,7 @@ _basic_types = {
if PYTHON2:
_basic_types[long] = NoProxy
_basic_types[unicode] = NoProxy
-else: #pragma NO COVER
+else: # pragma: no cover
_basic_types[type({}.values())] = NoProxy
_basic_types[type({}.keys())] = NoProxy
_basic_types[type({}.items())] = NoProxy
@@ -667,7 +682,7 @@ try:
import pytz
except ImportError:
pass
-else: #pragma NO COVER
+else: # pragma: no cover
_basic_types[type(pytz.UTC)] = NoProxy
BasicTypes = BasicTypes(_basic_types)
@@ -694,7 +709,7 @@ if PYTHON2:
BasicTypes_examples[long] = long(65536)
-class _Sequence(object): #pragma NO COVER
+class _Sequence(object): # pragma: no cover
def __len__(self): return 0
def __getitem__(self, i): raise IndexError
@@ -706,7 +721,7 @@ _Declaration_checker = InterfaceChecker(
__call__=CheckerPublic,
)
-def f(): #pragma NO COVER
+def f(): # pragma: no cover
yield f
@@ -940,7 +955,7 @@ _clear()
try:
from zope.testing.cleanup import addCleanUp
-except ImportError: #pragma NO COVER
+except ImportError: # pragma: no cover
pass
else:
addCleanUp(_clear)
diff --git a/src/zope/security/tests/__init__.py b/src/zope/security/tests/__init__.py
index b711d36..cab4c90 100644
--- a/src/zope/security/tests/__init__.py
+++ b/src/zope/security/tests/__init__.py
@@ -1,2 +1,16 @@
-#
-# This file is necessary to make this directory a package.
+import io
+
+
+class QuietWatchingChecker(object):
+ # zope.testrunner does not support setUp/tearDownModule,
+ # so we use a mixin class to make sure we don't flood stderr
+ # with pointless printing when testing watching checkers
+
+ def setUp(self):
+ from zope.security import checker
+ self.__old_file = checker.CheckerLoggingMixin._file
+ checker.CheckerLoggingMixin._file = io.StringIO() if bytes is not str else io.BytesIO()
+
+ def tearDown(self):
+ from zope.security import checker
+ checker.CheckerLoggingMixin._file = self.__old_file
diff --git a/src/zope/security/tests/test_checker.py b/src/zope/security/tests/test_checker.py
index 9aaee38..d5cdc7f 100644
--- a/src/zope/security/tests/test_checker.py
+++ b/src/zope/security/tests/test_checker.py
@@ -13,8 +13,11 @@
##############################################################################
"""Tests for zope.security.checker
"""
+
import unittest
+
from zope.security import checker
+from zope.security.tests import QuietWatchingChecker
def _skip_if_not_Py2(testfunc):
import sys
@@ -28,6 +31,7 @@ def _skip_if_no_btrees(testfunc):
else:
return testfunc
+
class Test_ProxyFactory(unittest.TestCase):
def _callFUT(self, object, checker=None):
@@ -199,7 +203,7 @@ class Test_canAccess(unittest.TestCase):
_marker = []
-class CheckerTestsBase(object):
+class CheckerTestsBase(QuietWatchingChecker):
def _getTargetClass(self):
raise NotImplementedError("Subclasses must define")
@@ -586,16 +590,20 @@ class CheckerTestsBase(object):
class TestCheckerPy(CheckerTestsBase, unittest.TestCase):
def _getTargetClass(self):
- from zope.security.checker import CheckerPy
- return CheckerPy
+ return checker.CheckerPy
class TestChecker(CheckerTestsBase, unittest.TestCase):
def _getTargetClass(self):
- from zope.security.checker import Checker
- return Checker
+ return checker.Checker
+@unittest.skipIf(checker.Checker is checker.WatchingChecker,
+ "WatchingChecker is the default")
+class TestWatchingChecker(TestChecker):
+
+ def _getTargetClass(self):
+ return checker.WatchingChecker
class TestTracebackSupplement(unittest.TestCase):
@@ -1116,7 +1124,8 @@ class Test_undefineChecker(unittest.TestCase):
self.assertFalse(Foo in _checkers)
-class TestCombinedChecker(unittest.TestCase):
+class TestCombinedChecker(QuietWatchingChecker,
+ unittest.TestCase):
def _getTargetClass(self):
from zope.security.checker import CombinedChecker
@@ -1339,6 +1348,12 @@ class TestCombinedChecker(unittest.TestCase):
finally:
del thread_local.interaction
+@unittest.skipIf(checker.WatchingCombinedChecker is checker.CombinedChecker,
+ "WatchingCombinedChecker is the default")
+class TestWatchingCombinedChecker(TestCombinedChecker):
+
+ def _getTargetClass(self):
+ return checker.WatchingCombinedChecker
class TestCheckerLoggingMixin(unittest.TestCase):
@@ -1605,23 +1620,26 @@ class TestBasicTypes(unittest.TestCase):
# Pre-geddon tests start here
-class TestSecurityPolicy(unittest.TestCase):
+class TestSecurityPolicy(QuietWatchingChecker,
+ unittest.TestCase):
def setUp(self):
+ super(TestSecurityPolicy, self).setUp()
+
from zope.security.management import newInteraction
from zope.security.management import setSecurityPolicy
- from zope.security.checker import _clear
- _clear()
+ checker._clear()
self.__oldpolicy = setSecurityPolicy(self._makeSecurityPolicy())
newInteraction()
def tearDown(self):
+ super(TestSecurityPolicy, self).tearDown()
+
from zope.security.management import endInteraction
from zope.security.management import setSecurityPolicy
- from zope.security.checker import _clear
endInteraction()
setSecurityPolicy(self.__oldpolicy)
- _clear()
+ checker._clear()
def _makeSecurityPolicy(self):
from zope.interface import implementer
@@ -2193,15 +2211,17 @@ class TestMixinDecoratedChecker(unittest.TestCase):
from zope.security.checker import Checker
return Checker(self.decorationGetMap, self.decorationSetMap)
-class TestCombinedCheckerMixin(TestMixinDecoratedChecker, unittest.TestCase):
+class TestCombinedCheckerMixin(QuietWatchingChecker,
+ TestMixinDecoratedChecker,
+ unittest.TestCase):
def setUp(self):
- unittest.TestCase.setUp(self)
+ super(TestCombinedCheckerMixin, self).setUp()
self.decoratedSetUp()
def tearDown(self):
self.decoratedTearDown()
- unittest.TestCase.tearDown(self)
+ super(TestCombinedCheckerMixin, self).tearDown()
def test_checking(self):
from zope.security.interfaces import Unauthorized
diff --git a/src/zope/security/tests/test_decorator.py b/src/zope/security/tests/test_decorator.py
index 9319e6b..650380d 100644
--- a/src/zope/security/tests/test_decorator.py
+++ b/src/zope/security/tests/test_decorator.py
@@ -14,14 +14,19 @@
"""Test zope.security.decorator
"""
import unittest
+from zope.security.tests import QuietWatchingChecker
-class DecoratedSecurityCheckerDescriptorTests(unittest.TestCase):
+
+class DecoratedSecurityCheckerDescriptorTests(QuietWatchingChecker,
+ unittest.TestCase):
def setUp(self):
+ super(DecoratedSecurityCheckerDescriptorTests, self).setUp()
from zope.security.checker import _clear
_clear()
def tearDown(self):
+ super(DecoratedSecurityCheckerDescriptorTests, self).tearDown()
from zope.security.checker import _clear
_clear()
@@ -168,6 +173,4 @@ class DecoratedSecurityCheckerDescriptorTests(unittest.TestCase):
def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite(DecoratedSecurityCheckerDescriptorTests),
- ))
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
diff --git a/src/zope/security/tests/test_location.py b/src/zope/security/tests/test_location.py
index 8905fca..5625f4e 100644
--- a/src/zope/security/tests/test_location.py
+++ b/src/zope/security/tests/test_location.py
@@ -15,21 +15,19 @@
"""
import unittest
+from zope.security.tests import QuietWatchingChecker
def _skip_wo_zope_location(testfunc):
try:
- import zope.location
+ import zope.location as zl
except ImportError:
- from functools import update_wrapper
- def dummy(self):
- pass
- update_wrapper(dummy, testfunc)
- return dummy
- else:
- return testfunc
+ zl = None
+ return unittest.skipIf(zl is None, "Need zope.location")(testfunc)
-class LocationSecurityProxyTests(unittest.TestCase):
+
+class LocationSecurityProxyTests(QuietWatchingChecker,
+ unittest.TestCase):
@_skip_wo_zope_location
def test_locationproxy_security(self):
@@ -53,6 +51,4 @@ class LocationSecurityProxyTests(unittest.TestCase):
def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite(LocationSecurityProxyTests),
- ))
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
diff --git a/tox.ini b/tox.ini
index c0e57fb..36a065c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,7 +3,7 @@ envlist =
# Jython support pending 2.7 support, due 2012-07-15 or so. See:
# http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html
# py27,pypy,jython,py33,coverage,docs
- py27,py27-pure,pypy,py34-pure,py34,py35,py36,coverage,docs
+ py27,py27-watch,pypy,pypy3,py34-watch,py34,py35,py36,coverage,docs
[testenv]
commands =
@@ -12,18 +12,19 @@ commands =
deps =
.[test,docs]
-[testenv:py27-pure]
+[testenv:py27-watch]
basepython =
python2.7
setenv =
PURE_PYTHON = 1
+ ZOPE_WATCH_CHECKERS = 1
PIP_CACHE_DIR = {envdir}/.cache
-[testenv:py34-pure]
+[testenv:py34-watch]
basepython =
python3.4
setenv =
- PURE_PYTHON = 1
+ ZOPE_WATCH_CHECKERS = 1
PIP_CACHE_DIR = {envdir}/.cache
[testenv:coverage]