Install & Compatibility
Where this runs
tested against v8.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 23.1MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 3.0s · import 0.000s · 24MB
26MB installed
● package 26MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
ClassSecurityInfo
✓ from zope.security.management import ClassSecurityInfo
✗ from zope.security import ClassSecurityInfo
This quickstart demonstrates how to define and check permissions using `zope.security` (via `AccessControl`). It sets up a basic secured object with a custom permission and then simulates two different user interactions: one with the required permission and one without. It uses `ClassSecurityInfo` for declarative security and `getSecurityManager().checkPermission()` for programmatic checks. Note that in a full Zope application, the interaction and permission checks are often handled implicitly by the Zope Publisher.
import os
from AccessControl.SecurityInfo import ClassSecurityInfo, ACCESS_PUBLIC
from AccessControl.SecurityManagement import setSecurityManager, getSecurityManager, noSecurityManager
from AccessControl.users import UnrestrictedUser, nobody
# Define a simple permission
VIEW_FOO_PERMISSION = 'View Foo'
# A dummy object to secure
class MySecuredObject:
security = ClassSecurityInfo()
security.declareObjectPublic() # Allow access to the object itself
security.declareProtected(VIEW_FOO_PERMISSION, 'foo_data')
def __init__(self, data):
self._data = data
def foo_data(self):
return self._data
# --- Example Usage ---
# 1. Setup a security manager (usually done by Zope)
# For standalone testing, we can simulate an interaction
# Create a principal (user)
class TestUser(UnrestrictedUser):
def __init__(self, id, roles=()):
super().__init__(id, '', roles, '')
self._roles = roles
def getRoles(self):
return self._roles
# User with permission
user_with_permission = TestUser('editor', roles=('Manager', VIEW_FOO_PERMISSION))
# User without permission
user_without_permission = TestUser('viewer', roles=())
# Create a secured object
obj = MySecuredObject('Secret Foo Content')
print(f"Object data: {obj.foo_data()}") # Access from unrestricted context is fine
try:
# Simulate an interaction for user_with_permission
setSecurityManager(user_with_permission)
sm = getSecurityManager()
print(f"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}")
# In a real Zope context, calling obj.foo_data() would be checked here
except Exception as e:
print(f"Error with user_with_permission: {e}")
finally:
noSecurityManager() # Clean up
print("---------------------")
try:
# Simulate an interaction for user_without_permission
setSecurityManager(user_without_permission)
sm = getSecurityManager()
print(f"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}")
# Attempting to access obj.foo_data() here would raise Unauthorized in a Zope context
except Exception as e:
# In a real Zope context, this would likely be an IUnauthorized or similar
print(f"Expected error for user_without_permission (no permission): {e}")
finally:
noSecurityManager() # Clean up
Debug
Known issues
breakingMajor Zope releases (e.g., Zope 4 to 5, or 5 to 6) often introduce breaking changes that can affect `zope.security` and its usage. For instance, Zope 6.0b1 replaced `pkg_resources` namespaces with PEP 420 native namespaces, requiring `zc.buildout` version 5 or higher.fixConsult the specific Zope release notes (e.g., Zope 6.x `CHANGES.rst` on GitHub) for migration guides. Update build tools like `zc.buildout` and review Python version compatibility.
affects: Zope 6.0b1 and later, affecting projects migrating from older Zope versions.
gotchaBy default, Zope's security policy denies access to any object or method that does not have explicit security declarations. Additionally, attributes or methods whose names begin with an underscore (`_`) are always denied access from restricted code.fixAlways provide explicit security declarations (e.g., using `ClassSecurityInfo.public()` or `declareProtected()`) for methods/attributes intended for external access. Avoid leading underscores for publicly accessible members.
affects: All versions
gotchaUsing `security.setDefaultAccess('allow')` within a `ClassSecurityInfo` assertion should be done with extreme caution. This reverses the default deny-all policy to an allow-all policy for any attributes not explicitly protected, potentially exposing sensitive data or functionality.fixPrefer explicit security declarations for each method or attribute. Use `setDefaultAccess('allow')` only when absolutely certain of its implications and that all sensitive parts are explicitly protected. affects: All versions
gotchaWhen using Python scripts 'through the web' (TTW) in Zope, security assertions for external Python modules (i.e., making them importable by restricted code) must be placed within an `__init__.py` file of a Zope 'Product' directory. Simply adding assertions in the module itself will not work.fixCreate a Zope Product (a directory in `Products` with an `__init__.py`). In its `__init__.py`, use `Products.PythonScripts.Utility.allow_module('your_module_name')` to declare external modules as safe for import by TTW scripts. Restart Zope after changes. affects: All versions, specifically for TTW Python scripts
Upgrade
Version history
8.3latest on PyPI · released Nov 17, 2025
Audit
Dependencies
AccessControlrequiredCore component providing `ClassSecurityInfo` and other fundamental security mechanisms.
ZopeoptionalOften used within a Zope application context, though `zope.security` can be used standalone.