summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTres Seaver <tseaver@palladion.com>2013-03-08 14:38:02 -0500
committerTres Seaver <tseaver@palladion.com>2013-03-08 14:38:02 -0500
commitaa830118284fc1c5a6881f8258f39e046a28ce79 (patch)
tree4a64e35121eac495f14c9d7405c30ba6dad69d79
parentd59c575269bafa1429608f9433bdaccb0f5568ee (diff)
parent21bedd54cead429a36545ab4107cd7b1b1b08417 (diff)
downloadzope-security-aa830118284fc1c5a6881f8258f39e046a28ce79.tar.gz
Merge branch 'master' into pure_python_proxy
-rw-r--r--.travis.yml12
-rw-r--r--CHANGES.rst54
-rw-r--r--TODO-4.0.txt10
-rw-r--r--bootstrap.py186
-rw-r--r--buildout.cfg2
-rw-r--r--docs/api/checker.rst113
-rw-r--r--docs/api/decorator.rst25
-rw-r--r--docs/api/permission.rst10
-rw-r--r--docs/api/zcml.rst14
-rw-r--r--setup.cfg1
-rw-r--r--setup.py26
-rw-r--r--src/zope/security/_proxy.c10
-rw-r--r--src/zope/security/_zope_security_checker.c21
-rw-r--r--src/zope/security/checker.py8
-rw-r--r--src/zope/security/examples/sandbox.py2
-rw-r--r--src/zope/security/metaconfigure.py4
-rw-r--r--src/zope/security/testing.py19
-rw-r--r--src/zope/security/tests/test_proxy.py16
-rw-r--r--tox.ini3
19 files changed, 325 insertions, 211 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6c854d4
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: python
+python:
+ - 2.6
+ - 2.7
+ - 3.2
+ - 3.3
+install:
+ - pip install . --use-mirrors
+script:
+ - python setup.py test -q
+notifications:
+ email: false
diff --git a/CHANGES.rst b/CHANGES.rst
index 5678dbf..66ba415 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,16 +2,38 @@
CHANGES
=======
-4.0.0 (unreleased)
-------------------
+4.0.0a6 (unreleased)
+--------------------
+
+- fixed extension compilation on windows python 3.x
+
+
+4.0.0a5 (2013-02-28)
+--------------------
-- TODO: Add PyPy support
+- Undo changes from 4.0.0a4. Instead, ``zope.untrustedpython`` is only
+ included during Python 2 installs.
-- TODO: add pure-Python implementations of:
- - ``z.s._proxy.getChecker``
- - ``z.s._proxy.getObject``
- - ``z.s._proxy._Proxy``
+4.0.0a4 (2013-02-28)
+--------------------
+
+- Remove ``untrustedpython`` extra again, since we do not want to support
+ ``zope.untrustedpython`` in ZTK 2.0. If BBB is really needed, we will create
+ a 3.10.0 release.
+
+4.0.0a3 (2013-02-15)
+--------------------
+
+- Fix test breakage in 4.0.0a2 due to deprecation strategy.
+
+4.0.0a2 (2013-02-15)
+--------------------
+
+- Added back the ``untrustedpython`` extra: now pulls in
+ ``zope.untrustedpython``. Restored deprecated backward-compatible imports
+ for ``zope.security.untrustedpython.{builtins,interpreter,rcompile}``
+ (the extra and the imports are to be removed in version 4.1).
4.0.0a1 (2013-02-14)
@@ -65,6 +87,24 @@ CHANGES
- Added test convenience helper ``create_interaction`` and
``with interaction()``.
+3.9.0 (2012-12-21)
+------------------
+
+- Pin ``zope.proxy >= 4.1.0``
+
+- Ship with an included ``proxy.h`` header which is compatible with the
+ 4.1.x version ov ``zope.proxy``.
+
+3.8.5 (2012-12-21)
+------------------
+
+- Ship with an included ``proxy.h`` header which is compatible with the
+ supported versions of ``zope.proxy``.
+
+3.8.4 (2012-12-20)
+------------------
+
+- Pin ``zope.proxy >= 3.4.2, <4.1dev``
3.8.3 (2011-09-24)
------------------
diff --git a/TODO-4.0.txt b/TODO-4.0.txt
new file mode 100644
index 0000000..bfae913
--- /dev/null
+++ b/TODO-4.0.txt
@@ -0,0 +1,10 @@
+4.0.0 TODO
+----------
+
+- TODO: Add PyPy support
+
+- TODO: add pure-Python implementations of:
+
+ - ``z.s._proxy.getChecker``
+ - ``z.s._proxy.getObject``
+ - ``z.s._proxy._Proxy``
diff --git a/bootstrap.py b/bootstrap.py
index a6da5d3..ec3757a 100644
--- a/bootstrap.py
+++ b/bootstrap.py
@@ -18,102 +18,148 @@ The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile
from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
-is_jython = sys.platform.startswith('java')
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-# parsing arguments
-parser = OptionParser()
-parser.add_option("-v", "--version", dest="version",
- help="use a specific zc.buildout version")
-parser.add_option("-d", "--distribute",
- action="store_true", dest="distribute", default=False,
- help="Use Disribute rather than Setuptools.")
+Bootstraps a buildout-based project.
-parser.add_option("-c", None, action="store", dest="config_file",
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
+parser.add_option("-f", "--find-links",
+ help=("Specify a URL to search for buildout releases"))
-options, args = parser.parse_args()
-
-# if -c was provided, we push it back into args for buildout' main function
-if options.config_file is not None:
- args += ['-c', options.config_file]
-if options.version is not None:
- VERSION = '==%s' % options.version
-else:
- VERSION = ''
+options, args = parser.parse_args()
-USE_DISTRIBUTE = options.distribute
-args = args + ['bootstrap']
+######################################################################
+# load/install distribute
to_reload = False
try:
- import pkg_resources
+ import pkg_resources, setuptools
if not hasattr(pkg_resources, '_distribute'):
to_reload = True
raise ImportError
except ImportError:
ez = {}
- if USE_DISTRIBUTE:
- exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
- ).read() in ez
- ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
- else:
- exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
- ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+
+ exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
+ setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
+ ez['use_setuptools'](**setup_args)
if to_reload:
reload(pkg_resources)
- else:
- import pkg_resources
-
-if sys.platform == 'win32':
- def quote(c):
- if ' ' in c:
- return '"%s"' % c # work around spawn lamosity on windows
- else:
- return c
-else:
- def quote (c):
- return c
-
-cmd = 'from setuptools.command.easy_install import main; main()'
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
ws = pkg_resources.working_set
-if USE_DISTRIBUTE:
- requirement = 'distribute'
-else:
- requirement = 'setuptools'
-
-if is_jython:
- import subprocess
-
- assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
- quote(tmpeggs), 'zc.buildout' + VERSION],
- env=dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse(requirement)).location
- ),
- ).wait() == 0
-
-else:
- assert os.spawnle(
- os.P_WAIT, sys.executable, quote (sys.executable),
- '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse(requirement)).location
- ),
- ) == 0
+cmd = [sys.executable, '-c',
+ 'from setuptools.command.easy_install import main; main()',
+ '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+ 'bootstrap-testing-find-links',
+ options.find_links or
+ ('http://downloads.buildout.org/'
+ if options.accept_buildout_test_releases else None)
+ )
+if find_links:
+ cmd.extend(['-f', find_links])
+
+distribute_path = ws.find(
+ pkg_resources.Requirement.parse('distribute')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[distribute_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
+ raise Exception(
+ "Failed to execute command:\n%s",
+ repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
ws.add_entry(tmpeggs)
-ws.require('zc.buildout' + VERSION)
+ws.require(requirement)
import zc.buildout.buildout
+
+if not [a for a in args if '=' not in a]:
+ args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args[0:0] = ['-c', options.config_file]
+
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
diff --git a/buildout.cfg b/buildout.cfg
index 5d65d3b..0a7118d 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -14,7 +14,7 @@ eggs =
[python]
recipe = zc.recipe.egg
eggs =
- zope.security
+ zope.security [test,zcml,pytz,untrustedpython]
interpreter = python
[coverage-test]
diff --git a/docs/api/checker.rst b/docs/api/checker.rst
index 8b321db..58d3595 100644
--- a/docs/api/checker.rst
+++ b/docs/api/checker.rst
@@ -82,8 +82,7 @@ directly, or via interface:
>>> context = AContext()
>>> allow(context, attributes=['foo', 'bar'], interface=[I1, I2])
- >>> context.actions.sort(
- ... lambda a, b: cmp(a['discriminator'], b['discriminator']))
+ >>> context.actions.sort(key=lambda a: a['discriminator'])
>>> pprint(context.actions)
[{'args': ('testmodule', 'a', 'zope.Public'),
'callable': 1,
@@ -136,8 +135,7 @@ directly, or via interface:
>>> require(context, attributes=['foo', 'bar'],
... interface=[I1, I2], permission='p')
- >>> context.actions.sort(
- ... lambda a, b: cmp(a['discriminator'], b['discriminator']))
+ >>> context.actions.sort(key=lambda a: a['discriminator'])
>>> pprint(context.actions)
[{'args': ('testmodule', 'a', 'p'),
'callable': 1,
@@ -182,26 +180,26 @@ Protections for standard objects
... from zope.security.interfaces import ForbiddenAttribute
... try:
... return getattr(object, attr)
- ... except ForbiddenAttribute, e:
- ... return 'ForbiddenAttribute: %s' % e[0]
+ ... except ForbiddenAttribute as e:
+ ... return 'ForbiddenAttribute: %s' % e.args[0]
>>> def check_forbidden_setitem(object, item, value):
... from zope.security.interfaces import ForbiddenAttribute
... try:
... object[item] = value
- ... except ForbiddenAttribute, e:
- ... return 'ForbiddenAttribute: %s' % e[0]
+ ... except ForbiddenAttribute as e:
+ ... return 'ForbiddenAttribute: %s' % e.args[0]
>>> def check_forbidden_delitem(object, item):
... from zope.security.interfaces import ForbiddenAttribute
... try:
... del object[item]
- ... except ForbiddenAttribute, e:
- ... return 'ForbiddenAttribute: %s' % e[0]
+ ... except ForbiddenAttribute as e:
+ ... return 'ForbiddenAttribute: %s' % e.args[0]
>>> def check_forbidden_call(callable, *args): # **
... from zope.security.interfaces import ForbiddenAttribute
... try:
... return callable(*args) # **
- ... except ForbiddenAttribute, e:
- ... return 'ForbiddenAttribute: %s' % e[0]
+ ... except ForbiddenAttribute as e:
+ ... return 'ForbiddenAttribute: %s' % e.args[0]
Rocks
#####
@@ -217,16 +215,12 @@ Rocks are immuatle, non-callable objects without interesting methods. They
1
>>> int(type(ProxyFactory( 1.0 )) is float)
1
- >>> int(type(ProxyFactory( 1l )) is long)
- 1
>>> int(type(ProxyFactory( 1j )) is complex)
1
>>> int(type(ProxyFactory( None )) is type(None))
1
>>> int(type(ProxyFactory( 'xxx' )) is str)
1
- >>> int(type(ProxyFactory( u'xxx' )) is unicode)
- 1
>>> int(type(ProxyFactory( True )) is type(True))
1
@@ -270,18 +264,18 @@ We can do everything we expect to be able to do with proxied dicts.
1
>>> len(d)
2
- >>> list(d)
+ >>> sorted(list(d))
['a', 'b']
>>> d.get('a')
1
- >>> int(d.has_key('a'))
+ >>> int('a' in d)
1
>>> c = d.copy()
>>> check_forbidden_get(c, 'clear')
'ForbiddenAttribute: clear'
>>> int(str(c) in ("{'a': 1, 'b': 2}", "{'b': 2, 'a': 1}"))
1
- >>> int(`c` in ("{'a': 1, 'b': 2}", "{'b': 2, 'a': 1}"))
+ >>> int(repr(c) in ("{'a': 1, 'b': 2}", "{'b': 2, 'a': 1}"))
1
>>> def sorted(x):
... x = list(x)
@@ -293,27 +287,12 @@ We can do everything we expect to be able to do with proxied dicts.
[1, 2]
>>> sorted(d.items())
[('a', 1), ('b', 2)]
- >>> sorted(d.iterkeys())
- ['a', 'b']
- >>> sorted(d.itervalues())
- [1, 2]
- >>> sorted(d.iteritems())
- [('a', 1), ('b', 2)]
-Always available:
+Always available (note, that dicts in python-3.x are not orderable, so we are
+not checking that under python > 2):
.. doctest::
- >>> int(d < d)
- 0
- >>> int(d > d)
- 0
- >>> int(d <= d)
- 1
- >>> int(d >= d)
- 1
- >>> int(d == d)
- 1
>>> int(d != d)
0
>>> int(bool(d))
@@ -351,7 +330,7 @@ We can do everything we expect to be able to do with proxied lists.
1
>>> str(l)
'[1, 2]'
- >>> `l`
+ >>> repr(l)
'[1, 2]'
>>> l + l
[1, 2, 1, 2]
@@ -398,7 +377,7 @@ We can do everything we expect to be able to do with proxied tuples.
1
>>> str(l)
'(1, 2)'
- >>> `l`
+ >>> repr(l)
'(1, 2)'
>>> l + l
(1, 2, 1, 2)
@@ -607,8 +586,8 @@ we can do everything we expect to be able to do with proxied frozensets.
... from zope.security.interfaces import ForbiddenAttribute
... try:
... return getattr(object, attr)
- ... except ForbiddenAttribute, e:
- ... return 'ForbiddenAttribute: %s' % e[0]
+ ... except ForbiddenAttribute as e:
+ ... return 'ForbiddenAttribute: %s' % e.args[0]
>>> from zope.security.checker import ProxyFactory
>>> from zope.security.interfaces import ForbiddenAttribute
>>> us = frozenset((1, 2))
@@ -779,6 +758,8 @@ iterators
.. doctest::
+ >>> [a for a in ProxyFactory(iter([1, 2]))]
+ [1, 2]
>>> list(ProxyFactory(iter([1, 2])))
[1, 2]
>>> list(ProxyFactory(iter((1, 2))))
@@ -815,7 +796,7 @@ We can iterate over sequences
>>> from zope.security.checker import NamesChecker
>>> from zope.security.checker import ProxyFactory
- >>> c = NamesChecker(['__getitem__'])
+ >>> c = NamesChecker(['__getitem__', '__len__'])
>>> p = ProxyFactory(x, c)
Even if they are proxied
@@ -856,7 +837,7 @@ New-style classes
>>> check_forbidden_get(C, '__dict__')
'ForbiddenAttribute: __dict__'
>>> s = str(C)
- >>> s = `C`
+ >>> s = repr(C)
>>> int(C.__module__ == __name__)
1
>>> len(C.__bases__)
@@ -868,14 +849,6 @@ Always available:
.. doctest::
- >>> int(C < C)
- 0
- >>> int(C > C)
- 0
- >>> int(C <= C)
- 1
- >>> int(C >= C)
- 1
>>> int(C == C)
1
>>> int(C != C)
@@ -907,14 +880,6 @@ Always available:
.. doctest::
- >>> int(c < c)
- 0
- >>> int(c > c)
- 0
- >>> int(c <= c)
- 1
- >>> int(c >= c)
- 1
>>> int(c == c)
1
>>> int(c != c)
@@ -938,24 +903,16 @@ Classic Classes
>>> check_forbidden_get(C, '__dict__')
'ForbiddenAttribute: __dict__'
>>> s = str(C)
- >>> s = `C`
+ >>> s = repr(C)
>>> int(C.__module__ == __name__)
1
>>> len(C.__bases__)
- 0
+ 1
Always available:
.. doctest::
- >>> int(C < C)
- 0
- >>> int(C > C)
- 0
- >>> int(C <= C)
- 1
- >>> int(C >= C)
- 1
>>> int(C == C)
1
>>> int(C != C)
@@ -984,14 +941,6 @@ Always available:
.. doctest::
- >>> int(c < c)
- 0
- >>> int(c > c)
- 0
- >>> int(c <= c)
- 1
- >>> int(c >= c)
- 1
>>> int(c == c)
1
>>> int(c != c)
@@ -1055,7 +1004,7 @@ We work with the ABCMeta meta class:
>>> check_forbidden_get(PBar, '__dict__')
'ForbiddenAttribute: __dict__'
>>> s = str(PBar)
- >>> s = `PBar`
+ >>> s = repr(PBar)
>>> int(PBar.__module__ == __name__)
1
>>> len(PBar.__bases__)
@@ -1065,19 +1014,11 @@ Always available:
.. doctest::
- >>> int(PBar < PBar)
- 0
- >>> int(PBar > PBar)
- 0
- >>> int(PBar <= PBar)
- 1
- >>> int(PBar >= PBar)
- 1
>>> int(PBar == PBar)
1
>>> int(PBar != PBar)
0
>>> int(bool(PBar))
1
- >>> int(PBar.__class__ == abc.ABCMeta)
+ >>> int(PBar.__class__ == type)
1
diff --git a/docs/api/decorator.rst b/docs/api/decorator.rst
index c4741b9..c05c692 100644
--- a/docs/api/decorator.rst
+++ b/docs/api/decorator.rst
@@ -48,13 +48,16 @@ Using `selectChecker()`, we can confirm that a `Foo` object uses
.. doctest::
>>> from zope.security.checker import selectChecker
+ >>> from zope.security.interfaces import ForbiddenAttribute
>>> foo = Foo()
>>> selectChecker(foo) is fooChecker
True
>>> fooChecker.check(foo, 'a')
- >>> fooChecker.check(foo, 'b') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('b', <zope.security.decorator.Foo object ...>)
+ >>> try:
+ ... fooChecker.check(foo, 'b') # doctest: +ELLIPSIS
+ ... except ForbiddenAttribute as e:
+ ... e
+ ForbiddenAttribute('b', <Foo object ...>)
and that a `Wrapper` object uses `wrappeChecker`:
@@ -64,9 +67,11 @@ and that a `Wrapper` object uses `wrappeChecker`:
>>> selectChecker(wrapper) is wrapperChecker
True
>>> wrapperChecker.check(wrapper, 'b')
- >>> wrapperChecker.check(wrapper, 'a') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('a', <zope.security.decorator.Foo object ...>)
+ >>> try:
+ ... wrapperChecker.check(wrapper, 'a') # doctest: +ELLIPSIS
+ ... except ForbiddenAttribute as e:
+ ... e
+ ForbiddenAttribute('a', <Foo object ...>)
(Note that the object description says `Foo` because the object is a
proxy and generally looks and acts like the object it's proxying.)
@@ -94,9 +99,11 @@ illustrate, we'll proxify `foo`:
>>> secure_foo = ProxyFactory(foo)
>>> secure_foo.a
'a'
- >>> secure_foo.b # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('b', <zope.security.decorator.Foo object ...>)
+ >>> try:
+ ... secure_foo.b # doctest: +ELLIPSIS
+ ... except ForbiddenAttribute as e:
+ ... e
+ ForbiddenAttribute('b', <Foo object ...>)
when we wrap the secured `foo`:
diff --git a/docs/api/permission.rst b/docs/api/permission.rst
index 64a4250..819cc90 100644
--- a/docs/api/permission.rst
+++ b/docs/api/permission.rst
@@ -48,7 +48,7 @@ The :data:`zope.security.checker.CheckerPublic` permission always exists:
>>> ids = list(allPermissions(None))
>>> ids.sort()
>>> ids
- [u'x', u'y']
+ ['x', 'y']
.. autofunction:: zope.security.permission.PermissionsVocabulary
@@ -100,9 +100,9 @@ The non-public permissions 'x' and 'y' are string values:
.. doctest::
>>> vocab.getTermByToken('x').value
- u'x'
+ 'x'
>>> vocab.getTermByToken('y').value
- u'y'
+ 'y'
However, the public permission value is CheckerPublic:
@@ -116,7 +116,7 @@ and its title is shortened:
.. doctest::
>>> vocab.getTermByToken('zope.Public').title
- u'Public'
+ 'Public'
The terms are sorted by title except for the public permission, which is
listed first:
@@ -124,7 +124,7 @@ listed first:
.. doctest::
>>> [term.title for term in vocab]
- [u'Public', u'x', u'y']
+ ['Public', 'x', 'y']
.. testcleanup::
diff --git a/docs/api/zcml.rst b/docs/api/zcml.rst
index 5fdc3a0..a23075a 100644
--- a/docs/api/zcml.rst
+++ b/docs/api/zcml.rst
@@ -11,8 +11,9 @@ a couple of permissions:
>>> from zope.component import getGlobalSiteManager
>>> from zope.configuration.xmlconfig import XMLConfig
+ >>> from zope.component.testing import setUp
>>> import zope.security
-
+ >>> setUp() # clear global component registry
>>> XMLConfig('permissions.zcml', zope.security)()
>>> len(list(getGlobalSiteManager().registeredUtilities()))
@@ -64,10 +65,13 @@ Now let's see whether validation works alright
>>> field._validate('zope.ManageCode')
>>> context._actions[0]['args']
(None, 'zope.foo')
- >>> field._validate('3 foo')
- Traceback (most recent call last):
- ...
- InvalidId: 3 foo
+
+ >>> from zope.schema.interfaces import InvalidId
+ >>> try:
+ ... field._validate('3 foo')
+ ... except InvalidId as e:
+ ... e
+ InvalidId('3 foo')
zope.Public is always valid
>>> field._validate('zope.Public')
diff --git a/setup.cfg b/setup.cfg
index 48d6297..6ceb809 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,6 +4,7 @@ cover-package=zope.security
cover-erase=1
with-doctest=0
where=src
+exclude=untrustedpython
[aliases]
dev = develop easy_install zope.security[testing]
diff --git a/setup.py b/setup.py
index ffca17f..3dae3b8 100644
--- a/setup.py
+++ b/setup.py
@@ -26,12 +26,28 @@ from setuptools import find_packages
from setuptools import setup
TESTS_REQUIRE = [
- 'zope.testing',
- 'zope.configuration',
'zope.component',
+ 'zope.configuration',
'zope.location',
+ 'zope.testing',
+ 'zope.testrunner',
]
+def alltests():
+ import os
+ import sys
+ import unittest
+ # use the zope.testrunner machinery to find all the
+ # test suites we've put under ourselves
+ import zope.testrunner.find
+ import zope.testrunner.options
+ here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
+ args = sys.argv[:]
+ defaults = ["--test-path", here]
+ options = zope.testrunner.options.get_options(args, defaults)
+ suites = list(zope.testrunner.find.find_suites(options))
+ return unittest.TestSuite(suites)
+
here = os.path.abspath(os.path.dirname(__file__))
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
@@ -66,6 +82,7 @@ include = [ModuleHeaderDir('zope.proxy')]
# Jython cannot build the C optimizations, while on PyPy they are
# anti-optimizations (the C extension compatibility layer is known-slow,
# and defeats JIT opportunities).
+py3 = sys.version_info[0] >= 3
py_impl = getattr(platform, 'python_implementation', lambda: None)
pure_python = os.environ.get('PURE_PYTHON', False)
is_pypy = py_impl() == 'PyPy'
@@ -88,7 +105,7 @@ else:
]
setup(name='zope.security',
- version='4.0.0dev',
+ version='4.0.0a6.dev0',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
description='Zope Security Framework',
@@ -130,10 +147,11 @@ setup(name='zope.security',
'zope.proxy >= 4.1.0',
'zope.schema',
],
- test_suite = 'zope.security',
+ test_suite = '__main__.alltests',
tests_require=TESTS_REQUIRE,
extras_require = dict(
pytz=["pytz"],
+ untrustedpython=['zope.untrustedpython'] if not py3 else [],
zcml=['zope.configuration'],
test=TESTS_REQUIRE,
testing=TESTS_REQUIRE + ['nose', 'coverage'],
diff --git a/src/zope/security/_proxy.c b/src/zope/security/_proxy.c
index 52b5040..27edbb3 100644
--- a/src/zope/security/_proxy.c
+++ b/src/zope/security/_proxy.c
@@ -983,6 +983,11 @@ MOD_INIT(_proxy)
{
PyObject *m;
+ MOD_DEF(m, "_proxy", module___doc__, module_functions)
+
+ if (m == NULL)
+ return MOD_ERROR_VAL;
+
if (Proxy_Import() < 0)
return MOD_ERROR_VAL;
@@ -1083,11 +1088,6 @@ if((str_op_##S = INTERN("__" #S "__")) == NULL) return MOD_ERROR_VAL
if (PyType_Ready(&SecurityProxyType) < 0)
return MOD_ERROR_VAL;
- MOD_DEF(m, "_proxy", module___doc__, module_functions)
-
- if (m == NULL)
- return MOD_ERROR_VAL;
-
Py_INCREF(&SecurityProxyType);
PyModule_AddObject(m, "_Proxy", (PyObject *)&SecurityProxyType);
diff --git a/src/zope/security/_zope_security_checker.c b/src/zope/security/_zope_security_checker.c
index 1b91312..e5a2528 100644
--- a/src/zope/security/_zope_security_checker.c
+++ b/src/zope/security/_zope_security_checker.c
@@ -589,6 +589,14 @@ module_functions[] = {
MOD_INIT(_zope_security_checker)
{
PyObject* m;
+ PyObject* mod;
+
+ MOD_DEF(mod, "_zope_security_checker", module___doc__, module_functions)
+
+ if (mod == NULL)
+ {
+ return MOD_ERROR_VAL;
+ }
CheckerType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CheckerType) < 0)
@@ -673,14 +681,7 @@ if((str_##S = INTERN(#S)) == NULL) return MOD_ERROR_VAL
return MOD_ERROR_VAL;
}
- MOD_DEF(m, "_zope_security_checker", module___doc__, module_functions)
-
- if (m == NULL)
- {
- return MOD_ERROR_VAL;
- }
-
-#define EXPORT(N) Py_INCREF(N); PyModule_AddObject(m, #N, N)
+#define EXPORT(N) Py_INCREF(N); PyModule_AddObject(mod, #N, N)
EXPORT(_checkers);
EXPORT(NoProxy);
@@ -688,7 +689,7 @@ if((str_##S = INTERN(#S)) == NULL) return MOD_ERROR_VAL
EXPORT(_available_by_default);
Py_INCREF(&CheckerType);
- PyModule_AddObject(m, "Checker", (PyObject *)&CheckerType);
+ PyModule_AddObject(mod, "Checker", (PyObject *)&CheckerType);
- return MOD_SUCCESS_VAL(m);
+ return MOD_SUCCESS_VAL(mod);
}
diff --git a/src/zope/security/checker.py b/src/zope/security/checker.py
index e5f88dc..5f1d7df 100644
--- a/src/zope/security/checker.py
+++ b/src/zope/security/checker.py
@@ -595,7 +595,7 @@ _typeChecker = NamesChecker(
'__implemented__'])
_namedChecker = NamesChecker(['__name__'])
-_iteratorChecker = NamesChecker(['next', '__iter__'])
+_iteratorChecker = NamesChecker(['next', '__iter__', '__len__'])
_setChecker = NamesChecker(['__iter__', '__len__', '__str__', '__contains__',
'copy', 'difference', 'intersection', 'issubset',
@@ -642,9 +642,13 @@ _basic_types = {
datetime.time: NoProxy,
datetime.tzinfo: NoProxy,
}
-if PYTHON2:
+if PYTHON2:
_basic_types[long] = NoProxy
_basic_types[unicode] = NoProxy
+else: #pragma NO COVER
+ _basic_types[type({}.values())] = NoProxy
+ _basic_types[type({}.keys())] = NoProxy
+ _basic_types[type({}.items())] = NoProxy
try:
import pytz
diff --git a/src/zope/security/examples/sandbox.py b/src/zope/security/examples/sandbox.py
index cb2455c..8a17984 100644
--- a/src/zope/security/examples/sandbox.py
+++ b/src/zope/security/examples/sandbox.py
@@ -253,7 +253,7 @@ class TimeGenerator(object):
home.transportAgent(a, new_home)
except Exception as e:
print('-- Exception --')
- print('moving "%s" from "%s" to "%s"' %(a, h,` new_home`))
+ print('moving "%s" from "%s" to "%s"' %(a, h, repr(new_home)))
print(e)
print()
self.teardownAgent(a)
diff --git a/src/zope/security/metaconfigure.py b/src/zope/security/metaconfigure.py
index 54484ac..e2dd0a0 100644
--- a/src/zope/security/metaconfigure.py
+++ b/src/zope/security/metaconfigure.py
@@ -109,7 +109,7 @@ class ClassDirective(object):
def __protectByInterface(self, interface, permission_id):
"Set a permission on names in an interface."
- for n, d in interface.namesAndDescriptions(1):
+ for n, d in sorted(interface.namesAndDescriptions(1)):
self.__protectName(n, permission_id)
self.__context.action(
discriminator = None,
@@ -143,7 +143,7 @@ class ClassDirective(object):
def __protectSetSchema(self, schema, permission_id):
"Set a permission on a bunch of names."
_context = self.__context
- for name in schema:
+ for name in sorted(schema):
field = schema[name]
if IField.providedBy(field) and not field.readonly:
_context.action(
diff --git a/src/zope/security/testing.py b/src/zope/security/testing.py
index 53d1ebe..ee13db8 100644
--- a/src/zope/security/testing.py
+++ b/src/zope/security/testing.py
@@ -15,13 +15,30 @@
This module provides some helper/stub objects for setting up interactions.
"""
+import sys
+import re
from zope import interface, component
from zope.security import interfaces
from zope.security.permission import Permission
import contextlib
import zope.security.management
-
+from zope.testing import renormalizing
+
+PY2 = sys.version_info[0] == 2
+
+if PY2:
+ _u = unicode
+ rules = [(re.compile("b('.*?')"), r"\1"),
+ (re.compile('b(".*?")'), r"\1"),
+ ]
+ output_checker = renormalizing.RENormalizing(rules)
+else:
+ _u = str
+ rules = [(re.compile("u('.*?')"), r"\1"),
+ (re.compile('u(".*?")'), r"\1"),
+ ]
+ output_checker = renormalizing.RENormalizing(rules)
@interface.implementer(interfaces.IPrincipal)
class Principal:
diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py
index 877616d..523cd03 100644
--- a/src/zope/security/tests/test_proxy.py
+++ b/src/zope/security/tests/test_proxy.py
@@ -14,6 +14,7 @@
"""Security proxy tests
"""
import unittest
+import sys
from zope.security._compat import PYTHON2
@@ -35,6 +36,15 @@ def _skip_if_Py2(testfunc):
return dummy
return testfunc
+def _fmt_address(obj):
+ # Try to replicate PyString_FromString("%p", obj), which actually uses
+ # the platform sprintf(buf, "%p", obj), which we cannot access from Python
+ # directly (and ctypes seems like overkill).
+ if sys.platform == 'win32':
+ return '0x%08x' % id(obj)
+ else:
+ return '0x%0x' % id(obj)
+
class ProxyTestBase(object):
@@ -153,9 +163,10 @@ class ProxyTestBase(object):
target = object()
checker = DummyChecker(ForbiddenAttribute)
proxy = self._makeOne(target, checker)
+ address = _fmt_address(target)
self.assertEqual(str(proxy),
'<security proxied %s.object '
- 'instance at 0x%0x>' % (_BUILTINS, id(target)))
+ 'instance at %s>' % (_BUILTINS, address))
def test___repr___checker_allows_str(self):
target = object()
@@ -169,9 +180,10 @@ class ProxyTestBase(object):
target = object()
checker = DummyChecker(ForbiddenAttribute)
proxy = self._makeOne(target, checker)
+ address = _fmt_address(target)
self.assertEqual(repr(proxy),
'<security proxied %s.object '
- 'instance at 0x%0x>' % (_BUILTINS, id(target)))
+ 'instance at %s>' % (_BUILTINS, address))
@_skip_if_not_Py2
def test___cmp___w_self(self):
diff --git a/tox.ini b/tox.ini
index ea5bc87..ee015f0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,6 +13,7 @@ deps =
zope.component
zope.location
zope.proxy
+ zope.testrunner
commands =
python setup.py test -q
@@ -40,7 +41,7 @@ deps =
[testenv:docs]
basepython =
- python2.6
+ python3.3
commands =
sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest