You are not logged in Log in Join
You are here: Home » Zope Documentation » How-To » Using External Methods

Log in
Name

Password

 

Using External Methods

Using External Methods

What are External Methods?

One of the core components of Zope is DTML (Document Template Markup Language), a powerful variable insertion and expression language that provides "safe scripting" of Zope objects and dynamic content generation. DTML is highly integrated with the Zope security model, and this security integration makes it possible to let less privileged users perform simple scripting and use the services provided by Zope objects without compromising the security of the site.

A key concept of "safe scripting" is that unlike some other templating systems such as PHP or ASP, DTML does not allow you to create blocks of arbitrary script code. The reason for this is security. It would be difficult to safely delegate work on a site to less priveleged users if their code could access the filesystem, perform system calls or consume system resources.

Instead of allowing arbitrary code embedded in DTML, Zope provides External Methods. External Methods allow site managers to write unrestricted code and provide those services to DTML authors in a controlled, secure way. External Methods are created by writing a method in a normal Python module, then creating a new External Method object on your Zope site associated with your Python method.

An External Method is a Zope object in its own right, and has its own security settings. This gives a site manager the ability to selectively provide extended services to DTML authors. External Methods can be added to Folders or any container object in Zope. When you add an External Method to a Folder, it can be thought of as adding a new custom method to that Folder.

Note that the actual Python code that an External Method encapsulates must be created in a file on the server machine - it is not possible to create a working External Method completely through the Web. This is a security measure - in order to write unrestricted code, you must have access to the machine.

The following examples assume that you have a basic familiarity with DTML and the Python programming language.

Creating an External Method

Let's look at the standard "Hello World" example implemented with an External Method. In this example we will create a helloWorld method in a Python module, create a new External Method object in Zope associated with it, and finally create a simple DTML Document that uses the services of our new External Method.

If you have not yet started using External Methods with your Zope installation, you will first need to create a directory named Extensions in the root directory of your Zope installation. For example, if you installed Zope in /usr/local/zope2, your Extensions directory should be /usr/local/zope2/Extensions. Note that the directory name is case-sensitive, and make sure that the new directory is readable by the user that is used to run your Zope server.

Next we will create a new file in the Extensions directory named demo.py. This is the Python module we will use to define our custom logic. Note that Python modules which define External Methods must be located in the Extensions directory. Edit the demo.py file and add the following Python code:

      def helloWorld(self):
          """A simple external method."""
          return 'Hello World!'

With your Web browser, access the management interface of your Zope site and create a new Folder object named demo. This is where we will implement our examples. In the new Folder, select "External Method" from the add list (at the bottom of the right hand management frame for the demo Folder). This will bring up the "Add External Method" form, which will let us provide an id and title for the External Method and provides fields for entering the function name and Python module file that implement the new External Method.

In the "Id" field of the form, enter "helloWorld". The id will be used as the id of the Zope External Method object. It does not have to be the same as the actual function name, but for these examples we will give our External Methods ids that match the names of the methods in the Python module for clarity.

In the "Title" field you may optionally enter a title for the External Method. In the "Function name" field, enter "helloWorld" and in the "Python module file" field enter "demo" (Note that you should omit the ".py" from the name of the Python module file). Click the "Add" button and you will be returned to the management screen of the demo Folder which now includes the newly created helloWorld External Method object in its contents listing.

Finally, to use the new External Method, create a new DTML Document object named test in the demo Folder. To call the External Method from the DTML Document, add the following tag to the source of your DTML Document:

      <dtml-var helloWorld>

The actual External Method object in Zope acts as a kind of pointer to the method definition in your Python module. To make changes to an External Method:

  • Make your changes and save the Python module.
  • Visit the the management interface of the corresponding External Method object and click the Edit button. This will "reload" the code of your External Method.

Tip: if you are running Zope in development mode, you don't need to click the "Edit" for External Methods when you make changes. When in development mode, External Methods detect changes to their corresponding Python modules and will reload as needed automatically when changes are made. To run Zope in development mode, pass the -D command line option to Zope at startup.

Key Concepts

Basic usage of simple External Methods is pretty straightforward, as demonstrated by the helloWorld example above. For more complex usage however, it is important to keep several key concepts in mind that will help you take full advantage of External Methods.

  • External Methods are methods of their containers

    As its name implies, an External Method acts as a method of the object that contains it. You may have noticed that the code for the helloWorld method in the previous example takes a self argument. When an External Method is called, the self argument will be the container of the actual External Method object - in the case of our example, self was the demo folder containing the helloWorld method.

    Understanding the nature of self in an External Method is important because self is usually what you will use when you need to interact with the Zope object system. A common question among new Zope users when writing External Methods is "what do I import to get access to the object in my Zope site?". The answer is that you don't import anything - you use the self parameter to interact with the object system.

    For example, knowing that self is the container of the External Method you can find and work with subobjects or parent objects of 'self':

            # Get refs to two subfolders of "self" that have
            # ids of "subfolder1" and "subfolder2".
            sub1=self.subfolder1
            sub2=self.subfolder2
    
            # Get a ref to the parent of "self".
            parent=self.aq_parent
    

    Also note that if self contains other External Methods, you can call them from an External Method just as if they were normal Python methods:

            # Call another external method called sayHello.
            msg=self.sayHello()
    

    At the time of this writing, API documentation describing the interfaces provided by the various Zope objects is still in progress. Until the API documentation is complete, a good way to find out about the services of various Zope object is to consult the Zope source code in the lib/python directory of your Zope installation.

  • Arguments must be passed explicitly from DTML

    In the previous example, we were able to call the helloWorld method using a normal DTML var tag. This is because the helloWorld method took only one argument (self). As in standard Python, the self argument is implicit when calling an External Method and does not need to be passed explicitly by the programmer. Zope will automatically bind self when an External Method is called from DTML.

    If you define an External Method that takes more arguments than simply self, you need to pass those arguments when calling the External Method from DTML. To expand on the previous example, let's update the helloWorld code to personalize its greeting based on the identity of the Web user. To do this, the helloWorld method will need access to the REQUEST object, so we will add it to the method argument list:

            def helloWorld(self, REQUEST):
                """A first external method."""
                user=REQUEST.AUTHENTICATED_USER
                return 'Hello %s!' % user
    

    Now that the helloWorld method requires an argument, it will be necessary to change the way it is called from DTML to make sure that the required argument is passed. To do this, we will use the DTML expression syntax to pass in the REQUEST object that exists in the DTML namespace when calling 'helloWorld':

            <dtml-var "helloWorld(REQUEST)">
    

    Argument semantics for External Methods are identical to those for normal Python methods. You can define External Methods with default or keyword arguments just as you can in Python. Like Python methods, External Methods can return any type of data. An External Method could return a list or tuple for example, which would allow you to iterate over the result in DTML using the "in" tag.

  • External Methods are Zope objects too

    External Methods have a dual personality - they act primarily as methods of their containers, but they are also Zope objects with many of the common features of other Zope objects. They have their own security settings like any other Zope object so you can control access to them on a method by method basis (though the actual code may all exist in a single Python module).

    Like DTML Documents and DTML Methods, you can also navigate directly to an External Method object through the Web. In the case of the helloWorld example, you can point your Web browser to the url /demo/helloWorld and the result of the External Method will be returned to the browser. While accessing External Methods directly through the Web is less common than calling them from DTML, the fact that you can access them directly can be extremely useful.

    One difference to note when External Methods are called through the Web is that Zope will automatically map form fields and other values found in the Web request to the arguments required by the External Method based on their names.

A Real World Example

The following example demonstrates an External Method that is called directly via the Web. This example implements a virtual "default document" that selects the correct actual default document to return to a user based on the language preferences sent by the user's Web browser.

The External Method is named index_html, which is the name that Zope looks for by default to use as the default document for a Folder. When the External method is called, it will look in the REQUEST object to determine the client's preferred language. Finally it will look in it's container (self) to see if there is a custom default document for that language and attempt to render the document and return it:

      def index_html(self, REQUEST):
          """A smart index document redirector"""

          # Look for preferred lang in the REQUEST. If it
          # is not found, 'en' will be used as the default.

          lang=REQUEST.get('HTTP_ACCEPT_LANGUAGE', 'en')

          # By convention, we have saved different language
          # versions of our index document in the Folder with
          # ids of 'index_xx.html', where 'xx' is the lang id.
          # This code will attempt to get the right document,
          # then return the rendered result to the client.

          docname='index_%s.html' % lang
          if hasattr(self, docname):
              # Try to return the document for the 
              # requested language.
              doc=getattr(self, docname)
              return doc(self, REQUEST)
          else:
              # Return english if we don't have the 
              # requested language.
              doc=getattr(self, 'index_en.html')
              return doc(self, REQUEST)

More Information

More information and examples of External Methods can be found in the Zope Content Manager's Guide.