zope.structuredtext-3.5.1/0000755000175000017500000000000011476217406015521 5ustar tseavertseaverzope.structuredtext-3.5.1/buildout.cfg0000644000175000017500000000041711476217350020031 0ustar tseavertseaver[buildout] develop = . parts = test py sphinx [test] recipe = zc.recipe.testrunner eggs = zope.structuredtext [py] recipe = zc.recipe.egg eggs = zope.structuredtext interpreter = py [sphinx] recipe = zc.recipe.egg eggs = Sphinx zope.structuredtext zope.structuredtext-3.5.1/COPYRIGHT.txt0000644000175000017500000000004011476217350017622 0ustar tseavertseaverZope Foundation and Contributorszope.structuredtext-3.5.1/README.txt0000644000175000017500000000047411476217350017222 0ustar tseavertseaver``zope.structuredtext`` README ============================== This package provides a parser and renderers for the classic Zope "structured text" markup dialect (STX). STX is a plain text markup in which document structure is signalled primarily by identation Please see ``docs/index.rst`` for the documentation. zope.structuredtext-3.5.1/LICENSE.txt0000644000175000017500000000402611476217350017344 0ustar tseavertseaverZope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zope.structuredtext-3.5.1/bootstrap.py0000644000175000017500000000330211476217350020104 0ustar tseavertseaver############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) zope.structuredtext-3.5.1/setup.py0000644000175000017500000000407011476217350017232 0ustar tseavertseaver############################################################################## # # Copyright (c) 2004-2007 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.structuredtext package """ import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() long_description = ( read('README.txt') + '\n' + read('CHANGES.txt') ) setup( name='zope.structuredtext', version = '3.5.1', url='http://pypi.python.org/pypi/zope.structuredtext', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', license='ZPL 2.1', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Software Development', ], description='StructuredText parser', long_description=long_description, packages=find_packages('src'), package_dir={'': 'src'}, namespace_packages=['zope',], include_package_data=True, install_requires=['setuptools'], zip_safe=False, ) zope.structuredtext-3.5.1/src/0000755000175000017500000000000011476217406016310 5ustar tseavertseaverzope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/0000755000175000017500000000000011476217406024067 5ustar tseavertseaverzope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/not-zip-safe0000644000175000017500000000000111476217364026320 0ustar tseavertseaver zope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/namespace_packages.txt0000644000175000017500000000000511476217406030415 0ustar tseavertseaverzope zope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/requires.txt0000644000175000017500000000001211476217406026460 0ustar tseavertseaversetuptoolszope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/SOURCES.txt0000644000175000017500000000325611476217406025761 0ustar tseavertseaver.bzrignore CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt TODO.txt bootstrap.py buildout.cfg convert.py setup.py docs/Makefile docs/api.rst docs/conf.py docs/index.rst docs/make.bat src/zope/__init__.py src/zope.structuredtext.egg-info/PKG-INFO src/zope.structuredtext.egg-info/SOURCES.txt src/zope.structuredtext.egg-info/dependency_links.txt src/zope.structuredtext.egg-info/namespace_packages.txt src/zope.structuredtext.egg-info/not-zip-safe src/zope.structuredtext.egg-info/requires.txt src/zope.structuredtext.egg-info/top_level.txt src/zope/structuredtext/__init__.py src/zope/structuredtext/docbook.py src/zope/structuredtext/document.py src/zope/structuredtext/html.py src/zope/structuredtext/stdom.py src/zope/structuredtext/stletters.py src/zope/structuredtext/stng.py src/zope/structuredtext/tests.py src/zope/structuredtext/regressions/Acquisition.ref src/zope/structuredtext/regressions/Acquisition.stx src/zope/structuredtext/regressions/ExtensionClass.ref src/zope/structuredtext/regressions/ExtensionClass.stx src/zope/structuredtext/regressions/InnerLinks.ref src/zope/structuredtext/regressions/InnerLinks.stx src/zope/structuredtext/regressions/Links.ref src/zope/structuredtext/regressions/Links.stx src/zope/structuredtext/regressions/MultiMapping.ref src/zope/structuredtext/regressions/MultiMapping.stx src/zope/structuredtext/regressions/examples.ref src/zope/structuredtext/regressions/examples.stx src/zope/structuredtext/regressions/examples1.ref src/zope/structuredtext/regressions/examples1.stx src/zope/structuredtext/regressions/index.ref src/zope/structuredtext/regressions/index.stx src/zope/structuredtext/regressions/table.ref src/zope/structuredtext/regressions/table.stxzope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/top_level.txt0000644000175000017500000000000511476217406026614 0ustar tseavertseaverzope zope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/dependency_links.txt0000644000175000017500000000000111476217406030135 0ustar tseavertseaver zope.structuredtext-3.5.1/src/zope.structuredtext.egg-info/PKG-INFO0000644000175000017500000000406711476217406025173 0ustar tseavertseaverMetadata-Version: 1.0 Name: zope.structuredtext Version: 3.5.1 Summary: StructuredText parser Home-page: http://pypi.python.org/pypi/zope.structuredtext Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ``zope.structuredtext`` README ============================== This package provides a parser and renderers for the classic Zope "structured text" markup dialect (STX). STX is a plain text markup in which document structure is signalled primarily by identation Please see ``docs/index.rst`` for the documentation. ``zope.structuredtext`` Changelog ================================= 3.5.1 (2010-12-03) ------------------ - Removed antique copyright assertions in regression texts, in conformance with repository policy. 3.5.0 (2010-04-30) ------------------ - Updated docs to conform to ZTK / Sphinx usage. - LP #120376: Output valid html for non-ASCII characters. 3.4.0 (2007/09/01) ------------------ - Public release for completeness of Zope 3.4. 3.2.0 (2006/01/05) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope 3.2.0 release. - Only coding style / documentation changes. 3.0.0 (2004/11/07) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope X3.0.0 release. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Software Development zope.structuredtext-3.5.1/src/zope/0000755000175000017500000000000011476217406017265 5ustar tseavertseaverzope.structuredtext-3.5.1/src/zope/__init__.py0000644000175000017500000000007011476217350021371 0ustar tseavertseaver__import__('pkg_resources').declare_namespace(__name__) zope.structuredtext-3.5.1/src/zope/structuredtext/0000755000175000017500000000000011476217406022376 5ustar tseavertseaverzope.structuredtext-3.5.1/src/zope/structuredtext/regressions/0000755000175000017500000000000011476217406024741 5ustar tseavertseaverzope.structuredtext-3.5.1/src/zope/structuredtext/regressions/InnerLinks.stx0000644000175000017500000000024011476217350027547 0ustar tseavertseaverThis is the InnerLinkTest see also [1] and [2] .. [1] "Zope Book" by Amos Lattmeier and Michel Pelletier .. [2] "Python Book" by Guido van Rossum zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/MultiMapping.stx0000644000175000017500000003170211476217350030110 0ustar tseavertseaverExample: MultiMapping objects As an example, consider an extension class that implements a "MultiMapping". A multi-mapping is an object that encapsulates 0 or more mapping objects. When an attempt is made to lookup an object, the encapsulated mapping objects are searched until an object is found. Consider an implementation of a MultiMapping extension type, without use of the extension class mechanism:: #include "Python.h" #define UNLESS(E) if(!(E)) typedef struct { PyObject_HEAD PyObject *data; } MMobject; staticforward PyTypeObject MMtype; static PyObject * MM_push(MMobject *self, PyObject *args){ PyObject *src; UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL; UNLESS(-1 != PyList_Append(self->data,src)) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * MM_pop(MMobject *self, PyObject *args){ long l; PyObject *r; static PyObject *emptyList=0; UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL; UNLESS(PyArg_ParseTuple(args, "")) return NULL; UNLESS(-1 != (l=PyList_Size(self->data))) return NULL; l--; UNLESS(r=PySequence_GetItem(self->data,l)) return NULL; UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err; return r; err: Py_DECREF(r); return NULL; } static struct PyMethodDef MM_methods[] = { {"push", (PyCFunction) MM_push, 1, "push(mapping_object) -- Add a data source"}, {"pop", (PyCFunction) MM_pop, 1, "pop() -- Remove and return the last data source added"}, {NULL, NULL} /* sentinel */ }; static PyObject * newMMobject(PyObject *ignored, PyObject *args){ MMobject *self; UNLESS(PyArg_ParseTuple(args, "")) return NULL; UNLESS(self = PyObject_NEW(MMobject, &MMtype)) return NULL; UNLESS(self->data=PyList_New(0)) goto err; return (PyObject *)self; err: Py_DECREF(self); return NULL; } static void MM_dealloc(MMobject *self){ Py_XDECREF(self->data); PyMem_DEL(self); } static PyObject * MM_getattr(MMobject *self, char *name){ return Py_FindMethod(MM_methods, (PyObject *)self, name); } static int MM_length(MMobject *self){ long l=0, el, i; PyObject *e=0; UNLESS(-1 != (i=PyList_Size(self->data))) return -1; while(--i >= 0) { e=PyList_GetItem(self->data,i); UNLESS(-1 != (el=PyObject_Length(e))) return -1; l+=el; } return l; } static PyObject * MM_subscript(MMobject *self, PyObject *key){ long i; PyObject *e; UNLESS(-1 != (i=PyList_Size(self->data))) return NULL; while(--i >= 0) { e=PyList_GetItem(self->data,i); if(e=PyObject_GetItem(e,key)) return e; PyErr_Clear(); } PyErr_SetObject(PyExc_KeyError,key); return NULL; } static PyMappingMethods MM_as_mapping = { (inquiry)MM_length, /*mp_length*/ (binaryfunc)MM_subscript, /*mp_subscript*/ (objobjargproc)NULL, /*mp_ass_subscript*/ }; /* -------------------------------------------------------- */ static char MMtype__doc__[] = "MultiMapping -- Combine multiple mapping objects for lookup" ; static PyTypeObject MMtype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "MultMapping", /*tp_name*/ sizeof(MMobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)MM_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)MM_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &MM_as_mapping, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, MMtype__doc__ /* Documentation string */ }; static struct PyMethodDef MultiMapping_methods[] = { {"MultiMapping", (PyCFunction)newMMobject, 1, "MultiMapping() -- Create a new empty multi-mapping"}, {NULL, NULL} /* sentinel */ }; void initMultiMapping(){ PyObject *m; m = Py_InitModule4( "MultiMapping", MultiMapping_methods, "MultiMapping -- Wrap multiple mapping objects for lookup", (PyObject*)NULL,PYTHON_API_VERSION); if (PyErr_Occurred()) Py_FatalError("can't initialize module MultiMapping"); } This module defines an extension type, 'MultiMapping', and exports a module function, 'MultiMapping', that creates 'MultiMapping' Instances. The type provides two methods, 'push', and 'pop', for adding and removing mapping objects to the multi-mapping. The type provides mapping behavior, implementing mapping length and subscript operators but not mapping a subscript assignment operator. Now consider an extension class implementation of MultiMapping objects:: #include "Python.h" #include "ExtensionClass.h" #define UNLESS(E) if(!(E)) typedef struct { PyObject_HEAD PyObject *data; } MMobject; staticforward PyExtensionClass MMtype; static PyObject * MM_push(self, args) MMobject *self; PyObject *args; { PyObject *src; UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL; UNLESS(-1 != PyList_Append(self->data,src)) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * MM_pop(self, args) MMobject *self; PyObject *args; { long l; PyObject *r; static PyObject *emptyList=0; UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL; UNLESS(PyArg_ParseTuple(args, "")) return NULL; UNLESS(-1 != (l=PyList_Size(self->data))) return NULL; l--; UNLESS(r=PySequence_GetItem(self->data,l)) return NULL; UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err; return r; err: Py_DECREF(r); return NULL; } static PyObject * MM__init__(self, args) MMobject *self; PyObject *args; { UNLESS(PyArg_ParseTuple(args, "")) return NULL; UNLESS(self->data=PyList_New(0)) goto err; Py_INCREF(Py_None); return Py_None; err: Py_DECREF(self); return NULL; } static struct PyMethodDef MM_methods[] = { {"__init__", (PyCFunction)MM__init__, 1, "__init__() -- Create a new empty multi-mapping"}, {"push", (PyCFunction) MM_push, 1, "push(mapping_object) -- Add a data source"}, {"pop", (PyCFunction) MM_pop, 1, "pop() -- Remove and return the last data source added"}, {NULL, NULL} /* sentinel */ }; static void MM_dealloc(self) MMobject *self; { Py_XDECREF(self->data); PyMem_DEL(self); } static PyObject * MM_getattr(self, name) MMobject *self; char *name; { return Py_FindMethod(MM_methods, (PyObject *)self, name); } static int MM_length(self) MMobject *self; { long l=0, el, i; PyObject *e=0; UNLESS(-1 != (i=PyList_Size(self->data))) return -1; while(--i >= 0) { e=PyList_GetItem(self->data,i); UNLESS(-1 != (el=PyObject_Length(e))) return -1; l+=el; } return l; } static PyObject * MM_subscript(self, key) MMobject *self; PyObject *key; { long i; PyObject *e; UNLESS(-1 != (i=PyList_Size(self->data))) return NULL; while(--i >= 0) { e=PyList_GetItem(self->data,i); if(e=PyObject_GetItem(e,key)) return e; PyErr_Clear(); } PyErr_SetObject(PyExc_KeyError,key); return NULL; } static PyMappingMethods MM_as_mapping = { (inquiry)MM_length, /*mp_length*/ (binaryfunc)MM_subscript, /*mp_subscript*/ (objobjargproc)NULL, /*mp_ass_subscript*/ }; /* -------------------------------------------------------- */ static char MMtype__doc__[] = "MultiMapping -- Combine multiple mapping objects for lookup" ; static PyExtensionClass MMtype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "MultMapping", /*tp_name*/ sizeof(MMobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)MM_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)MM_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &MM_as_mapping, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, MMtype__doc__, /* Documentation string */ METHOD_CHAIN(MM_methods) }; static struct PyMethodDef MultiMapping_methods[] = { {NULL, NULL} /* sentinel */ }; void initMultiMapping() { PyObject *m, *d; m = Py_InitModule4( "MultiMapping", MultiMapping_methods, "MultiMapping -- Wrap multiple mapping objects for lookup", (PyObject*)NULL,PYTHON_API_VERSION); d = PyModule_GetDict(m); PyExtensionClass_Export(d,"MultiMapping",MMtype); if (PyErr_Occurred()) Py_FatalError("can't initialize module MultiMapping"); } This version includes 'ExtensionClass.h'. The two declarations of 'MMtype' have been changed from 'PyTypeObject' to 'PyExtensionClass'. The 'METHOD_CHAIN' macro has been used to add methods to the end of the definition for 'MMtype'. The module function, newMMobject has been replaced by the 'MMtype' method, 'MM__init__'. Note that this method does not create or return a new object. Finally, the lines:: d = PyModule_GetDict(m); PyExtensionClass_Export(d,"MultiMapping",MMtype); Have been added to both initialize the extension class and to export it in the module dictionary. To use this module, compile, link, and import it as with any other extension module. The following python code illustrates the module's use:: from MultiMapping import MultiMapping m=MultiMapping() m.push({'spam':1, 'eggs':2}) m.push({'spam':3, 'ham':4}) m['spam'] # returns 3 m['ham'] # returns 4 m['foo'] # raises a key error Creating the 'MultiMapping' object took three steps, one to create an empty 'MultiMapping', and two to add mapping objects to it. We might wish to simplify the process of creating MultiMapping objects by providing a constructor that takes source mapping objects as parameters. We can do this by sub-classing MultiMapping in Python:: from MultiMapping import MultiMapping class ExtendedMultiMapping(MultiMapping): def __init__(self,*data): MultiMapping.__init__(self) for d in data: self.push(d) m=ExtendedMultiMapping({'spam':1, 'eggs':2}, {'spam':3, 'ham':4}) m['spam'] # returns 3 m['ham'] # returns 4 m['foo'] # raises a key error Note that the source file included in the ExtensionClass distribution has numerous enhancements beyond the version shown in this document. zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/InnerLinks.ref0000644000175000017500000000052411476217350027512 0ustar tseavertseaver This is the InnerLinkTest

This is the InnerLinkTest

see also [1] and [2]

[1] "Zope Book" by Amos Lattmeier and Michel Pelletier

[2] "Python Book" by Guido van Rossum

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/examples1.stx0000644000175000017500000000014211476217350027373 0ustar tseavertseaverTest For instance::
blabla
zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/examples1.ref0000644000175000017500000000033311476217350027333 0ustar tseavertseaver Test

Test

For instance:

    <table border="0">
      <tr><td>blabla</td></tr>
    </table>
zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/index.stx0000644000175000017500000000327611476217350026616 0ustar tseavertseaverExtension Class A lightweight mechanism has been developed for making Python extension types more class-like. Classes can be developed in an extension language, such as C or C++, and these classes can be treated like other python classes: - They can be sub-classed in python, - They provide access to method documentation strings, and - They can be used to directly create new instances. Extension classes provide additional extensions to class and instance semantics, including: - A protocol for accessing subobjects "in the context of" their containers. This is used to implement custom method types and "environmental acquisition":Acquisition.html. - A protocol for overriding method call semantics. This is used to implement "synchonized" classes and could be used to implement argument type checking. - A protocol for class initialization that supports execution of a special '__class_init__' method after a class has been initialized. Extension classes illustrate how the Python class mechanism can be extended and may provide a basis for improved or specialized class models. Releases The current release is "1.2":ExtensionClass-1.2.tar.gz, To find out what's changed in this release, see the "release notes":release.html. Documentation is available "on-line":ExtensionClass.html. Windows Binaries A win32 binary release, "ec12.zip":ec12.zip, is available. This release includes all of the ExtensionClass modules built as Windows extension modules (.pyd) files. These were built for Python 1.5.1 using Microsoft Visual C++ 5.0 in "Release" mode. zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/table.stx0000644000175000017500000000253211476217350026570 0ustar tseavertseaver|-------------------------------------------------| | Function | Documentation | |=================================================| | '__str__' | This method converts the | | | the object to a string. | | | | | | - Blah | | | | | | - Blaf | | | | | | |--------------------------| | | | | Name | Favorite | | | | | | Color | | | | |==========================| | | | | Jim | Red | | | | |--------------------------| | | | | John | Blue | | | | |--------------------------| | |-------------------------------------------------| |---------------------------------------| | This should give a row with colspan 3 | |---------------------------------------| | Col 1 | Col 2 | Col 3 | |---------------------------------------| | Col 1 | Col 2 | |---------------------------------------| | Col 1 | Col 2 | |---------------------------------------| zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/Acquisition.ref0000644000175000017500000002475211476217350027737 0ustar tseavertseaver Acquisition

Acquisition

Acquisition [1] is a mechanism that allows objects to obtain attributes from their environment. It is similar to inheritence, except that, rather than traversing an inheritence hierarchy to obtain attributes, a containment hierarchy is traversed.

The ExtensionClass. release includes mix-in extension base classes that can be used to add acquisition as a feature to extension subclasses. These mix-in classes use the context-wrapping feature of ExtensionClasses to implement acquisition. Consider the following example:

    import ExtensionClass, Acquisition

    class C(ExtensionClass.Base):
      color='red'

    class A(Acquisition.Implicit):

      def report(self):
        print self.color

    a=A()
    c=C()
    c.a=A()

    c.a.report() # prints 'red'

    d=C()
    d.color='green'
    d.a=a

    d.a.report() # prints 'green'

    a.report() # raises an attribute error

The class A inherits acquisition behavior from Acquisition.Implicit. The object, a, "has" the color of objects c and d when it is accessed through them, but it has no color by itself. The object a obtains attributes from it's environment, where it's environment is defined by the access path used to reach a.

Acquisition wrappers

When an object that supports acquisition is accessed through an extension class instance, a special object, called an acquisition wrapper, is returned. In the example above, the expression c.a returns an acquisition wrapper that contains references to both c and a. It is this wrapper that performs attribute lookup in c when an attribute cannot be found in a.

Aquisition wrappers provide access to the wrapped objects through the attributes aq_parent, aq_self, aq_base. In the example above, the expressions:

       'c.a.aq_parent is c'

and:

       'c.a.aq_self is a'

both evaluate to true, but the expression:

       'c.a is a'

evaluates to false, because the expression c.a evaluates to an acquisition wrapper around c and a, not a itself.

The attribute aq_base is similar to aq_self. Wrappers may be nested and aq_self may be a wrapped object. The aq_base attribute is the underlying object with all wrappers removed.

Acquisition Control

Two styles of acquisition are supported in the current ExtensionClass release, implicit and explicit aquisition.

Implicit acquisition

Implicit acquisition is so named because it searches for attributes from the environment automatically whenever an attribute cannot be obtained directly from an object or through inheritence.

An attribute may be implicitly acquired if it's name does not begin with an underscore, _.

To support implicit acquisition, an object should inherit from the mix-in class Acquisition.Implicit.

Explicit Acquisition

When explicit acquisition is used, attributes are not automatically obtained from the environment. Instead, the method aq_aquire must be used, as in:

        print c.a.aq_acquire('color')

To support explicit acquisition, an object should inherit from the mix-in class Acquisition.Explicit.

Controlled Acquisition

A class (or instance) can provide attribute by attribute control over acquisition. This is done by:

Filtered Acquisition

The acquisition method, aq_acquire, accepts two optional arguments. The first of the additional arguments is a "filtering" function that is used when considering whether to acquire an object. The second of the additional arguments is an object that is passed as extra data when calling the filtering function and which defaults to None.

The filter function is called with five arguments:

If the filter returns a true object that the object found is returned, otherwise, the acquisition search continues.

For example, in:

        from Acquisition import Explicit

        class HandyForTesting:
            def __init__(self, name): self.name=name
            def __str__(self):
                return "%s(%s)" % (self.name, self.__class__.__name__)
            __repr__=__str__

        class E(Explicit, HandyForTesting): pass

        class Nice(HandyForTesting):
            isNice=1
            def __str__(self):
                return HandyForTesting.__str__(self)+' and I am nice!'
            __repr__=__str__

        a=E('a')
        a.b=E('b')
        a.b.c=E('c')
        a.p=Nice('spam')
        a.b.p=E('p')

        def find_nice(self, ancestor, name, object, extra):
            return hasattr(object,'isNice') and object.isNice

        print a.b.c.aq_acquire('p', find_nice)

The filtered acquisition in the last line skips over the first attribute it finds with the name p, because the attribute doesn't satisfy the condition given in the filter. The output of the last line is:

        spam(Nice) and I am nice!

Acquisition and methods

Python methods of objects that support acquisition can use acquired attributes as in the report method of the first example above. When a Python method is called on an object that is wrapped by an acquisition wrapper, the wrapper is passed to the method as the first argument. This rule also applies to user-defined method types and to C methods defined in pure mix-in classes.

Unfortunately, C methods defined in extension base classes that define their own data structures, cannot use aquired attributes at this time. This is because wrapper objects do not conform to the data structures expected by these methods.

Acquiring Acquiring objects

Consider the following example:

      from Acquisition import Implicit

      class C(Implicit):
          def __init__(self, name): self.name=name
          def __str__(self):
              return "%s(%s)" % (self.name, self.__class__.__name__)
          __repr__=__str__

      a=C("a")
      a.b=C("b")
      a.b.pref="spam"
      a.b.c=C("c")
      a.b.c.color="red"
      a.b.c.pref="eggs"
      a.x=C("x")

      o=a.b.c.x

The expression o.color might be expected to return "red". In earlier versions of ExtensionClass, however, this expression failed. Acquired acquiring objects did not acquire from the environment they were accessed in, because objects were only wrapped when they were first found, and were not rewrapped as they were passed down the acquisition tree.

In the current release of ExtensionClass, the expression "o.color" does indeed return "red".

When searching for an attribute in o, objects are searched in the order x, a, b, c. So, for example, the expression, o.pref returns "spam", not "eggs". In earlier releases of ExtensionClass, the attempt to get the pref attribute from o would have failed.

If desired, the current rules for looking up attributes in complex expressions can best be understood through repeated application of the __of__ method:

a.x
x.__of__(a)
a.b
b.__of__(a)
a.b.x
x.__of__(a).__of__(b.__of__(a))
a.b.c
c.__of__(b.__of__(a))
a.b.c.x
x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))

and by keeping in mind that attribute lookup in a wrapper is done by trying to lookup the attribute in the wrapped object first and then in the parent object. In the expressions above involving the __of__ method, lookup proceeds from left to right.

Note that heuristics are used to avoid most of the repeated lookups. For example, in the expression: a.b.c.x.foo, the object a is searched no more than once, even though it is wrapped three times.

[1] Gil, J., Lorenz, D., Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism, OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/table.ref0000644000175000017500000000345011476217350026526 0ustar tseavertseaver

Function

Documentation

__str__

This method converts the the object to a string.

  • Blah
  • Blaf

    Name

    Favorite Color

    Jim

    Red

    John

    Blue

This should give a row with colspan 3

Col 1

Col 2

Col 3

Col 1

Col 2

Col 1

Col 2

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/Acquisition.stx0000644000175000017500000002165611476217350030001 0ustar tseavertseaverAcquisition Acquisition [1] is a mechanism that allows objects to obtain attributes from their environment. It is similar to inheritence, except that, rather than traversing an inheritence hierarchy to obtain attributes, a containment hierarchy is traversed. The "ExtensionClass":ExtensionClass.html. release includes mix-in extension base classes that can be used to add acquisition as a feature to extension subclasses. These mix-in classes use the context-wrapping feature of ExtensionClasses to implement acquisition. Consider the following example:: import ExtensionClass, Acquisition class C(ExtensionClass.Base): color='red' class A(Acquisition.Implicit): def report(self): print self.color a=A() c=C() c.a=A() c.a.report() # prints 'red' d=C() d.color='green' d.a=a d.a.report() # prints 'green' a.report() # raises an attribute error The class 'A' inherits acquisition behavior from 'Acquisition.Implicit'. The object, 'a', "has" the color of objects 'c' and 'd' when it is accessed through them, but it has no color by itself. The object 'a' obtains attributes from it's environment, where it's environment is defined by the access path used to reach 'a'. Acquisition wrappers When an object that supports acquisition is accessed through an extension class instance, a special object, called an acquisition wrapper, is returned. In the example above, the expression 'c.a' returns an acquisition wrapper that contains references to both 'c' and 'a'. It is this wrapper that performs attribute lookup in 'c' when an attribute cannot be found in 'a'. Aquisition wrappers provide access to the wrapped objects through the attributes 'aq_parent', 'aq_self', 'aq_base'. In the example above, the expressions:: 'c.a.aq_parent is c' and:: 'c.a.aq_self is a' both evaluate to true, but the expression:: 'c.a is a' evaluates to false, because the expression 'c.a' evaluates to an acquisition wrapper around 'c' and 'a', not 'a' itself. The attribute 'aq_base' is similar to 'aq_self'. Wrappers may be nested and 'aq_self' may be a wrapped object. The 'aq_base' attribute is the underlying object with all wrappers removed. Acquisition Control Two styles of acquisition are supported in the current ExtensionClass release, implicit and explicit aquisition. Implicit acquisition Implicit acquisition is so named because it searches for attributes from the environment automatically whenever an attribute cannot be obtained directly from an object or through inheritence. An attribute may be implicitly acquired if it's name does not begin with an underscore, '_'. To support implicit acquisition, an object should inherit from the mix-in class 'Acquisition.Implicit'. Explicit Acquisition When explicit acquisition is used, attributes are not automatically obtained from the environment. Instead, the method 'aq_aquire' must be used, as in:: print c.a.aq_acquire('color') To support explicit acquisition, an object should inherit from the mix-in class 'Acquisition.Explicit'. Controlled Acquisition A class (or instance) can provide attribute by attribute control over acquisition. This is done by: - subclassing from 'Acquisition.Explicit', and - setting all attributes that should be acquired to the special value: 'Acquisition.Acquired'. Setting an attribute to this value also allows inherited attributes to be overridden with acquired ones. For example, in:: class C(Acquisition.Explicit): id=1 secret=2 color=Acquisition.Acquired __roles__=Acquisition.Acquired The *only* attributes that are automatically acquired from containing objects are 'color', and '__roles__'. Note also that the '__roles__' attribute is acquired even though it's name begins with an underscore. In fact, the special 'Acquisition.Acquired' value can be used in 'Acquisition.Implicit' objects to implicitly acquire selected objects that smell like private objects. Filtered Acquisition The acquisition method, 'aq_acquire', accepts two optional arguments. The first of the additional arguments is a "filtering" function that is used when considering whether to acquire an object. The second of the additional arguments is an object that is passed as extra data when calling the filtering function and which defaults to 'None'. The filter function is called with five arguments: - The object that the 'aq_acquire' method was called on, - The object where an object was found, - The name of the object, as passed to 'aq_acquire', - The object found, and - The extra data passed to 'aq_acquire'. If the filter returns a true object that the object found is returned, otherwise, the acquisition search continues. For example, in:: from Acquisition import Explicit class HandyForTesting: def __init__(self, name): self.name=name def __str__(self): return "%s(%s)" % (self.name, self.__class__.__name__) __repr__=__str__ class E(Explicit, HandyForTesting): pass class Nice(HandyForTesting): isNice=1 def __str__(self): return HandyForTesting.__str__(self)+' and I am nice!' __repr__=__str__ a=E('a') a.b=E('b') a.b.c=E('c') a.p=Nice('spam') a.b.p=E('p') def find_nice(self, ancestor, name, object, extra): return hasattr(object,'isNice') and object.isNice print a.b.c.aq_acquire('p', find_nice) The filtered acquisition in the last line skips over the first attribute it finds with the name 'p', because the attribute doesn't satisfy the condition given in the filter. The output of the last line is:: spam(Nice) and I am nice! Acquisition and methods Python methods of objects that support acquisition can use acquired attributes as in the 'report' method of the first example above. When a Python method is called on an object that is wrapped by an acquisition wrapper, the wrapper is passed to the method as the first argument. This rule also applies to user-defined method types and to C methods defined in pure mix-in classes. Unfortunately, C methods defined in extension base classes that define their own data structures, cannot use aquired attributes at this time. This is because wrapper objects do not conform to the data structures expected by these methods. Acquiring Acquiring objects Consider the following example:: from Acquisition import Implicit class C(Implicit): def __init__(self, name): self.name=name def __str__(self): return "%s(%s)" % (self.name, self.__class__.__name__) __repr__=__str__ a=C("a") a.b=C("b") a.b.pref="spam" a.b.c=C("c") a.b.c.color="red" a.b.c.pref="eggs" a.x=C("x") o=a.b.c.x The expression 'o.color' might be expected to return '"red"'. In earlier versions of ExtensionClass, however, this expression failed. Acquired acquiring objects did not acquire from the environment they were accessed in, because objects were only wrapped when they were first found, and were not rewrapped as they were passed down the acquisition tree. In the current release of ExtensionClass, the expression "o.color" does indeed return '"red"'. When searching for an attribute in 'o', objects are searched in the order 'x', 'a', 'b', 'c'. So, for example, the expression, 'o.pref' returns '"spam"', not '"eggs"'. In earlier releases of ExtensionClass, the attempt to get the 'pref' attribute from 'o' would have failed. If desired, the current rules for looking up attributes in complex expressions can best be understood through repeated application of the '__of__' method: 'a.x' -- 'x.__of__(a)' 'a.b' -- 'b.__of__(a)' 'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))' 'a.b.c' -- 'c.__of__(b.__of__(a))' 'a.b.c.x' -- 'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))' and by keeping in mind that attribute lookup in a wrapper is done by trying to lookup the attribute in the wrapped object first and then in the parent object. In the expressions above involving the '__of__' method, lookup proceeds from left to right. Note that heuristics are used to avoid most of the repeated lookups. For example, in the expression: 'a.b.c.x.foo', the object 'a' is searched no more than once, even though it is wrapped three times. .. [1] Gil, J., Lorenz, D., "Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism", http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz, OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996 zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/ExtensionClass.ref0000644000175000017500000010025111476217350030376 0ustar tseavertseaver Extension Classes, Python Extension Types Become Classes

Extension Classes, Python Extension Types Become Classes

Jim Fulton, Digital Creations, Inc. jim@digicool.com

Abstract

A lightweight mechanism has been developed for making Python extension types more class-like. Classes can be developed in an extension language, such as C or C++, and these classes can be treated like other python classes:

An example class shows how extension classes are implemented and how they differ from extension types.

Extension classes provide additional extensions to class and instance semantics, including:

Extension classes illustrate how the Python class mechanism can be extended and may provide a basis for improved or specialized class models.

Releases

To find out what's changed in this release, see the release notes.

Problem

Currently, Python provides two ways of defining new kinds of objects:

Each approach has it's strengths. Extension types provide much greater control to the programmer and, generally, better performance. Because extension types are written in C, the programmer has greater access to external resources. (Note that Python's use of the term type has little to do with the notion of type as a formal specification.)

Classes provide a higher level of abstraction and are generally much easier to develop. Classes provide full inheritance support, while support for inheritance when developing extension types is very limited. Classes provide run-time meta-data, such as method documentation strings, that are useful for documentation and discovery. Classes act as factories for creating instances, while separate functions must be provided to create instances of types.

It would be useful to combine the features of the two approaches. It would be useful to be able to have better support for inheritance for types, or to be able to subclass from types in Python. It would be useful to be able to have class-like meta-data support for types and the ability to construct instances directly from types.

Our software is developed in Python. When necessary, we convert debugged Python routines and classes to C for improved performance. In most cases, a small number of methods in a class is responsible for most of the computation. It should be possible to convert only these methods to C, while leaving the other method in Python. A natural way to approach this is to create a base class in C that contains only the performance-critical aspects of a class' implementation and mix this base class into a Python class.

We have need, in a number of projects, for semantics that are slightly different than the usual class and instance semantics, yet we don't want to do most of our development in C. For example, we have developed a persistence mechanism [1] that redefines __getattr__ and __setattr__ to take storage-related actions when object state is accessed or modified. We want to be able to take certain actions on every attribute reference, but for python class instances, __getattr__ is only called when attribute lookup fails by normal means.

As another example, we would like to have greater control over how methods are bound. Currently, when accessing a class instance attribute, the attribute value is bound together with the instance in a method object if and only if the attribute value is a python function. For some applications, we might also want to be able to bind extension functions, or other types of callable objects, such as HTML document templates [2]. Furthermore, we might want to have greater control over how objects are bound. For example, we might want to bind instances and callable objects with special method objects that assure that no more than one thread accesses the object or method at one time.

We can provide these special semantics in extension types, but we wish to provide them for classes developed in Python.

Background

At the first Python Workshop, Don Beaudry presented work [3] done at V.I. Corp to integrate Python with C++ frameworks. This system provided a number of important features, including:

This work was not released, initially.

Shortly after the workshop, changes were made to Python to support the sub-classing features described in [3]. These changes were not documented until the fourth Python Workshop [4].

At the third Python workshop, I presented some work I had done on generating module documentation for extension types. Based on the discussion at this workshop, I developed a meta-type proposal [5]. This meta-type proposal was for an object that simply stored meta-information for a type, for the purpose of generating module documentation.

In the summer of 1996, Don Beaudry released the system described in [3] under the name MESS [6]. MESS addresses a number of needs but has a few drawbacks:

As MESS matures, we expect most of these problems to be addressed.

Extension Classes

To meet short term needs for a C-based persistence mechanism [1], an extension class module was developed using the mechanism described in [4] and building on ideas from MESS [6]. The extension class module recasts extension types as "extension classes" by seeking to eliminate, or at least reduce semantic differences between types and classes. The module was designed to meet the following goal:

Note: I use non-standard terminology here. By standard python terminology, only standard python classes can be called classes. ExtensionClass "classes" are technically just "types" that happen to swim, walk and quack like python classes.

Base extension classes and extension subclasses

Base extension classes are implemented in C. Extension subclasses are implemented in Python and inherit, directly or indirectly from one or more base extension classes. An extension subclass may inherit from base extension classes, extension subclasses, and ordinary python classes. The usual inheritance order rules apply. Currently, extension subclasses must conform to the following two rules:

Meta Information

Like standard python classes, extension classes have the following attributes containing meta-data:

__doc__
a documentation string for the class,
__name__
the class name,
__bases__
a sequence of base classes,
__dict__
a class dictionary, and
__module__
the name of the module in which the class was defined.

The class dictionary provides access to unbound methods and their documentation strings, including extension methods and special methods, such as methods that implement sequence and numeric protocols. Unbound methods can be called with instance first arguments.

Subclass instance data

Extension subclass instances have instance dictionaries, just like Python class instances do. When fetching attribute values, extension class instances will first try to obtain data from the base extension class data structure, then from the instance dictionary, then from the class dictionary, and finally from base classes. When setting attributes, extension classes first attempt to use extension base class attribute setting operations, and if these fail, then data are placed in the instance dictionary.

Implementing base extension classes

A base extension class is implemented in much the same way that an extension type is implemented, except:

where name is the module name and type is the extension class type object.

Attribute lookup

Attribute lookup is performed by calling the base extension class getattr operation for the base extension class that includes C data, or for the first base extension class, if none of the base extension classes include C data. ExtensionClass.h defines a macro Py_FindAttrString that can be used to find an object's attributes that are stored in the object's instance dictionary or in the object's class or base classes:

         v = Py_FindAttrString(self,name);

where name is a C string containing the attribute name.

In addition, a macro is provided that replaces Py_FindMethod calls with logic to perform the same sort of lookup that is provided by Py_FindAttrString.

If an attribute name is contained in a Python string object, rather than a C string object, then the macro Py_FindAttr should be used to look up an attribute value.

Linking

The extension class mechanism was designed to be useful with dynamically linked extension modules. Modules that implement extension classes do not have to be linked against an extension class library. The macro PyExtensionClass_Export imports the ExtensionClass module and uses objects imported from this module to initialize an extension class with necessary behavior.

Example: MultiMapping objects

An example, is provided that illustrates the changes needed to convert an existing type to an ExtensionClass.

Implementing base extension class constructors

Some care should be taken when implementing or overriding base class constructors. When a Python class overrides a base class constructor and fails to call the base class constructor, a program using the class may fail, but it will not crash the interpreter. On the other hand, an extension subclass that overrides a constructor in an extension base class must call the extension base class constructor or risk crashing the interpreter. This is because the base class constructor may set C pointers that, if not set properly, will cause the interpreter to crash when accessed. This is the case with the MultiMapping extension base class shown in the example above.

If no base class constructor is provided, extension class instance memory will be initialized to 0. It is a good idea to design extension base classes so that instance methods check for uninitialized memory and perform initialialization if necessary. This was not done above to simplify the example.

Overriding methods inherited from Python base classes

A problem occurs when trying to overide methods inherited from Python base classes. Consider the following example:

      from ExtensionClass import Base

      class Spam:

        def __init__(self, name):
          self.name=name

      class ECSpam(Base, Spam):

        def __init__(self, name, favorite_color):
          Spam.__init__(self,name)
          self.favorite_color=favorite_color

This implementation will fail when an ECSpam object is instantiated. The problem is that ECSpam.__init__ calls Spam.__init__, and Spam.__init__ can only be called with a Python instance (an object of type "instance") as the first argument. The first argument passed to Spam.__init__ will be an ECSpam instance (an object of type ECSPam).

To overcome this problem, extension classes provide a class method inheritedAttribute that can be used to obtain an inherited attribute that is suitable for calling with an extension class instance. Using the inheritedAttribute method, the above example can be rewritten as:

      from ExtensionClass import Base

      class Spam:

        def __init__(self, name):
          self.name=name

      class ECSpam(Base, Spam):

        def __init__(self, name, favorite_color):
          ECSpam.inheritedAttribute('__init__')(self,name)
          self.favorite_color=favorite_color

This isn't as pretty but does provide the desired result.

New class and instance semantics

Context Wrapping

It is sometimes useful to be able to wrap up an object together with a containing object. I call this "context wrapping" because an object is accessed in the context of the object it is accessed through.

We have found many applications for this, including:

User-defined method objects

Python classes wrap Python function attributes into methods. When a class has a function attribute that is accessed as an instance attribute, a method object is created and returned that contains references to the original function and instance. When the method is called, the original function is called with the instance as the first argument followed by any arguments passed to the method.

Extension classes provide a similar mechanism for attributes that are Python functions or inherited extension functions. In addition, if an extension class attribute is an instance of an extension class that defines an __of__ method, then when the attribute is accessed through an instance, it's __of__ method will be called to create a bound method.

Consider the following example:

          import ExtensionClass

          class CustomMethod(ExtensionClass.Base):

            def __call__(self,ob): 
              print 'a %s was called' % ob.__class__.__name__

            class wrapper:

              def __init__(self,m,o): self.meth, self.ob=m,o

              def __call__(self): self.meth(self.ob)

            def __of__(self,o): return self.wrapper(self,o)

          class bar(ExtensionClass.Base):
            hi=CustomMethod()

          x=bar()
          hi=x.hi()

Note that ExtensionClass.Base is a base extension class that provides very basic ExtensionClass behavior.

When run, this program outputs: a bar was called.

Computed Attributes

It is not uncommon to wish to expose information via the attribute interface without affecting implementation data structures. One can use a custom __getattr__ method to implement computed attributes, however, this can be a bit cumbersome and can interfere with other uses of __getattr__, such as for persistence.

The __of__ protocol provides a convenient way to implement computed attributes. First, we define a ComputedAttribute class. a ComputedAttribute is constructed with a function to be used to compute an attribute, and calls the function when it's __of__ method is called:

import ExtensionClass

class ComputedAttribute(ExtensionClass.Base):

def __init__(self, func): self.func=func

def __of__(self, parent): return self.func(parent)

Then we can use this class to create computed attributes. In the example below, we create a computed attribute, 'radius':

from math import sqrt

class Point(ExtensionClass.Base):

def __init__(self, x, y): self.x, self.y = x, y

radius=ComputedAttribute(lambda self: sqrt(self.x2+self.y2))

which we can use just like an ordinary attribute:

p=Point(2,2) print p.radius

Overriding method calls

Normally, when a method is called, the function wrapped by the method is called directly by the method. In some cases, it is useful for user-defined logic to participate in the actual function call. Extension classes introduce a new protocol that provides extension classes greater control over how their methods are called. If an extension class defines a special method, __call_method__, then this method will be called to call the functions (or other callable object) wrapped by the method. The method. __call_method__ should provide the same interface as provided by the Python builtin apply function.

For example, consider the expression: x.meth(arg1, arg2). The expression is evaluated by first computing a method object that wraps x and the attribute of x stored under the name meth. Assuming that x has a __call_method__ method defined, then the __call_method__ method of x will be called with two arguments, the attribute of x stored under the name meth, and a tuple containing x, arg1, and arg2.

To see how this feature may be used, see the Python module, Syn.py, which is included in the ExtensionClass distribution. This module provides a mix-in class that provides Java-like "synchonized" classes that limit access to their methods to one thread at a time.

An interesting application of this mechanism would be to implement interface checking on method calls.

Method attributes

Methods of ExtensionClass instances can have user-defined attributes, which are stored in their associated instances.

For example:

        class C(ExtensionClass.Base):

          def get_secret(self):
            "Get a secret"
            ....

        c=C()

        c.f.__roles__=['Trusted People']

        print c.f.__roles__ # outputs ['Trusted People']
        print c.f__roles__  # outputs ['Trusted People']

        print C.f.__roles__ # fails, unbound method

A bound method attribute is set by setting an attribute in it's instance with a name consisting of the concatination of the method's __name__ attribute and the attribute name. Attributes cannot be set on unbound methods.

Class initialization

Normal Python class initialization is similar to but subtley different from instance initialization. An instance __init__ function is called on an instance immediately after it is created. An instance __init__ function can use instance information, like it's class and can pass the instance to other functions. On the other hand, the code in class statements is executed immediately before the class is created. This means that the code in a class statement cannot use class attributes, like __bases__, or pass the class to functions.

Extension classes provide a mechanism for specifying code to be run after a class has been created. If a class or one of it's base classes defines a __class_init__ method, then this method will be called just after a class has been created. The one argument passed to the method will be the class, not an instance of the class.

Useful macros defined in ExtensionClass.h

A number of useful macros are defined in ExtensionClass.h. These are documented in ExtensionClass.h.

Pickleability

Classes created with ExtensionClass, including extension base classes are automatically pickleable. The usual gymnastics necessary to pickle non-standard types are not necessray for types that have been modified to be extension base classes.

Status

The current release of the extension class module is 1.1. The core implementation has less than four thousand lines of code, including comments. This release requires Python 1.4 or higher.

To find out what's changed in this release, see the release notes.

Installation instructions, are provided.

Issues

There are a number of issues that came up in the course of this work and that deserve mention.

Applications

Aside from test and demonstration applications, the extension class mechanism has been used to provide an extension-based implementation of the persistence mechanism described in [1]. We have developed this further to provide features such as automatic deactivation of objects not used after some period of time and to provide more efficient persistent-object cache management.

Acquisition has been heavily used in our recent products. Synchonized classes have also been used in recent products.

Summary

The extension-class mechanism described here provides a way to add class services to extension types. It allows:

In addition, the extension class module provides a relatively concise example of the use of mechanisms that were added to Python to support MESS [6], and that were described at the fourth Python Workshop [4]. It is hoped that this will spur research in improved and specialized models for class implementation in Python.

References

[1] Fulton, J., Providing Persistence for World-Wide-Web Applications, Proceedings of the 5th Python Workshop.

[2] Page, R. and Cropper, S., Document Template, Proceedings of the 5th Python Workshop.

[3] Beaudry, D., Deriving Built-In Classes in Python, Proceedings of the First International Python Workshop.

[4] Van Rossum, G., Don Beaudry Hack - MESS, presented in the Developer's Future Enhancements session of the 4th Python Workshop.

[5] Fulton, J., Meta-Type Object, This is a small proposal, the text of which is contained in a sample implementation source file,

[6] Beaudry, D., and Ascher, D., The Meta-Extension Set.

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/examples.stx0000644000175000017500000000213711476217350027320 0ustar tseavertseaverSmall Trials for Structured Text Formatting This paragraph should be preceded by a level 1 header. It should not, itself, be made into a header, just a regular paragraph. Here are a few presentation styles, in a list [1]: - A word: *emphasized*. - A word: _underlined_. - A word **strong**. - An inline example: '1+2'. - Another example with a different format: ``x='spam''' or ``y='spam''' or ``''.' We can use expressions in the DTML var tag as in ``'' - A mult-line example:: blah *foo bar* .. [1] (The referring text should be a paragraph, not a header, and should contain a reference to this footnote, footnote "[1]".) Some hrefs, in a definition list: _Regular_ -- "http://www.zope.org/":http://www.zope.org _W/trailing punctuation_ -- "http://www.zope.org/":http://www.zope.org. _W protocol implicit_ -- "locallink"::locallink _W protocol implicit_, alternate -- "locallink", :locallink |||| A Simple Two-column Table || || Column A || Column B || || Apples || Oranges || zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/ExtensionClass.stx0000644000175000017500000007251711476217350030455 0ustar tseavertseaverExtension Classes, Python Extension Types Become Classes Jim Fulton, Digital Creations, Inc. jim@digicool.com Abstract A lightweight mechanism has been developed for making Python extension types more class-like. Classes can be developed in an extension language, such as C or C++, and these classes can be treated like other python classes: - They can be sub-classed in python, - They provide access to method documentation strings, and - They can be used to directly create new instances. An example class shows how extension classes are implemented and how they differ from extension types. Extension classes provide additional extensions to class and instance semantics, including: - A protocol for accessing subobjects "in the context of" their containers. This is used to implement custom method types and "environmental acquisition":Acquisition.html. - A protocol for overriding method call semantics. This is used to implement "synchonized" classes and could be used to implement argument type checking. - A protocol for class initialization that supports execution of a special '__class_init__' method after a class has been initialized. Extension classes illustrate how the Python class mechanism can be extended and may provide a basis for improved or specialized class models. Releases To find out what's changed in this release, see the "release notes":release.html. Problem Currently, Python provides two ways of defining new kinds of objects: - Python classes - Extension types Each approach has it's strengths. Extension types provide much greater control to the programmer and, generally, better performance. Because extension types are written in C, the programmer has greater access to external resources. (Note that Python's use of the term type has little to do with the notion of type as a formal specification.) Classes provide a higher level of abstraction and are generally much easier to develop. Classes provide full inheritance support, while support for inheritance when developing extension types is very limited. Classes provide run-time meta-data, such as method documentation strings, that are useful for documentation and discovery. Classes act as factories for creating instances, while separate functions must be provided to create instances of types. It would be useful to combine the features of the two approaches. It would be useful to be able to have better support for inheritance for types, or to be able to subclass from types in Python. It would be useful to be able to have class-like meta-data support for types and the ability to construct instances directly from types. Our software is developed in Python. When necessary, we convert debugged Python routines and classes to C for improved performance. In most cases, a small number of methods in a class is responsible for most of the computation. It should be possible to convert only these methods to C, while leaving the other method in Python. A natural way to approach this is to create a base class in C that contains only the performance-critical aspects of a class' implementation and mix this base class into a Python class. We have need, in a number of projects, for semantics that are slightly different than the usual class and instance semantics, yet we don't want to do most of our development in C. For example, we have developed a persistence mechanism [1] that redefines '__getattr__' and '__setattr__' to take storage-related actions when object state is accessed or modified. We want to be able to take certain actions on *every* attribute reference, but for python class instances, '__getattr__' is only called when attribute lookup fails by normal means. As another example, we would like to have greater control over how methods are bound. Currently, when accessing a class instance attribute, the attribute value is bound together with the instance in a method object *if and only if* the attribute value is a python function. For some applications, we might also want to be able to bind extension functions, or other types of callable objects, such as HTML document templates [2]. Furthermore, we might want to have greater control over how objects are bound. For example, we might want to bind instances and callable objects with special method objects that assure that no more than one thread accesses the object or method at one time. We can provide these special semantics in extension types, but we wish to provide them for classes developed in Python. Background At the first Python Workshop, Don Beaudry presented work [3] done at V.I. Corp to integrate Python with C++ frameworks. This system provided a number of important features, including: - Definition of extension types that provide class-like meta-data and that can be called to create instances. - Ability to subclass in python from C types. - Ability to define classes in python who's data are stored as C structures rather than in dictionaries to better interface to C and C++ libraries, and for better performance. - Less dynamic data structures. In particular, the data structure for a class is declared during class definition. - Support for enumeration types. This work was not released, initially. Shortly after the workshop, changes were made to Python to support the sub-classing features described in [3]. These changes were not documented until the fourth Python Workshop [4]. At the third Python workshop, I presented some work I had done on generating module documentation for extension types. Based on the discussion at this workshop, I developed a meta-type proposal [5]. This meta-type proposal was for an object that simply stored meta-information for a type, for the purpose of generating module documentation. In the summer of 1996, Don Beaudry released the system described in [3] under the name MESS [6]. MESS addresses a number of needs but has a few drawbacks: - Only single inheritance is supported. - The mechanisms for defining MESS extension types is very different from and more complicated than the standard Python type creation mechanism. - Defining MESS types requires the use of an extensive C applications programming interface. This presents problems for configuring dynamically-loaded extension modules unless the MESS library is linked into the Python interpreter. - Because the system tries to do a number of different things, it is fairly large, about 15,000 lines. - There is very little documentation, especially for the C programming interface. - The system is a work in progress, with a number of outstanding bugs. As MESS matures, we expect most of these problems to be addressed. Extension Classes To meet short term needs for a C-based persistence mechanism [1], an extension class module was developed using the mechanism described in [4] and building on ideas from MESS [6]. The extension class module recasts extension types as "extension classes" by seeking to eliminate, or at least reduce semantic differences between types and classes. The module was designed to meet the following goal: - Provide class-like behavior for extension types, including interfaces for meta information and for constructing instances. - Support sub-classing in Python from extension classes, with support for multiple inheritance. - Provide a small hardened implementation that can be used for current products. - Provide a mechanism that requires minimal modification to existing extension types. - Provide a basis for research on alternative semantics for classes and inheritance. **Note:** I use *non-standard* terminology here. By standard *python* terminology, only standard python classes can be called classes. ExtensionClass "classes" are technically just "types" that happen to swim, walk and quack like python classes. Base extension classes and extension subclasses Base extension classes are implemented in C. Extension subclasses are implemented in Python and inherit, directly or indirectly from one or more base extension classes. An extension subclass may inherit from base extension classes, extension subclasses, and ordinary python classes. The usual inheritance order rules apply. Currently, extension subclasses must conform to the following two rules: - The first super class listed in the class statement defining an extension subclass must be either a base extension class or an extension subclass. This restriction will be removed in Python-1.5. - At most one base extension direct or indirect super class may define C data members. If an extension subclass inherits from multiple base extension classes, then all but one must be mix-in classes that provide extension methods but no data. Meta Information Like standard python classes, extension classes have the following attributes containing meta-data: '__doc__' -- a documentation string for the class, '__name__' -- the class name, '__bases__' -- a sequence of base classes, '__dict__' -- a class dictionary, and '__module__' -- the name of the module in which the class was defined. The class dictionary provides access to unbound methods and their documentation strings, including extension methods and special methods, such as methods that implement sequence and numeric protocols. Unbound methods can be called with instance first arguments. Subclass instance data Extension subclass instances have instance dictionaries, just like Python class instances do. When fetching attribute values, extension class instances will first try to obtain data from the base extension class data structure, then from the instance dictionary, then from the class dictionary, and finally from base classes. When setting attributes, extension classes first attempt to use extension base class attribute setting operations, and if these fail, then data are placed in the instance dictionary. Implementing base extension classes A base extension class is implemented in much the same way that an extension type is implemented, except: - The include file, 'ExtensionClass.h', must be included. - The type structure is declared to be of type 'PyExtensionClass', rather than of type 'PyTypeObject'. - The type structure has an additional member that must be defined after the documentation string. This extra member is a method chain ('PyMethodChain') containing a linked list of method definition ('PyMethodDef') lists. Method chains can be used to implement method inheritance in C. Most extensions don't use method chains, but simply define method lists, which are null-terminated arrays of method definitions. A macro, 'METHOD_CHAIN' is defined in 'ExtensionClass.h' that converts a method list to a method chain. (See the example below.) - Module functions that create new instances must be replaced by '__init__' methods that initialize, but does not create storage for instances. - The extension class must be initialized and exported to the module with:: PyExtensionClass_Export(d,"name",type); where 'name' is the module name and 'type' is the extension class type object. Attribute lookup Attribute lookup is performed by calling the base extension class 'getattr' operation for the base extension class that includes C data, or for the first base extension class, if none of the base extension classes include C data. 'ExtensionClass.h' defines a macro 'Py_FindAttrString' that can be used to find an object's attributes that are stored in the object's instance dictionary or in the object's class or base classes:: v = Py_FindAttrString(self,name); where 'name' is a C string containing the attribute name. In addition, a macro is provided that replaces 'Py_FindMethod' calls with logic to perform the same sort of lookup that is provided by 'Py_FindAttrString'. If an attribute name is contained in a Python string object, rather than a C string object, then the macro 'Py_FindAttr' should be used to look up an attribute value. Linking The extension class mechanism was designed to be useful with dynamically linked extension modules. Modules that implement extension classes do not have to be linked against an extension class library. The macro 'PyExtensionClass_Export' imports the 'ExtensionClass' module and uses objects imported from this module to initialize an extension class with necessary behavior. Example: MultiMapping objects An "example":MultiMapping.html, is provided that illustrates the changes needed to convert an existing type to an ExtensionClass. Implementing base extension class constructors Some care should be taken when implementing or overriding base class constructors. When a Python class overrides a base class constructor and fails to call the base class constructor, a program using the class may fail, but it will not crash the interpreter. On the other hand, an extension subclass that overrides a constructor in an extension base class must call the extension base class constructor or risk crashing the interpreter. This is because the base class constructor may set C pointers that, if not set properly, will cause the interpreter to crash when accessed. This is the case with the 'MultiMapping' extension base class shown in the example above. If no base class constructor is provided, extension class instance memory will be initialized to 0. It is a good idea to design extension base classes so that instance methods check for uninitialized memory and perform initialialization if necessary. This was not done above to simplify the example. Overriding methods inherited from Python base classes A problem occurs when trying to overide methods inherited from Python base classes. Consider the following example:: from ExtensionClass import Base class Spam: def __init__(self, name): self.name=name class ECSpam(Base, Spam): def __init__(self, name, favorite_color): Spam.__init__(self,name) self.favorite_color=favorite_color This implementation will fail when an 'ECSpam' object is instantiated. The problem is that 'ECSpam.__init__' calls 'Spam.__init__', and 'Spam.__init__' can only be called with a Python instance (an object of type '"instance"') as the first argument. The first argument passed to 'Spam.__init__' will be an 'ECSpam' instance (an object of type 'ECSPam'). To overcome this problem, extension classes provide a class method 'inheritedAttribute' that can be used to obtain an inherited attribute that is suitable for calling with an extension class instance. Using the 'inheritedAttribute' method, the above example can be rewritten as:: from ExtensionClass import Base class Spam: def __init__(self, name): self.name=name class ECSpam(Base, Spam): def __init__(self, name, favorite_color): ECSpam.inheritedAttribute('__init__')(self,name) self.favorite_color=favorite_color This isn't as pretty but does provide the desired result. New class and instance semantics Context Wrapping It is sometimes useful to be able to wrap up an object together with a containing object. I call this "context wrapping" because an object is accessed in the context of the object it is accessed through. We have found many applications for this, including: - User-defined method objects, - "Acquisition":Acquisition.html, and - Computed attributes User-defined method objects Python classes wrap Python function attributes into methods. When a class has a function attribute that is accessed as an instance attribute, a method object is created and returned that contains references to the original function and instance. When the method is called, the original function is called with the instance as the first argument followed by any arguments passed to the method. Extension classes provide a similar mechanism for attributes that are Python functions or inherited extension functions. In addition, if an extension class attribute is an instance of an extension class that defines an '__of__' method, then when the attribute is accessed through an instance, it's '__of__' method will be called to create a bound method. Consider the following example:: import ExtensionClass class CustomMethod(ExtensionClass.Base): def __call__(self,ob): print 'a %s was called' % ob.__class__.__name__ class wrapper: def __init__(self,m,o): self.meth, self.ob=m,o def __call__(self): self.meth(self.ob) def __of__(self,o): return self.wrapper(self,o) class bar(ExtensionClass.Base): hi=CustomMethod() x=bar() hi=x.hi() Note that 'ExtensionClass.Base' is a base extension class that provides very basic ExtensionClass behavior. When run, this program outputs: 'a bar was called'. Computed Attributes It is not uncommon to wish to expose information via the attribute interface without affecting implementation data structures. One can use a custom '__getattr__' method to implement computed attributes, however, this can be a bit cumbersome and can interfere with other uses of '__getattr__', such as for persistence. The '__of__' protocol provides a convenient way to implement computed attributes. First, we define a ComputedAttribute class. a ComputedAttribute is constructed with a function to be used to compute an attribute, and calls the function when it's '__of__' method is called: import ExtensionClass class ComputedAttribute(ExtensionClass.Base): def __init__(self, func): self.func=func def __of__(self, parent): return self.func(parent) Then we can use this class to create computed attributes. In the example below, we create a computed attribute, 'radius': from math import sqrt class Point(ExtensionClass.Base): def __init__(self, x, y): self.x, self.y = x, y radius=ComputedAttribute(lambda self: sqrt(self.x**2+self.y**2)) which we can use just like an ordinary attribute: p=Point(2,2) print p.radius Overriding method calls Normally, when a method is called, the function wrapped by the method is called directly by the method. In some cases, it is useful for user-defined logic to participate in the actual function call. Extension classes introduce a new protocol that provides extension classes greater control over how their methods are called. If an extension class defines a special method, '__call_method__', then this method will be called to call the functions (or other callable object) wrapped by the method. The method. '__call_method__' should provide the same interface as provided by the Python builtin 'apply' function. For example, consider the expression: 'x.meth(arg1, arg2)'. The expression is evaluated by first computing a method object that wraps 'x' and the attribute of 'x' stored under the name 'meth'. Assuming that 'x' has a '__call_method__' method defined, then the '__call_method__' method of 'x' will be called with two arguments, the attribute of 'x' stored under the name 'meth', and a tuple containing 'x', 'arg1', and 'arg2'. To see how this feature may be used, see the Python module, 'Syn.py', which is included in the ExtensionClass distribution. This module provides a mix-in class that provides Java-like "synchonized" classes that limit access to their methods to one thread at a time. An interesting application of this mechanism would be to implement interface checking on method calls. Method attributes Methods of ExtensionClass instances can have user-defined attributes, which are stored in their associated instances. For example:: class C(ExtensionClass.Base): def get_secret(self): "Get a secret" .... c=C() c.f.__roles__=['Trusted People'] print c.f.__roles__ # outputs ['Trusted People'] print c.f__roles__ # outputs ['Trusted People'] print C.f.__roles__ # fails, unbound method A bound method attribute is set by setting an attribute in it's instance with a name consisting of the concatination of the method's '__name__' attribute and the attribute name. Attributes cannot be set on unbound methods. Class initialization Normal Python class initialization is similar to but subtley different from instance initialization. An instance '__init__' function is called on an instance immediately *after* it is created. An instance '__init__' function can use instance information, like it's class and can pass the instance to other functions. On the other hand, the code in class statements is executed immediately *before* the class is created. This means that the code in a class statement cannot use class attributes, like '__bases__', or pass the class to functions. Extension classes provide a mechanism for specifying code to be run *after* a class has been created. If a class or one of it's base classes defines a '__class_init__' method, then this method will be called just after a class has been created. The one argument passed to the method will be the class, *not* an instance of the class. Useful macros defined in ExtensionClass.h A number of useful macros are defined in ExtensionClass.h. These are documented in 'ExtensionClass.h'. Pickleability Classes created with ExtensionClass, including extension base classes are automatically pickleable. The usual gymnastics necessary to pickle 'non-standard' types are not necessray for types that have been modified to be extension base classes. Status The current release of the extension class module is "1.1", http://www.digicool.com/releases/ExtensionClass/ExtensionClass-1.1.tar.gz. The core implementation has less than four thousand lines of code, including comments. This release requires Python 1.4 or higher. To find out what's changed in this release, see the "release notes":release.html. "Installation instructions":Installation.html, are provided. Issues There are a number of issues that came up in the course of this work and that deserve mention. - In Python 1.4, the class extension mechanism described in [4] required that the first superclass in a list of super-classes must be of the extended class type. This may not be convenient if mix-in behavior is desired. If a list of base classes starts with a standard python class, but includes an extension class, then an error was raised. It would be more useful if, when a list of base classes contains one or more objects that are not python classes, the first such object was used to control the extended class definition. To get around this, the 'ExtensionClass' module exports a base extension class, 'Base', that can be used as the first base class in a list of base classes to assure that an extension subclass is created. Python 1.5 allows the class extension even if the first non-class object in the list of base classes is not the first object in the list. This issue appears to go away in Python 1.5, however, the restriction that the first non-class object in a list of base classes must be the first in the list may reappear in later versions of Python. - Currently, only one base extension class can define any data in C. The data layout of subclasses-instances is the same as for the base class that defines data in C, except that the data structure is extended to hold an instance dictionary. The data structure begins with a standard python header, and extension methods expect the C instance data to occur immediately after the object header. If two or more base classes defined C data, the methods for the different base classes would expect their data to be in the same location. A solution might be to allocate base class instances and store pointers to these instances in the subclass data structure. The method binding mechanism would have to be a more complicated to make sure that methods were bound to the correct base data structure. Alternatively, the signature of C methods could be expanded to allow pointers to expected class data to be passed in addition to object pointers. - There is currently no support for sub-classing in C, beyond that provided by method chains. - Rules for mixed-type arithmetic are different for python class instances than they are for extension type instances. Python classes can define right and left versions of numeric binary operators, or they can define a coercion operator for converting binary operator operands to a common type. For extension types, only the latter, coercion-based, approach is supported. The coercion-based approach does not work well for many data types for which coercion rules depend on the operator. Because extension classes are based on extension types, they are currently limited to the coercion-based approach. It should be possible to extend the extension class implementation to allow both types of mixed-type arithmetic control. - I considered making extension classes immutable, meaning that class attributes could not be set after class creation. I also considered making extension subclasses cache inherited attributes. Both of these are related and attractive for some applications, however, I decided that it would be better to retain standard class instance semantics and provide these features as options at a later time. - The extension class module defines new method types to bind C and python methods to extension class instances. It would be useful for these method objects to provide access to function call information, such as the number and names of arguments and the number of defaults, by parsing extension function documentation strings. Applications Aside from test and demonstration applications, the extension class mechanism has been used to provide an extension-based implementation of the persistence mechanism described in [1]. We have developed this further to provide features such as automatic deactivation of objects not used after some period of time and to provide more efficient persistent-object cache management. Acquisition has been heavily used in our recent products. Synchonized classes have also been used in recent products. Summary The extension-class mechanism described here provides a way to add class services to extension types. It allows: - Sub-classing extension classes in Python, - Construction of extension class instances by calling extension classes, - Extension classes to provide meta-data, such as unbound methods and their documentation string. In addition, the extension class module provides a relatively concise example of the use of mechanisms that were added to Python to support MESS [6], and that were described at the fourth Python Workshop [4]. It is hoped that this will spur research in improved and specialized models for class implementation in Python. References .. [1] Fulton, J., "Providing Persistence for World-Wide-Web Applications", http://www.digicool.com/papers/Persistence.html, Proceedings of the 5th Python Workshop. .. [2] Page, R. and Cropper, S., "Document Template", http://www.digicool.com/papers/DocumentTemplate.html, Proceedings of the 5th Python Workshop. .. [3] Beaudry, D., "Deriving Built-In Classes in Python", http://www.python.org/workshops/1994-11/BuiltInClasses/BuiltInClasses_1.html, Proceedings of the First International Python Workshop. .. [4] Van Rossum, G., "Don Beaudry Hack - MESS", http://www.python.org/workshops/1996-06/notes/thursday.html, presented in the Developer's Future Enhancements session of the 4th Python Workshop. .. [5] Fulton, J., "Meta-Type Object", http://www.digicool.com/jim/MetaType.c, This is a small proposal, the text of which is contained in a sample implementation source file, .. [6] Beaudry, D., and Ascher, D., "The Meta-Extension Set", http://starship.skyport.net/~da/mess/. zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/MultiMapping.ref0000644000175000017500000003233211476217350030046 0ustar tseavertseaver Example: MultiMapping objects

Example: MultiMapping objects

As an example, consider an extension class that implements a "MultiMapping". A multi-mapping is an object that encapsulates 0 or more mapping objects. When an attempt is made to lookup an object, the encapsulated mapping objects are searched until an object is found.

Consider an implementation of a MultiMapping extension type, without use of the extension class mechanism:

    #include "Python.h"

    #define UNLESS(E) if(!(E))

    typedef struct {
        PyObject_HEAD
        PyObject *data;
    } MMobject;

    staticforward PyTypeObject MMtype;

    static PyObject *
    MM_push(MMobject *self, PyObject *args){
        PyObject *src;
        UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
        UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
        Py_INCREF(Py_None);
        return Py_None;
    }

    static PyObject *
    MM_pop(MMobject *self, PyObject *args){
        long l;
        PyObject *r;
        static PyObject *emptyList=0;

        UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
        UNLESS(PyArg_ParseTuple(args, "")) return NULL;
        UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
        l--;
        UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
        UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
        return r;
    err:
        Py_DECREF(r);
        return NULL;
    }

    static struct PyMethodDef MM_methods[] = {
        {"push", (PyCFunction) MM_push, 1,
         "push(mapping_object) -- Add a data source"},
        {"pop",  (PyCFunction) MM_pop,  1,
         "pop() -- Remove and return the last data source added"}, 
        {NULL,              NULL}           /* sentinel */
    };

    static PyObject *
    newMMobject(PyObject *ignored, PyObject *args){
        MMobject *self;

        UNLESS(PyArg_ParseTuple(args, "")) return NULL;
        UNLESS(self = PyObject_NEW(MMobject, &MMtype)) return NULL;
        UNLESS(self->data=PyList_New(0)) goto err;
        return (PyObject *)self;
    err:
        Py_DECREF(self);
        return NULL;
    }

    static void
    MM_dealloc(MMobject *self){
        Py_XDECREF(self->data);
        PyMem_DEL(self);
    }

    static PyObject *
    MM_getattr(MMobject *self, char *name){
        return Py_FindMethod(MM_methods, (PyObject *)self, name);
    }

    static int
    MM_length(MMobject *self){
        long l=0, el, i;
        PyObject *e=0;

        UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
        while(--i >= 0)
          {
            e=PyList_GetItem(self->data,i);
            UNLESS(-1 != (el=PyObject_Length(e))) return -1;
            l+=el;
          }
        return l;
    }

    static PyObject *
    MM_subscript(MMobject *self, PyObject *key){
        long i;
        PyObject *e;

        UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
        while(--i >= 0)
          {
            e=PyList_GetItem(self->data,i);
            if(e=PyObject_GetItem(e,key)) return e;
            PyErr_Clear();
          }
        PyErr_SetObject(PyExc_KeyError,key);
        return NULL;
    }

    static PyMappingMethods MM_as_mapping = {
              (inquiry)MM_length,           /*mp_length*/
              (binaryfunc)MM_subscript,             /*mp_subscript*/
              (objobjargproc)NULL,          /*mp_ass_subscript*/
    };

    /* -------------------------------------------------------- */

    static char MMtype__doc__[] = 
    "MultiMapping -- Combine multiple mapping objects for lookup"
    ;

    static PyTypeObject MMtype = {
              PyObject_HEAD_INIT(&PyType_Type)
              0,                            /*ob_size*/
              "MultMapping",                        /*tp_name*/
              sizeof(MMobject),             /*tp_basicsize*/
              0,                            /*tp_itemsize*/
              /* methods */
              (destructor)MM_dealloc,               /*tp_dealloc*/
              (printfunc)0,                 /*tp_print*/
              (getattrfunc)MM_getattr,      /*tp_getattr*/
              (setattrfunc)0,                       /*tp_setattr*/
              (cmpfunc)0,                   /*tp_compare*/
              (reprfunc)0,                  /*tp_repr*/
              0,                            /*tp_as_number*/
              0,                            /*tp_as_sequence*/
              &MM_as_mapping,                       /*tp_as_mapping*/
              (hashfunc)0,                  /*tp_hash*/
              (ternaryfunc)0,                       /*tp_call*/
              (reprfunc)0,                  /*tp_str*/

              /* Space for future expansion */
              0L,0L,0L,0L,
              MMtype__doc__ /* Documentation string */
    };

    static struct PyMethodDef MultiMapping_methods[] = {
        {"MultiMapping", (PyCFunction)newMMobject, 1,
         "MultiMapping() -- Create a new empty multi-mapping"},
        {NULL,              NULL}           /* sentinel */
    };

    void
    initMultiMapping(){
        PyObject *m;

        m = Py_InitModule4(
            "MultiMapping", MultiMapping_methods,
              "MultiMapping -- Wrap multiple mapping objects for lookup",
              (PyObject*)NULL,PYTHON_API_VERSION);

        if (PyErr_Occurred()) 
           Py_FatalError("can't initialize module MultiMapping");
    }

This module defines an extension type, MultiMapping, and exports a module function, MultiMapping, that creates MultiMapping Instances. The type provides two methods, push, and pop, for adding and removing mapping objects to the multi-mapping. The type provides mapping behavior, implementing mapping length and subscript operators but not mapping a subscript assignment operator.

Now consider an extension class implementation of MultiMapping objects:

    #include "Python.h"
    #include "ExtensionClass.h"

    #define UNLESS(E) if(!(E))

    typedef struct {
        PyObject_HEAD
        PyObject *data;
    } MMobject;

    staticforward PyExtensionClass MMtype;

    static PyObject *
    MM_push(self, args)
              MMobject *self;
              PyObject *args;
    {
        PyObject *src;
        UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
        UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
        Py_INCREF(Py_None);
        return Py_None;
    }

    static PyObject *
    MM_pop(self, args)
              MMobject *self;
              PyObject *args;
    {
        long l;
        PyObject *r;
        static PyObject *emptyList=0;

        UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
        UNLESS(PyArg_ParseTuple(args, "")) return NULL;
        UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
        l--;
        UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
        UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
        return r;
    err:
        Py_DECREF(r);
        return NULL;
    }

    static PyObject *
    MM__init__(self, args)
           MMobject *self;
           PyObject *args;
    {
        UNLESS(PyArg_ParseTuple(args, "")) return NULL;
        UNLESS(self->data=PyList_New(0)) goto err;
        Py_INCREF(Py_None);
        return Py_None;
    err:
        Py_DECREF(self);
        return NULL;
    }

    static struct PyMethodDef MM_methods[] = {
        {"__init__", (PyCFunction)MM__init__, 1,
         "__init__() -- Create a new empty multi-mapping"},
        {"push", (PyCFunction) MM_push, 1,
         "push(mapping_object) -- Add a data source"},
        {"pop",  (PyCFunction) MM_pop,  1,
         "pop() -- Remove and return the last data source added"}, 
        {NULL,              NULL}           /* sentinel */
    };

    static void
    MM_dealloc(self)
           MMobject *self;
    {
        Py_XDECREF(self->data);
        PyMem_DEL(self);
    }

    static PyObject *
    MM_getattr(self, name)
              MMobject *self;
              char *name;
    {
        return Py_FindMethod(MM_methods, (PyObject *)self, name);
    }

    static int
    MM_length(self)
              MMobject *self;
    {
        long l=0, el, i;
        PyObject *e=0;

        UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
        while(--i >= 0)
          {
            e=PyList_GetItem(self->data,i);
            UNLESS(-1 != (el=PyObject_Length(e))) return -1;
            l+=el;
          }
        return l;
    }

    static PyObject *
    MM_subscript(self, key)
              MMobject *self;
              PyObject *key;
    {
        long i;
        PyObject *e;

        UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
        while(--i >= 0)
          {
            e=PyList_GetItem(self->data,i);
            if(e=PyObject_GetItem(e,key)) return e;
            PyErr_Clear();
          }
        PyErr_SetObject(PyExc_KeyError,key);
        return NULL;
    }

    static PyMappingMethods MM_as_mapping = {
              (inquiry)MM_length,           /*mp_length*/
              (binaryfunc)MM_subscript,             /*mp_subscript*/
              (objobjargproc)NULL,          /*mp_ass_subscript*/
    };

    /* -------------------------------------------------------- */

    static char MMtype__doc__[] = 
    "MultiMapping -- Combine multiple mapping objects for lookup"
    ;

    static PyExtensionClass MMtype = {
              PyObject_HEAD_INIT(&PyType_Type)
              0,                            /*ob_size*/
              "MultMapping",                        /*tp_name*/
              sizeof(MMobject),             /*tp_basicsize*/
              0,                            /*tp_itemsize*/
              /* methods */
              (destructor)MM_dealloc,               /*tp_dealloc*/
              (printfunc)0,                 /*tp_print*/
              (getattrfunc)MM_getattr,      /*tp_getattr*/
              (setattrfunc)0,                       /*tp_setattr*/
              (cmpfunc)0,                   /*tp_compare*/
              (reprfunc)0,                  /*tp_repr*/
              0,                            /*tp_as_number*/
              0,                            /*tp_as_sequence*/
              &MM_as_mapping,                       /*tp_as_mapping*/
              (hashfunc)0,                  /*tp_hash*/
              (ternaryfunc)0,                       /*tp_call*/
              (reprfunc)0,                  /*tp_str*/

              /* Space for future expansion */
              0L,0L,0L,0L,
              MMtype__doc__, /* Documentation string */
              METHOD_CHAIN(MM_methods)
    };

    static struct PyMethodDef MultiMapping_methods[] = {
        {NULL,              NULL}           /* sentinel */
    };

    void
    initMultiMapping()
    {
        PyObject *m, *d;

        m = Py_InitModule4(
            "MultiMapping", MultiMapping_methods,
            "MultiMapping -- Wrap multiple mapping objects for lookup",
            (PyObject*)NULL,PYTHON_API_VERSION);
        d = PyModule_GetDict(m);
        PyExtensionClass_Export(d,"MultiMapping",MMtype);

        if (PyErr_Occurred()) 
           Py_FatalError("can't initialize module MultiMapping");
    }

This version includes ExtensionClass.h. The two declarations of MMtype have been changed from PyTypeObject to PyExtensionClass. The METHOD_CHAIN macro has been used to add methods to the end of the definition for MMtype. The module function, newMMobject has been replaced by the MMtype method, MM__init__. Note that this method does not create or return a new object. Finally, the lines:

    d = PyModule_GetDict(m);
    PyExtensionClass_Export(d,"MultiMapping",MMtype);

Have been added to both initialize the extension class and to export it in the module dictionary.

To use this module, compile, link, and import it as with any other extension module. The following python code illustrates the module's use:

    from MultiMapping import MultiMapping
    m=MultiMapping()
    m.push({'spam':1, 'eggs':2})
    m.push({'spam':3, 'ham':4})

    m['spam'] # returns 3
    m['ham']  # returns 4
    m['foo']  # raises a key error

Creating the MultiMapping object took three steps, one to create an empty MultiMapping, and two to add mapping objects to it. We might wish to simplify the process of creating MultiMapping objects by providing a constructor that takes source mapping objects as parameters. We can do this by sub-classing MultiMapping in Python:

    from MultiMapping import MultiMapping
    class ExtendedMultiMapping(MultiMapping):
        def __init__(self,*data):
          MultiMapping.__init__(self)
          for d in data: self.push(d)

    m=ExtendedMultiMapping({'spam':1, 'eggs':2}, {'spam':3, 'ham':4})

    m['spam'] # returns 3
    m['ham']  # returns 4
    m['foo']  # raises a key error

Note that the source file included in the ExtensionClass distribution has numerous enhancements beyond the version shown in this document.

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/Links.stx0000644000175000017500000000142211476217350026556 0ustar tseavertseaverThis is LinkTest - please click "here":/Members/Zope - please click "here":/Members/Zope?a=b&c=d%20blabla - please click "here":http://www.zope.org - please click "here":http://www.zope.org/members/ - please click "here":http://www.zope.org:2001 - please click "here":http://www.zope.org:2001/members/ - please click "here":http://www.zope.org:2001/%20/Members/zope?a=222&b=213&_xc=just%20a%20test - please click "here":http://www.zope.org:2001/%20/Members/zope?a=222&b=213&_xc=just%20a%20test - please click "here", http://www.zope.org:2001/%20/Members/zope?a=222&b=213&_xc=just%20a%20test And now a paragraph with "Link 1":http://www.zope-rocks.org and "Link 2":http://www.zope-is-kewl.com and "one more link - yeah.":http://www.freshmeat.net zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/examples.ref0000644000175000017500000000301211476217350027247 0ustar tseavertseaver Small Trials for Structured Text Formatting

Small Trials for Structured Text Formatting

This paragraph should be preceded by a level 1 header. It should not, itself, be made into a header, just a regular paragraph.

Here are a few presentation styles, in a list [1]:

  • A word: emphasized.
  • A word: underlined.
  • A word strong.
  • An inline example: 1+2.
  • Another example with a different format: ``x='spam''' or ``y='spam''' or ``'.

    We can use expressions in the DTML var tag as in ``''

  • A mult-line example:
         blah
    
         *foo bar*
    
         <dtml-var yeha>
    

[1] (The referring text should be a paragraph, not a header, and should contain a reference to this footnote, footnote "[1]".)

Some hrefs, in a definition list:

Regular
http://www.zope.org/
W/trailing punctuation
http://www.zope.org/.
W protocol implicit
locallink
W protocol implicit, alternate
"locallink", :locallink

|||| A Simple Two-column Table || || Column A || Column B || || Apples || Oranges ||

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/Links.ref0000644000175000017500000000205311476217350026515 0ustar tseavertseaver This is LinkTest

This is LinkTest

And now a paragraph with Link 1 and Link 2 and one more link - yeah.

zope.structuredtext-3.5.1/src/zope/structuredtext/regressions/index.ref0000644000175000017500000000364111476217350026550 0ustar tseavertseaver Extension Class

Extension Class

A lightweight mechanism has been developed for making Python extension types more class-like. Classes can be developed in an extension language, such as C or C++, and these classes can be treated like other python classes:

  • They can be sub-classed in python,
  • They provide access to method documentation strings, and
  • They can be used to directly create new instances.

Extension classes provide additional extensions to class and instance semantics, including:

  • A protocol for accessing subobjects "in the context of" their containers. This is used to implement custom method types and environmental acquisition.
  • A protocol for overriding method call semantics. This is used to implement "synchonized" classes and could be used to implement argument type checking.
  • A protocol for class initialization that supports execution of a special __class_init__ method after a class has been initialized.

Extension classes illustrate how the Python class mechanism can be extended and may provide a basis for improved or specialized class models.

Releases

The current release is 1.2, To find out what's changed in this release, see the release notes.

Documentation is available on-line.

Windows Binaries

A win32 binary release, ec12.zip, is available. This release includes all of the ExtensionClass modules built as Windows extension modules (.pyd) files. These were built for Python 1.5.1 using Microsoft Visual C++ 5.0 in "Release" mode.

zope.structuredtext-3.5.1/src/zope/structuredtext/docbook.py0000644000175000017500000002266411476217350024400 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Render STX document as docbook. """ __metaclass__ = type class DocBook: """ Structured text document renderer for Docbook. """ element_types = { '#text': '_text', 'StructuredTextDocument': 'document', 'StructuredTextParagraph': 'paragraph', 'StructuredTextExample': 'example', 'StructuredTextBullet': 'bullet', 'StructuredTextNumbered': 'numbered', 'StructuredTextDescription': 'description', 'StructuredTextDescriptionTitle': 'descriptionTitle', 'StructuredTextDescriptionBody': 'descriptionBody', 'StructuredTextSection': 'section', 'StructuredTextSectionTitle': 'sectionTitle', 'StructuredTextLiteral': 'literal', 'StructuredTextEmphasis': 'emphasis', 'StructuredTextStrong': 'strong', 'StructuredTextLink': 'link', 'StructuredTextXref': 'xref', 'StructuredTextSGML': 'sgml', } def dispatch(self, doc, level, output): getattr(self, self.element_types[doc.getNodeName()] )(doc, level, output) def __call__(self, doc, level=1): r=[] self.dispatch(doc, level-1, r.append) return ''.join(r) def _text(self, doc, level, output): if doc.getNodeName() == 'StructuredTextLiteral': output(doc.getNodeValue()) else: output(doc.getNodeValue().lstrip()) def document(self, doc, level, output): output('\n') output('\n') children=doc.getChildNodes() if (children and children[0].getNodeName() == 'StructuredTextSection'): output('%s' % children[0].getChildNodes()[0].getNodeValue()) for c in children: getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('\n') def section(self, doc, level, output): output('\n
\n') children=doc.getChildNodes() for c in children: getattr(self, self.element_types[c.getNodeName()] )(c, level+1, output) output('\n
\n') def sectionTitle(self, doc, level, output): output('') for c in doc.getChildNodes(): try: getattr(self, self.element_types[c.getNodeName()] )(c, level, output) except: print "failed", c.getNodeName(), c output('\n') def description(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() if n is None or n.getNodeName() is not doc.getNodeName(): output('\n') def descriptionTitle(self, doc, level, output): output('\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('\n') def descriptionBody(self, doc, level, output): output('\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('\n') output('\n') def bullet(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('\n') output('\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() output('\n') if n is None or n.getNodeName() is not doc.getNodeName(): output('\n') def numbered(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('\n') output('\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() output('\n') if n is None or n.getNodeName() is not doc.getNodeName(): output('\n') def example(self, doc, level, output): i=0 for c in doc.getChildNodes(): if i==0: output('\n' in your body will break this... ## output(prestrip(c.getNodeValue())) output('\n]]>\n') else: getattr(self, self.element_types[c.getNodeName()])( c, level, output) def paragraph(self, doc, level, output): output('\n\n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()])( c, level, output) output('\n\n') def link(self, doc, level, output): output('' % doc.href) for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('') def emphasis(self, doc, level, output): output('') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output(' ') def literal(self, doc, level, output): output('') for c in doc.getChildNodes(): output(c.getNodeValue()) output('') def strong(self, doc, level, output): output('') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('') def xref(self, doc, level, output): output('' % doc.getNodeValue()) def sgml(self, doc, level, output): output(doc.getNodeValue()) def prestrip(v): v=v.replace( '\r\n', '\n') v=v.replace( '\r', '\n') v=v.replace( '\t', ' ') lines=v.split('\n') indent=len(lines[0]) for line in lines: if not len(line): continue i=len(line)-len(line.lstrip()) if i < indent: indent=i nlines=[] for line in lines: nlines.append(line[indent:]) return '\n'.join(nlines) class DocBookChapter(DocBook): def document(self, doc, level, output): output('\n') children=doc.getChildNodes() if (children and children[0].getNodeName() == 'StructuredTextSection'): output('%s' % children[0].getChildNodes()[0].getNodeValue()) for c in children[0].getChildNodes()[1:]: getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('\n') class DocBookChapterWithFigures(DocBookChapter): element_types = DocBook.element_types element_types.update({'StructuredTextImage': 'image'}) def image(self, doc, level, output): if hasattr(doc, 'key'): output('
%s\n' % (doc.key, doc.getNodeValue()) ) else: output('
%s\n' % doc.getNodeValue()) output('\n
\n' % doc.href) class DocBookArticle(DocBook): def document(self, doc, level, output): output('\n') output('
\n') children=doc.getChildNodes() if (children and children[0].getNodeName() == 'StructuredTextSection'): output('\n%s\n\n' % children[0].getChildNodes()[0].getNodeValue()) for c in children: getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('
\n') class DocBookBook: def __init__(self, title=''): self.title = title self.chapters = [] def addChapter(self, chapter): self.chapters.append(chapter) def read(self): out = ('\n' '\n') out = out + '%s\n' % self.title for chapter in self.chapters: out = out + chapter + '\n\n' return out def __str__(self): return self.read() zope.structuredtext-3.5.1/src/zope/structuredtext/tests.py0000644000175000017500000002710411476217350024114 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import unittest import os here = os.path.dirname(__file__) regressions = os.path.join(here, 'regressions') files = ['index.stx', 'Acquisition.stx', 'ExtensionClass.stx', 'MultiMapping.stx', 'examples.stx', 'Links.stx', 'examples1.stx', 'table.stx', 'InnerLinks.stx', ] def readFile(dirname,fname): myfile = open(os.path.join(dirname, fname), "r") lines = myfile.readlines() myfile.close() return ''.join(lines) class StngTests(unittest.TestCase): def testDocumentClass(self): # testing Document # *cough* *cough* this can't be enough... from zope.structuredtext import stng from zope.structuredtext.document import Document for f in files: doc = Document() raw_text = readFile(regressions, f) text = stng.structurize(raw_text) self.assert_(doc(text)) def testRegressionsTests(self): # HTML regression test from zope.structuredtext import stng from zope.structuredtext.document import Document from zope.structuredtext.html import HTML for f in files: raw_text = readFile(regressions, f) doc = stng.structurize(raw_text) doc = Document()(doc) html = HTML()(doc) reg_fname = f.replace('.stx','.ref') reg_html = readFile(regressions , reg_fname) self.assertEqual(reg_html.strip(), html.strip()) class BasicTests(unittest.TestCase): def _test(self, stxtxt, expected): from zope.structuredtext import stng from zope.structuredtext.document import DocumentWithImages from zope.structuredtext.html import HTMLWithImages doc = stng.structurize(stxtxt) doc = DocumentWithImages()(doc) output = HTMLWithImages()(doc, level=1) if not expected in output: print "Text: ", stxtxt.encode('utf-8') print "Converted:", output.encode('utf-8') print "Expected: ", expected.encode('utf-8') self.fail("'%s' not in result" % expected) def testUnderline(self): self._test("xx _this is html_ xx", "xx this is html xx") def testUnderlineNonASCII(self): self._test("xx _D\xc3\xbcsseldorf underlined_ xx", "xx D\xc3\xbcsseldorf underlined xx") def testUnderline1(self): self._test("xx _this is html_", "this is html") def testUnderline1NonASCII(self): self._test("xx _D\xc3\xbcsseldorf underlined_", "D\xc3\xbcsseldorf underlined") def testEmphasis(self): self._test("xx *this is html* xx", "xx this is html xx") def testEmphasisNonASCII(self): self._test("xx *Emphasising D\xc3\xbcsseldorf* xx", "xx Emphasising D\xc3\xbcsseldorf xx") def testStrong(self): self._test("xx **this is html** xx", "xx this is html xx") def testStrongNonASCII(self): self._test("xx **Greetings from D\xc3\xbcsseldorf** xx", "xx Greetings from D\xc3\xbcsseldorf xx") def testUnderlineThroughoutTags(self): self._test('index_html', 'index_html') def testUnderlineThroughoutTagsNonASCII(self): self._test('D\xc3\xbcsseldorf', 'D\xc3\xbcsseldorf') def testUnderscoresInLiteral1(self): self._test("def __init__(self)", "def __init__(self)") def testUnderscoresInLiteral1NonASCII(self): self._test("def __init__(D\xc3\xbcsself)", "def __init__(D\xc3\xbcsself)") def testUnderscoresInLiteral2(self): self._test("this is '__a_literal__' eh", "__a_literal__") def testUnderscoresInLiteral2NonASCII(self): self._test("this is '__literally_D\xc3\xbcsseldorf__' eh", "__literally_D\xc3\xbcsseldorf__") def testUnderlinesWithoutWithspaces(self): self._test("Zopes structured_text is sometimes a night_mare", "Zopes structured_text is sometimes a night_mare") def testUnderlinesWithoutWithspacesNonASCII(self): self._test("D\xc3\xbcsseldorf by night is sometimes a night_mare", "D\xc3\xbcsseldorf by night is sometimes a night_mare") def testAsterisksInLiteral(self): self._test("this is a '*literal*' eh", "*literal*") def testAsterisksInLiteralNonASCII(self): self._test("this is a '*D\xc3\xbcsseldorf*' eh", "*D\xc3\xbcsseldorf*") def testDoubleAsterisksInLiteral(self): self._test("this is a '**literal**' eh", "**literal**") def testDoubleAsterisksInLiteralNonASCII(self): self._test("this is a '**D\xc3\xbcsseldorf**' eh", "**D\xc3\xbcsseldorf**") def testLinkInLiteral(self): self._test("this is a '\"literal\":http://www.zope.org/.' eh", '"literal":http://www.zope.org/.') def testLinkInLiteralNonASCII(self): self._test("this is a '\"D\xc3\xbcsseldorf\":http://www.zope.org/.' eh", '"D\xc3\xbcsseldorf":http://www.zope.org/.') def testLink(self): self._test('"foo":http://www.zope.org/foo/bar', '

foo

') self._test('"foo":http://www.zope.org/foo/bar/%20x', '

foo

') self._test('"foo":http://www.zope.org/foo/bar?arg1=1&arg2=2', '

foo

') self._test('"foo bar":http://www.zope.org/foo/bar', '

foo bar

') self._test('"[link goes here]":http://www.zope.org/foo/bar', '

[link goes here]

') self._test('"[Dad\'s car]":http://www.zope.org/foo/bar', '

[Dad\'s car]

') def testLinkNonASCII(self): self._test('"D\xc3\xbcsseldorf":http://www.zope.org/foo/bar', '

D\xc3\xbcsseldorf

') self._test('"D\xc3\xbcsseldorf":http://www.zope.org/foo/bar/%20x', '

D\xc3\xbcsseldorf

') self._test('"D\xc3\xbcsseldorf":http://www.zope.org/foo/bar?arg1=1&arg2=2', '

D\xc3\xbcsseldorf

') self._test('"D\xc3\xbcsseldorf am Rhein":http://www.zope.org/foo/bar', '

D\xc3\xbcsseldorf am Rhein

') self._test('"[D\xc3\xbcsseldorf am Rhein]":http://www.zope.org/foo/bar', '

[D\xc3\xbcsseldorf am Rhein]

') self._test('"[D\xc3\xbcsseldorf\'s Homepage]":http://www.zope.org/foo/bar', '

[D\xc3\xbcsseldorf\'s Homepage]

') def testImgLink(self): self._test('"foo":img:http://www.zope.org/bar.gif', 'foo') self._test('"foo":img:http://www.zope.org:8080/bar.gif', 'foo') self._test('"foo":img:http://www.zope.org:8080/foo/bar?arg=1', 'foo') self._test('"foo":img:http://www.zope.org:8080/foo/b%20ar?arg=1', 'foo') self._test('"foo bar":img:http://www.zope.org:8080/foo/bar', 'foo bar') self._test('"[link goes here]":img:http://www.zope.org:8080/foo/bar', '[link goes here]') self._test('"[Dad\'s new car]":img:http://www.zope.org:8080/foo/bar', '[Dad\'s new car]') def testImgLinkNonASCII(self): self._test('"D\xc3\xbcsseldorf":img:http://www.zope.org/bar.gif', 'D\xc3\xbcsseldorf') self._test('"D\xc3\xbcsseldorf":img:http://www.zope.org:8080/bar.gif', 'D\xc3\xbcsseldorf') self._test('"D\xc3\xbcsseldorf":img:http://www.zope.org:8080/foo/bar?arg=1', 'D\xc3\xbcsseldorf') self._test('"D\xc3\xbcsseldorf":img:http://www.zope.org:8080/foo/b%20ar?arg=1', 'D\xc3\xbcsseldorf') self._test('"D\xc3\xbcsseldorf am Rhein":img:http://www.zope.org:8080/foo/bar', 'D\xc3\xbcsseldorf am Rhein') self._test('"[D\xc3\xbcsseldorf am Rhein]":img:http://www.zope.org:8080/foo/bar', '[D\xc3\xbcsseldorf am Rhein]') self._test('"[D\xc3\xbcsseldorf\'s Homepage]":img:http://www.zope.org:8080/foo/bar', '[D\xc3\xbcsseldorf\'s Homepage]') def testBulletList(self): self._test("* item in a list", "
    \n
  • item in a list
  • ") def testOrderedList(self): self._test("1. First item", "
      \n
    1. First item
    2. ") def testDefinitionList(self): self._test("Term -- Definition", "
      Term
      \n
      Definition
      ") def testHeader1(self): self._test("Title\n\n following paragraph", ("

      Title

      \n

      following paragraph

      ")) def testHeader1_again(self): self._test("""Title first paragraph Subtitle second paragraph""", ("""

      Title

      first paragraph

      Subtitle

      second paragraph

      """)) def testUnicodeContent(self): # This fails because ST uses the default locale to get "letters" # whereas it should use \w+ and re.U if the string is Unicode. self._test(u"h\xe9 **y\xe9** xx", u"h\xe9 y\xe9 xx") def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(StngTests)) suite.addTest(unittest.makeSuite(BasicTests)) return suite zope.structuredtext-3.5.1/src/zope/structuredtext/document.py0000644000175000017500000006446011476217350024576 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Structured text document parser """ import re from zope.structuredtext.stletters import letters from zope.structuredtext.stletters import literal_punc from zope.structuredtext.stletters import under_punc from zope.structuredtext.stletters import strongem_punc from zope.structuredtext.stletters import phrase_delimiters from zope.structuredtext.stletters import dbl_quoted_punc from zope.structuredtext.stng import StructuredTextBullet from zope.structuredtext.stng import StructuredTextDescription from zope.structuredtext.stng import StructuredTextDocument from zope.structuredtext.stng import StructuredTextEmphasis from zope.structuredtext.stng import StructuredTextExample from zope.structuredtext.stng import StructuredTextImage from zope.structuredtext.stng import StructuredTextInnerLink from zope.structuredtext.stng import StructuredTextLink from zope.structuredtext.stng import StructuredTextNamedLink from zope.structuredtext.stng import StructuredTextNumbered from zope.structuredtext.stng import StructuredTextLiteral from zope.structuredtext.stng import StructuredTextParagraph from zope.structuredtext.stng import StructuredTextSGML from zope.structuredtext.stng import StructuredTextSection from zope.structuredtext.stng import StructuredTextStrong from zope.structuredtext.stng import StructuredTextTable from zope.structuredtext.stng import StructuredTextUnderline from zope.structuredtext.stng import StructuredTextXref from zope.structuredtext.stng import structurize __metaclass__ = type class Document: """ Class instance calls [ex.=> x()] require a structured text structure. Doc will then parse each paragraph in the structure and will find the special structures within each paragraph. Each special structure will be stored as an instance. Special structures within another special structure are stored within the 'top' structure EX : '-underline this-' => would be turned into an underline instance. '-underline **this**' would be stored as an underline instance with a strong instance stored in its string """ paragraph_types = [ 'doc_bullet', 'doc_numbered', 'doc_description', 'doc_header', 'doc_table', ] #'doc_inner_link', #'doc_named_link', #'doc_underline' text_types = [ 'doc_literal', 'doc_sgml', 'doc_inner_link', 'doc_named_link', 'doc_href1', 'doc_href2', 'doc_strong', 'doc_emphasize', 'doc_underline', 'doc_sgml', 'doc_xref', ] def __call__(self, doc): if isinstance(doc, basestring): doc = structurize(doc) doc.setSubparagraphs(self.color_paragraphs( doc.getSubparagraphs())) else: doc = StructuredTextDocument(self.color_paragraphs( doc.getSubparagraphs())) return doc def parse(self, raw_string, text_type, type=type): """ Parse accepts a raw_string, an expr to test the raw_string, and the raw_string's subparagraphs. Parse will continue to search through raw_string until all instances of expr in raw_string are found. If no instances of expr are found, raw_string is returned. Otherwise a list of substrings and instances is returned """ tmp = [] # the list to be returned if raw_string is split if isinstance(text_type, basestring): text_type = getattr(self, text_type) while True: t = text_type(raw_string) if not t: break #an instance of expr was found t, start, end = t if start: tmp.append(raw_string[:start]) if isinstance(t, basestring): # if we get a string back, add it to text to be parsed raw_string = t + raw_string[end:len(raw_string)] else: if isinstance(t, list): # is we get a list, append it's elements tmp.extend(t) else: # normal case, an object tmp.append(t) raw_string = raw_string[end:len(raw_string)] if not tmp: return raw_string # nothing found if raw_string: tmp.append(raw_string) elif len(tmp) == 1: return tmp[0] return tmp def color_text(self, text, types=None): """Search the paragraph for each special structure """ if types is None: types = self.text_types for text_type in types: if isinstance(text, basestring): text = self.parse(text, text_type) elif isinstance(text, list): #Waaaa result = [] for s in text: if isinstance(s, basestring): s = self.parse(s, text_type) if isinstance(s, list): result.extend(s) else: result.append(s) else: s.setColorizableTexts( map(self.color_text, s.getColorizableTexts() )) result.append(s) text = result else: result = [] color = self.color_text for s in text.getColorizableTexts(): color(s, (text_type, )) result.append(s) text.setColorizableTexts(result) return text def color_paragraphs(self, raw_paragraphs, type=type, sequence_types=(tuple, list), sts=basestring): result=[] for paragraph in raw_paragraphs: if paragraph.getNodeName() != 'StructuredTextParagraph': result.append(paragraph) continue for pt in self.paragraph_types: if isinstance(pt, sts): # grab the corresponding function pt=getattr(self, pt) # evaluate the paragraph new_paragraphs=pt(paragraph) if new_paragraphs: if not isinstance(new_paragraphs, sequence_types): new_paragraphs = (new_paragraphs, ) for paragraph in new_paragraphs: subs = self.color_paragraphs( paragraph.getSubparagraphs() ) paragraph.setSubparagraphs(subs) break else: # copy, retain attributes atts = getattr(paragraph, '_attributes', []) kw = dict([(att, getattr(paragraph, att)) for att in atts]) subs = self.color_paragraphs(paragraph.getSubparagraphs()) new_paragraphs=StructuredTextParagraph( paragraph. getColorizableTexts()[0], subs, **kw), # color the inline StructuredText types # for each StructuredTextParagraph for paragraph in new_paragraphs: if paragraph.getNodeName() is "StructuredTextTable": # cells = paragraph.getColumns() text = paragraph.getColorizableTexts() text = map(structurize, text) text = map(self.__call__,text) for t in range(len(text)): text[t] = text[t].getSubparagraphs() paragraph.setColorizableTexts(text) paragraph.setColorizableTexts( map(self.color_text, paragraph.getColorizableTexts() )) result.append(paragraph) return result def doc_table(self, paragraph, expr = re.compile(r'\s*\|[-]+\|').match): text = paragraph.getColorizableTexts()[0] m = expr(text) subs = paragraph.getSubparagraphs() if not (m): return None rows = [] spans = [] ROWS = [] COLS = [] indexes = [] ignore = [] TDdivider = re.compile("[\-]+").match THdivider = re.compile("[\=]+").match col = re.compile('\|').search innertable = re.compile('\|([-]+|[=]+)\|').search text = text.strip() rows = text.split('\n') foo = "" for row in range(len(rows)): rows[row] = rows[row].strip() # have indexes store if a row is a divider # or a cell part for index in range(len(rows)): tmpstr = rows[index][1:len(rows[index])-1] if TDdivider(tmpstr): indexes.append("TDdivider") elif THdivider(tmpstr): indexes.append("THdivider") else: indexes.append("cell") for index in range(len(indexes)): if indexes[index] is "TDdivider" or indexes[index] is "THdivider": ignore = [] # reset ignore #continue # skip dividers tmp = rows[index].strip() # clean the row up tmp = tmp[1:-1] # remove leading + trailing | offset = 0 # find the start and end of inner # tables. ignore everything between if innertable(tmp): tmpstr = tmp.strip() while innertable(tmpstr): start,end = innertable(tmpstr).span() if not (start, end-1) in ignore: ignore.append((start,end-1)) tmpstr = " " + tmpstr[end:] # find the location of column dividers # NOTE: |'s in inner tables do not count # as column dividers if col(tmp): while col(tmp): bar = 1 # true if start is not in ignore start, end = col(tmp).span() if not start + offset in spans: for s,e in ignore: if start + offset >= s or start + offset <= e: bar = None break if bar: # start is clean spans.append(start + offset) if not bar: foo += tmp[:end] tmp = tmp[end:] offset += end else: COLS.append((foo + tmp[:start], start + offset)) foo = "" tmp = " " + tmp[end:] offset = offset + start if not offset + len(tmp) in spans: spans.append(offset + len(tmp)) COLS.append((foo + tmp, offset + len(tmp))) foo = "" ROWS.append(COLS) COLS = [] spans.sort() ROWS = ROWS[1:] # find each column span cols = [] tmp = [] for row in ROWS: for c in row: tmp.append(c[1]) cols.append(tmp) tmp = [] cur = 1 tmp = [] C = [] for col in cols: for span in spans: if not span in col: cur += 1 else: tmp.append(cur) cur = 1 C.append(tmp) tmp = [] for index in range(len(C)): for i in range(len(C[index])): ROWS[index][i] = (ROWS[index][i][0], C[index][i]) rows = ROWS # label things as either TableData or # Table header TD = [] TH = [] all = [] for index in range(len(indexes)): if indexes[index] is "TDdivider": TD.append(index) all.append(index) if indexes[index] is "THdivider": TH.append(index) all.append(index) TD = TD[1:] dividers = all[1:] #print "TD => ", TD #print "TH => ", TH #print "all => ", all, "\n" for div in dividers: if div in TD: index = all.index(div) for rowindex in range(all[index-1],all[index]): for i in range(len(rows[rowindex])): rows[rowindex][i] = (rows[rowindex][i][0], rows[rowindex][i][1], "td") else: index = all.index(div) for rowindex in range(all[index-1], all[index]): for i in range(len(rows[rowindex])): rows[rowindex][i] = (rows[rowindex][i][0], rows[rowindex][i][1], "th") # now munge the multi-line cells together # as paragraphs ROWS = [] COLS = [] for row in rows: for index in range(len(row)): if not COLS: COLS = range(len(row)) for i in range(len(COLS)): COLS[i] = ["", 1 ,""] if TDdivider(row[index][0]) or THdivider(row[index][0]): ROWS.append(COLS) COLS = [] else: COLS[index][0] = COLS[index][0] + (row[index][0]) + "\n" COLS[index][1] = row[index][1] COLS[index][2] = row[index][2] # now that each cell has been munged together, # determine the cell's alignment. # Default is to center. Also determine the cell's # vertical alignment, top, middle, bottom. Default is # to middle rows = [] cols = [] for row in ROWS: for index in range(len(row)): topindent = 0 bottomindent = 0 leftindent = 0 rightindent = 0 left = [] right = [] text = row[index][0] text = text.split('\n') text = text[:-1] align = "" valign = "" for t in text: t = t.strip() if not t: topindent += 1 else: break text.reverse() for t in text: t = t.strip() if not t: bottomindent += 1 else: break text.reverse() tmp = '\n'.join(text[topindent:len(text)-bottomindent]) pars = re.compile("\n\s*\n").split(tmp) for par in pars: if index > 0: par = par[1:] par = par.split(' ') for p in par: if not p: leftindent += 1 else: break left.append(leftindent) leftindent = 0 par.reverse() for p in par: if not p: rightindent += 1 else: break right.append(rightindent) rightindent = 0 left.sort() right.sort() if topindent == bottomindent: valign="middle" elif topindent < 1: valign="top" elif bottomindent < 1: valign="bottom" else: valign="middle" if left[0] < 1: align = "left" elif right[0] < 1: align = "right" elif left[0] > 1 and right[0] > 1: align="center" else: align="left" cols.append( (row[index][0], row[index][1], align, valign, row[index][2]) ) rows.append(cols) cols = [] return StructuredTextTable(rows, text, subs, indent=paragraph.indent) def doc_bullet(self, paragraph, expr = re.compile(r'\s*[-*o]\s+').match): top = paragraph.getColorizableTexts()[0] m = expr(top) if not m: return None subs=paragraph.getSubparagraphs() if top[-2:] == '::': subs=[StructuredTextExample(subs)] top=top[:-1] return StructuredTextBullet(top[m.span()[1]:], subs, indent=paragraph.indent, bullet=top[:m.span()[1]] ) def doc_numbered(self, paragraph, expr = re.compile( r'(\s*[%s]\.)|(\s*[0-9]+\.)|(\s*[0-9]+\s+)' % letters).match ): # This is the old expression. It had a nasty habit # of grabbing paragraphs that began with a single # letter word even if there was no following period. #expr = re.compile('\s*' # '(([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.)*' # '([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.?' # '\s+').match): top = paragraph.getColorizableTexts()[0] m = expr(top) if not m: return None subs = paragraph.getSubparagraphs() if top[-2:] == '::': subs = [StructuredTextExample(subs)] top = top[:-1] return StructuredTextNumbered(top[m.span()[1]:], subs, indent=paragraph.indent, number=top[:m.span()[1]]) def doc_description( self, paragraph, delim = re.compile(r'\s+--\s+').search, nb = re.compile(r'[^\000- ]').search, ): top = paragraph.getColorizableTexts()[0] d = delim(top) if not d: return None start, end = d.span() title=top[:start] if title.find('\n') >= 0: return None if not nb(title): return None d = top[start:end] top = top[end:] subs = paragraph.getSubparagraphs() if top[-2:] == '::': subs = [StructuredTextExample(subs)] top = top[:-1] return StructuredTextDescription( title, top, subs, indent=paragraph.indent, delim=d) def doc_header(self, paragraph): subs = paragraph.getSubparagraphs() if not subs: return None top = paragraph.getColorizableTexts()[0] if not top.strip(): return None if top[-2:] == '::': subs = StructuredTextExample(subs) if top.strip() == '::': return subs # copy attrs when returning a paragraph kw = {} atts = getattr(paragraph, '_attributes', []) for att in atts: kw[att] = getattr(paragraph, att) return StructuredTextParagraph(top[:-1], [subs], **kw) if top.find('\n') >= 0: return None return StructuredTextSection(top, subs, indent=paragraph.indent) def doc_literal(self, s, expr = re.compile( r"(\W+|^)'([\w%s\s]+)'([%s]+|$)"\ % (literal_punc, phrase_delimiters), re.UNICODE).search, ): r = expr(s) if r: start, end = r.span(2) return (StructuredTextLiteral(s[start:end]), start-1, end+1) def doc_emphasize(self, s, expr = re.compile(r'\*([\w%s\s]+?)\*' \ % (strongem_punc), re.UNICODE).search ): r=expr(s) if r: start, end = r.span(1) return (StructuredTextEmphasis(s[start:end]), start-1, end+1) def doc_inner_link(self, s, expr1 = re.compile(r"\.\.\s*").search, expr2 = re.compile(r"\[[\w]+\]", re.UNICODE ).search): # make sure we dont grab a named link if expr2(s) and expr1(s): start1, end1 = expr1(s).span() start2, end2 = expr2(s).span() if end1 == start2: # uh-oh, looks like a named link return None else: # the .. is somewhere else, ignore it return (StructuredTextInnerLink(s[start2 + 1:end2 - 1]), start2,end2) return None elif expr2(s) and not expr1(s): start, end = expr2(s).span() return (StructuredTextInnerLink(s[start + 1:end - 1]), start,end) def doc_named_link(self, s, expr=re.compile(r"(\.\.\s)(\[[\w]+\])", re.UNICODE).search ): result = expr(s) if result: start,end = result.span(2) str = s[start + 1:end - 1] st,en = result.span() return (StructuredTextNamedLink(str), st, en) def doc_underline(self, s, expr=re.compile(r'_([\w%s\s]+)_([\s%s]|$)'\ % (under_punc, phrase_delimiters), re.UNICODE).search ): result = expr(s) if result: if result.group(1)[:1] == '_': return None # no double unders start,end = result.span(1) st, e = result.span() return (StructuredTextUnderline(s[start:end]), st, e-len(result.group(2))) def doc_strong(self, s, expr = re.compile('\*\*([\w%s\s]+?)\*\*' \ % (strongem_punc), re.UNICODE).search ): r=expr(s) if r: start, end = r.span(1) return (StructuredTextStrong(s[start:end]), start-2, end+2) ## Some constants to make the doc_href() regex easier to read. # ## double quoted text _DQUOTEDTEXT = r'("[ \w\n\r%s]+")' % (dbl_quoted_punc) _ABSOLUTE_URL = r'((http|https|ftp|mailto|file|about)[:/]+?[\w\@\.\,\?\!\/\:\;\-\#\~\=\&\%%\+]+)' _ABS_AND_RELATIVE_URL = r'([\w\@\.\,\?\!\/\:\;\-\#\~\=\&\%%\+]+)' _SPACES = r'(\s*)' def doc_href1(self, s, expr=re.compile(_DQUOTEDTEXT \ + "(:)" \ + _ABS_AND_RELATIVE_URL \ + _SPACES, re.UNICODE).search ): return self.doc_href(s, expr) def doc_href2(self, s, expr=re.compile(_DQUOTEDTEXT\ + r'(\,\s+)' \ + _ABSOLUTE_URL \ + _SPACES, re.UNICODE).search ): return self.doc_href(s, expr) def doc_href(self, s, expr, punctuation=re.compile(r"[\,\.\?\!\;]+", re.UNICODE).match ): r = expr(s) if r: # need to grab the href part and the # beginning part start, e = r.span(1) name = s[start:e] name = name.replace('"', '', 2) #start = start + 1 st,end = r.span(3) if punctuation(s[end-1:end]): end = end -1 link = s[st:end] #end = end - 1 # name is the href title, link is the target # of the href return (StructuredTextLink(name, href=link), start, end) def doc_sgml(self, s, expr=re.compile(r"\<[\w\.\=\'\"\:\/\-\#\+\s\*]+\>", re.UNICODE).search): """SGML text is ignored and outputed as-is """ r = expr(s) if r: start, end = r.span() text = s[start:end] return (StructuredTextSGML(text), start, end) def doc_xref(self, s, expr = re.compile('\[([\w\-.:/;,\n\r\~]+)\]', re.UNICODE).search ): r = expr(s) if r: start, end = r.span(1) return (StructuredTextXref(s[start:end]), start-1, end+1) class DocumentWithImages(Document): """Document with images """ text_types = [ 'doc_img', ] + Document.text_types def doc_img(self, s, expr = re.compile(Document._DQUOTEDTEXT \ + ":img:" \ + Document._ABS_AND_RELATIVE_URL, re.UNICODE).search ): r = expr(s) if r: startt, endt = r.span(1) starth, endh = r.span(2) start, end = r.span() return (StructuredTextImage( s[startt + 1:endt - 1], href=s[starth:endh]), start, end) return None zope.structuredtext-3.5.1/src/zope/structuredtext/__init__.py0000644000175000017500000000420611476217350024507 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Zope structured text markeup Consider the following example:: >>> from zope.structuredtext.stng import structurize >>> from zope.structuredtext.document import DocumentWithImages >>> from zope.structuredtext.html import HTMLWithImages >>> from zope.structuredtext.docbook import DocBook We first need to structurize the string and make a full-blown document out of it: >>> struct = structurize(structured_string) >>> doc = DocumentWithImages()(struct) Now feed it to some output generator, in this case HTML or DocBook: >>> output = HTMLWithImages()(doc, level=1) >>> output = DocBook()(doc, level=1) """ __docformat__ = 'restructuredtext' import re from string import letters from zope.structuredtext.stng import structurize from zope.structuredtext.document import DocumentWithImages from zope.structuredtext.html import HTMLWithImages def stx2html(aStructuredString, level=1, header=1): st = structurize(aStructuredString) doc = DocumentWithImages()(st) return HTMLWithImages()(doc, header=header, level=level) def stx2htmlWithReferences(text, level=1, header=1): text = re.sub( r'[\000\n]\.\. \[([0-9_%s-]+)\]' % letters, r'\n [\1]', text) text = re.sub( r'([\000- ,])\[(?P[0-9_%s-]+)\]([\000- ,.:])' % letters, r'\1[\2]\3', text) text = re.sub( r'([\000- ,])\[([^]]+)\.html\]([\000- ,.:])', r'\1[\2]\3', text) return stx2html(text, level=level, header=header) zope.structuredtext-3.5.1/src/zope/structuredtext/stng.py0000644000175000017500000003703211476217350023726 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Core document model. """ import re import stdom __metaclass__ = type def indention(str, front=re.compile("^\s+").match): """Find the number of leading spaces. If none, return 0. """ result = front(str) if result is not None: start, end = result.span() return end-start else: return 0 # no leading spaces def insert(struct, top, level): """Find what will be the parant paragraph of a sentence and return that paragraph's sub-paragraphs. The new paragraph will be appended to those sub-paragraphs """ if not top-1 in range(len(struct)): if struct: return struct[len(struct)-1].getSubparagraphs() return struct run = struct[top-1] i = 0 while i+1 < level: run = run.getSubparagraphs()[len(run.getSubparagraphs())-1] i = i + 1 return run.getSubparagraphs() def display(struct): """Runs through the structure and prints out the paragraphs. If the insertion works correctly, display's results should mimic the orignal paragraphs. """ if struct.getColorizableTexts(): print '\n'.join(struct.getColorizableTexts()) if struct.getSubparagraphs(): for x in struct.getSubparagraphs(): display(x) def display2(struct): """Runs through the structure and prints out the paragraphs. If the insertion works correctly, display's results should mimic the orignal paragraphs. """ if struct.getNodeValue(): print struct.getNodeValue(),"\n" if struct.getSubparagraphs(): for x in struct.getSubparagraphs(): display(x) def findlevel(levels,indent): """Remove all level information of levels with a greater level of indentation. Then return which level should insert this paragraph """ keys = levels.keys() for key in keys: if levels[key] > indent: del(levels[key]) keys = levels.keys() if not(keys): return 0 else: for key in keys: if levels[key] == indent: return key highest = 0 for key in keys: if key > highest: highest = key return highest-1 def flatten(obj, append): if obj.getNodeType() == stdom.TEXT_NODE: append(obj.getNodeValue()) else: for child in obj.getChildNodes(): flatten(child, append) para_delim = r'(\n\s*\n|\r\n\s*\r\n)' # UNIX or DOS line endings, respectively def structurize(paragraphs, delimiter=re.compile(para_delim)): """Accepts paragraphs, which is a list of lines to be parsed. structurize creates a structure which mimics the structure of the paragraphs. Structure => [paragraph,[sub-paragraphs]] """ currentlevel = 0 currentindent = 0 levels = {0:0} level = 0 # which header are we under struct = [] # the structure to be returned run = struct paragraphs = paragraphs.expandtabs() paragraphs = '%s%s%s' % ('\n\n', paragraphs, '\n\n') paragraphs = delimiter.split(paragraphs) paragraphs = [ x for x in paragraphs if x.strip() ] if not paragraphs: return StructuredTextDocument() ind = [] # structure based on indention levels for paragraph in paragraphs: ind.append([indention(paragraph), paragraph]) currentindent = indention(paragraphs[0]) levels[0] = currentindent for indent,paragraph in ind : if indent == 0: level = level + 1 currentlevel = 0 currentindent = 0 levels = {0:0} struct.append(StructuredTextParagraph(paragraph, indent=indent, level=currentlevel)) elif indent > currentindent: currentlevel = currentlevel + 1 currentindent = indent levels[currentlevel] = indent run = insert(struct,level,currentlevel) run.append(StructuredTextParagraph(paragraph, indent=indent, level=currentlevel)) elif indent < currentindent: result = findlevel(levels,indent) if result > 0: currentlevel = result currentindent = indent if not level: struct.append(StructuredTextParagraph(paragraph, indent=indent, level=currentlevel)) else: run = insert(struct,level,currentlevel) run.append(StructuredTextParagraph(paragraph, indent=indent, level=currentlevel)) else: if insert(struct,level,currentlevel): run = insert(struct,level,currentlevel) else: run = struct currentindent = indent run.append(StructuredTextParagraph(paragraph, indent=indent, level=currentlevel)) return StructuredTextDocument(struct) class StructuredTextParagraph(stdom.Element): indent = 0 def __init__(self, src, subs=None, **kw): if subs is None: subs=[] self._src = src self._subs = list(subs) self._attributes = kw.keys() for k, v in kw.items(): setattr(self, k, v) def getChildren(self): src=self._src if not isinstance(src, list): src=[src] return src+self._subs def getAttribute(self, name): return getattr(self, name, None) def getAttributeNode(self, name): if hasattr(self, name): return stdom.Attr(name, getattr(self, name)) else: return None def getAttributes(self): d = {} for a in self._attributes: d[a]=getattr(self, a, '') return stdom.NamedNodeMap(d) def getSubparagraphs(self): return self._subs def setSubparagraphs(self, subs): self._subs=subs def getColorizableTexts(self): return (self._src,) def setColorizableTexts(self, src): self._src=src[0] def __repr__(self): r=[]; a=r.append a((' '*(self.indent or 0))+ ('%s(' % self.__class__.__name__) +str(self._src)+', [' ) for p in self._subs: a(`p`) a((' '*(self.indent or 0))+'])') return '\n'.join(r) class StructuredTextDocument(StructuredTextParagraph): """A StructuredTextDocument holds StructuredTextParagraphs as its subparagraphs. """ _attributes=() def __init__(self, subs=None, **kw): super(StructuredTextDocument, self).__init__('', subs, **kw) def getChildren(self): return self._subs def getColorizableTexts(self): return () def setColorizableTexts(self, src): pass def __repr__(self): r=[]; a=r.append a('%s([' % self.__class__.__name__) for p in self._subs: a(`p`+',') a('])') return '\n'.join(r) class StructuredTextExample(StructuredTextParagraph): """Represents a section of document with literal text, as for examples""" def __init__(self, subs, **kw): t = [] for s in subs: flatten(s, t.append) super(StructuredTextExample, self).__init__('\n\n'.join(t), (), **kw) def getColorizableTexts(self): return () def setColorizableTexts(self, src): pass # never color examples class StructuredTextBullet(StructuredTextParagraph): """Represents a section of a document with a title and a body """ class StructuredTextNumbered(StructuredTextParagraph): """Represents a section of a document with a title and a body """ class StructuredTextDescriptionTitle(StructuredTextParagraph): """Represents a section of a document with a title and a body """ class StructuredTextDescriptionBody(StructuredTextParagraph): """Represents a section of a document with a title and a body """ class StructuredTextDescription(StructuredTextParagraph): """Represents a section of a document with a title and a body """ def __init__(self, title, src, subs, **kw): super(StructuredTextDescription, self).__init__(src, subs, **kw) self._title = title def getColorizableTexts(self): return self._title, self._src def setColorizableTexts(self, src): self._title, self._src = src def getChildren(self): return (StructuredTextDescriptionTitle(self._title), StructuredTextDescriptionBody(self._src, self._subs)) class StructuredTextSectionTitle(StructuredTextParagraph): """Represents a section of a document with a title and a body""" class StructuredTextSection(StructuredTextParagraph): """Represents a section of a document with a title and a body""" def __init__(self, src, subs=None, **kw): super(StructuredTextSection, self).__init__( StructuredTextSectionTitle(src), subs, **kw) def getColorizableTexts(self): return self._src.getColorizableTexts() def setColorizableTexts(self,src): self._src.setColorizableTexts(src) # a StructuredTextTable holds StructuredTextRows class StructuredTextTable(StructuredTextParagraph): """ rows is a list of lists containing tuples, which represent the columns/cells in each rows. EX rows = [[('row 1:column1',1)],[('row2:column1',1)]] """ def __init__(self, rows, src, subs, **kw): super(StructuredTextTable, self).__init__(subs, **kw) self._rows = [] for row in rows: if row: self._rows.append(StructuredTextRow(row,kw)) def getRows(self): return [self._rows] def _getRows(self): return self.getRows() def getColumns(self): result = [] for row in self._rows: result.append(row.getColumns()) return result def _getColumns(self): return self.getColumns() def setColumns(self,columns): for index in range(len(self._rows)): self._rows[index].setColumns(columns[index]) def _setColumns(self,columns): return self.setColumns(columns) def getColorizableTexts(self): """ return a tuple where each item is a column/cell's contents. The tuple, result, will be of this format. ("r1 col1", "r1=col2", "r2 col1", "r2 col2") """ result = [] for row in self._rows: for column in row.getColumns()[0]: result.append(column.getColorizableTexts()[0]) return result def setColorizableTexts(self,texts): """ texts is going to a tuple where each item is the result of being mapped to the colortext function. Need to insert the results appropriately into the individual columns/cells """ for row_index in range(len(self._rows)): for column_index in range(len(self._rows[row_index]._columns)): self._rows[row_index ]._columns[column_index ].setColorizableTexts((texts[0],)) texts = texts[1:] def _getColorizableTexts(self): return self.getColorizableTexts() def _setColorizableTexts(self, texts): return self.setColorizableTexts(texts) # StructuredTextRow holds StructuredTextColumns class StructuredTextRow(StructuredTextParagraph): def __init__(self,row,kw): """ row is a list of tuples, where each tuple is the raw text for a cell/column and the span of that cell/column. EX [('this is column one',1), ('this is column two',1)] """ super(StructuredTextRow, self).__init__([], **kw) self._columns = [] for column in row: self._columns.append(StructuredTextColumn(column[0], column[1], column[2], column[3], column[4], kw)) def getColumns(self): return [self._columns] def _getColumns(self): return [self._columns] def setColumns(self,columns): self._columns = columns def _setColumns(self,columns): return self.setColumns(columns) # this holds the text of a table cell class StructuredTextColumn(StructuredTextParagraph): """ StructuredTextColumn is a cell/column in a table. A cell can hold multiple paragraphs. The cell is either classified as a StructuredTextTableHeader or StructuredTextTableData. """ def __init__(self,text,span,align,valign,typ,kw): super(StructuredTextColumn, self).__init__(text, [], **kw) self._span = span self._align = align self._valign = valign self._type = typ def getSpan(self): return self._span def _getSpan(self): return self._span def getAlign(self): return self._align def _getAlign(self): return self.getAlign() def getValign(self): return self._valign def _getValign(self): return self.getValign() def getType(self): return self._type def _getType(self): return self.getType() class StructuredTextTableHeader(StructuredTextParagraph): pass class StructuredTextTableData(StructuredTextParagraph): pass class StructuredTextMarkup(stdom.Element): def __init__(self, value, **kw): self._value = value self._attributes = kw.keys() for key, value in kw.items(): setattr(self, key, value) def getChildren(self): v=self._value if not isinstance(v, list): v = [v] return v def getColorizableTexts(self): return self._value, def setColorizableTexts(self, v): self._value=v[0] def __repr__(self): return '%s(%s)' % (self.__class__.__name__, `self._value`) class StructuredTextLiteral(StructuredTextMarkup): def getColorizableTexts(self): return () def setColorizableTexts(self, v): pass class StructuredTextEmphasis(StructuredTextMarkup): pass class StructuredTextStrong(StructuredTextMarkup): pass class StructuredTextInnerLink(StructuredTextMarkup): pass class StructuredTextNamedLink(StructuredTextMarkup): pass class StructuredTextUnderline(StructuredTextMarkup): pass class StructuredTextSGML(StructuredTextMarkup): pass class StructuredTextLink(StructuredTextMarkup): pass class StructuredTextXref(StructuredTextMarkup): pass class StructuredTextImage(StructuredTextMarkup): """A simple embedded image """ zope.structuredtext-3.5.1/src/zope/structuredtext/html.py0000644000175000017500000002406111476217350023715 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ HTML renderer for STX documents. """ from cgi import escape __metaclass__ = type class HTML: paragraph_nestable = { '#text': '_text', 'StructuredTextLiteral': 'literal', 'StructuredTextEmphasis': 'emphasis', 'StructuredTextStrong': 'strong', 'StructuredTextLink': 'link', 'StructuredTextXref': 'xref', 'StructuredTextInnerLink':'innerLink', 'StructuredTextNamedLink':'namedLink', 'StructuredTextUnderline':'underline', 'StructuredTextSGML':'sgml', # this might or might not be valid } element_types = paragraph_nestable.copy() element_types.update({ 'StructuredTextDocument': 'document', 'StructuredTextParagraph': 'paragraph', 'StructuredTextExample': 'example', 'StructuredTextBullet': 'bullet', 'StructuredTextNumbered': 'numbered', 'StructuredTextDescription': 'description', 'StructuredTextDescriptionTitle': 'descriptionTitle', 'StructuredTextDescriptionBody': 'descriptionBody', 'StructuredTextSection': 'section', 'StructuredTextSectionTitle': 'sectionTitle', 'StructuredTextTable':'table', }) def dispatch(self, doc, level, output): getattr(self, self.element_types[doc.getNodeName()] )(doc, level, output) def __call__(self, doc, level=1, header=True): r=[] self.header = header self.dispatch(doc, level-1, r.append) return ''.join(r) def _text(self, doc, level, output): output(doc.getNodeValue()) def document(self, doc, level, output): children=doc.getChildNodes() if self.header: output('\n') if (children and children[0].getNodeName() == 'StructuredTextSection'): output('\n%s\n\n' % children[0].getChildNodes()[0].getNodeValue()) output('\n') for c in children: getattr(self, self.element_types[c.getNodeName()] )(c, level, output) if self.header: output('\n') output('\n') def section(self, doc, level, output): children=doc.getChildNodes() for c in children: getattr(self, self.element_types[c.getNodeName()] )(c, level+1, output) def sectionTitle(self, doc, level, output): output('' % (level)) for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('\n' % (level)) def description(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('
      \n') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() if n is None or n.getNodeName() is not doc.getNodeName(): output('
      \n') def descriptionTitle(self, doc, level, output): output('
      ') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('
      \n') def descriptionBody(self, doc, level, output): output('
      ') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('
      \n') def bullet(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('\n
        \n') output('
      • ') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() output('
      • \n') if n is None or n.getNodeName() is not doc.getNodeName(): output('\n
      \n') def numbered(self, doc, level, output): p=doc.getPreviousSibling() if p is None or p.getNodeName() is not doc.getNodeName(): output('\n
        \n') output('
      1. ') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) n=doc.getNextSibling() output('
      2. \n') if n is None or n.getNodeName() is not doc.getNodeName(): output('\n
      \n') def example(self, doc, level, output): i=0 for c in doc.getChildNodes(): if i==0: output('\n
      \n')
                      output(escape(c.getNodeValue()))
                      output('\n
      \n') else: getattr(self, self.element_types[c.getNodeName()])( c, level, output) def paragraph(self, doc, level, output): output('

      ') in_p = True for c in doc.getChildNodes(): if c.getNodeName() in self.paragraph_nestable: if not in_p: output('

      ') in_p = True self.dispatch(c, level, output) else: if in_p: output('

      \n') in_p = False self.dispatch(c, level, output) if in_p: output('

      \n') in_p = False def link(self, doc, level, output): output('' % doc.href) for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('') def emphasis(self, doc, level, output): output('') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('') def literal(self, doc, level, output): output('') for c in doc.getChildNodes(): output(escape(c.getNodeValue())) output('') def strong(self, doc, level, output): output('') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output('') def underline(self, doc, level, output): output("") for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output("") def innerLink(self, doc, level, output): output('[') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output(']') def namedLink(self, doc, level, output): output('[') for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) output(']') def sgml(self,doc,level,output): for c in doc.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) def xref(self, doc, level, output): val = doc.getNodeValue() output('[%s]' % (val, val) ) def table(self,doc,level,output): """ A StructuredTextTable holds StructuredTextRow(s) which holds StructuredTextColumn(s). A StructuredTextColumn is a type of StructuredTextParagraph and thus holds the actual data. """ output('\n') for row in doc.getRows()[0]: output("\n") for column in row.getColumns()[0]: if hasattr(column,"getAlign"): str = ('<%s colspan="%s" align="%s" valign="%s">' % (column.getType(), column.getSpan(), column.getAlign(), column.getValign())) else: str = '\n") output("\n") output("
      ' % column.getSpan() output(str) for c in column.getChildNodes(): getattr(self, self.element_types[c.getNodeName()] )(c, level, output) if hasattr(column,"getType"): output("\n") else: output("
      \n") class HTMLWithImages(HTML): paragraph_nestable = HTML.paragraph_nestable.copy() paragraph_nestable.update({'StructuredTextImage': 'image'}) element_types = HTML.element_types.copy() element_types.update({'StructuredTextImage': 'image'}) def image(self, doc, level, output): if hasattr(doc, 'key'): output('\n' % doc.key) output('%s\n' % (doc.href, doc.getNodeValue())) if doc.getNodeValue() and hasattr(doc, 'key'): output('

      Figure %s %s

      \n' % (doc.key, doc.getNodeValue())) zope.structuredtext-3.5.1/src/zope/structuredtext/stletters.py0000644000175000017500000000203111476217350024773 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Structured text character classes """ import string def punc_func(exclude): punc = r'' for char in string.punctuation: if char not in exclude: punc = punc + r'\%s' % char return punc digits = string.digits letters = string.letters literal_punc = punc_func("'") dbl_quoted_punc = punc_func("\"") strongem_punc = punc_func('*') under_punc = punc_func('_<>') phrase_delimiters = r'\s\.\,\?\/\!\&\(\)' zope.structuredtext-3.5.1/src/zope/structuredtext/stdom.py0000644000175000017500000003146711476217350024107 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """DOM implementation in StructuredText: read-only methods """ string_types = (str, unicode) __metaclass__ = type # Node type codes # --------------- ELEMENT_NODE = 1 ATTRIBUTE_NODE = 2 TEXT_NODE = 3 CDATA_SECTION_NODE = 4 ENTITY_REFERENCE_NODE = 5 ENTITY_NODE = 6 PROCESSING_INSTRUCTION_NODE = 7 COMMENT_NODE = 8 DOCUMENT_NODE = 9 DOCUMENT_TYPE_NODE = 10 DOCUMENT_FRAGMENT_NODE = 11 NOTATION_NODE = 12 # Exception codes # --------------- INDEX_SIZE_ERR = 1 DOMSTRING_SIZE_ERR = 2 HIERARCHY_REQUEST_ERR = 3 WRONG_DOCUMENT_ERR = 4 INVALID_CHARACTER_ERR = 5 NO_DATA_ALLOWED_ERR = 6 NO_MODIFICATION_ALLOWED_ERR = 7 NOT_FOUND_ERR = 8 NOT_SUPPORTED_ERR = 9 INUSE_ATTRIBUTE_ERR = 10 # Exceptions # ---------- class DOMException(Exception): pass class IndexSizeException(DOMException): code = INDEX_SIZE_ERR class DOMStringSizeException(DOMException): code = DOMSTRING_SIZE_ERR class HierarchyRequestException(DOMException): code = HIERARCHY_REQUEST_ERR class WrongDocumentException(DOMException): code = WRONG_DOCUMENT_ERR class InvalidCharacterException(DOMException): code = INVALID_CHARACTER_ERR class NoDataAllowedException(DOMException): code = NO_DATA_ALLOWED_ERR class NoModificationAllowedException(DOMException): code = NO_MODIFICATION_ALLOWED_ERR class NotFoundException(DOMException): code = NOT_FOUND_ERR class NotSupportedException(DOMException): code = NOT_SUPPORTED_ERR class InUseAttributeException(DOMException): code = INUSE_ATTRIBUTE_ERR # Node classes # ------------ class ParentNode: """ A node that can have children, or, more precisely, that implements the child access methods of the DOM. """ def getChildNodes(self, type=type, sts=string_types): """ Returns a NodeList that contains all children of this node. If there are no children, this is a empty NodeList """ r = [] for n in self.getChildren(): if type(n) in sts: n=TextNode(n) r.append(n.__of__(self)) return NodeList(r) def getFirstChild(self, type=type, sts=string_types): """ The first child of this node. If there is no such node this returns None """ children = self.getChildren() if not children: return None n = children[0] if type(n) in sts: n = TextNode(n) return n.__of__(self) def getLastChild(self, type=type, sts=string_types): """ The last child of this node. If there is no such node this returns None. """ children = self.getChildren() if not children: return None n = children[-1] if type(n) in sts: n=TextNode(n) return n.__of__(self) class NodeWrapper(ParentNode): """ This is an acquisition-like wrapper that provides parent access for DOM sans circular references! """ def __init__(self, aq_self, aq_parent): self.aq_self=aq_self self.aq_parent=aq_parent def __getattr__(self, name): return getattr(self.aq_self, name) def getParentNode(self): """ The parent of this node. All nodes except Document DocumentFragment and Attr may have a parent """ return self.aq_parent def _getDOMIndex(self, children, getattr=getattr): i=0 self=self.aq_self for child in children: if getattr(child, 'aq_self', child) is self: self._DOMIndex=i return i i=i+1 return None def getPreviousSibling(self): """ The node immediately preceding this node. If there is no such node, this returns None. """ children = self.aq_parent.getChildren() if not children: return None index=getattr(self, '_DOMIndex', None) if index is None: index=self._getDOMIndex(children) if index is None: return None index=index-1 if index < 0: return None try: n=children[index] except IndexError: return None else: if type(n) in string_types: n=TextNode(n) n._DOMIndex=index return n.__of__(self) def getNextSibling(self): """ The node immediately preceding this node. If there is no such node, this returns None. """ children = self.aq_parent.getChildren() if not children: return None index=getattr(self, '_DOMIndex', None) if index is None: index=self._getDOMIndex(children) if index is None: return None index=index+1 try: n=children[index] except IndexError: return None else: if type(n) in string_types: n=TextNode(n) n._DOMIndex=index return n.__of__(self) def getOwnerDocument(self): """ The Document object associated with this node, if any. """ return self.aq_parent.getOwnerDocument() class Node(ParentNode): """Node Interface """ # Get a DOM wrapper with a parent link def __of__(self, parent): return NodeWrapper(self, parent) # DOM attributes def getNodeName(self): """The name of this node, depending on its type """ def getNodeValue(self): """The value of this node, depending on its type """ return None def getParentNode(self): """ The parent of this node. All nodes except Document DocumentFragment and Attr may have a parent """ def getChildren(self): """Get a Python sequence of children """ return () def getPreviousSibling(self): """ The node immediately preceding this node. If there is no such node, this returns None. """ def getNextSibling(self): """ The node immediately preceding this node. If there is no such node, this returns None. """ def getAttributes(self): """ Returns a NamedNodeMap containing the attributes of this node (if it is an element) or None otherwise. """ return None def getOwnerDocument(self): """The Document object associated with this node, if any. """ # DOM Methods # ----------- def hasChildNodes(self): """ Returns true if the node has any children, false if it doesn't. """ return len(self.getChildren()) class TextNode(Node): def __init__(self, str): self._value=str def getNodeType(self): return TEXT_NODE def getNodeName(self): return '#text' def getNodeValue(self): return self._value class Element(Node): """Element interface """ # Element Attributes # ------------------ def getTagName(self): """The name of the element""" return self.__class__.__name__ def getNodeName(self): """The name of this node, depending on its type""" return self.__class__.__name__ def getNodeType(self): """A code representing the type of the node.""" return ELEMENT_NODE def getNodeValue(self): r=[] for c in self.getChildren(): if type(c) not in string_types: c=c.getNodeValue() r.append(c) return ''.join(r) def getParentNode(self): """ The parent of this node. All nodes except Document DocumentFragment and Attr may have a parent """ # Element Methods # --------------- _attributes=() def getAttribute(self, name): return getattr(self, name, None) def getAttributeNode(self, name): if hasattr(self, name): return Attr(name, getattr(self, name)) def getAttributes(self): d={} for a in self._attributes: d[a]=getattr(self, a, '') return NamedNodeMap(d) def getAttribute(self, name): """Retrieves an attribute value by name.""" return None def getAttributeNode(self, name): """ Retrieves an Attr node by name or None if there is no such attribute. """ return None def getElementsByTagName(self, tagname): """ Returns a NodeList of all the Elements with a given tag name in the order in which they would be encountered in a preorder traversal of the Document tree. Parameter: tagname The name of the tag to match (* = all tags). Return Value: A new NodeList object containing all the matched Elements. """ nodeList = [] for child in self.getChildren(): if not hasattr(child, 'getNodeType'): continue if (child.getNodeType()==ELEMENT_NODE and \ child.getTagName()==tagname or tagname== '*'): nodeList.append(child) if hasattr(child, 'getElementsByTagName'): n1 = child.getElementsByTagName(tagname) nodeList = nodeList + n1._data return NodeList(nodeList) class NodeList: """NodeList interface - Provides the abstraction of an ordered collection of nodes. Python extensions: can use sequence-style 'len', 'getitem', and 'for..in' constructs. """ def __init__(self,list=None): self._data = list or [] def __getitem__(self, index, type=type, sts=string_types): return self._data[index] def __getslice__(self, i, j): return self._data[i:j] def item(self, index): """Returns the index-th item in the collection """ return self._data.get(index, None) def getLength(self): """The length of the NodeList """ return len(self._data) __len__ = getLength class NamedNodeMap: """ NamedNodeMap interface - Is used to represent collections of nodes that can be accessed by name. NamedNodeMaps are not maintained in any particular order. Python extensions: can use sequence-style 'len', 'getitem', and 'for..in' constructs, and mapping-style 'getitem'. """ def __init__(self, data=None): if data is None: data = {} self._data = data def item(self, index): """Returns the index-th item in the map """ return self._data.values().get(index, None) def __getitem__(self, key): if isinstance(key, int): return self.item(key) else: return self._data[key] def getLength(self): """ The length of the NodeList """ return len(self._data) __len__ = getLength def getNamedItem(self, name): """ Retrieves a node specified by name. Parameters: name Name of a node to retrieve. Return Value A Node (of any type) with the specified name, or None if the specified name did not identify any node in the map. """ return self._data.get(name, None) class Attr(Node): """ Attr interface - The Attr interface represents an attriubte in an Element object. Attr objects inherit the Node Interface """ def __init__(self, name, value, specified=1): self.name = name self.value = value self.specified = specified def getNodeName(self): """ The name of this node, depending on its type """ return self.name def getName(self): """ Returns the name of this attribute. """ return self.name def getNodeValue(self): """ The value of this node, depending on its type """ return self.value def getNodeType(self): """ A code representing the type of the node. """ return ATTRIBUTE_NODE def getSpecified(self): """ If this attribute was explicitly given a value in the original document, this is true; otherwise, it is false. """ return self.specified zope.structuredtext-3.5.1/.bzrignore0000644000175000017500000000011611476217350017517 0ustar tseavertseaver./.installed.cfg ./bin ./develop-eggs ./eggs ./parts *.egg-info docs/_build/* zope.structuredtext-3.5.1/docs/0000755000175000017500000000000011476217406016451 5ustar tseavertseaverzope.structuredtext-3.5.1/docs/Makefile0000644000175000017500000000611611476217350020113 0ustar tseavertseaver# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/zopestructuredtext.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/zopestructuredtext.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." zope.structuredtext-3.5.1/docs/index.rst0000644000175000017500000001265011476217350020314 0ustar tseavertseaver:mod:`zope.structuredtext` Documentation ======================================== Using Structured Text --------------------- The goal of StructuredText is to make it possible to express structured text using a relatively simple plain text format. Simple structures, like bullets or headings are indicated through conventions that are natural, for some definition of "natural". Hierarchical structures are indicated through indentation. The use of indentation to express hierarchical structure is inspired by the Python programming language. Use of StructuredText consists of one to three logical steps. In the first step, a text string is converted to a network of objects using the :func:`structurize` facility, as in the following example: .. code-block:: python raw = open("mydocument.txt").read() from zope.structuredtext.stng import structurize st = structurize(raw) The output of :func:`structurize` is simply a :class:`StructuredTextDocument` object containing :class:`StructuredTextParagraph` objects arranged in a hierarchy. Paragraphs are delimited by strings of two or more whitespace characters beginning and ending with newline characters. Hierarchy is indicated by indentation. The indentation of a paragraph is the minimum number of leading spaces in a line containing non-white-space characters after converting tab characters to spaces (assuming a tab stop every eight characters). :class:`StructuredTextNode` objects support the read-only subset of the Document Object Model (DOM) API. It should be possible to process :class:`StructuredTextNode` hierarchies using XML tools such as XSLT. The second step in using StructuredText is to apply additional structuring rules based on text content. A variety of differentText rules can be used. Typically, these are used to implement a structured text language for producing documents, but any sort of structured text language could be implemented in the second step. For example, it is possible to use StructuredText to implement structured text formats for representing structured data. The second step, which could consist of multiple processing steps, is performed by processing, or "coloring", the hierarchy of generic StructuredTextParagraph objects into a network of more specialized objects. Typically, the objects produced should also implement the DOM API to allow processing with XML tools. A document processor is provided to convert a StructuredTextDocument object containing only StructuredTextParagraph objects into a StructuredTextDocument object containing a richer collection of objects such as bullets, headings, emphasis, and so on using hints in the text. Hints are selected based on conventions of the sort typically seen in electronic mail or news-group postings. It should be noted, however, that these conventions are somewhat culturally dependent, fortunately, the document processor is easily customized to implement alternative rules. Here's an example of using the DOC processor to convert the output of the previous example: .. code-block:: python from zope.structuredtext.document import Document doc = Document()(st) The final step is to process the colored networks produced from the second step to produce additional outputs. The final step could be performed by Python programs, or by XML tools. A Python outputter is provided for the document processor output that produces Hypertext Markup Language (HTML) text: .. code-block:: python from zope.structuredtext.html import HTML html = HTML()(doc) Customizing the document processor ---------------------------------- The document processor is driven by two tables. The first table, named ``paragraph_types``, is a sequence of callable objects or method names for coloring paragraphs. If a table entry is a string, then it is the name of a method of the document processor to be used. For each input paragraph, the objects in the table are called until one returns a value (not 'None'). The value returned replaces the original input paragraph in the output. If none of the objects in the paragraph types table return a value, then a copy of the original paragraph is used. The new object returned by calling a paragraph type should implement the ``ReadOnlyDOM``, ``StructuredTextColorizable``, and ``StructuredTextSubparagraphContainer`` interfaces. See the :mod:`zope.structuredtext.document` source file for examples. A paragraph type may return a list or tuple of replacement paragraphs, this allowing a paragraph to be split into multiple paragraphs. The second table, ``text_types``, is a sequence of callable objects or method names for coloring text. The callable objects in this table are used in sequence to transform the input text into new text or objects. The callable objects are passed a string and return nothing (``None``) or a three-element tuple consisting of: - a replacement object, - a starting position, and - an ending position The text from the starting position is (logically) replaced with the replacement object. The replacement object is typically an object that implements that implements the ``ReadOnlyDOM`` and ``StructuredTextColorizable`` interfaces. The replacement object can also be a string or a list of strings or objects. Replacement is done from beginning to end and text after the replacement ending position will be passed to the character type objects for processing. Contents: .. toctree:: :maxdepth: 2 api Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` zope.structuredtext-3.5.1/docs/make.bat0000644000175000017500000000602711476217350020061 0ustar tseavertseaver@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\zopestructuredtext.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\zopestructuredtext.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end zope.structuredtext-3.5.1/docs/conf.py0000644000175000017500000001457011476217350017755 0ustar tseavertseaver# -*- coding: utf-8 -*- # # zope.structuredtext documentation build configuration file, created by # sphinx-quickstart on Fri Apr 30 17:11:17 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os, pkg_resources # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append(os.path.abspath('../src')) rqmt = pkg_resources.require('zope.structuredtext')[0] # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'zope.structuredtext' copyright = u'2010, Zope Foundation and Contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '3.5.0' # The full version, including alpha/beta/rc tags. release = '3.5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'zopestructuredtextdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'zopestructuredtext.tex', u'zope.structuredtext Documentation', u'Zope Foundation and Contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True zope.structuredtext-3.5.1/docs/api.rst0000644000175000017500000000164411476217350017757 0ustar tseavertseaver:mod:`zope.structuredtext` API ============================== :mod:`zope.structuredtext.document` ----------------------------------- .. automodule:: zope.structuredtext.document :members: :mod:`zope.structuredtext.stletters` ------------------------------------ .. automodule:: zope.structuredtext.stletters :members: :mod:`zope.structuredtext.stng` ------------------------------- .. automodule:: zope.structuredtext.stng :members: :mod:`zope.structuredtext.stdom` -------------------------------- .. automodule:: zope.structuredtext.stdom :members: :mod:`zope.structuredtext.html` ------------------------------- .. automodule:: zope.structuredtext.html :members: :mod:`zope.structuredtext.docbook` ---------------------------------- .. automodule:: zope.structuredtext.docbook :members: :mod:`zope.structuredtext` -------------------------- .. automodule:: zope.structuredtext :members: zope.structuredtext-3.5.1/CHANGES.txt0000644000175000017500000000144211476217350017331 0ustar tseavertseaver``zope.structuredtext`` Changelog ================================= 3.5.1 (2010-12-03) ------------------ - Removed antique copyright assertions in regression texts, in conformance with repository policy. 3.5.0 (2010-04-30) ------------------ - Updated docs to conform to ZTK / Sphinx usage. - LP #120376: Output valid html for non-ASCII characters. 3.4.0 (2007/09/01) ------------------ - Public release for completeness of Zope 3.4. 3.2.0 (2006/01/05) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope 3.2.0 release. - Only coding style / documentation changes. 3.0.0 (2004/11/07) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope X3.0.0 release. zope.structuredtext-3.5.1/convert.py0000644000175000017500000000176311476217350017560 0ustar tseavertseaver"""Utility to convert stx in regression dir to html """ import sys import os.path from zope.structuredtext import stng from zope.structuredtext.document import Document from zope.structuredtext.html import HTML def readFile(dirname,fname): myfile = open(os.path.join(dirname, fname), "r") lines = myfile.readlines() myfile.close() return ''.join(lines) def writeFile(dirname,fname, data): myfile = open(os.path.join(dirname, fname), "w") myfile.truncate() myfile.write(data) if __name__ == '__main__': files = ['index.stx','Acquisition.stx','ExtensionClass.stx', 'MultiMapping.stx','examples.stx','Links.stx','examples1.stx', 'table.stx','InnerLinks.stx'] dirname = sys.argv[1] for f in files: raw_text = readFile(dirname, f) doc = stng.structurize(raw_text) doc = Document()(doc) html = HTML()(doc) reg_fname = f.replace('.stx','.ref') reg_html = writeFile(dirname , reg_fname, html) zope.structuredtext-3.5.1/setup.cfg0000644000175000017500000000007311476217406017342 0ustar tseavertseaver[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.structuredtext-3.5.1/TODO.txt0000644000175000017500000000053411476217350017027 0ustar tseavertseaver - html.py should be made to produce valid (x)html, this requires i) extending the paragraph_nestable concept to observe all html nesting rules - see http://www.cs.tut.fi/~jkorpela/html/nesting.html ii) html quoting in the _text method. - better unit tests - make usage easier - decrease amount of spaghetti code in stng and document zope.structuredtext-3.5.1/PKG-INFO0000644000175000017500000000406711476217406016625 0ustar tseavertseaverMetadata-Version: 1.0 Name: zope.structuredtext Version: 3.5.1 Summary: StructuredText parser Home-page: http://pypi.python.org/pypi/zope.structuredtext Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ``zope.structuredtext`` README ============================== This package provides a parser and renderers for the classic Zope "structured text" markup dialect (STX). STX is a plain text markup in which document structure is signalled primarily by identation Please see ``docs/index.rst`` for the documentation. ``zope.structuredtext`` Changelog ================================= 3.5.1 (2010-12-03) ------------------ - Removed antique copyright assertions in regression texts, in conformance with repository policy. 3.5.0 (2010-04-30) ------------------ - Updated docs to conform to ZTK / Sphinx usage. - LP #120376: Output valid html for non-ASCII characters. 3.4.0 (2007/09/01) ------------------ - Public release for completeness of Zope 3.4. 3.2.0 (2006/01/05) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope 3.2.0 release. - Only coding style / documentation changes. 3.0.0 (2004/11/07) ------------------ - Corresponds to the verison of the ``zope.structuredtext`` package shipped as part of the Zope X3.0.0 release. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Software Development