Zope Publisher
The Zope publisher publishes Python objects on the web. It is a core component of the Zope application server and related frameworks, responsible for dispatching HTTP requests to Python objects and generating responses. As of version 8.0, it supports Python 3.9+ and maintains its role in the Zope ecosystem as a low-level building block for web applications.
Common errors
-
TypeError: Can't adapt <your_object> to zope.publisher.interfaces.IRequest
cause The object you are passing as a request to a Zope publisher function (or related component) does not implement the `IRequest` interface, or no suitable adapter is registered for it.fixEnsure your request object is an instance of `zope.publisher.http.HTTPRequest` or `zope.publisher.browser.BrowserRequest` (for browser contexts), or explicitly implements `zope.publisher.interfaces.IRequest` and its sub-interfaces via `zope.interface.implementer`. -
ImportError: cannot import name 'HTTPRequest' from 'zope.publisher'
cause You are trying to import `HTTPRequest` (or `HTTPResponse`) directly from the top-level `zope.publisher` package.fixThe `HTTPRequest` and `HTTPResponse` classes are located in the `zope.publisher.http` submodule. Correct your import statement to `from zope.publisher.http import HTTPRequest`. -
AttributeError: 'HTTPRequest' object has no attribute 'form' or 'POST' data is missing.
cause When handling POST requests, `request.form` combines query string parameters and POST body data. If `wsgi.input` (the stream for the request body) was not correctly provided or the `CONTENT_TYPE` was incorrect, POST data might not be parsed.fixFor POST requests, ensure the `request_environ['wsgi.input']` is a file-like object containing the raw request body bytes, and `request_environ['CONTENT_TYPE']` is set appropriately (e.g., `application/x-www-form-urlencoded` or `multipart/form-data`) so `HTTPRequest` can parse it.
Warnings
- breaking Python 2 support was dropped as of `zope.publisher` 5.0. All subsequent versions, including 8.0, are Python 3.x only. Code written for Python 2 will not run on recent versions.
- gotcha `zope.publisher` is a low-level component designed for the Zope Component Architecture (ZCA). It is not a standalone web framework like Flask or FastAPI. Direct usage for simple web apps is often overly complex and requires manual setup of interfaces, adapters, and traversers.
- gotcha Zope packages are tightly coupled. Incorrect versions of other `zope.*` dependencies can lead to runtime errors or unexpected behavior. This is especially true for `zope.interface`, `zope.traversing`, and `zope.security`.
Install
-
pip install zope.publisher
Imports
- HTTPRequest
from zope.publisher import HTTPRequest
from zope.publisher.http import HTTPRequest
- HTTPResponse
from zope.publisher import HTTPResponse
from zope.publisher.http import HTTPResponse
- IPublisher
from zope.publisher.interfaces import IPublisher
Quickstart
from io import BytesIO
from zope.publisher.http import HTTPRequest, HTTPResponse
# Simulate a WSGI-like environment for the request
request_environ = {
'REQUEST_METHOD': 'GET',
'PATH_INFO': '/my/path',
'QUERY_STRING': 'param1=value1¶m2=value2',
'SERVER_NAME': 'localhost',
'SERVER_PORT': '8080',
'wsgi.input': BytesIO(b''), # For GET, body is usually empty
'wsgi.url_scheme': 'http',
'HTTP_HOST': 'localhost:8080',
'CONTENT_TYPE': 'text/plain; charset=utf-8',
}
# Create a request object
# The first argument (input_stream) can be a BytesIO or similar for POST bodies
request = HTTPRequest(BytesIO(b''), request_environ)
# Create a response object
response = HTTPResponse()
# --- Interact with the Request ---
print(f"Request URL: {request.getURL()}")
print(f"Request Method: {request.method}")
print(f"Path Info: {request.getURL('PATH_INFO')}")
print(f"Query parameters (combined form): {request.form}")
print(f"Request header 'Host': {request.get('HTTP_HOST')}")
# --- Interact with the Response ---
response.setStatus(200)
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.setBody('<h1>Hello from Zope Publisher!</h1>')
print(f"\nResponse Status: {response.getStatus()}")
print(f"Response Header 'Content-Type': {response.getHeader('Content-Type')}")
print(f"Response Body: {response.consumeBody().decode('utf-8')}")