Python Extension Designer / Builder.

Gustavo Córdova Avila rangerelf at axtel.net
Fri Jan 25 11:27:03 EST 2002


I'm thinking *very* seriously about making a python module
which will build the skeleton to a python extension module
(with types and all). I haven't read very much about it yet,
because I'm trying to concentrate on the designer for the
extension module.

My idea is that the description of the external module
(with documentation and all) should be an XML document,
with all relevant information contained. I have a (very
preliminar?) example of the DTD and a little example module
which implements a "ramp-like" funcion (a'la xrange).

So, I'd really like a bit of criticism of this idea; maybe
I'm doing something that already has been done, maybe I'm
pissing up the wrong tree, etc. I'm starting with all this
XML stuff, and it's potential for metadata storing and
retrieval is awesome :)

The code generator is supposed to take this document
and build a suitable skeletone source file in C,
adjusted for the correct platform (linux, win32, etc)
and the specified python version.

I know that there's SWIG, but something about it
just rubs me the wrong way; I don't know exactly
what it is, but I feel that it's backwards from
what I want.

Without further ado...

Here's the DTD for the extension module document:
==================================================
<!-- This is the root element -->
<!ELEMENT python-extension (module+) >
<!ATTLIST python-extension python-version CDATA #IMPLIED
                           platform       ( linux | win32 ) "linux" >

<!ELEMENT module (docstring?,(variable|exception|function|object)*) >
<!ATTLIST module name            CDATA #REQUIRED
                 version         CDATA #IMPLIED >

<!ELEMENT docstring (#PCDATA) >
<!ATTLIST docstring type CDATA #IMPLIED
                    src  CDATA #IMPLIED >

<!ELEMENT variable (value?) >
<!ATTLIST variable name CDATA #REQUIRED
                   type CDATA #IMPLIED >

<!ELEMENT exception (docstring?) >
<!ATTLIST exception name     CDATA #REQUIRED
                    inherits CDATA #IMPLIED >

<!ELEMENT function (docstring?,argument*) >
<!ATTLIST function name CDATA #REQUIRED >

<!ELEMENT argument (default?) >
<!ATTLIST argument name    CDATA #REQUIRED
                   type    CDATA #IMPLIED
                   keyword ( yes | no ) "no" >

<!ELEMENT default (#PCDATA) >

<!ELEMENT object (docstring?,(constructor|method|attribute)*) >
<!ATTLIST object name CDATA #REQUIRED >

<!ELEMENT constructor (docstring?,argument*) >
<!ATTLIST constructor name CDATA #REQUIRED >

<!ELEMENT method (docstring?,argument*) >
<!ATTLIST method name  CDATA #REQUIRED
                 scope ( class | instance ) "instance" >

<!ELEMENT attribute (docstring?,default) >
<!ATTLIST attribute name   CDATA #REQUIRED
                    scope  ( class | instance ) "instance"
                    access ( read-write | read-only | write-only )
"read-write" >

==================================================
END OF THE DTD.


So, according to this DTD, the document for a little
module I've been thinking about (just as an example)
is the following:

START OF DOCUMENT.
==================================================
<?xml version="1.0">
<!DOCTYPE python-extension SYSTEM "python-extension.dtd">

<python-extension platform="linux" python-version="2.1">
  <module name="Rampa" version="1.0">
    <docstring type="text/plain">
Este es un pequeño módulo que implementa una o dos funciones
sencillitas, y además implementa un tipo de dato que se accesa
igual que un arreglo, pero el resultado que regresa es una
función lineal dependiendo de los parámetros de construcción.
    </docstring>

    <variable name="some_var">
      <default type="FloatType">3.141592654</default>
    </variable>

    <function name="multiply">
      <docstring type="text/plain">
This function just multiplies two numbers.
      </docstring>
      <argument name="n1" type="FloatType" />
      <argument name="n2" type="FloatType" />
    </function>

    <exception name="RampIndexError" inherits="IndexError">
      <docstring type="text/plain">
This error is raised when you try to access a
key outside the Ramp's range.
      </docstring>
    </exception>

    <object name="Ramp">
      <docstring type="text/plain">
This little type implements an array-like interface,
and returns a number between a min and max value,
which corresponds to a linear equation created upon
instantiation.
      </docstring>

      <constructor name="Ramp">
        <docstring type="text/plain">
Create an IntRamp object:
>>> import Ramp
>>> r = Ramp.IntRamp(10,3)
>>> print r[0]
0
>>> print r[1]
3
>>> print r[2]
6
...
>>> print r[9]
21
>>> print r[10]
Error: IndexError

The first argument is the number of elements, and the second
argument is the step value. The result is an integer linear
equation, beginning on zero, with a slant equal to the second
argument.

A third optional argument indicates the starting value, which
is added to every result:
>>> rr = Ramp.IntRamp(10, 3, 2)
>>> print rr[0]
2
>>> print rr[1]
5
... etc
        </docstring>

        <argument name="count" type="IntType" />
        <argument name="slant" type="IntType">
          <default>1</default>
        </argument>
        <argument name="start" type="IntType">
          <default>0</default>
        </argument>
      </constructor>

      <method name="__getitem__">
        <!-- "self" is implied -->
        <argument name="key" type="IntType" />
      </method>

      <method name="__len__" />
      <method name="__str__" />
      <method name="__repr__" />

      <attribute name="last_key" access="read-only" />
      <attribute name="last_value" access="read-only" />
    </object>

  </module>
</python-extension>
==================================================
END OF DOCUMENT.

Thanks. :)
--
Gustavo Córdova Avila
› gcordova at sismex.com





More information about the Python-list mailing list