Tutorials for extending Python programs and Zope servers using the C language

Source: Internet
Author: User
There are several reasons why you might want to extend Zope with C. Most likely you have a ready-made C library that can help you do something, but you're not interested in converting it to Python. In addition, because Python is an explanatory language, any Python code that is heavily invoked will slow you down. So, even if you've already written some extensions in Python, you still have to consider using C to write the most commonly called parts. Either way, expanding Zope begins with extending Python. In addition, extending Python will give you additional benefits because your code will be accessible from any Python script, not just from Zope. The only thing to be reminded here is that the current version of Python is 2.1 at the time of writing this article, but Zope still only works with Python 1.5.21. There are no changes to the two versions of the C extension, but if you are interested in Python wrapping your library and want to work with Zope, you should be careful not to use anything newer than 1.5.2.
What is Zope?

Zope stands for "Z Object publishing Environment (Z Objects Publishing Environment)", which is an application server implemented in Python. "Great," you say, "But what exactly does the application server mean?" "The application server is a long-running process that serves the content of the activity." The WEB server calls the application server during the run to build the page.
Extend Python: Interesting and rewarding

To extend Zope, you first need to extend Python. Although extended Python is not as complex as "brain surgery", it is not as leisurely as "walking in the park". There are two basic components for a Python extension. The first one is obviously the C code. I will discuss it immediately. The other part is the installation file. The installation file describes the module by providing the module name, the location of the module's C code, and any compiler flags you may need. The file is preprocessed to create makefile (on UNIX) or msvc++ project files (msvc++ project file, on Windows). First of all, the Python on ―windows is actually compiled with the Microsoft compiler. Python.org people also recommend compiling extensions with msvc++. Obviously, you should be able to persuade the GNU compilers to succeed, but I haven't tried them myself.

Anyway, let's define a module called ' foo '. The ' foo ' module will have a function called ' bar '. When we want to use, we can use import foo; To import this function into a Python script, just like importing any module. The installation file is very simple:
Listing 1. A Typical installation file

# You can include comment lines. The *shared* directive indicates# that the following module (s) is to be compiled and linked for# dynamic loading as Oppos Ed to static:. So on Unix,. dll on windows.*shared*# then you can use the variables later using the $ (variable) syntax# th At ' Make ' uses. This next line defines our module and tells# Python where its source code Is.foo FOOMAIN.C

Writing code

So how do we actually write the code that Python knows how to use, you ask? FOOMAIN.C (Of course, you can name it) the file contains three items: A method table, an initialization function, and the rest of the code. The method table simply links the function name to the function and informs Python about the parameter passing mechanism used by each function (you can choose to use a generic positional parameter list or a mixed list of positional parameters and keyword parameters). Python invokes the initialization function when the module is loaded. The initialization function completes all the initialization required by the module, but more importantly, it also passes a pointer to the method table back to Python.

So let's take a look at the C code of our small Foo module.
Listing 2. A typical Python expansion module

#include 
 
  
   
  /* Define the method table. */static pyobject *foo_bar (pyobject *self, Pyobject *args); static Pymet Hoddef foomethods[] = {  {"bar", Foo_bar, Meth_varargs},  {NULL, null}};/* here ' s the initialization function. We don ' t need to does anything  for our own needs, but Python needs this method table. */void Initfoo () {  (void) py_in Itmodule ("foo", Foomethods);} /* Finally, let's do something ... involved ... as an example function. */static pyobject *foo_bar (pyobject *self, Pyobject *args) {  char *string;  int  Len;  if (! Pyarg_parsetuple (args, "s", &string))    return NULL;  Len = strlen (string);  Return Py_buildvalue ("I", Len);
 
  

In-depth research

Let's take a look at the code. First, please note that you must include Python.h. Unless you have set the path to the file in the include path, you may need to include the-I flag in the installation file to point to the file.

The initialization function must be named Init <模块名> , which in our case is initfoo. The name of the initialization function, without a doubt, is all the information that Python knows about the module when it loads the module, which is why the name of the initialization function is so inflexible. By the way, the initialization function must be the only global identifier in the file that is not declared static. This is more important for static links than for dynamic links, because non-static identifiers will be globally visible. This is not a big problem for dynamic linking, but if you are going to link everything during compilation without declaring all the things that can be declared static as static, you are likely to encounter name collisions.

Now let's look at the actual code, see how the parameters are handled, and how the return value is passed. Of course, everything is the object on the Pyobject―python heap. What you get from the parameter is a reference to the "This" object (this is for the object method, NULL for the parameterless old-fashioned function like bar (), and a parameter tuple stored in args. You use Pyarg_parsetuple to retrieve your parameters, and then use Py_buildvalue to pass the results back. These functions (and more) are archived in the "python/c API" section of the Python document. Unfortunately, there is no simple list of functions by name, and documents are arranged by topic.

Also note that the function returns NULL in case of an error. Returning NULL indicates an error, and if you want to make Python better, you should throw an exception. I'll show you the documentation on how to do this.

Compiling extensions

Now all that remains is the compile module. You can do this in two ways. The first is to run Make-f Makefile.pre.in boot as instructed in the documentation, which will use your Setup to compile a Makefile. You will then use the Makefile to compile your project. This approach applies only to UNIX. For Windows, there is a script called "compile.py" (see Resources later in this article). The original script was hard to find; I found a large number of changed copies of Robin Dunn (behind the scenes of WxPython) from a mailing list. This script can work on UNIX and Windows, and on Windows it will compile the msvc++ project file from your Setup.

To compile, you must make the included files and libraries available. The standard Zope installation of Python does not contain these files, so you will need to install Python's regular installation from www.python.org (see Resources). On Windows, you must also get the Config.h file from the PC directory where the source code is installed; It is a manual version of the config.h that UNIX installs for your compilation. So, on UNIX, you should already have it.

Once these are complete, you will get a file with an extension of ". PYD". Put this file into the "Lib" directory in the Python installation directory (under Zope, Python is in the "bin" directory, so your extension ends up in the "Bin/lib" directory, which is strange.) You can then invoke it, just as you would call any source-native Python module.

>>> import foo; >>> Foo.bar ("This is a Test"); 14

When I do this, my first question is asking myself how to define classes that are visible from Python in C. In fact, I may have asked a wrong question. In the example I've studied, Python-specific everything is done only with Python, and only C functions exported from your extension are called.

Take it to Zope.

Once you have completed your Python extension, the next step is to make Zope work with it. There are several ways you can choose, but to some extent, how you want your extension to work with Zope will first affect how you compile the extension. The basic way to use Python (and extensions in C) from Zope is to:

    • If the function is simple, you can think of it as a variable. These are called "external methods".
    • More complex classes that can be called from the Zope script (this is a new feature of Zope 2.3).
    • You can define a Zope Product, and then you can extend it with Zclass (a set of well-made, Web-accessible objects), use it in a script, publish it according to its own permissions (its instance is treated as a page).

Of course, your own application can use a combination of these methods.

Create an external method

The simplest way to invoke Python from Zope is to make your Python code an external method. The external method is a Python function that is placed in the "Extensions" directory under the Zope installation directory. Once you have such a Python file, you can go to any folder, choose Add External Method, and add a variable that calls the function you want to use. You can then add the DTML field to any page in the folder that displays the result of the call. Let's look at a simple example that uses the Python extension ―foo.bar― defined above.

First, let's look at the extension itself: we put it in a file, for example, called Foo.pyd. Remember, this file is located in the Extensions directory under Zope. To be able to proceed smoothly, of course, the foo.pyd we created above must be in the Python library located in Bin/lib. A simple package for this purpose might look like this:
Listing 3. A simple external method (file: extensions/foo.py)

Import Foodef Bar (Self,arg): ""  A Simple external method.  "" " Return ' ARG length:%d '% foo.bar (ARG)

It's simple, isn't it? It defines an external method "bar" that can be attached to any folder using the Zope admin interface. To call our extension from any page in the folder, we simply insert a DTML variable reference, as follows:

 
 
  

When a user views our page, the DTML field is replaced by the text "Arg length:14". That's how we expanded Zope with C.

Zope script: Cliff Notes Edition

The Zope script is a new feature in Python 2.3 that you want to use instead of an external method. External methods can do it, and it can be better integrated with security and management systems, provides more flexibility in integration, and has many access to all of the Zope features exposed in the Zope API.

A script is basically a short Python program. It can define a class or function, but it is not required. It is installed as an object in the Zope folder and can then be invoked as a DTML variable or call (just like an external method) or "from the Web" (meaning in Zope that it will be called as a page). Of course, this means that a script can generate a response to a form submission as a CGI program does, but without the overhead of CGI. It's really a great feature. In addition, the script has access to the callee or caller object (through the "context" object), the folder where the object resides (through the "container" object), and some other fragmented information. To get more information about scripting, see the chapter "Advanced Zope Scripting (Scripting)" in the Zope manual (see Resources).

You may mistakenly think that you can simply import foo from the script and use Foo.bar (I know I did make the mistake). But that is not the case. Because of security restrictions, only Product can be imported, not what modules can be. In general, Zope's designers believe that any scripting requires access to the file system, since the script objects are managed by the WEB using the Zope management interface, so they are not completely trustworthy. So I'm going to stop here and not show you the sample script, but instead discuss the Product and the base class.

Focus on Product

Product is a powerful tool for expanding Zope. From the level of the installation directory, Product is a directory in the "lib/python/products" directory located in the Zope directory. You can see many product samples in your own Zope installation directory, but in essence, the smallest product consists of only two files in that directory: an arbitrarily named code file and a Zope called __init__ that initiates Si cho to initialize product. PY file. (Note: Zope only reads the Product file at startup, which means that you must be able to stop and restart the Zope process for testing purposes). This article is just as much as possible to provide you with hints that you can do by using Zope Product.

You know that Product encapsulates one or more classes that can be used from zclass, scripts, or URLs directly from the Web. (Of course, in the last case, an instance of Product is treated as a folder; The last part of the URL specifies the method that will be called, which returns any HTML.) You do not have to treat Product as an "additive" object, although that is the main purpose. To see an excellent, realistic example, you can see the Zcatalog implementation, which is part of the standard Zope distribution. There you can see a very simple installation script in __init__.py, you can see the Zcatalog class in zcatalog.py, which provides many publishing methods. Note that Zope uses a strange convention to determine which methods can be accessed through the web-if a method contains a doc string, the method can be accessed through the web, otherwise it is considered private.

Anyway, let's look at a very simple Product that uses the C module (which we defined above). First look at the very simple __init__.py; Please note that it only does one thing, which tells Zope the name of the class we are installing. More complex initialization scripts can do more, including declaring global variables maintained by the server, setting access permissions, and so on. For more details, please refer to the Zope Developer's Guide in the online documentation, as well as study the ready-made Product in your Zope installation directory. As you might have guessed, our example Product is called "Foo". This will create an Foo subdirectory in the Lib/python/products directory.
Listing 4. Basic Product Initialization Script

Import Foodef Initialize (context):  Context.registerclass (    foo.foo,     permission= ' Add Foo ',    Constructors=foo.manage_addfoo    )

Now notice that this initialization script not only imports that class, it can be accessed by other parts of Zope, but also registers the class as "additive." The Context.registerclass call is done by first naming the class that we imported, and then specifying the name of the method that can be used to add the instance (this method must display a management page and the method will automatically integrate with the Zope management interface). Cool.

Let's summarize this short, simple Product. It exposes our Foo.bar functions to scripts and Zclass, and also has a small interface as an "add-on" object, which is the whole content.
Listing 5. A simple Zope Product

Import fooclass foo (simpleitem.item): "A foo Product" meta_type = ' foo ' def bar (self, string):   return Foo.bar (String) def __init__ (self, id):   ' Initialize An instance '   self.id = ID def index_html (self):   "Basic View of Object" 
  return ' My ID is%s and its length was%d. '% (self.id, Foo.bar (self.id)) def manage_addfoo (self, RESPONSE):   "Managem ENT handler to add an instance to a folder. "   Self._setobject (' foo_id ', Foo (' foo_id '))   Response.Redirect (' index_html ')

This is just one of the simplest Product. It is not absolutely possible to say that it is the smallest of the Product, but it is already close. However, it does illustrate some of the key features of Product. First, notice the "index_html" method: It is called to display an object instance, which is done by building HTML. It's actually a page. The Manage_addfoo method is the interface that the Zope object manages, and we reference it in the __init__.py above. The "__init__" method initializes the object; all it has to do is record the unique identifier of the instance.

This miniature Product does not interoperate with Zope security. It does not do much management work. It has no interactive functionality. So you can add a lot of things to it (even the very useful features it doesn't). I hope this is a good start for you.

What to do in the future

A brief introduction to Zope Product has taught you how to change C functions from C code to Zope. To learn how to write product, you have to read more documents (many of which are still being perfected), and, frankly, study the existing product to see how they do it. The Zope model has a lot of power and flexibility, and they're all worth exploring.

I am currently doing a big project integrating C and Zope: Integrating my Workflow Toolkit (Workflow Toolkit). Before this article was published, I would like to see its embryonic form. It has been listed in the resources below to see it; you should have been able to find a sample extension from this article as you read it. Wish me luck.

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.