Z Object Publishing Environment

Search | Download | Documentation | Resources | Development




Join Zope.org
Log in

Developer Home
Get Involved!
The Fishbowl

 Zope Exits

Zope Newbies

Zope.org is sponsored by Digital Creations

PythonMethods Table of Contents Last edited on Jan 20, 2001 4:46 pm

Python Methods User Guide Draft


This document is not finalized. Please make editorial comments about the draft in the UserGuideDiscussion rather than in the draft document directly. We are about to finalize the draft, so speak now or forever hold your peace! :^)


All of Zope's capabilities are provided by methods, one way or another. When you ask Zope for a URL, it first fetches an object from the ZODB and then calls some method of that object. The methods of built-in Zope objects are defined in Zope's source code, or in Python classes stored in Product modules on the filesystem. Additional object classes (and their methods) can be defined by creating new filesystem Products, and this is appropriate when the implementation of a class requires extensive access to resources (such as the filesystem) which should be carefully protected.

Methods can also be defined through the web, by writing DTML or Python code in special Method objects. The execution of this code is carefully constrained, because the ability to edit it through the insecure medium of the Web makes it untrustworthy. Such code must not be allowed direct access to the filesystem, for example, or a compromise of Zope security would compromise the entire user account under which Zope is run. Web-editable code is also subject to Zope security restrictions so that it can be created and edited by users with varying levels of Zope access.

Python Methods are the kinds of web-editable objects which allow you to use Python code in your Zope applications. They come in two flavors, Unrestricted and Restricted. Unrestricted Python Methods provide access to code stored in files in an Extensions directory, external to the ZODB. This is merely a slightly simpler alternative to writing code in a filesystem Product. Restricted Python Methods store their code in the ZODB, in the actual Method object. They therefore enjoy the advantages of all web-editable Zope objects, such as versioning, history, and undo. They can be distributed by ZEO, and copied or backed up along with all other Zope objects simply by copying or backing up the ZODB storage. For the rest of this document, PM will be used as shorthand for "Python Method", rPM for "Restricted Python Method", and uPM for "Unrestricted Python Method"

Creating Python Methods

When creating a PM, you need to start by deciding three things: where it should live, under what Id, and should it be Restricted or Unrestricted.

A PM's "home" is the container in which you create it. This is determined by its intended use, and by the objects it needs to operate upon. For example, a widely used PM that performs simple calculations on its parameters should probably be placed in the root folder, or in some other easily accessed place. A PM that defines part of the behavior of a ZClassx would, of course, live in the ZClassx. If you place a PM in a Folder, it can act as a method for manipulating that Folder.

The Id is less important. It simply needs to be a reasonably descriptive name that doesn't clash with the names of other Zope objects. Normally, it should start with a letter and consist entirely of of letters, digits, and underscores. This makes it easy to refer to from other code, but isn't strictly necessary.

uPMs are more awkward to use than Restricted PMsx, but aren't subject to security restrictions (hence the name). You would probably only use them if you had a serious need to get at the internals of Zope or of other objects, or at filesystem resources. You might also use them to protect code that must be kept secret. Most of the time, you are likely to want to use rPMs.

Creation of PMsx is discussed in more detail at CreateRestrictedPythonMethod and CreateUnrestrictedPythonMethod.

Writing Restricted Python Methods

rPMs behave much like normal Python functions, and have the same basic parts. When you create an rPM, you start by giving it an id, a parameter list, and a function body. The id is the name by which the rPM is accessed from other Zope objects, and the parameter list is a list of names, separated by commas, for data that will need to be passed to the rPM. An rPM with id "spam" and parameter list "x, y" could be called from other code be writing "spam(ham, 4)" or "spam(x='ham', y=4)". The body consists of lines of Python code which use the parameter names to perform some actions and/or compute some result. http://www.python.org is a good place to start, if you want to learn about programming in Python.

Restrictions on Python code

Python code in an rPM has a few restrictions:

  • "exec" statements are not allowed.

  • "import" statements can only import modules for which Zope security information has been supplied.

  • some built-in functions, such as "open" and "eval", are removed or restricted.

Also, the meaning of the "print" statement is changed. Printed output is not sent to sys.stdout. Instead, it is collected in a read-only variable named "printed". This allows code to use "print", then return or otherwise process the printed text.

Notes for Experienced Python Programmers

The rPM actually constructs and compiles a Python function internally, by indenting every line of the body a single space and adding the "def f(params):" header line. The id of the rPM is not used as the name of this internal function, since a Zope id need not be a valid Python identifier, but tracebacks will show the proper name.

If you want to test whether two or more objects have the same type, you must use the new builtin same_type function, since type is not available.

Using Python Methods from DTML code

You can call a PM from DTML code in the same way that you would call any other Zope method, by naming it or looking it up in the namespace object. To call PM "spam" with no parameters, use &dtml-spam; or <dtml-var name="spam">. To call it with parameters, you must use a DTML expression such as <dtml-var expr="spam(1, foo)">. Notice that unlike DTML Methods, which require keyword parameters, PMsx can be called with positional parameters. In other words, you don't have to specify the parameter name for an argument, as long as you provide arguments in the correct order.

An PM does not automatically find its parameters in the namespace like DTML does, unless you specifically turn on this behavior in the Binding Tab.

Python Method Access to Zope Objects

You cannot get a Zope object from a PM simply by using its name. Instead, you must either pass the object to the PM as an argument, or acquire the object from another object passed as a parameter or named on the Binding Tab.

For example, given PM "spindle" with parameter "folder", if we call "spindle(myFolder)" then the code in "spindle" can use "folder.penguin" to acquire "penguin", or "folder['index_html']" to access folder contents, or "folder.manage_delObjects(['foo'])" to manipulate the folder.

Parameters are Not (Always) Enough

Explicitly passing a Zope object to a PM works well when you already have (or can easily get) the object. Sometimes, however, you want a PM to have access to its container, or to the object on which it was invoked.

For example, suppose we are defining a ZClassx "Spam" and wish to provide a method "getTitle" in Spam that returns the title of an instance. A method which calls "getTitle" will often do so by acquiring it, and so will not have a reference to the actual instance.

For that matter, you may not trust the caller to pass the correct instance object. In this case, you want some way to declare a variable named "instance", guaranteed to contain the ZClassx instance from which "getTitle" was acquired, no matter what parameters were passed to it. Then you could use "return instance.title".

Now suppose that you want to provide a method named "getPathFromSpam" that returns the path from the Spam instance to the object on which the method is called. If we have a Spam instance "spam1" containing Folder "f1", which contains object "myOb", we want a call to "getPathFromSpam" from myOb to return "f1/myOb". In this case, we not only want the "instance" variable, we want a "target" variable that contains myOb.

The way you declare these special variables is with the Binding tab. It allows you to give a PM access to various useful objects and information by choosing a variable name. In the example above, you would type "instance" into the Container binding field, and "target" into the Context binding field. You would not include "instance" or "target" in the parameter list of the PMsx. They are not parameters, they are bound variables.


The implementation of Python Methods described in this document is expected to be available in Zope 2.3 and higher.

View source UserGuide
Advanced Actions / History
Visitor: Anonymous User
Jump to:
... by pagename prefix or search term.
For a plain search:
Privacy policy       Printable Page       Feedback about Zope.org

served by app2