kid-0.9.6/0000755000175000017500000000000010646655235012215 5ustar tstanektstanekkid-0.9.6/bin/0000755000175000017500000000000010646655235012765 5ustar tstanektstanekkid-0.9.6/bin/kid0000755000175000017500000000132310646650135013453 0ustar tstanektstanek#!/usr/bin/env python __revision__ = "$Rev: 139 $" __date__ = "$Date: 2005-03-14 19:28:22 -0500 (Mon, 14 Mar 2005) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " try: from kid.run import main except ImportError: # adjust sys.path if we're running directly within a source distribution import sys from os.path import dirname, abspath, join as joinpath from os import access, F_OK bin_dir = dirname(__file__) lib_dir = abspath(joinpath(bin_dir, '..')) if access(joinpath(lib_dir, 'kid', '__init__.py'), F_OK): sys.path.insert(0, lib_dir) from kid.run import main main() kid-0.9.6/bin/kidc0000755000175000017500000000131710646650135013621 0ustar tstanektstanek#!/usr/bin/env python __revision__ = "$Rev: 139 $" __date__ = "$Date: 2005-03-14 19:28:22 -0500 (Mon, 14 Mar 2005) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " try: from kid.compile import main except ImportError: from os.path import join as joinpath, dirname, abspath import sys import os # adjust sys.path if we're running directly within a source distribution bin_dir = dirname(__file__) lib_dir = abspath(joinpath(bin_dir, '..')) if os.access(joinpath(lib_dir, 'kid', '__init__.py'), os.F_OK): sys.path.insert(0, lib_dir) from kid.compile import main main() kid-0.9.6/doc/0000755000175000017500000000000010646655235012762 5ustar tstanektstanekkid-0.9.6/doc/html/0000755000175000017500000000000010646655235013726 5ustar tstanektstanekkid-0.9.6/doc/html/kid/0000755000175000017500000000000010646655235014475 5ustar tstanektstanekkid-0.9.6/doc/html/kid/test/0000755000175000017500000000000010646655235015454 5ustar tstanektstanekkid-0.9.6/doc/html/kid/test/__init__.py.html0000644000175000017500000002237010443617634020530 0ustar tstanektstanekkid/test/__init__.py
0001"""Kid test package."""
0002
0003__revision__ = "$Rev: 59 $"
0004__date__ = "$Date: 2005-02-16 15:43:38 -0500 (Wed, 16 Feb 2005) $"
0005__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0006__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0007__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0008
0009
0010import os
0011import glob
0012from os.path import dirname, basename, join, abspath
0013
0014_mydir = abspath(join(dirname(__file__))) + '/../../'
0015template_dir = _mydir + 'test'
0016output_dir = template_dir
0017template_package = 'test.'
0018
0019test_modules = [basename(f)[:-3] for f in
0020    glob.glob(_mydir + 'kid/test/test*.py')]
0021
0022additional_tests = 0
0023basic_tests = 0
0024
0025def run_tests():
0026    from kid.test.util import run_tests
0027    tests = ['kid.test.%s' % m for m in test_modules]
0028    run_tests(tests)
0029
0030from kid.test.util import dot
0031
0032__all__ = ['dot', 'run_tests', 'template_package', 'output_dir',
0033           'template_dir']
0034
0035if __name__ == '__main__':
0036    run_tests()
kid-0.9.6/doc/html/kid/__init__.py.html0000644000175000017500000027770410443621772017564 0ustar tstanektstanekkid/__init__.py
0001"""Pythonic, XML Templating
0002
0003Kid is a simple, Python-based template language for generating and
0004transforming XML vocabularies. Kid was spawned as a result of a kinky love
0005triangle between XSLT, TAL, and PHP. We believe many of the best features
0006of these languages live on in Kid with much of the limitations and
0007complexity stamped out (well, eventually :).
0008
0009"""
0010
0011__revision__ = "$Rev: 332 $"
0012__date__ = "$Date: 2006-05-20 22:26:35 +0000 (Sat, 20 May 2006) $"
0013
0014import release
0015__version__ = release.version
0016__author__ = release.author
0017__email__ = release.email
0018__copyright__ = release.copyright
0019__license__ = release.license
0020
0021
0022import sys
0023import os
0024
0025from kid.util import xml_sniff, QuickTextReader
0026from kid.namespace import Namespace
0027from kid.pull import ElementStream, Element, SubElement, Fragment,                        XML, document, _coalesce
0029from kid.et import ElementTree, Comment, ProcessingInstruction
0030from kid.parser import KID_XMLNS
0031from kid.serialization import Serializer, XMLSerializer, HTMLSerializer, PlainSerializer, XHTMLSerializer
0032
0033assume_encoding = sys.getdefaultencoding()
0034
0035def enable_import(suffixes=None):
0036    """Enable the kid module loader and import hooks.
0037    
0038    This function must be called before importing kid templates if templates
0039    are not pre-compiled.
0040    
0041    Note that if your application uses ZODB, you will need to import ZODB
0042    before calling this function as ZODB's import hooks have some issues if
0043    installed after the kid import hooks.
0044    
0045    """
0046    import kid.importer
0047    kid.importer.install(suffixes)
0048
0049#
0050# Turn on import hook if KID_IMPORT is set
0051#
0052if os.environ.get('KID_IMPORT', None) is not None:
0053    enable_import()
0054
0055def import_template(name):
0056    """Import template by name.
0057
0058    This is identical to calling `enable_import` followed by an import
0059    statement. For example, importing a template named foo using the normal
0060    import mechanism looks like this::
0061
0062        import kid
0063        kid.enable_import()
0064        import foo
0065
0066    This function can be used to achieve the same result as follows::
0067
0068        import kid
0069        foo = kid.import_template('foo')
0070
0071    This is sometimes useful when the name of the template is available only
0072    as a string.
0073    """
0074    enable_import()
0075    mod = __import__(name)
0076    components = name.split('.')
0077    for comp in components[1:]:
0078        mod = getattr(mod, comp)
0079    return mod
0080
0081def load_template(file, name='', cache=1, encoding=None, ns={}):
0082    """Bypass import machinery and load a template module directly.
0083
0084    This can be used as an alternative to accessing templates using the
0085    native python import mechanisms.
0086    
0087    file
0088      Can be a filename, a kid template string, or an open file object.
0089    name
0090      Optionally specifies the module name to use for this template. This
0091      is a hack to enable relative imports in templates.
0092    cache
0093      Whether to look for a byte-compiled version of the template. If
0094      no byte-compiled version is found, an attempt is made to dump a
0095      byte-compiled version after compiling. This argument is ignored if
0096      file is not a filename.
0097    """
0098    if isinstance(file, basestring):
0099        if xml_sniff(file):
0100            fo = QuickTextReader(file)
0101            filename = '<string>'
0102        else:
0103            fo = None
0104            filename = file
0105    else:
0106        fo = file
0107        filename = '<string>'
0108    import kid.importer as importer
0109    if filename != '<string>':
0110        abs_filename = path.find(filename)
0111        if not abs_filename:
0112            raise Exception, "Template not found: %s (in %s)" % (
0113                filename, ', '.join(path.paths))
0114        filename = abs_filename
0115        name = importer.get_template_name(name, filename)
0116        if sys.modules.has_key(name):
0117            return sys.modules.get(name)
0118    import kid.compiler as compiler
0119    if filename == '<string>':
0120        code = compiler.compile(fo, filename, encoding)
0121    else:
0122        template = compiler.KidFile(filename, 0, encoding)
0123        code = template.compile(dump_code=cache, dump_source=os.environ.get('KID_OUTPUT_PY'))
0124
0125    mod = importer._create_module(code, name, filename, store=cache, ns=ns)
0126    return mod
0127
0128# create some default serializers..
0129output_methods = {
0130    'xml'          : XMLSerializer(decl=1),
0131    'xhtml'        : XHTMLSerializer(decl=0, doctype='xhtml'),
0132    'xhtml-strict' : XHTMLSerializer(decl=0, doctype='xhtml-strict'),
0133    'html'         : HTMLSerializer(doctype='html'),
0134    'html-strict'  : HTMLSerializer(doctype='html-strict'),
0135    'plain':         PlainSerializer()}
0136
0137def Template(file=None, source=None, name=None, **kw):
0138    """Get a Template class quickly given a module name, file, or string.
0139    
0140    This is a convenience function for getting a template in a variety of
0141    ways. One and only one of the arguments name or file must be specified.
0142    
0143    file:string
0144      The template module is loaded by calling
0145      ``load_template(file, name='', cache=1)``
0146    name:string
0147      The kid import hook is enabled and the template module is located
0148      using the normal Python import mechanisms.
0149    source:string
0150      string containing the templates source.
0151
0152    Once the template module is obtained, a new instance of the module's
0153    Template class is created with the keyword arguments passed to this
0154    function.
0155    """
0156    if name:
0157        mod = import_template(name)
0158    elif file is not None:
0159        mod = load_template(file)
0160    elif source is not None:
0161        mod = load_template(QuickTextReader(source), hex(id(source)))
0162    else:
0163        raise Exception("Must specify one of name, file, or source.")
0164    mod.Template.module = mod
0165    return mod.Template(**kw)
0166
0167from kid.filter import transform_filter
0168
0169class BaseTemplate(object):
0170
0171    """Base class for compiled Templates.
0172
0173    All kid template modules expose a class named ``Template`` that
0174    extends from this class making the methods defined here available on
0175    all Template subclasses.
0176    
0177    This class should not be instantiated directly.
0178    """
0179
0180    # the serializer to use when writing output
0181    serializer = output_methods['xml']
0182    _filters = [transform_filter]
0183
0184    def __init__(self, *args, **kw):
0185        """
0186        Initialize a template with instance attributes specified by
0187        keyword arguments.
0188           
0189        Keyword arguments are available to the template using self.var
0190        notation.
0191        """
0192        self.__dict__.update(kw)
0193        self._layout_classes = []
0194
0195    def write(self, file, encoding=None, fragment=0, output=None):
0196        """
0197        Execute template and write output to file.
0198        
0199        file:file
0200          A filename or a file like object (must support write()).
0201        encoding:string
0202          The output encoding. Default: utf-8.
0203        fragment:bool
0204          Controls whether prologue information (such as <?xml?>
0205          declaration and DOCTYPE should be written). Set to 1
0206          when generating fragments meant to be inserted into
0207          existing XML documents.
0208        output:string,`Serializer`
0209          A string specifying an output method ('xml', 'html',
0210          'xhtml') or a Serializer object.
0211        """
0212        serializer = self._get_serializer(output)
0213        return serializer.write(self, file, encoding, fragment)
0214
0215    def serialize(self, encoding=None, fragment=0, output=None):
0216        """
0217        Execute a template and return a single string.
0218        
0219        encoding
0220          The output encoding. Default: utf-8.
0221        fragment
0222          Controls whether prologue information (such as <?xml?>
0223          declaration and DOCTYPE should be written). Set to 1
0224          when generating fragments meant to be inserted into
0225          existing XML documents.
0226        output
0227          A string specifying an output method ('xml', 'html',
0228          'xhtml') or a Serializer object.
0229        
0230        This is a convienence method, roughly equivalent to::
0231        
0232          ''.join([x for x in obj.generate(encoding, fragment, output)]
0233        
0234        """
0235        serializer = self._get_serializer(output)
0236        return serializer.serialize(self, encoding, fragment)
0237
0238    def generate(self, encoding=None, fragment=0, output=None):
0239        """
0240        Execute template and generate serialized output incrementally.
0241        
0242        This method returns an iterator that yields an encoded string
0243        for each iteration. The iteration ends when the template is done
0244        executing.
0245        
0246        encoding
0247          The output encoding. Default: utf-8.
0248        fragment
0249          Controls whether prologue information (such as <?xml?>
0250          declaration and DOCTYPE should be written). Set to 1
0251          when generating fragments meant to be inserted into
0252          existing XML documents.
0253        output
0254          A string specifying an output method ('xml', 'html',
0255          'xhtml') or a Serializer object.
0256        """
0257        serializer = self._get_serializer(output)
0258        return serializer.generate(self, encoding, fragment)
0259
0260    def __iter__(self):
0261        return iter(self.transform())
0262
0263    def __str__(self):
0264        return self.serialize()
0265
0266    def __unicode__(self):
0267        return unicode(self.serialize(encoding='utf-16'), 'utf-16')
0268
0269    def initialize(self):
0270        pass
0271
0272    def pull(self):
0273        """Returns an iterator over the items in this template."""
0274        # create stream and apply filters
0275        self.initialize()
0276        stream = ElementStream(_coalesce(self.content(), self._get_assume_encoding()))
0277        return stream
0278
0279    def _pull(self):
0280        """Generate events for this template.
0281        
0282        Compiled templates implement this method.
0283        """
0284        return []
0285
0286    def content(self):
0287        from inspect import getmro
0288        visited = self._layout_classes
0289        mro = list(getmro(self.__class__))
0290        mro.reverse()
0291        for c in mro:
0292            if c.__dict__.has_key('layout') and c not in visited:
0293                visited.insert(0, c)
0294                return c.__dict__['layout'](self)
0295        return self._pull()
0296
0297    def transform(self, stream=None, filters=[]):
0298        """
0299        Execute the template and apply any match transformations.
0300        
0301        If stream is specified, it must be one of the following:
0302        
0303        Element
0304          An ElementTree Element.
0305        ElementStream
0306          An `pull.ElementStream` instance or other iterator that yields
0307          stream events.
0308        string
0309          A file or URL unless the string starts with
0310          '<' in which case it is considered an XML document
0311          and processed as if it had been an Element.
0312
0313        By default, the `pull` method is called to obtain the stream.
0314        """
0315        if stream is None:
0316            stream = self.pull()
0317        elif isinstance(stream, basestring):
0318            if xml_sniff(stream):
0319                stream = XML(stream, fragment=0)
0320            else:
0321                stream = document(stream)
0322        elif hasattr(stream, 'tag'):
0323            stream = ElementStream(stream)
0324        else:
0325            stream = ElementStream.ensure(stream)
0326        for f in filters + self._filters:
0327            stream = f(stream, self)
0328        return stream
0329
0330    def _get_match_templates(self):
0331        # XXX: use inspect instead of accessing __mro__ directly
0332        try:
0333            rslt = self._match_templates_cached
0334        except AttributeError:
0335            rslt = []
0336            mro = self.__class__.__mro__
0337            for C in mro:
0338                try:
0339                    templates = C._match_templates
0340                except AttributeError:
0341                    continue
0342                rslt += templates
0343            self._match_templates_cached = rslt
0344        return rslt
0345
0346    def _get_serializer(self, serializer):
0347        if serializer is None:
0348            return self.serializer
0349        elif isinstance(serializer, basestring):
0350            return output_methods[serializer]
0351        else:
0352            return serializer
0353
0354    def _get_assume_encoding(self):
0355        global assume_encoding
0356
0357        if hasattr(self, "assume_encoding"):
0358            return self.assume_encoding
0359        else:
0360            return assume_encoding
0361
0362    def defined(self, name):
0363        return hasattr(self, name)
0364
0365    def value_of(self, name, default=None):
0366        return getattr(self, name, default)
0367
0368class TemplatePath(object):
0369    def __init__(self, paths=None):
0370        if isinstance(paths, basestring):
0371            paths = [paths]
0372        elif paths is None:
0373            paths = []
0374        paths += [os.getcwd(), '/']
0375        self.paths = [self._cleanse_path(p) for p in paths]
0376
0377    def _cleanse_path(self, path):
0378        from os.path import normpath, expanduser, abspath
0379        return abspath(normpath(expanduser(path)))
0380
0381    def insert(self, path, pos=0):
0382        self.paths.insert(pos, self._cleanse_path(path))
0383
0384    def append(self, path):
0385        self.paths.append(self._cleanse_path(path))
0386
0387    def find(self, path, rel="/"):
0388        from os.path import normpath, join, exists, dirname
0389        path = normpath(path)
0390        for p in self.paths + [dirname(rel)]:
0391            p = join(p, path)
0392            if exists(p):
0393                return p
0394
0395path = TemplatePath()
0396
0397import kid.properties
0398properties = kid.properties
0399
0400__all__ = ['KID_XMLNS', 'BaseTemplate', 'Template',
0401           'enable_import', 'import_template', 'load_template',
0402           'Element', 'SubElement', 'XML', 'document', 'Namespace',
0403           'Serializer', 'XMLSerializer', 'HTMLSerializer', 'XHTMLSerializer', 'output_methods',
0404           'filter', 'namespace', 'serialization', 'util', 'properties']
kid-0.9.6/doc/html/kid/compile.py.html0000644000175000017500000005400610415050402017422 0ustar tstanektstanekkid/compile.py
0001#!/usr/bin/python
0002
0003# This module provides the "kidc" command
0004
0005"""Usage: kidc [OPTIONS] [file...]
0006Compile kid templates into Python byte-code (.pyc) files.
0007
0008OPTIONS:
0009
0010  -f, --force
0011          Force compilation even if .pyc file already exists.
0012  -s, --source
0013          Generate .py source files along with .pyc files.
0014          This is sometimes useful for debugging.
0015  -d, --strip-dest-dir <destdir>
0016          Strips the supplied path from the beginning of source
0017          filenames stored for error messages in the generated
0018          .pyc files
0019
0020The file list may have files and/or directories. If a directory is specified,
0021all .kid files found in the directory and any sub-directories are compiled.
0022"""
0023
0024__revision__ = "$Rev: 139 $"
0025__date__ = "$Date: 2005-03-14 19:28:22 -0500 (Mon, 14 Mar 2005) $"
0026__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0027__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0028__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0029
0030import sys
0031from os.path import isdir
0032from getopt import getopt, GetoptError as gerror
0033
0034import kid.compiler
0035
0036def main():
0037    # get options
0038    try:
0039        opts, args = getopt(sys.argv[1:], 'fshd=', ['force', 'source', 'help', 'strip-dest-dir='])
0040    except gerror, msg:
0041        sys.stderr.write(str(e) + '\n')
0042        sys.stdout.write(__doc__)
0043        sys.exit(2)
0044    force = 0
0045    source = 0
0046    strip_dest_dir = None
0047    for o, a in opts:
0048        if o in ('-f', '--force'):
0049            force = True
0050        elif o in ('-s', '--source'):
0051            source = True
0052        elif o in ('-h', '--help'):
0053            sys.stdout.write(__doc__)
0054            sys.exit(0)
0055        elif o in ('-d', '--strip-dest-dir'):
0056            strip_dest_dir = a
0057    files = args
0058
0059    if not files:
0060        sys.stderr.write('kidc: No kid template specified.\n')
0061        sys.stderr.write("      Try 'kidc --help' for usage information.\n")
0062        sys.exit(2)
0063
0064    # a quick function for printing results
0065    def print_result(rslt):
0066        (rslt, file) = rslt
0067        if rslt == True:
0068            msg = 'compile: %s\n' % file
0069        elif rslt == False:
0070            msg = 'fresh: %s\n' % file
0071        else:
0072            msg = 'error: %s (%s)\n' % (file, rslt)
0073        sys.stderr.write(msg)
0074
0075    # run through files and compile
0076    for f in files:
0077        if isdir(f):
0078            for rslt in kid.compiler.compile_dir(f, force=force, source=source, strip_dest_dir=strip_dest_dir):
0079                print_result(rslt)
0080        else:
0081            kid.compiler.compile_file(f, force=force, source=source, strip_dest_dir=strip_dest_dir)
0082            print_result((True, f))
0083
0084if __name__ == '__main__':
0085    main()
kid-0.9.6/doc/html/kid/compiler.py.html0000644000175000017500000015622410415050402017611 0ustar tstanektstanekkid/compiler.py
0001"""Kid Compiler
0002
0003Compile XML to Python byte-code.
0004"""
0005
0006from __future__ import generators
0007
0008__revision__ = "$Rev: 262 $"
0009__date__ = "$Date: 2006-01-28 16:38:09 +0000 (Sat, 28 Jan 2006) $"
0010__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0011__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0012__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0013
0014import sys
0015import re
0016import os
0017import os.path
0018import imp
0019import stat
0020import struct
0021import marshal
0022import new
0023
0024import kid.parser
0025
0026__all__ = ['KID_EXT', 'compile', 'compile_file', 'compile_dir']
0027
0028# kid filename extension
0029KID_EXT = ".kid"
0030
0031py_compile = compile
0032
0033def actualize(code, dict=None):
0034    if dict is None:
0035        dict = {}
0036    exec code in dict
0037    return dict
0038
0039def compile(source, filename='<string>', encoding=None):
0040    """Compiles kid xml source to a Python code object.
0041
0042    source   -- A file like object - must support read.
0043    filename -- An optional filename that is used
0044
0045    """
0046    # XXX all kinds of work to do here catching syntax errors and
0047    #     adjusting line numbers..
0048    py = kid.parser.parse(source, encoding, filename=filename)
0049    return py_compile(py, filename, 'exec')
0050
0051_timestamp = lambda filename : os.stat(filename)[stat.ST_MTIME]
0052
0053class KidFile(object):
0054    magic = imp.get_magic()
0055
0056    def __init__(self, kid_file, force=0, encoding=None, strip_dest_dir=None):
0057        self.kid_file = kid_file
0058        self.py_file = os.path.splitext(kid_file)[0] + '.py'
0059        self.strip_dest_dir = strip_dest_dir
0060        self.pyc_file = self.py_file + 'c'
0061        self.encoding = encoding or 'utf-8'
0062        fp = None
0063        if force:
0064            stale = 1
0065        else:
0066            stale = 0
0067            try:
0068                fp = open(self.pyc_file, "rb")
0069            except IOError:
0070                stale = 1
0071            else:
0072                if fp.read(4) != self.magic:
0073                    stale = 1
0074                else:
0075                    mtime = struct.unpack('<I', fp.read(4))[0]
0076                    kid_mtime = _timestamp(kid_file)
0077                    if kid_mtime is None or mtime < kid_mtime:
0078                        stale = 1
0079        self.stale = stale
0080        self._pyc_fp = fp
0081        self._python = None
0082        self._code = None
0083
0084    def compile(self, dump_code=1, dump_source=0):
0085        if dump_source:
0086            self.dump_source()
0087        code = self.code
0088        if dump_code and self.stale:
0089            self.dump_code()
0090        return code
0091
0092    def code(self):
0093        if self._code is None:
0094            if not self.stale:
0095                self._code = marshal.load(self._pyc_fp)
0096            else:
0097                pyfile = self.py_file
0098                if self.strip_dest_dir and                      self.py_file.startswith(self.strip_dest_dir):
0100                    pyfile = os.path.normpath(self.py_file[len(self.strip_dest_dir):])
0101                self._code = py_compile(self.python, pyfile, 'exec')
0102        return self._code
0103    code = property(code)
0104
0105    def python(self):
0106        """Get the Python source for the template."""
0107        if self._python is None:
0108            py = kid.parser.parse_file(self.kid_file, self.encoding)
0109            self._python = py
0110        return self._python
0111    python = property(python)
0112
0113    def dump_source(self, file=None):
0114        py = self.python
0115        file = file or self.py_file
0116        try:
0117            fp = _maybe_open(file, 'wb')
0118            fp.write('# -*- coding: utf-8 -*-\n') # PEP 0263
0119            fp.write(self.python.encode('utf-8'))
0120        except IOError:
0121            try:
0122                os.unlink(file)
0123            except OSError:
0124                pass
0125            return 0
0126        else:
0127            return 1
0128
0129    def dump_code(self, file=None):
0130        code = self.code
0131        file = file or self.pyc_file
0132        try:
0133            fp = _maybe_open(file, 'wb')
0134            if self.kid_file:
0135                mtime = os.stat(self.kid_file)[stat.ST_MTIME]
0136            else:
0137                mtime = 0
0138            fp.write('\0\0\0\0')
0139            fp.write(struct.pack('<I', mtime))
0140            marshal.dump(code, fp)
0141            fp.flush()
0142            fp.seek(0)
0143            fp.write(self.magic)
0144        except IOError:
0145            try:
0146                os.unlink(file)
0147            except OSError:
0148                pass
0149            return 0
0150        else:
0151            return 1
0152
0153def _maybe_open(f, mode):
0154    if isinstance(f, basestring):
0155        return open(f, mode)
0156    else:
0157        return f
0158
0159#
0160# functions for compiling files directly and the kidc utility
0161#
0162
0163def compile_file(file, force=0, source=0, encoding=None, strip_dest_dir=None):
0164    """Compile the file specified.
0165
0166    Return True if the file was compiled, False if the compiled file already
0167    exists and is up-to-date.
0168
0169    """
0170    template = KidFile(file, force, encoding, strip_dest_dir)
0171    if template.stale:
0172        template.compile(dump_source=source)
0173        return 1
0174    else:
0175        return 0
0176
0177
0178def compile_dir(dir, maxlevels=10, force=0, source=0, encoding=None, strip_dest_dir=None):
0179    """Byte-compile all kid modules in the given directory tree.
0180
0181    Keyword Arguments: (only dir is required)
0182    dir       -- the directory to byte-compile
0183    maxlevels -- maximum recursion level (default 10)
0184    force     -- if true, force compilation, even if timestamps are up-to-date.
0185    source    -- if true, dump python source (.py) files along with .pyc files.
0186
0187    """
0188    names = os.listdir(dir)
0189    names.sort()
0190    success = 1
0191    ext_len = len(KID_EXT)
0192    for name in names:
0193        fullname = os.path.join(dir, name)
0194        if os.path.isfile(fullname):
0195            head, tail = name[:-ext_len], name[-ext_len:]
0196            if tail == KID_EXT:
0197                try:
0198                    rslt = compile_file(fullname, force, source, encoding, strip_dest_dir)
0199                except Exception, e:
0200                    # TODO: grab the traceback and yield it with the other stuff
0201                    rslt = e
0202                yield (rslt, fullname)
0203        elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
0204                    os.path.isdir(fullname) and not os.path.islink(fullname)):
0205            for rslt in compile_dir(fullname, maxlevels - 1, force, source, strip_dest_dir):
0206                yield rslt
0207    return
kid-0.9.6/doc/html/kid/et.py.html0000644000175000017500000005727510457613120016425 0ustar tstanektstanekkid/et.py
0001"""ElementTree extensions."""
0002
0003__revision__ = "$Rev$"
0004__date__ = "$Date: 2005-02-16 15:43:38 -0500 (Wed, 16 Feb 2005) $"
0005__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0006__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0007__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0008
0009import os
0010
0011# If allowed and possible, import all objects from CElementTree:
0012
0013try:
0014    if os.environ.get('KID_NOCET'):
0015        raise ImportError
0016    else:
0017        try:
0018            if os.environ.get('KID_NOET'):
0019                raise ImportError
0020            else:
0021                import cElementTree as CET
0022                from cElementTree import *
0023        except ImportError:
0024            # you must have Python 2.5 or newer
0025            import xml.etree.cElementTree as CET
0026            from xml.etree.cElementTree import *
0027except:
0028    CET = None
0029
0030# Otherwise, import all objects from ElementTree:
0031
0032try:
0033    if os.environ.get('KID_NOET'):
0034        raise ImportError
0035    else:
0036        import elementtree.ElementTree as ET
0037        if not CET:
0038            from elementtree.ElementTree import *
0039except ImportError:
0040    # you must have Python 2.5 or newer
0041    import xml.etree.ElementTree as ET
0042    if not CET:
0043        from xml.etree.ElementTree import *
0044
0045# These functions exist only in ET, not in CET:
0046
0047encode_entity = ET._encode_entity
0048raise_serialization_error = ET._raise_serialization_error
0049
0050def Comment(text=None):
0051    elem = Element(Comment)
0052    elem.text = text
0053    return elem
0054
0055def ProcessingInstruction(target, text=None):
0056    element = Element(ProcessingInstruction)
0057    element.text = target
0058    if text:
0059        element.text = element.text + " " + text
0060    return element
0061
0062# The fragment factory does not exist in ElementTree:
0063
0064def Fragment(text=''):
0065    """XML fragment factory.
0066
0067    Fragments hold TEXT and children but do not have a tag or attributes.
0068
0069    """
0070    elem = Element(Fragment)
0071    elem.text = text
0072    return elem
0073
0074def namespaces(elem, remove=0):
0075    """Get the namespace declarations for an Element.
0076
0077    This function looks for attributes on the Element provided that have the
0078    following characteristics:
0079
0080       * Begin with 'xmlns:' and have no namespace URI.
0081       * Are named 'xmlns' and have no namespace URI.
0082
0083    The result is a dictionary containing namespace prefix -> URI mappings.
0084    Default namespace attributes result in a key of ''.
0085
0086    If remove is truthful, namespace declaration attributes are removed
0087    from the passed in Element.
0088
0089    """
0090    names = {}
0091    for k in elem.keys():
0092        if k.startswith('xmlns:'):
0093            names[k[6:]] = elem.get(k)
0094            if remove: del elem.attrib[k]
0095        elif k == 'xmlns':
0096            names[''] = elem.get(k)
0097            if remove: del elem.attrib[k]
0098    return names
0099
0100__all__ = ['Element', 'SubElement', 'Comment', 'ProcessingInstruction',
0101           'Fragment', 'ElementTree', 'QName', 'dump',
0102           'parse', 'tostring', 'namespaces',
0103           'encode_entity', 'raise_serialization_error']
kid-0.9.6/doc/html/kid/filter.py.html0000644000175000017500000005403510415050402017261 0ustar tstanektstanekkid/filter.py
0001"""Kid tranformations"""
0002
0003from __future__ import generators
0004
0005__revision__ = "$Rev: 53 $"
0006__date__ = "$Date: 2005-02-15 08:10:35 -0500 (Tue, 15 Feb 2005) $"
0007__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0008__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0009__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0010
0011from types import GeneratorType
0012from kid.pull import ElementStream, START, XML_DECL,  _coalesce
0013from kid.namespace import Namespace
0014from template_util import generate_content
0015
0016def transform_filter(stream, template):
0017    templates = template._get_match_templates()
0018    def apply_func(item):
0019        return transform_filter(generate_content(item), template)
0020    stream = ElementStream.ensure(stream)
0021    for ev, item in apply_matches(stream, template, templates, apply_func):
0022        yield ev, item
0023
0024def apply_matches(stream, template, templates, apply_func):
0025    for ev, item in stream:
0026        if ev == START:
0027            matched = 0
0028            for i in range(0, len(templates)):
0029                (match, call) = templates[i]
0030                if match(item):
0031                    item = stream.expand()
0032                    newstream = _coalesce(call(template, item, apply_func),
0033                        template._get_assume_encoding())
0034                    if len(templates) < 2:
0035                        for ev, item in newstream:
0036                            yield (ev, item)
0037                    else:
0038                        for ev, item in apply_matches(ElementStream(newstream),
0039                            template, templates[:i] + templates[i+1:], apply_func):
0040                                yield ev, item
0041                    matched = 1
0042                    break
0043            if matched:
0044                continue
0045        yield (ev, item)
0046
0047# XXX haven't tested this yet..
0048def xinclude_filter(stream, template):
0049    xi = Namespace('http://www.w3.org/2001/XInclude')
0050    include = xi.include
0051    fallback = xi.fallback
0052    for ev, item in stream:
0053        if ev == START and item.tag == xi.include:
0054            item = item.expand()
0055            href = item.get('href')
0056            try:
0057                doc = document(href, template._get_assume_encoding())
0058            except:
0059                fallback_elm = item.find(fallback)
0060                for ev, item in ElementStream(fallback_elm).strip(1):
0061                    yield ev, item
0062            else:
0063                for ev, item in doc:
0064                    if ev != XML_DECL:
0065                        yield ev
kid-0.9.6/doc/html/kid/importer.py.html0000644000175000017500000010664310422121476017650 0ustar tstanektstanekkid/importer.py
0001"""Kid Import Hooks.
0002
0003When installed, these hooks allow importing .kid files as if they were
0004Python modules.
0005
0006"""
0007
0008__revision__ = "$Rev: 317 $"
0009__date__ = "$Date: 2006-04-21 08:51:24 +0000 (Fri, 21 Apr 2006) $"
0010__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0011__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0012__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0013
0014import os, sys, time, new
0015import __builtin__
0016
0017import kid.compiler
0018KID_EXT = kid.compiler.KID_EXT
0019
0020assert sys.hexversion >= 0x20000b1, "need Python 2.0b1 or later"
0021
0022_installed = False
0023
0024def install(suffixes=None):
0025    global _installed
0026    if not _installed:
0027        _install_hook(suffixes=suffixes)
0028        _installed = True
0029
0030def uninstall():
0031    global _installed
0032    if _installed:
0033        _uninstall_hook()
0034        _installed = False
0035
0036def import_template(name, filename, force=0):
0037    if not force and name and sys.modules.has_key(name):
0038        return sys.modules[name]
0039    template = kid.compiler.KidFile(filename)
0040    code = template.compile(dump_source=os.environ.get('KID_OUTPUT_PY'))
0041    module = _create_module(code, name, filename)
0042    return module
0043
0044def get_template_name(name, filename):
0045    if name:
0046        return name
0047    else:
0048        return 'kid.util.template_%x' % (hash(filename) + sys.maxint + 1)
0049
0050def _create_module(code, name, filename, store=1, ns={}):
0051    name = get_template_name(name, filename)
0052    mod = new.module(name)
0053    mod.__file__ = filename
0054    mod.__ctime__ = time.time()
0055    mod.__dict__.update(ns)
0056    exec code in mod.__dict__
0057    if store:
0058        sys.modules[name] = mod
0059    return mod
0060
0061# this is put in a pyc file to signal that it is a kid file
0062KID_FILE = object()
0063
0064try: # if possible, use new (PEP 302) import hooks
0065    from sys import path_hooks, path_importer_cache
0066except ImportError:
0067    path_hooks = None
0068
0069if path_hooks is not None:
0070
0071    class KIDLoader(object):
0072
0073        def __init__(self, path=None):
0074            if path and os.path.isdir(path):
0075                self.path = path
0076            else:
0077                raise ImportError
0078
0079        def find_module(self, fullname):
0080            path = os.path.join(self.path, fullname.split('.')[-1])
0081            for ext in [KID_EXT] + self.suffixes:
0082                if os.path.exists(path + ext):
0083                    self.filename = path + ext
0084                    return self
0085            return None
0086
0087        def load_module(self, fullname):
0088            return import_template(fullname, self.filename, force=1)
0089
0090    def _install_hook(suffixes=None):
0091        KIDLoader.suffixes = suffixes or []
0092        path_hooks.append(KIDLoader)
0093        sys.path_importer_cache.clear()
0094
0095    def _uninstall_hook():
0096        i = 0
0097        while i < len(path_hooks):
0098            if path_hooks[i] is KIDLoader:
0099                del path_hooks[i]
0100            else:
0101                i += 1
0102        sys.path_importer_cache.clear()
0103
0104else: # Python < 2.3, fall back to using the old ihooks module
0105
0106    import ihooks, imp
0107
0108    class KIDHooks(ihooks.Hooks):
0109
0110        def __init__(self, verbose=ihooks.VERBOSE, suffixes=None):
0111            ihooks.Hooks.__init__(self, verbose)
0112            self.suffixes = suffixes or []
0113
0114        def get_suffixes(self):
0115            return [(suffix, 'r', KID_FILE)
0116                for suffix in [KID_EXT] + self.suffixes] + imp.get_suffixes()
0117
0118    class KIDLoader(ihooks.ModuleLoader):
0119
0120        def load_module(self, name, stuff):
0121            file, filename, info = stuff
0122            (suff, mode, type) = info
0123            if type is KID_FILE:
0124                return import_template(name, filename, force=1)
0125            else:
0126                return ihooks.ModuleLoader.load_module(self, name, stuff)
0127
0128    def _install_hook(suffixes=None):
0129        hooks = KIDHooks(suffixes=suffixes)
0130        loader = KIDLoader(hooks)
0131        importer = ihooks.ModuleImporter(loader)
0132        ihooks.install(importer)
0133
0134    def _uninstall_hook():
0135        ihooks.uninstall()
kid-0.9.6/doc/html/kid/namespace.py.html0000644000175000017500000003404210457613120017734 0ustar tstanektstanekkid/namespace.py
0001namespaces = {}
0002
0003class Namespace(object):
0004    def __init__(self, uri, prefix=None):
0005        self.uri = uri
0006        self.prefix = prefix
0007        if prefix:
0008            namespaces[uri] = prefix
0009
0010    def qname(self, name):
0011        if self.prefix:
0012            return self.prefix + ':' + name
0013        else:
0014            return name
0015
0016    def clarkname(self, name):
0017        if self.uri:
0018            return '{%s}%s' % (self.uri, name)
0019        else:
0020            return name
0021
0022    __getattr__ = clarkname
0023    __getitem__ = clarkname
0024
0025    def __str__(self):
0026        return self.uri
0027
0028    def __unicode__(self):
0029        return unicode(self.uri)
0030
0031    def __repr__(self):
0032        return 'Namespace(%r, %r)' % (self.uri, self.prefix)
0033
0034    def __equals__(self, other):
0035        if isinstance(other, basestring):
0036            return self.uri == other
0037        elif isinstance(other, Namespace):
0038            return self.uri == other.uri
0039        else:
0040            return False
0041
0042xml = Namespace('http://www.w3.org/XML/1998/namespace', 'xml')
0043xhtml = Namespace('http://www.w3.org/1999/xhtml', 'html')
0044atom = Namespace('http://purl.org/atom/ns#', 'atom')
0045rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf')
0046rss = Namespace('http://purl.org/rss/1.0/', 'rss')
0047nons = Namespace(None, None)
0048
0049__all__ = ['xml', 'xhtml', 'atom', 'rdf', 'rss', 'nons', 'Namespace']
kid-0.9.6/doc/html/kid/parser.py.html0000644000175000017500000046754610454024620017315 0ustar tstanektstanekkid/parser.py
0001"""Kid Parser
0002
0003Parses Kid embedded XML to Python source code.
0004"""
0005
0006from __future__ import generators
0007
0008__revision__ = "$Rev: 346 $"
0009__date__ = "$Date: 2006-06-20 11:09:56 +0000 (Tue, 20 Jun 2006) $"
0010__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0011__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0012__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0013
0014import re
0015from kid.pull import *
0016from kid.et import namespaces
0017from kid import Namespace
0018
0019# the kid xml namespace
0020KID_XMLNS = "http://purl.org/kid/ns#"
0021KID_PREFIX = 'py'
0022kidns = Namespace(KID_XMLNS)
0023QNAME_FOR = kidns['for']
0024QNAME_IF = kidns['if']
0025QNAME_DEF = kidns['def']
0026QNAME_SLOT = kidns['slot']
0027QNAME_CONTENT = kidns['content']
0028QNAME_REPLACE = kidns['replace']
0029QNAME_MATCH = kidns['match']
0030QNAME_STRIP = kidns['strip']
0031QNAME_ATTRIBUTES = kidns['attrs']
0032QNAME_EXTENDS = kidns['extends']
0033QNAME_LAYOUT = kidns['layout']
0034
0035# deprectaed
0036QNAME_OMIT = kidns['omit']
0037QNAME_REPEAT = kidns['repeat']
0038
0039# the kid processing instruction name
0040KID_PI = 'python'
0041KID_ALT_PI = 'py'
0042KID_OLD_PI = 'kid'
0043
0044def parse(source, encoding=None, filename=None):
0045    parser = KidParser(document(source, encoding=encoding, filename=filename), encoding)
0046    return parser.parse()
0047
0048def parse_file(filename, encoding=None):
0049    """Parse the file specified.
0050
0051    filename -- the name of a file.
0052    fp       -- an optional file like object to read from. If not specified,
0053                filename is opened.
0054
0055    """
0056    source = open(filename, 'rb')
0057    try:
0058        return parse(source, encoding, filename=filename)
0059    finally:
0060        source.close()
0061
0062class KidParser(object):
0063    def __init__(self, stream, encoding=None):
0064        self.stream = stream
0065        self.encoding = encoding or 'utf-8'
0066        self.depth = 0
0067        self.module_code = CodeGenerator()
0068        self.class_code = CodeGenerator()
0069        self.expand_code = CodeGenerator(level=1)
0070        self.end_module_code = CodeGenerator()
0071        self.module_defs = []
0072        self.inst_defs = []
0073
0074    def parse(self):
0075        self.begin()
0076        self.proc_stream(self.module_code)
0077        self.end()
0078        parts = []
0079        parts += self.module_code.code
0080        for c in self.module_defs:
0081            parts += c.code
0082        parts += self.class_code.code
0083        parts += self.expand_code.code
0084        for c in self.inst_defs:
0085            parts += c.code
0086        parts += self.end_module_code.code
0087        return '\n'.join(parts)
0088
0089    def begin(self):
0090        code = self.module_code
0091        code.line('from __future__ import generators')
0092        code.line('import kid')
0093        code.line('from kid.template_util import *')
0094        code.line('import kid.template_util as template_util')
0095        code.line('_def_names = []')
0096
0097        # default variables. can be overridden by template
0098        code.line('encoding = "%s"' % self.encoding)
0099        code.line('doctype = None')
0100        code.line('omit_namespaces = [kid.KID_XMLNS]')
0101        code.line('layout_params = {}')
0102
0103        # module methods.
0104        code.line('def pull(**kw): return Template(**kw).pull()')
0105        code.line("def generate(encoding=encoding, fragment=0, output=None, **kw): "
0106                  "return Template(**kw).generate(encoding=encoding, fragment=fragment, output=output)")
0107        code.line("def serialize(encoding=encoding, fragment=0, output=None, **kw): "
0108                  "return Template(**kw).serialize(encoding=encoding, fragment=fragment, output=output)")
0109        code.line("def write(file, encoding=encoding, fragment=0, output=None, **kw): "
0110                  "return Template(**kw).write(file, encoding=encoding, fragment=fragment, output=output)")
0111        code.line('BaseTemplate = kid.BaseTemplate')
0112        code.line('def initialize(template): pass')
0113
0114        # expand code
0115        code = self.expand_code
0116        code.start_block('def initialize(self):')
0117        code.line('rslt = initialize(self)')
0118        code.line('if rslt != 0: super(Template, self).initialize()')
0119        code.end_block()
0120        code.start_block('def _pull(self):')
0121        # XXX hack: nasty kluge for making kwargs locals
0122        code.line("exec template_util.get_locals(self, locals())")
0123        code.line('current, ancestors = None, []')
0124        code.line('if doctype: yield (DOCTYPE, doctype)')
0125
0126        code = self.end_module_code
0127        code.line('')
0128
0129    def end(self):
0130        self.expand_code.end_block()
0131
0132    def proc_stream(self, code):
0133        for (ev, item) in self.stream:
0134            if ev == START:
0135                if item.tag == Comment:
0136                    text = item.text.lstrip()
0137                    if text.startswith('!'):
0138                        continue
0139                    line = code.line
0140                    if text.startswith('<') or text.startswith('['):
0141                        sub = interpolate(item.text)
0142                        if isinstance(sub, list):
0143                            text = "''.join([unicode(o) for o in %r])" % sub
0144                        else:
0145                            text = repr(sub)
0146                    else:
0147                        text = repr(item.text)
0148                    line('_e = Comment(%s)' % text)
0149                    line('yield (START, _e); yield (END, _e); del _e')
0150                elif item.tag == ProcessingInstruction:
0151                    if ' ' in item.text.strip():
0152                        (name, data) = item.text.split(' ', 1)
0153                    else:
0154                        (name, data) = (item.text, '')
0155                    if name in (KID_PI, KID_ALT_PI, KID_OLD_PI):
0156                        if data:
0157                            code.insert_block(data)
0158                    else:
0159                        c = self.depth and code or self.expand_code
0160                        c.line('_e = ProcessingInstruction(%r, %r)'                                     % (name, data) )
0162                        c.line('yield (START, _e); yield (END, _e); del _e')
0163                        del c
0164                else:
0165                    layout = None
0166                    if code is self.module_code:
0167                        layout = item.get(QNAME_LAYOUT)
0168                        if layout is not None:
0169                            del item.attrib[QNAME_LAYOUT]
0170                        decl = ['class Template(']
0171                        extends = item.get(QNAME_EXTENDS)
0172                        parts = []
0173                        if extends is not None:
0174                            del item.attrib[QNAME_EXTENDS]
0175                            for c in extends.split(','):
0176                                parts.append('template_util.get_base_class(%s, __file__)' % c)
0177                        parts.append('BaseTemplate')
0178                        decl.append(','.join(parts))
0179                        decl.append('):')
0180                        code = self.class_code
0181                        code.start_block(''.join(decl))
0182                        code.line('_match_templates = []')
0183                        code = self.expand_code
0184                        del decl, parts
0185                    self.def_proc(item, item.attrib, code)
0186                    if layout is not None:
0187                        old_code = code
0188                        code = CodeGenerator(level=1)
0189                        code.start_block("def _pull(self):")
0190                        code.line('exec template_util.get_locals(self, locals())')
0191                        code.line('kw = dict(layout_params)')
0192                        code.line('kw.update(dict([(name, getattr(self, name)) for name in _def_names]))')
0193                        code.line('kw.update(self.__dict__)')
0194                        # XXX hack: this could be avoided if template args were not stored in self.__dict__
0195                        # Note: these names cannot be passed to the layout template via layout_params
0196                        code.line('kw.pop("assume_encoding", None)')
0197                        code.line('kw.pop("_layout_classes", None)')
0198                        code.line('temp = template_util.get_base_class(%s, __file__)(**kw)' % layout)
0199                        code.line('temp._match_templates = self._match_templates + temp._match_templates')
0200                        code.line('return temp._pull()')
0201                        code.end_block()
0202                        self.inst_defs.append(code)
0203                        code = old_code
0204            elif ev == END and not item.tag in (ProcessingInstruction, Comment):
0205                break
0206            elif ev == TEXT:
0207                self.text_interpolate(item, code)
0208            elif ev == XML_DECL and item[1] is not None:
0209                self.module_code.line('encoding = %r' % item[1])
0210            elif ev == DOCTYPE:
0211                self.module_code.line('doctype = (%r, %r, %r)' % item)
0212
0213    def def_proc(self, item, attrib, code):
0214        attr_name = QNAME_DEF
0215        decl = attrib.get(attr_name)
0216        if decl is None:
0217            attr_name = QNAME_SLOT
0218            decl = attrib.get(attr_name)
0219        if decl is not None:
0220            del attrib[attr_name]
0221            old_code = code
0222            if '(' not in decl:
0223                decl = decl + '()'
0224            name, args = decl.split('(', 1)
0225            pos = args.rfind(')')
0226            args = args[0:pos].strip()
0227            self_ = args and 'self, ' or 'self'
0228            class_decl = '%s(%s%s)' % (name, self_, args)
0229
0230            # module function code
0231            code = CodeGenerator()
0232            code.start_block('def %s(*args, **kw):' % name)
0233            code.line('return Template().%s(*args, **kw)' % name)
0234            code.end_block()
0235            code.line('_def_names.append("%s")' % name)
0236            self.module_defs.append(code)
0237
0238            # instance method code
0239            code = CodeGenerator(level=1)
0240            code.start_block('def %s:' % class_decl)
0241            code.line('exec template_util.get_locals(self, locals())')
0242            code.line('current, ancestors = None, []')
0243            self.inst_defs.append(code)
0244            self.match_proc(item, attrib, code)
0245            code.end_block()
0246            if attr_name == QNAME_SLOT:
0247                old_code.line('for _e in template_util.generate_content(self.%s()): yield _e' % name)
0248        else:
0249            self.match_proc(item, attrib, code)
0250
0251    def match_proc(self, item, attrib, code):
0252        expr = attrib.get(QNAME_MATCH)
0253        if expr is not None:
0254            del attrib[QNAME_MATCH]
0255            old_code = code
0256            code = CodeGenerator(level=1)
0257            code.start_block('def _match_func(self, item, apply):')
0258            code.line('exec template_util.get_locals(self, locals())')
0259            code.line('current, ancestors = None, []')
0260            self.for_proc(item, attrib, code)
0261            code.end_block()
0262            code.line('_match_templates.append((lambda item: %s, _match_func))'                         % expr)
0264            self.inst_defs.append(code)
0265        else:
0266            self.for_proc(item, attrib, code)
0267
0268    def for_proc(self, item, attrib, code):
0269        expr = attrib.get(QNAME_FOR)
0270        if expr is not None:
0271            code.start_block('for %s:' % expr)
0272            del attrib[QNAME_FOR]
0273            self.if_proc(item, attrib, code)
0274            code.end_block()
0275        else:
0276            self.if_proc(item, attrib, code)
0277
0278    def if_proc(self, item, attrib, code):
0279        expr = attrib.get(QNAME_IF)
0280        if expr is not None:
0281            code.start_block('if %s:' % expr)
0282            del attrib[QNAME_IF]
0283            self.replace_proc(item, attrib, code)
0284            code.end_block()
0285        else:
0286            self.replace_proc(item, attrib, code)
0287
0288    def replace_proc(self, item, attrib, code):
0289        expr = attrib.get(QNAME_REPLACE)
0290        if expr is not None:
0291            del attrib[QNAME_REPLACE]
0292            attrib[QNAME_STRIP] = ""
0293            attrib[QNAME_CONTENT] = expr
0294        self.strip_proc(item, attrib, code)
0295
0296    def strip_proc(self, item, attrib, code):
0297        has_content = self.content_proc(item, attrib, code)
0298        expr, attr = (attrib.get(QNAME_STRIP), QNAME_STRIP)
0299        if expr is None:
0300            # XXX py:omit is deprecated equivalent of py:strip
0301            expr, attr = (attrib.get(QNAME_OMIT), QNAME_OMIT)
0302        start_block, end_block = (code.start_block, code.end_block)
0303        line = code.line
0304        if expr is not None:
0305            del attrib[attr]
0306            if expr != '':
0307                start_block("if not (%s):" % expr)
0308                self.attrib_proc(item, attrib, code)
0309                end_block()
0310            else:
0311                pass # element is always stripped
0312        else:
0313            self.attrib_proc(item, attrib, code)
0314        if has_content:
0315            code.start_block(
0316                'for _e in template_util.generate_content(_cont, current):')
0317            line('yield _e')
0318            line('del _e')
0319            code.end_block()
0320            self.stream.eat()
0321        else:
0322            self.depth += 1
0323            self.proc_stream(code)
0324            self.depth -= 1
0325        if expr:
0326            start_block("if not (%s):" % expr)
0327            line('yield (END, current)')
0328            line('current = ancestors.pop(0)')
0329            end_block()
0330        elif expr != '':
0331            line('yield (END, current)')
0332            line('current = ancestors.pop(0)')
0333
0334    def attrib_proc(self, item, attrib, code):
0335        interp = 0
0336        line = code.line
0337        need_interpolation = 0
0338        names = namespaces(item, remove=1)
0339        for (k,v) in attrib.items():
0340            sub = interpolate(v)
0341            if id(sub) != id(v):
0342                attrib[k] = sub
0343                if isinstance(sub, list):
0344                    need_interpolation = 1
0345        expr = attrib.get(QNAME_ATTRIBUTES)
0346
0347        if expr is not None:
0348            del attrib[QNAME_ATTRIBUTES]
0349            attr_text = 'template_util.update_dict(%r, "%s", globals(), locals())'                   % (attrib, expr.replace('"', '\\\"'))
0351            attr_text = 'template_util.make_attrib(%s,self._get_assume_encoding())' % attr_text
0352        else:
0353            if attrib:
0354                if need_interpolation:
0355                    attr_text = 'template_util.make_attrib(%r,self._get_assume_encoding())' % attrib
0356                else:
0357                    attr_text = repr(attrib)
0358            else:
0359                attr_text = '{}'
0360        line('ancestors.insert(0, current)')
0361        line('current = Element(%r, %s)' % (item.tag, attr_text))
0362        if len(names):
0363            code.start_block('for _p, _u in %r.items():' % names)
0364            line('if not _u in omit_namespaces: yield (START_NS, (_p,_u))')
0365            code.end_block()
0366        line('yield (START, current)')
0367
0368    def content_proc(self, item, attrib, code):
0369        expr = attrib.get(QNAME_CONTENT)
0370        if expr is not None:
0371            del attrib[QNAME_CONTENT]
0372            code.line('_cont = %s' % expr)
0373            return 1
0374
0375    def text_interpolate(self, text, code):
0376        interp = 0
0377        line = code.line
0378        sub = interpolate(text)
0379        if isinstance(sub, list):
0380            code.start_block('for _e in %r:' % sub)
0381            code.line('for _e2 in template_util.generate_content(_e): yield _e2')
0382            code.end_block()
0383        else:
0384            line('yield (TEXT, %r)' % sub)
0385
0386class SubExpression(list):
0387    def __repr__(self):
0388        return "[%s]" % ', '.join(self)
0389
0390_sub_expr = re.compile(r"(?<!\$)\$\{(.+?)\}")
0391_sub_expr_short = re.compile(r"(?<!\$)\$([a-zA-Z][a-zA-Z0-9_\.]*)")
0392
0393def interpolate(text):
0394    parts = _sub_expr.split(text)
0395    if len(parts) == 1:
0396        parts = _sub_expr_short.split(text)
0397        if len(parts) == 1:
0398            return text.replace('$$', '$')
0399        else:
0400            last_checked = len(parts)
0401    else:
0402        last_checked = -1
0403    new_parts = SubExpression()
0404    i = 0
0405    while i < len(parts):
0406        part = parts[i]
0407        if (i % 2) == 1:
0408            # odd positioned elements are code
0409            new_parts.append(part)
0410        elif part:
0411            # even positioned elements are text
0412            if i >= last_checked:
0413                more_parts = _sub_expr_short.split(part)
0414                parts[i:i+1] = more_parts
0415                last_checked = i + len(more_parts)
0416                continue
0417            else:
0418                new_parts.append(repr(part.replace('$$', '$')))
0419        i += 1
0420    return new_parts
0421
0422
0423class CodeGenerator:
0424    """A simple Python code generator."""
0425
0426    level = 0
0427    tab = '\t'
0428
0429    def __init__(self, code=None, level=0, tab='\t'):
0430        self.code = code or []
0431        if level != self.level:
0432            self.level = level
0433        if tab != self.tab:
0434            self.tab = tab
0435
0436    def line(self, text):
0437        self.code.append('%s%s' % (self.tab * self.level, text))
0438
0439    def start_block(self, text):
0440        self.line(text)
0441        self.level+=1
0442
0443    def end_block(self, nblocks=1, with_pass=False):
0444        for n in range(nblocks):
0445            if with_pass:
0446                self.line('pass')
0447            self.level-=1
0448
0449    def insert_block(self, block):
0450        output_line = self.line
0451        lines = block.splitlines()
0452        if len(lines) == 1:
0453            # special case single lines
0454            output_line(lines[0].strip())
0455        else:
0456            # adjust the block
0457            for line in _adjust_python_block(lines, self.tab):
0458                output_line(line)
0459
0460    def __str__(self):
0461        self.code.append('')
0462        return '\n'.join(self.code)
0463
0464# Auxiliary function
0465
0466def _adjust_python_block(lines, tab='\t'):
0467    """Adjust the indentation of a Python block."""
0468    lines = [lines[0].strip()] + [line.rstrip() for line in lines[1:]]
0469    ind = None # find least index
0470    for line in lines[1:]:
0471        if line != '':
0472            s = line.lstrip()
0473            if s[0] != '#':
0474                i = len(line) - len(s)
0475                if ind is None or i < ind:
0476                    ind = i
0477                    if i == 0:
0478                        break
0479    if ind is not None or ind != 0: # remove indentation
0480        lines[1:] = [line[:ind].lstrip() + line[ind:]
0481            for line in lines[1:]]
0482    if lines[0] and not lines[0][0] == '#':
0483        # the first line contains code
0484        try: # try to compile it
0485            compile(lines[0], '<string>', 'exec')
0486            # if it works, line does not start new block
0487        except SyntaxError: # unexpected EOF while parsing?
0488            try: # try to compile the whole block
0489                block = '\n'.join(lines) + '\n'
0490                compile(block, '<string>', 'exec')
0491                # if it works, line does not start new block
0492            except IndentationError: # expected an indented block?
0493                # so try to add some indentation:
0494                lines2 = lines[:1] + [tab + line for line in lines[1:]]
0495                block = '\n'.join(lines2) + '\n'
0496                # try again to compile the whole block:
0497                compile(block, '<string>', 'exec')
0498                lines = lines2 # if it works, keep the indentation
0499            except:
0500                pass # leave it as it is
0501        except:
0502            pass # leave it as it is
0503    return lines
0504
0505# Python < 2.3 compatibility
0506try:
0507    enumerate
0508except NameError:
0509    def enumerate(seq):
0510        for i, elem in zip(range(len(seq)), seq):
0511            yield (i, elem)
kid-0.9.6/doc/html/kid/properties.py.html0000644000175000017500000002105310443617634020203 0ustar tstanektstanekkid/properties.py
0001"""Configuration API."""
0002
0003import release
0004__revision__ = "$Rev: 332 $"
0005__date__ = "$Date: 2006-05-20 22:26:35 +0000 (Sat, 20 May 2006) $"
0006__author__ = "David Stanek <dstanek@dstanek.com>"
0007__copyright__ = "Copyright 2006, David Stanek"
0008__license__ = release.license
0009
0010_properties = {
0011}
0012
0013def get(name, default=None):
0014    """Get the property identified by name if it exists or return default.
0015
0016    name: the name of the property to retrieve
0017    default: the value returned for non-existing properties, defaults to None
0018
0019    """
0020    return _properties.get(name, default)
0021
0022def set(name, value):
0023    """The the property identified by name with the value identified by value.
0024
0025    Returns the value passed in.
0026    """
0027    _properties[name] = value
0028    return value
0029
0030def isset(name):
0031    """Returns True if a property exists or False if it doesn't."""
0032    return _properties.has_key(name)
0033
0034def remove(name):
0035    """Remove a property."""
0036    if name in _properties:
0037        del _properties[name]
kid-0.9.6/doc/html/kid/pull.py.html0000644000175000017500000041553110443617634016773 0ustar tstanektstanekkid/pull.py
0001"""Pull-style interface for ElementTree."""
0002
0003from __future__ import generators
0004
0005__revision__ = "$Rev$"
0006__date__ = "$Date: 2005-02-16 15:43:38 -0500 (Wed, 16 Feb 2005) $"
0007__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0008__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0009__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0010
0011from kid.et import *  # ElementTree
0012from kid.util import open_resource, QuickTextReader
0013
0014from xml.parsers import expat
0015
0016# This is the default entity map.
0017import htmlentitydefs
0018default_entity_map = {}
0019default_external_dtd = []
0020for k, v in htmlentitydefs.name2codepoint.items():
0021    default_entity_map[k] = unichr(v)
0022    default_external_dtd.append('<!ENTITY %s "&#%d;">' % (k, v))
0023default_external_dtd = '\n'.join(default_external_dtd)
0024
0025# Bring common ElementTree objects into scope
0026class InvalidStreamState(Exception):
0027    def __init__(self, msg="Invalid stream state."):
0028        Exception.__init__(self, msg)
0029
0030def XML(text, fragment=1, encoding=None, xmlns=None):
0031    """Element generator that reads from a string"""
0032    if text.startswith('<?xml ') or text.startswith('<!DOCTYPE '):
0033        fragment = 0
0034    if fragment:
0035        # allow XML fragments
0036        if xmlns:
0037            text = '<xml xmlns="%s">%s</xml>' % (xmlns,text)
0038        else:
0039            text = '<xml>%s</xml>' % text
0040        if isinstance(text, unicode):
0041            encoding = 'utf-16'
0042            text = text.encode(encoding)
0043        p = Parser(QuickTextReader(text), encoding)
0044        p._sourcetext = text
0045        return ElementStream(_coalesce(p, encoding=encoding)).strip()
0046    else:
0047        if isinstance(text, unicode):
0048            encoding = 'utf-16'
0049            text = text.encode(encoding)
0050        p = Parser(QuickTextReader(text), encoding)
0051        p._sourcetext = text
0052        return ElementStream(_coalesce(p, encoding=encoding))
0053
0054def document(file, encoding=None, filename=None):
0055    if not hasattr(file, 'read'):
0056        if filename is None:
0057            filename = file
0058        file = open_resource(file, 'rb')
0059    else:
0060        if filename is None:
0061            filename = '<string>'
0062    p = Parser(file, encoding)
0063    p._filename = filename
0064    return ElementStream(_coalesce(p, encoding=encoding))
0065
0066class ElementStream(object):
0067
0068    """Provides a pull/streaming interface to ElementTree.
0069    
0070    Instances of this class are iterable. Most methods of the class act on
0071    the Element that is currently being visited.
0072    
0073    """
0074
0075    def __init__(self, stream, current=None):
0076        """Create an ElementStream.
0077        
0078        stream - an iterator that returns ElementStream events.
0079        current - If an Element is provided in this parameter than
0080                  it is yielded as the first element in the stream.
0081
0082        """
0083        if hasattr(stream, 'tag') and hasattr(stream, 'attrib'):
0084            stream = self._pull(stream, tail=1)
0085        self.current = None
0086        self._iter = self._track(iter(stream), current)
0087
0088    def __iter__(self):
0089        return self._iter
0090
0091    def expand(self):
0092        """Expand the current item in the stream as an Element."""
0093
0094        current = self.current
0095        if current is None:
0096            current = []
0097        stack = [current]
0098        last = None
0099        for ev, item in self._iter:
0100            if ev == START:
0101                current = item
0102                if len(stack) > 0:
0103                    stack[-1].append(current)
0104                last = None
0105                stack.append(current)
0106            elif ev == END:
0107                last = stack.pop()
0108                assert last is item
0109                if len(stack) == 0:
0110                    break
0111            elif ev == TEXT:
0112                if last is not None:
0113                    last.tail = item
0114                else:
0115                    current.text = item
0116        if isinstance(last, list):
0117            return last[0]
0118        else:
0119            return last
0120
0121    def strip(self, levels=1):
0122        depth = self.current is not None and 1 or 0
0123        for (ev, item) in self._iter:
0124            if ev == START:
0125                depth += 1
0126            if depth > levels or (depth == levels and ev not in (START, END)):
0127                yield (ev, item)
0128            if ev == END:
0129                depth -= 1
0130                if depth == 0:
0131                    break
0132                elif depth < 0:
0133                    raise InvalidStreamState()
0134
0135    def eat(self):
0136        """Eat the current element and all decendant items."""
0137        depth = self.current is not None and 1 or 0
0138        for (ev, item) in self._iter:
0139            if ev == START:
0140                depth += 1
0141            elif ev == END:
0142                depth -= 1
0143                if depth == 0:
0144                    break
0145        return self
0146
0147    def _pull(self, elem, tail=0):
0148        orig = elem
0149        elem = Element(orig.tag, dict(orig.attrib))
0150        ## XXX: find a better way
0151        if elem.tag in (Comment, ProcessingInstruction):
0152            elem.text = orig.text
0153            orig.text = None
0154        yield (START, elem)
0155        if orig.text:
0156            yield (TEXT, orig.text)
0157        for child in orig.getchildren():
0158            for event in self._pull(child, tail=1):
0159                yield event
0160        yield (END, elem)
0161        if tail and orig.tail:
0162            yield (TEXT, orig.tail)
0163
0164    def _track(self, stream, current=None):
0165        if current is not None:
0166            self.current = current
0167            yield (START, current)
0168        for p in stream:
0169            ev, item = p
0170            if ev == START:
0171                self.current = item
0172            elif ev == END:
0173                self.current = None
0174            yield (ev, item)
0175
0176    def ensure(cls, stream, current=None):
0177        if isinstance(stream, cls):
0178            return stream
0179        else:
0180            return cls(stream, current)
0181    ensure = classmethod(ensure)
0182
0183
0184def to_unicode(value, encoding):
0185    if isinstance(value, unicode):
0186        return value
0187
0188    if hasattr(value, '__unicode__'):
0189        return unicode(value)
0190
0191    if not isinstance(value, str):
0192        value = str(value)
0193
0194    return unicode(value, encoding)
0195
0196
0197def _coalesce(stream, encoding, extended=1):
0198    """Coalesces TEXT events and namespace events.
0199    
0200    Fold multiple sequential TEXT events into a single event.
0201    
0202    The 'encoding' attribute is for the source strings.
0203    """
0204    textbuf = []
0205    namespaces = []
0206    last_ev = None
0207    last = None
0208    current = None
0209    stack = [None]
0210    for ev, item in stream:
0211        if ev == TEXT:
0212            textbuf.append(item)
0213            last_ev = TEXT
0214            continue
0215        if last_ev == TEXT:
0216            text = u""
0217            for value in textbuf:
0218                text += to_unicode(value, encoding)
0219
0220            textbuf = []
0221            if text:
0222                yield (TEXT, text)
0223        if ev == START:
0224            attrib = item.attrib
0225            for prefix, uri in namespaces:
0226                if prefix:
0227                    attrib['xmlns:%s' % prefix] = uri
0228                else:
0229                    attrib['xmlns'] =  uri
0230            namespaces = []
0231            current = item
0232            stack.append(item)
0233        elif ev == END:
0234            current = stack.pop()
0235        elif ev == START_NS:
0236            prefix, uri = item
0237            namespaces.append( (prefix, uri) )
0238            continue
0239        elif ev == END_NS:
0240            continue
0241        yield ev, item
0242    if last_ev == TEXT:
0243        text = u""
0244        for value in textbuf:
0245            text += to_unicode(value, encoding)
0246
0247        if text:
0248            yield (TEXT, text)
0249
0250# Common Events
0251START = 1
0252END = 2
0253TEXT = 3
0254DOCTYPE = 4
0255XML_DECL = 5
0256
0257# These events aren't used after initial parsing
0258START_NS = 10
0259END_NS = 11
0260PI = 12
0261COMMENT = 13
0262
0263def Parser(source, encoding=None):
0264    return ExpatParser(source)
0265
0266
0267# Most of the following copied from ElementTree.XMLTreeBuilder
0268# Differences from ET implementation:
0269#
0270#   * Specialized for generator based processing. Elements are built
0271#     using a iterator approach instead of the TreeBuilder approach.
0272#
0273#   * Support for DOCTYPE, Comment, and Processing Instruction nodes.
0274
0275class ExpatParser(object):
0276
0277    def __init__(self, source, encoding=None):
0278        if not hasattr(source, 'read'):
0279            filename = source
0280            source = open(source, 'rb')
0281        else:
0282            filename = '<string>'
0283        self._filename = filename
0284        self._source = source
0285        self._parser = parser = expat.ParserCreate(encoding, "}")
0286        self._queue = []
0287
0288        # callbacks
0289        parser.DefaultHandler = self._default
0290        parser.StartElementHandler = self._start
0291        parser.EndElementHandler = self._end
0292        parser.CharacterDataHandler = self._data
0293        parser.ProcessingInstructionHandler = self._pi
0294        parser.CommentHandler = self._comment
0295        parser.StartNamespaceDeclHandler = self._start_ns
0296        parser.EndNamespaceDeclHandler = self._end_ns
0297        parser.XmlDeclHandler = self._xmldecl_handler
0298        parser.StartDoctypeDeclHandler = self._doctype_handler
0299
0300        # let expat do the buffering, if supported
0301        try:
0302            self._parser.buffer_text = 1
0303        except AttributeError:
0304            pass
0305        # use new-style attribute handling, if supported
0306        try:
0307            self._parser.ordered_attributes = 1
0308            self._parser.specified_attributes = 1
0309            parser.StartElementHandler = self._start_list
0310        except AttributeError:
0311            pass
0312        self._doctype = None
0313        # these should be come customizable at some point
0314        self.entity = default_entity_map
0315        self.external_dtd = default_external_dtd
0316        # setup entity handling
0317        self._parser.SetParamEntityParsing(
0318            expat.XML_PARAM_ENTITY_PARSING_ALWAYS)
0319        self._parser.ExternalEntityRefHandler = self._buildForeign
0320        self._parser.UseForeignDTD()
0321
0322    def _buildForeign(self, context, base, systemId, publicId):
0323        import StringIO
0324        parseableFile = StringIO.StringIO(default_external_dtd)
0325        original_parser = self._parser
0326        self._parser = self._parser.ExternalEntityParserCreate(context)
0327        self._parser.ParseFile(parseableFile)
0328        self._parser = original_parser
0329        return 1
0330
0331    def push(self, ev, stuff):
0332        self._queue.append( (ev, stuff) )
0333
0334    def _expat_stream(self):
0335        bufsize = 4 * 1024 # 4K
0336        feed = self.feed
0337        read = self._source.read
0338        done = 0
0339        while 1:
0340            while not done and len(self._queue) == 0:
0341                data = read(bufsize)
0342                if data == '':
0343                    self.close()
0344                    done = 1
0345                else:
0346                    feed(data)
0347            for i in self._queue:
0348                yield i
0349            self._queue = []
0350            if done:
0351                break
0352
0353    def __iter__(self):
0354        names = {}
0355
0356        # XXX: hack to enable old namespace. This should be removed for 0.7
0357        old_ns = 'http://naeblis.cx/ns/kid#'
0358        new_ns = 'http://purl.org/kid/ns#'
0359        def fixname(key):
0360            if key.startswith(old_ns):
0361                key = ''.join([new_ns, key[len(old_ns):]])
0362            try:
0363                name = names[key]
0364            except KeyError:
0365                name = key
0366                if "}" in name:
0367                    name = "{" + name
0368                names[key] = name
0369            return name
0370
0371        stack = []
0372        parent = None
0373        current = None
0374        for (ev, stuff) in self._expat_stream():
0375            if ev == TEXT:
0376                yield (TEXT, stuff)
0377            elif ev == START:
0378                tag, attrib_in = stuff
0379                tag = fixname(tag)
0380                attrib = {}
0381                if attrib_in:
0382                    for key, value in attrib_in.items():
0383                        attrib[fixname(key)] = value
0384                parent = current
0385                current = Element(tag, attrib)
0386                stack.append(current)
0387                yield (START, current)
0388            elif ev == END:
0389                current = stack.pop()
0390                assert fixname(stuff) == current.tag
0391                parent = len(stack) and stack[-1] or None
0392                yield (END, current)
0393            elif ev == COMMENT:
0394                current = Comment(stuff)
0395                yield (START, current)
0396                yield (END, current)
0397            elif ev == PI:
0398                current = ProcessingInstruction(stuff[0], stuff[1])
0399                yield (START, current)
0400                yield (END, current)
0401            else:
0402                yield (ev, stuff)
0403
0404    def feed(self, data):
0405        try:
0406            self._parser.Parse(data, 0)
0407        except expat.ExpatError, e:
0408            e.filename = self._filename
0409            if hasattr(self, '_sourcetext'):
0410                line = e.lineno
0411                e.source = self._sourcetext.split('\n', line)[-1]
0412            else:
0413                e.source = '???'
0414            raise e
0415
0416    def close(self):
0417        if hasattr(self, '_parser'):
0418            self._parser.Parse('', 1) # end of data
0419            del self._parser # get rid of circular references
0420
0421    def _start(self, tag, attrib_in):
0422        self._queue.append((START, (tag, attrib_in)))
0423
0424    def _start_list(self, tag, attrib_in):
0425        attrib = None
0426        if attrib_in:
0427            attrib = {}
0428            for i in range(0, len(attrib_in), 2):
0429                attrib[attrib_in[i]] = attrib_in[i+1]
0430        self._queue.append((START, (tag, attrib)))
0431
0432    def _data(self, text):
0433        self._queue.append((TEXT, text))
0434
0435    def _end(self, tag):
0436        self._queue.append((END, tag))
0437
0438    def _default(self, text):
0439        prefix = text[:1]
0440        if prefix == "&":
0441            # deal with undefined entities
0442            try:
0443                self._queue.append((TEXT, self.entity[text[1:-1]]))
0444            except KeyError:
0445                from xml.parsers import expat
0446                raise expat.error(
0447                    "undefined entity %s: line %d, column %d" %
0448                    (text, self._parser.ErrorLineNumber,
0449                    self._parser.ErrorColumnNumber)
0450                    )
0451        else:
0452            # XXX not sure what should happen here.
0453            # This gets: \n at the end of documents?, <![CDATA[, etc..
0454            pass
0455
0456    def _pi(self, target, data):
0457        self._queue.append((PI, (target, data)))
0458
0459    def _comment(self, text):
0460        self._queue.append((COMMENT, text))
0461
0462    def _start_ns(self, prefix, uri):
0463        # XXX: hack to enable backward compatibility for kid templates.
0464        #      remove in version 0.7
0465        if uri == 'http://naeblis.cx/ns/kid#':
0466            newuri = 'http://purl.org/kid/ns#'
0467            from warnings import warn
0468            warn('Document uses old kid namespace [%s] this should be changed'
0469                 ' to [%s].' % (uri, newuri))
0470            uri = newuri
0471        self._queue.append((START_NS, (prefix or '', uri)))
0472
0473    def _end_ns(self, prefix):
0474        self._queue.append((END_NS, prefix or ''))
0475
0476    def _xmldecl_handler(self, version, encoding, standalone):
0477        self._queue.append((XML_DECL, (version, encoding, standalone)))
0478
0479    def _doctype_handler(self, name, sysid, pubid, has_internal_subset):
0480        self._queue.append((DOCTYPE, (name, pubid, sysid)))
0481
0482
0483# utilities =================================================================
0484
0485
0486__all__ = ['Element', 'SubElement', 'Comment','ProcessingInstruction',
0487           'ElementStream', 'XML', 'document', 'Parser', 'ExpatParser',
0488           'START', 'END', 'TEXT', 'COMMENT', 'PI', 'XML_DECL', 'DOCTYPE']
kid-0.9.6/doc/html/kid/release.py.html0000644000175000017500000001130510460014362017412 0ustar tstanektstanekkid/release.py
0001version = "0.9.3"
0002author = "Ryan Tomayko"
0003email = "rtomayko@gmail.com"
0004copyright = "Copyright 2004-2006, Ryan Tomayko, David Stanek, Christoph Zwerschke, Daniel Miller"
0005license = "MIT" # http://www.opensource.org/licenses/mit-license.php
0006long_description = """Pythonic, XML Templating
0007
0008Kid is a simple, Python-based template language for generating and
0009transforming XML vocabularies. Kid was spawned as a result of a kinky love
0010triangle between XSLT, TAL, and PHP. We believe many of the best features
0011of these languages live on in Kid with much of the limitations and
0012complexity stamped out (well, eventually :).
0013
0014"""
kid-0.9.6/doc/html/kid/run.py.html0000644000175000017500000011325110443617634016615 0ustar tstanektstanekkid/run.py
0001#!/usr/bin/python
0002
0003# This module provides the "kid" command
0004
0005"""Usage: kid [options] file [args]
0006Expand a Kid template file.
0007
0008OPTIONS:
0009
0010  -e enc, --encoding=enc
0011          Specify the output character encoding.
0012          Default: utf-8
0013  -o outfile, --output=outfile
0014          Specify the output file.
0015          Default: standard output
0016  -s host:port, --server=host:port
0017          Specify the server address if
0018          you want to start the HTTP server.
0019          Instead of the Kid template,
0020          you can specify a base directory.
0021  -h, --help
0022          Print this help message and exit.
0023  -V, --version
0024          Print the Kid version number and exit.
0025
0026file:
0027  filename of the Kid template to be processed
0028  or "-" for reading the template from stdin.
0029
0030args:
0031  key=value or other arguments passed to the template.
0032"""
0033
0034__revision__ = "$Rev: 139 $"
0035__date__ = "$Date: 2005-03-14 19:28:22 -0500 (Mon, 14 Mar 2005) $"
0036__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0037__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0038__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0039
0040import sys
0041from os.path import dirname, abspath
0042from getopt import getopt, GetoptError as gerror
0043
0044import kid
0045
0046def main():
0047    # get options
0048    try:
0049        opts, args = getopt(sys.argv[1:], 'e:o:s:hV',
0050            ['encoding=', 'output=', 'server=', 'help', 'version'])
0051    except gerror, e:
0052        sys.stderr.write(str(e) + '\n')
0053        sys.stdout.write(__doc__)
0054        sys.exit(2)
0055    enc = 'utf-8'
0056    outfile = server = None
0057    for o, a in opts:
0058        if o in ('-e', '--encoding'):
0059            enc = a
0060        elif o in ('-o', '--output'):
0061            outfile = a
0062        elif o in ('-s', '--server'):
0063            server = a
0064        elif o in ('-h', '--help'):
0065            sys.stdout.write(__doc__)
0066            sys.exit(0)
0067        elif o in ('-V', '--version'):
0068            from kid import __version__
0069            sys.stdout.write('Kid %s\n' % __version__)
0070            sys.exit(0)
0071    if server is None:
0072        if args:
0073            # get template file
0074            f = args.pop(0)
0075            sys.argv = [f]
0076            if f != '-':
0077                # make sure template dir is on sys.path
0078                path = abspath(dirname(f))
0079                if not path in sys.path:
0080                    sys.path.insert(0, path)
0081            else:
0082                f = sys.stdin.read()
0083            # get arguments for the template file
0084            kw = {}
0085            while args:
0086                a = args.pop(0).split('=', 1)
0087                if len(a) > 1:
0088                    kw[a[0]] = a[1]
0089                else:
0090                    sys.argv.append(a[0])
0091            # do not run as __main__ module
0092            sys.modules['__kid_main__'] = sys.modules['__main__']
0093            __name__ = '__kid_main__'
0094            del sys.modules['__main__']
0095            # load kid template as __main__ module
0096            module = kid.load_template(f, name='__main__', cache=0)
0097            # execute the template and write output
0098            if not outfile:
0099                    outfile = sys.stdout
0100            module.write(outfile, encoding=enc, **kw)
0101        else:
0102            sys.stderr.write('kid: No template file specified.\n')
0103            sys.stderr.write("     Try 'kid --help' for usage information.\n")
0104            sys.exit(2)
0105    else:
0106        if len(args) < 2:
0107            if outfile:
0108                stderr = file(outfile, 'a', 1)
0109                sys.stderr = stderr
0110            sys.stdout.write('Starting HTTP server ...\n')
0111            if args:
0112                # get base directory
0113                basedir = args.pop(0)
0114                from os import chdir
0115                chdir(basedir)
0116            from os import getcwd
0117            basedir = getcwd()
0118            sys.stdout.write('Base directory: %s\n' % basedir)
0119            if outfile:
0120                sys.stdout.write('Server log: %s\n' % outfile)
0121            if server == '-':
0122                server = 'localhost'
0123            sys.argv[1:] = [server]
0124            from kid.server import main
0125            main()
0126            if outfile:
0127                sys.stderr = sys.__stderr__
0128                out.close()
0129        else:
0130            sys.stderr.write('kid: Server does not need additional arguments.\n')
0131            sys.stderr.write("     Try 'kid --help' for usage information.\n")
0132            sys.exit(2)
0133
0134if __name__ == '__main__':
0135    main()
kid-0.9.6/doc/html/kid/serialization.py.html0000644000175000017500000047635410457613120020675 0ustar tstanektstanekkid/serialization.py
0001"""Infoset serialization formats (XML, XHTML, HTML, etc)"""
0002
0003from __future__ import generators
0004
0005__revision__ = "$Rev$"
0006__date__ = "$Date: 2005-02-16 15:43:38 -0500 (Wed, 16 Feb 2005) $"
0007__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0008__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0009__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0010
0011import re
0012
0013from kid.et import *
0014from kid.pull import *
0015from kid.pull import _coalesce
0016
0017# bring in well known namespaces
0018import kid.namespace as namespace
0019
0020__all__ = ['doctypes', 'Serializer', 'XMLSerializer', 'HTMLSerializer']
0021
0022# some doctypes. you can pass strings from here or doctype tuples to
0023# Serializers
0024doctypes = {
0025    'html-strict'  : ('HTML', '-//W3C//DTD HTML 4.01//EN',
0026                      'http://www.w3.org/TR/html4/strict.dtd'),
0027    'html'         : ('HTML', '-//W3C//DTD HTML 4.01 Transitional//EN',
0028                      'http://www.w3.org/TR/html4/loose.dtd'),
0029    'xhtml-strict' : ('html', '-//W3C//DTD XHTML 1.0 Strict//EN',
0030                      'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'),
0031    'xhtml'        : ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
0032                      'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd') }
0033
0034
0035class Serializer(object):
0036
0037    namespaces = namespace.namespaces
0038    encoding = 'utf-8'
0039    balanced_blocks = False
0040    strip_whitespace = 0
0041
0042    def __init__(self, encoding=None, src_encoding="utf-8"):
0043        if encoding is not None:
0044            self.encoding = encoding
0045        self.src_encoding = src_encoding
0046
0047    def has_only_pcdata(self, tagname):
0048        return False
0049
0050    def serialize(self, stream, encoding=None, fragment=0):
0051        text = list(self.generate(stream, encoding, fragment))
0052        return ''.join(text)
0053
0054    def write(self, stream, file, encoding=None, fragment=0):
0055        needs_closed = False
0056        if not hasattr(file, 'write'):
0057            needs_closed = True
0058            file = open(file, 'wb')
0059        try:
0060            write = file.write
0061            for text in self.generate(stream, encoding, fragment):
0062                write(text)
0063        finally:
0064            # only close a file if it was opened locally
0065            if needs_closed:
0066                file.close()
0067
0068    def generate(self, stream, encoding=None, fragment=0):
0069        pass
0070
0071    def apply_filters(self, stream):
0072        stream = _coalesce(stream, self.src_encoding)
0073        if self.strip_whitespace:
0074            stream = self.whitespace_filter(stream)
0075        else:
0076            if self.balanced_blocks:
0077                stream = self.balancing_filter(stream)
0078        return stream
0079
0080    def balancing_filter(self, stream):
0081        line_collapse = re.compile('\n{2,}')
0082        text = ''
0083        hops = 0
0084        for ev, item in stream:
0085            if ev == TEXT:
0086                text = item
0087                hops = 0
0088            elif ev in (START, END) and item.tag != Fragment:
0089                if hops > 0:
0090                    if text and text.strip() == '':
0091                        yield (TEXT, line_collapse.sub('\n', text))
0092                elif text:
0093                    if text.strip() == '':
0094                        yield (TEXT, line_collapse.sub('\n', text))
0095                    else:
0096                        yield (TEXT, text)
0097                yield (ev, item)
0098                hops+=1
0099                # pre-tag indentation was used.
0100                # Make sure it's not used again for #PCDATA-sensitive elements
0101                if ev == START and (self.has_only_pcdata(item.tag)
0102                        or item.tag == Comment):
0103                    text = ''
0104            else:
0105                yield (ev, item)
0106
0107    def whitespace_filter(self, stream):
0108        for ev, item in stream:
0109            if ev == TEXT:
0110                yield (TEXT, item.strip())
0111            else:
0112                yield (ev, item)
0113
0114class XMLSerializer(Serializer):
0115
0116    decl = 1
0117    doctype = None
0118    cdata_elements = []
0119
0120    def __init__(self, encoding=None, decl=None, doctype=None,
0121                 namespaces=None):
0122        Serializer.__init__(self, encoding)
0123        if decl is not None:
0124            self.decl = decl
0125        if doctype is not None:
0126            self.doctype = doctype
0127        if isinstance(self.doctype, basestring):
0128            # allow doctype strings
0129            self.doctype = doctypes[self.doctype]
0130        if namespaces:
0131            self.namespaces = namespaces
0132
0133    def can_be_empty_element(self, ns_stack, item_name):
0134        return True
0135
0136    def generate(self, stream, encoding=None, fragment=0):
0137        """Serializes an event stream to bytes of the specified encoding.
0138
0139        This function yields an encoded string over and over until the
0140        stream is exhausted.
0141
0142        """
0143
0144        encoding = encoding or self.encoding or 'utf-8'
0145        escape_cdata = XMLSerializer.escape_cdata
0146        escape_attrib = XMLSerializer.escape_attrib
0147
0148        lastev = None
0149        stream = iter(stream)
0150        names = NamespaceStack(self.namespaces)
0151        if not fragment:
0152            if self.decl:
0153                yield '<?xml version="1.0" encoding="%s"?>\n' % encoding
0154            if self.doctype is not None:
0155                yield serialize_doctype(self.doctype) + '\n'
0156        text = None
0157        for ev, item in self.apply_filters(stream):
0158            if ev in (START, END) and item.tag == Fragment:
0159                continue
0160            elif ev == TEXT:
0161                if text is not None:
0162                    text = u''.join([text, item])
0163                else:
0164                    text = item
0165                continue
0166            if lastev == START:
0167                if ev == END and (not text or not text.strip()) and self.can_be_empty_element(names, item.tag):
0168                    yield ' />'
0169                    lastev = END
0170                    text = None
0171                    names.pop()
0172                    continue
0173                yield ">"
0174            if text:
0175                yield escape_cdata(text, encoding)
0176                text = None
0177            if ev == START:
0178                if item.tag == Comment:
0179                    yield "<!--%s-->" % item.text.encode(encoding)
0180                    lastev = COMMENT
0181                    continue
0182                elif item.tag == ProcessingInstruction:
0183                    yield "<?%s?>" % item.text.encode(encoding)
0184                    lastev = PI
0185                    continue
0186                else:
0187                    tag = item.tag
0188                    names.push(namespaces(item, remove=1))
0189                    qname = names.qname(tag, default=1)
0190                    yield "<" + qname.encode(encoding)
0191                    attrs = item.attrib.items()
0192                    if attrs:
0193                        for k, v in attrs:
0194                            qname = names.qname(k, default=0)
0195                            yield ' %s="%s"' % (qname.encode(encoding),
0196                                                escape_attrib(v, encoding))
0197                    for prefix, uri in names.current.items():
0198                        if prefix == '':
0199                            yield ' xmlns="%s"' % escape_attrib(uri, encoding)
0200                        else:
0201                            yield ' xmlns:%s="%s"' % (prefix.encode(encoding),
0202                                                      escape_attrib(uri, encoding))
0203            elif ev == END and item.tag not in (Comment, ProcessingInstruction):
0204                qname = names.qname(item.tag, default=1)
0205                yield "</%s>" % qname.encode(encoding)
0206                names.pop()
0207            lastev = ev
0208        return
0209
0210    def escape_cdata(text, encoding=None):
0211        """Escape character data."""
0212        try:
0213            if encoding:
0214                try:
0215                    text = text.encode(encoding)
0216                except UnicodeError:
0217                    return encode_entity(text)
0218            text = text.replace("&", "&amp;")
0219            text = text.replace("<", "&lt;")
0220            return text
0221        except (TypeError, AttributeError):
0222            raise_serialization_error(text)
0223    escape_cdata = staticmethod(escape_cdata)
0224
0225    def escape_attrib(text, encoding=None):
0226        """Escape attribute value."""
0227        try:
0228            if encoding:
0229                try:
0230                    text = text.encode(encoding)
0231                except UnicodeError:
0232                    return encode_entity(text)
0233            text = text.replace("&", "&amp;")
0234            text = text.replace("<", "&lt;")
0235            text = text.replace("\"", "&quot;")
0236            return text
0237        except (TypeError, AttributeError):
0238            raise_serialization_error(text)
0239    escape_attrib = staticmethod(escape_attrib)
0240
0241
0242# sets
0243try:
0244    set
0245except NameError:
0246    try:
0247        from sets import Set as set
0248    except ImportError:
0249        def set(seq):
0250            return seq
0251
0252import kid.namespace as namespace
0253xhtml = namespace.xhtml.uri
0254import string
0255
0256class HTMLSerializer(Serializer):
0257
0258    doctype = doctypes['html']
0259    transpose = string.upper
0260    transpose = staticmethod(transpose)
0261    inject_type = 1
0262    empty_elements = set(['area', 'base', 'basefont', 'br', 'col', 'frame',
0263                          'hr', 'img', 'input', 'isindex', 'link', 'meta',
0264                          'param'])
0265    # These element tags should not be indented
0266    elements_with_pcdata = set(['option', 'textarea', 'fieldset', 'title'])
0267    noescape_elements = set(['script', 'style'])
0268    boolean_attributes = set(['selected', 'checked', 'compact', 'declare',
0269                          'defer', 'disabled', 'ismap', 'multiple', 'nohref',
0270                          'noresize', 'noshade', 'nowrap'])
0271
0272    def __init__(self, encoding='utf-8', doctype=None, transpose=None):
0273        Serializer.__init__(self, encoding)
0274        if doctype:
0275            self.doctype = doctype
0276        if isinstance(self.doctype, basestring):
0277            # allow doctype strings
0278            self.doctype = doctypes[self.doctype]
0279        if transpose:
0280            self.transpose = transpose
0281
0282    def has_only_pcdata(self, tagname):
0283        if isinstance(tagname, basestring) and tagname[0] == '{':
0284            tagname = tagname.split('}')[1]
0285        return tagname in self.elements_with_pcdata
0286
0287    def generate(self, stream, encoding=None, fragment=0):
0288        """Serializes an event stream to bytes of the specified encoding.
0289
0290        This function yields an encoded string over and over until the
0291        stream is exhausted.
0292
0293        """
0294
0295        encoding = encoding or self.encoding or 'utf-8'
0296
0297        escape_cdata = HTMLSerializer.escape_cdata
0298        escape_attrib = HTMLSerializer.escape_attrib
0299        noescape_elements = self.noescape_elements
0300        boolean_attributes = self.boolean_attributes
0301        empty_elements = self.empty_elements
0302
0303        names = NamespaceStack(self.namespaces)
0304
0305        def grok_name(tag):
0306            if tag[0] == '{':
0307                uri, localname = tag[1:].split('}', 1)
0308            else:
0309                uri, localname = None, tag
0310            if uri and uri != xhtml:
0311                qname = names.qname(tag, default=0)
0312            else:
0313                qname = localname
0314                if self.transpose is not None:
0315                    qname = self.transpose(qname)
0316            return (uri, localname, qname)
0317
0318        attr_http_equiv = 'http-equiv'
0319        attr_content = 'content'
0320        if self.transpose:
0321            attr_http_equiv = self.transpose('http-equiv')
0322            attr_content = self.transpose('content')
0323
0324        current = None
0325        stack = [current]
0326        stream = iter(stream)
0327        if not fragment and self.doctype is not None:
0328            yield serialize_doctype(self.doctype) + '\n'
0329        for ev, item in self.apply_filters(stream):
0330            if ev == TEXT and item:
0331                escape = current not in noescape_elements
0332                yield escape_cdata(item, encoding, escape)
0333            elif ev == START:
0334                if item.tag == Comment:
0335                    yield "<!--%s-->" % item.text.encode(encoding)
0336                    lastev = COMMENT
0337                    continue
0338                elif item.tag == ProcessingInstruction:
0339                    yield "<?%s>" % item.text.encode(encoding)
0340                    lastev = PI
0341                    continue
0342                elif item.tag == Fragment:
0343                    continue
0344                else:
0345                    names.push(namespaces(item, remove=1))
0346                    tag = item.tag
0347                    (uri, localname, qname) = grok_name(tag)
0348
0349                    # push this name on the stack so we know where we are
0350                    current = qname.lower()
0351                    stack.append(current)
0352
0353                    yield "<" + qname.encode(encoding)
0354                    attrs = item.attrib.items()
0355                    if attrs:
0356                        for k, v in attrs:
0357                            (u, l, q) = grok_name(k)
0358                            lq = q.lower()
0359                            if lq == 'xml:lang': continue
0360                            if lq in boolean_attributes:
0361                                # XXX: what if v is 0, false, or no.
0362                                #      should we omit the attribute?
0363                                yield ' %s' % q.encode(encoding)
0364                            else:
0365                                yield ' %s="%s"' % (q.encode(encoding),
0366                                                    escape_attrib(v, encoding))
0367                    yield ">"
0368                    if self.inject_type:
0369                        if current == 'head':
0370                            (uri, localname, qname) = grok_name("meta")
0371                            yield '<%s %s="text/html; charset=%s"'                                     ' %s="Content-Type">'                                     % (qname.encode(encoding),
0374                                     attr_content,
0375                                     encoding,
0376                                     attr_http_equiv)
0377
0378            elif ev == END and item.tag not in (Comment,
0379                                                ProcessingInstruction,
0380                                                Fragment):
0381                current = stack.pop()
0382                if current not in empty_elements:
0383                    tag = item.tag
0384                    (uri, localname, qname) = grok_name(tag)
0385                    yield "</%s>" % qname.encode(encoding)
0386                current = stack[-1]
0387                names.pop()
0388        return
0389
0390    def escape_cdata(text, encoding=None, escape=1):
0391        """Escape character data."""
0392        try:
0393            if encoding:
0394                try:
0395                    text = text.encode(encoding)
0396                except UnicodeError:
0397                    return encode_entity(text)
0398            if escape:
0399                text = text.replace("&", "&amp;")
0400                text = text.replace("<", "&lt;")
0401            return text
0402        except (TypeError, AttributeError):
0403            raise_serialization_error(text)
0404    escape_cdata = staticmethod(escape_cdata)
0405
0406    def escape_attrib(text, encoding=None):
0407        """Escape attribute value."""
0408        try:
0409            if encoding:
0410                try:
0411                    text = text.encode(encoding)
0412                except UnicodeError:
0413                    return encode_entity(text)
0414            text = text.replace("&", "&amp;")
0415            text = text.replace("\"", "&quot;")
0416            return text
0417        except (TypeError, AttributeError):
0418            raise_serialization_error(text)
0419    escape_attrib = staticmethod(escape_attrib)
0420
0421class XHTMLSerializer(XMLSerializer):
0422    empty_elements = [namespace.xhtml.clarkname(name) for name in HTMLSerializer.empty_elements]
0423    elements_with_pcdata = [namespace.xhtml.clarkname(name) for name in HTMLSerializer.elements_with_pcdata]
0424
0425    def can_be_empty_element(self, ns_stack, tagname):
0426        return tagname in self.empty_elements
0427
0428    def has_only_pcdata(self, tagname):
0429        return tagname in self.elements_with_pcdata
0430
0431class PlainSerializer(Serializer):
0432
0433    def generate(self, stream, encoding=None, fragment=0):
0434        # XXX: Should this be ASCII?
0435        encoding = encoding or self.encoding or 'utf-8'
0436        for ev, item in self.apply_filters(stream):
0437            if ev == TEXT:
0438                yield item
0439
0440
0441class NamespaceStack:
0442
0443    """Maintains a stack of namespace prefix to URI mappings."""
0444
0445    def __init__(self, default_map=namespace.namespaces):
0446        self.stack = []
0447        self.default_map = default_map
0448        self.push()
0449        self.ns_count = 0
0450
0451    def push(self, names=None):
0452        if names is None:
0453            names = {}
0454        self.current = names
0455        self.stack.insert(0, self.current)
0456
0457    def pop(self):
0458        ns = self.stack[0]
0459        del self.stack[0]
0460        if self.stack:
0461            self.current = self.stack[0]
0462        return ns
0463
0464    def resolve_prefix(self, uri, default=1):
0465        """Figure out prefix given a URI."""
0466
0467        if uri == 'http://www.w3.org/XML/1998/namespace':
0468            return 'xml'
0469        # first check if the default is correct
0470        is_default = -1
0471        prefix = None
0472        for names in self.stack:
0473            for k, v in names.items(): # (k,v) = (prefix, uri)
0474                if default and is_default == -1 and k == '':
0475                    # this is the current default namespace
0476                    is_default = (v == uri)
0477                    if (default and is_default) or prefix:
0478                        break
0479                if v == uri and k != '':
0480                    prefix = k
0481                    if is_default > -1:
0482                        break
0483        if default and is_default == 1:
0484            return ''
0485        elif prefix:
0486            return prefix
0487        else:
0488            return None
0489
0490    def resolve_uri(self, prefix):
0491        """Figure out URI given a prefix."""
0492
0493        if prefix == 'xml':
0494            return 'http://www.w3.org/XML/1998/namespace'
0495        for names in self.stack:
0496            uri = names.get(prefix)
0497            if uri:
0498                return uri
0499        return None
0500
0501    def qname(self, cname, default=0):
0502        if isinstance(cname, QName):
0503            cname = cname.text
0504        if cname[0] != '{':
0505            # XXX: need to make sure default namespace is "no-namespace"
0506            return cname
0507        uri, localname = cname[1:].split('}', 1)
0508        prefix = self.resolve_prefix(uri, default)
0509        if prefix is None:
0510            # see if we have it in our default map
0511            prefix = self.default_map.get(uri)
0512            if prefix is not None:
0513                self.current[prefix] = uri
0514            else:
0515                if default and not self.current.has_key(''):
0516                    prefix = ''
0517                    self.current[prefix] = uri
0518                else:
0519                    self.ns_count += 1
0520                    # XXX : need to check for collisions here.
0521                    prefix = 'ns%d' % self.ns_count
0522                    self.current[prefix] = uri
0523        if prefix != '':
0524            return '%s:%s' % (prefix, localname)
0525        else:
0526            return localname
0527
0528def serialize_doctype(doctype):
0529    return '<!DOCTYPE %s PUBLIC "%s" "%s">' % doctype
kid-0.9.6/doc/html/kid/server.py.html0000644000175000017500000020422010415050402017273 0ustar tstanektstanekkid/server.py
0001"""Kid-savvy HTTP Server.
0002
0003Written by Christoph Zwerschke based on CGIHTTPServer 0.4.
0004
0005This module builds on SimpleHTTPServer by implementing GET and POST
0006requests to Kid templates.
0007
0008In all cases, the implementation is intentionally naive -- all
0009requests are executed by the same process and sychronously.
0010
0011Code to create and run the server looks like this:
0012
0013    from kid.server import HTTPServer
0014    host, port = 'localhost', 8000
0015    HTTPServer((host, port)).serve_forever()
0016
0017This serves files and kid templates from the current directory
0018and any of its subdirectories.
0019
0020If you want the server to be accessible via the network,
0021use your local host name or an empty string as the host.
0022(Security warning: Don't do this unless you are inside a firewall.)
0023
0024You can also call the test() function to run the server, or run this
0025module as a script, providing host and port as command line arguments.
0026
0027The Kid templates have access to the following predefined objects:
0028
0029    FieldStorage (access to GET/POST variables)
0030    environ (CGI environment)
0031    request (the request handler object)
0032
0033Here is a simple Kid template you can use to test the server:
0034
0035    <html xmlns="http://www.w3.org/1999/xhtml"
0036    xmlns:py="http://purl.org/kid/ns#">
0037    <head><title>Python Expression Evaluator</title></head>
0038    <body>
0039    <h3 py:if="FieldStorage.has_key('expr')">
0040    ${FieldStorage.getvalue('expr')} =
0041    ${eval(FieldStorage.getvalue('expr'))}</h3>
0042    <form action="${environ['SCRIPT_NAME']}" method="post">
0043    <h3>Enter a Python expression:</h3>
0044    <input name="expr" type="text" size="40" maxlength="40" />
0045    <input type="submit" value="Submit" />
0046    </form>
0047    </body>
0048    </html>
0049"""
0050
0051__revision__ = "$Rev: 1 $"
0052__date__ = "$Date: 2005-01-01 00:00:00 +0000 (Mon, 1 Jan 2005) $"
0053__author__ = "Christoph Zwerschke (cito@online.de)"
0054__copyright__ = "Copyright 2005, Christoph Zwerschke"
0055__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0056
0057
0058__all__ = ["HTTPServer", "HTTPRequestHandler"]
0059
0060import os.path
0061from urllib import unquote
0062from BaseHTTPServer import HTTPServer as BaseHTTPServer
0063from SimpleHTTPServer import SimpleHTTPRequestHandler
0064from cgi import FieldStorage
0065from kid import load_template
0066
0067
0068default_host = 'localhost'
0069default_port = 8000
0070
0071
0072class HTTPRequestHandler(SimpleHTTPRequestHandler):
0073
0074    """Complete HTTP server with GET, HEAD and POST commands.
0075    GET and HEAD also support running Kid templates.
0076    The POST command is *only* implemented for Kid templates."""
0077
0078    def do_POST(self):
0079        """Serve a POST request implemented for Kid templates."""
0080        if self.is_kid():
0081            self.run_kid()
0082        else:
0083            self.send_error(501, "Can only POST to Kid templates")
0084
0085    def send_head(self):
0086        """Version of send_head that supports Kid templates."""
0087        if self.is_kid():
0088            return self.run_kid()
0089        else:
0090            return SimpleHTTPRequestHandler.send_head(self)
0091
0092    def is_kid(self):
0093        """Test whether self.path corresponds to a Kid template.
0094
0095        The default implementation tests whether the path ends
0096        with one of the strings in the list self.kid_extensions.
0097
0098        """
0099        path = self.path
0100        i = path.rfind('?')
0101        if i >= 0:
0102            path, query = path[:i], path[i+1:]
0103        else:
0104            query = ''
0105        for x in self.kid_extensions:
0106            if path.endswith(x):
0107                self.cgi_info = path, query
0108                return True
0109        return False
0110
0111    kid_extensions = ['.kid', '.kid.html']
0112
0113    def run_kid(self):
0114        """Execute a Kid template."""
0115        scriptname, query = self.cgi_info
0116        scriptfile = self.translate_path(scriptname)
0117        if not os.path.exists(scriptfile):
0118            self.send_error(404, "No such Kid template (%r)"
0119                % scriptname)
0120            return
0121        if not os.path.isfile(scriptfile):
0122            self.send_error(403, "Kid template is not a plain file (%r)"
0123                % scriptname)
0124            return
0125
0126        env = {}
0127        env['SERVER_SOFTWARE'] = self.version_string()
0128        env['SERVER_NAME'] = self.server.server_name
0129        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
0130        env['SERVER_PROTOCOL'] = self.protocol_version
0131        env['SERVER_PORT'] = str(self.server.server_port)
0132        env['REQUEST_METHOD'] = self.command
0133        uqpath = unquote(scriptname)
0134        env['PATH_INFO'] = uqpath
0135        env['PATH_TRANSLATED'] = self.translate_path(uqpath)
0136        env['SCRIPT_NAME'] = scriptname
0137        if query:
0138            env['QUERY_STRING'] = query
0139        host = self.address_string()
0140        if host != self.client_address[0]:
0141            env['REMOTE_HOST'] = host
0142        env['REMOTE_ADDR'] = self.client_address[0]
0143        authorization = self.headers.getheader("authorization")
0144        if authorization:
0145            authorization = authorization.split()
0146            if len(authorization) == 2:
0147                import base64, binascii
0148                env['AUTH_TYPE'] = authorization[0]
0149                if authorization[0].lower() == "basic":
0150                    try:
0151                        authorization = base64.decodestring(authorization[1])
0152                    except binascii.Error:
0153                        pass
0154                    else:
0155                        authorization = authorization.split(':')
0156                        if len(authorization) == 2:
0157                            env['REMOTE_USER'] = authorization[0]
0158        if self.headers.typeheader is None:
0159            env['CONTENT_TYPE'] = self.headers.type
0160        else:
0161            env['CONTENT_TYPE'] = self.headers.typeheader
0162        length = self.headers.getheader('content-length')
0163        if length:
0164            env['CONTENT_LENGTH'] = length
0165        accept = []
0166        for line in self.headers.getallmatchingheaders('accept'):
0167            if line[:1] in "\t\n\r ":
0168                accept.append(line.strip())
0169            else:
0170                accept = accept + line[7:].split(',')
0171        env['HTTP_ACCEPT'] = ','.join(accept)
0172        ua = self.headers.getheader('user-agent')
0173        if ua:
0174            env['HTTP_USER_AGENT'] = ua
0175        co = filter(None, self.headers.getheaders('cookie'))
0176        if co:
0177            env['HTTP_COOKIE'] = ', '.join(co)
0178
0179        self.send_response(200, "Script output follows")
0180
0181        # Execute template in this process
0182        try:
0183            template_module = load_template(scriptfile, cache=1)
0184            template = template_module.Template(
0185                request=self, environ=env,
0186                FieldStorage=FieldStorage(self.rfile, environ=env))
0187            s = str(template)
0188            self.send_header("Content-type", "text/html")
0189            self.send_header("Content-Length", str(len(s)))
0190            self.end_headers()
0191            self.wfile.write(s)
0192        except Exception, e:
0193            self.log_error("Kid template exception: %s", str(e))
0194        else:
0195            self.log_message("Kid template exited OK")
0196
0197
0198class HTTPServer(BaseHTTPServer):
0199
0200    def __init__(self,
0201        server_address = None,
0202        RequestHandlerClass = HTTPRequestHandler):
0203        if server_address is None:
0204            server_address = (default_host, default_port)
0205        BaseHTTPServer.__init__(self,
0206            server_address, HTTPRequestHandler)
0207
0208
0209def test(server_address = None,
0210            HandlerClass = HTTPRequestHandler,
0211            ServerClass = HTTPServer,
0212            protocol = "HTTP/1.0"):
0213    """Test the HTTP request handler class."""
0214
0215    HandlerClass.protocol_version = protocol
0216    server = ServerClass(server_address, HandlerClass)
0217    sa = server.socket.getsockname()
0218    print "Serving HTTP on", sa[0], "port", sa[1], "..."
0219    server.serve_forever()
0220
0221
0222def main():
0223    """This runs the Kid-savvy HTTP server.
0224
0225    Provide host and port as command line arguments.
0226    The current directory serves as the root directory.
0227
0228    """
0229
0230    from sys import argv, exit
0231
0232    if len(argv) > 3:
0233        print "Usage:", argv[0], "[host]:[port]"
0234        exit(2)
0235
0236    if len(argv) < 2:
0237        server_address = (default_host, default_port)
0238    else:
0239        if len(argv) == 3:
0240            host = argv[1]
0241            port = argv[2]
0242        else:
0243            host = argv[1].split(':', 1)
0244            if len(host) < 2:
0245                host = host[0]
0246                if host.isdigit():
0247                    port = host
0248                    host = ''
0249                else:
0250                    port = None
0251            else:
0252                host, port = host
0253        if port:
0254            if port.isdigit():
0255                port = int(port)
0256            else:
0257                print "Bad port number."
0258                exit(1)
0259        else:
0260            port = default_port
0261        server_address = (host, port)
0262
0263    test(server_address)
0264
0265
0266if __name__ == '__main__':
0267    main()
kid-0.9.6/doc/html/kid/template_util.py.html0000644000175000017500000014452110422400245020646 0ustar tstanektstanekkid/template_util.py
0001"""Utility functions used by generated kid modules.
0002"""
0003
0004from __future__ import generators
0005
0006__revision__ = "$Rev: 314 $"
0007__date__ = "$Date: 2006-04-18 00:37:38 +0000 (Tue, 18 Apr 2006) $"
0008__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0009__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0010__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0011
0012import inspect
0013import sys
0014from types import TypeType, ModuleType
0015from os.path import join, normpath, abspath, dirname
0016
0017# these are for use by template code
0018import kid
0019from kid.pull import XML, document, ElementStream,                        Element, SubElement, Comment, ProcessingInstruction,                        START, END, TEXT, START_NS, COMMENT, PI, DOCTYPE,                        XML_DECL, to_unicode
0023
0024class TemplateNotFound(Exception): pass
0025
0026_local_excludes = ['generate', 'module', 'pull', 'serialize', 'transform', 'write']
0027def get_locals(inst, _locals=None):
0028    if _locals is None:
0029        _locals = {}
0030    ls = []
0031    local_excludes = _local_excludes # local copy
0032    for var, value in inspect.getmembers(inst):
0033        if not var.startswith('_') and not var in local_excludes                   and var not in _locals:
0035            ls.append('%s=self.%s' % (var, var))
0036    return ';'.join(ls)
0037
0038def get_base_class(thing, from_file):
0039    if thing is None or thing is kid.BaseTemplate:
0040        cls = kid.BaseTemplate
0041    elif isinstance(thing, basestring):
0042        path = kid.path.find(thing, from_file)
0043        cls = kid.load_template(path).Template
0044    elif isinstance(thing, TypeType):
0045        cls = thing
0046    elif isinstance(thing, ModuleType):
0047        cls = thing.Template
0048    else:
0049        raise TemplateNotFound("Could not find template: %r" % thing)
0050    return cls
0051
0052def make_attrib(attrib, encoding=None):
0053    if attrib is None:
0054        return {}
0055    if encoding is None:
0056        encoding = sys.getdefaultencoding()
0057
0058    for (k, v) in attrib.items():
0059        if isinstance(v, list):
0060            ls = [to_unicode(i, encoding) for i in v if i is not None]
0061            if not ls:
0062                del attrib[k]
0063            else:
0064                attrib[k] = ''.join(ls)
0065        else:
0066            attrib[k] = to_unicode(v, encoding)
0067    return attrib
0068
0069def generate_content(content, parent=None):
0070    if content is None:
0071        return []
0072    if isinstance(content, basestring):
0073        return [(TEXT, content)]
0074    elif hasattr(content, 'tag') and hasattr(content, 'attrib'):
0075        # if we get an Element back, make it an ElementStream
0076        return ElementStream(content)
0077    elif hasattr(content, '__iter__'):
0078        # if we get an iterable back, there are two cases:
0079        if hasattr(content, '__getitem__'):
0080            # if we get a sequence back, we simply flatten it
0081            def flatten(seq):
0082                for i in seq:
0083                    for ev, item in generate_content(i):
0084                        yield ev, item
0085            return flatten(content)
0086        else:
0087            # if we get a generator back, pray it's an ElementStream
0088            return content
0089    else:
0090        return [(TEXT, unicode(content))]
0091
0092def filter_names(names, omit_list):
0093    for ns in names.keys():
0094        if ns in omit_list:
0095            del names[ns]
0096    return names
0097
0098def update_dict(a, s, globals, locals):
0099    """Update dictionary a from keyword argument string s."""
0100    try:
0101        strings = None
0102        try:
0103            b = eval('dict(%s)' % s, globals, locals)
0104        except (TypeError, SyntaxError):
0105            # TypeErrror happens with Python <2.3, because building
0106            # dictionaries from keyword arguments was not supported.
0107            # SyntaxError can happen if one of the keyword arguments
0108            # is the same as a Python keyword (e.g. "class") or if it is a
0109            # qualified name containing a namespace prefixed with a colon.
0110            # So in these cases we parse the keyword arguments manually:
0111            try:
0112                from cStringIO import StringIO
0113            except ImportError:
0114                from StringIO import StringIO
0115            from tokenize import generate_tokens
0116            from token import NAME, OP
0117            depth, types, strings = 0, [], []
0118            for token in generate_tokens(StringIO(s).readline):
0119                type_, string = token[:2]
0120                if type_ == OP:
0121                    if string == '=':
0122                        if depth == 0:
0123                            if len(types) > 0                                   and types[-1] == NAME and strings[-1]:
0125                                if len(types) > 2                                       and types[-2] == OP and strings[-2] == ':'                                       and types[-3] == NAME and strings[-3]:
0128                                    strings[-3:] = ["'%s'" % ''.join(strings[-3:])]
0129                                else:
0130                                    strings[-1] = "'%s'" % strings[-1]
0131                                string = ':'
0132                    elif string in '([{':
0133                        depth += 1
0134                    elif depth > 0 and string in ')]}':
0135                        depth -= 1
0136                types.append(type_)
0137                strings.append(string)
0138            b = eval('{%s}' % ''.join(strings), globals, locals)
0139    except Exception:
0140        exc_type, exc_obj, tb = sys.exc_info()
0141        if strings is None:
0142            code = s
0143        else:
0144            code = "%s -> %s" % (s, ''.join(strings))
0145        raise exc_type("%s in %s" % (exc_obj, code))
0146    for k in b.keys():
0147        if b[k] is None:
0148            del b[k]
0149            if k in a:
0150                del a[k]
0151    a.update(b)
0152    return a
0153
0154__all__ = ['XML', 'document', 'ElementStream',
0155           'Element', 'SubElement', 'Comment', 'ProcessingInstruction',
0156           'START', 'END', 'TEXT', 'START_NS', 'COMMENT',
0157           'PI', 'DOCTYPE', 'XML_DECL']
kid-0.9.6/doc/html/kid/util.py.html0000644000175000017500000002221610415050402016745 0ustar tstanektstanekkid/util.py
0001class QuickTextReader(object):
0002    def __init__(self, text):
0003        self.text = text
0004
0005    def read(self, amount):
0006        t = self.text
0007        self.text = ''
0008        return t
0009
0010def xml_sniff(text):
0011    """Sniff text to see if it looks like XML.
0012    Return 1 if text looks like XML, otherwise return 0.
0013    """
0014    for x in text:
0015        if x in '\t\r\n ':
0016            continue
0017        elif x == '<':
0018            return 1
0019        else:
0020            return 0
0021
0022from urllib import splittype
0023def open_resource(uri, mode='rb'):
0024    """Generic resource opener."""
0025    (scheme, rest) = splittype(uri)
0026    if not scheme or (len(scheme) == 1 and rest.startswith('\\')):
0027        return open(uri, mode)
0028    else:
0029        import urllib2
0030        return urllib2.urlopen(uri)
kid-0.9.6/doc/html/almodovar.css0000644000175000017500000001005310443722745016417 0ustar tstanektstanek/* Theme Name: Almodovar Theme URI: http://blog.ratterobert.com/archiv/2005/03/09/almodovar/ Description: Das Theme basiert im Ursprung auf Michael Heilemanns Kubrick-Template und ist von dem einen oder anderen Gimmick anderer sehr guter Templates inspiriert worden. Version: 0.7 Author: ratte / robert Author URI: http://blog.ratterobert.com/ */ /* Begin Typography & Colors */ body { font-size: 75%; font-family: 'Lucida Grande', 'Trebuchet MS', 'Bitstream Vera Sans', Sans-Serif; background-color: #d5d6d7; color: #333; text-align: center; } #page { background-color: #fff; border: 1px solid #999; text-align: left; } #content { font-size: 1.2em; margin: 0; } #content p, #content ul, #content blockquote { line-height: 1.6em; } #footer { border-top: 1px solid #000; margin-top: 2em; } small { font-family: 'Trebuchet MS', Arial, Helvetica, Sans-Serif; font-size: 0.9em; line-height: 1.5em; } h1, h2, h3 { font-family: 'Trebuchet MS', 'Lucida Grande', Verdana, Arial, Sans-Serif; font-weight: bold; margin-top: .7em; margin-bottom: .7em; } h1 { font-size: 2.5em; } h2 { font-size: 2em; } h3 { font-size: 1.5em; } h1, h2, h3 { color: #777; } h1 a, h2 a, h3 a { color: #777; } h1, h1 a, h1 a:hover, h1 a:visited, h2, h2 a, h2 a:hover, h2 a:visited, h3, h3 a, h3 a:hover, h3 a:visited, cite { text-decoration: none; } #content p a:visited { color: #c63 font-weight: normal; } small, blockquote, strike { color: #777; } #links ul ul li, #links li { list-style: none; } code { font: 1.1em 'Courier', 'Courier New', Fixed; } acronym, abbr, span.caps { font-size: 0.9em; letter-spacing: .07em; } a { color: #FF5000; text-decoration: none; font-weight: bold; } a:hover { color: #FF8000; } /* Special case doc-title */ h1.doc-title { text-transform: lowercase; font-size: 4em; margin: 0; } h1.doc-title a { display: block; padding-left: 0.8em; padding-bottom: .5em; padding-top: .5em; margin: 0; border-bottom: 1px #fff solid; } h1.doc-title, h1.doc-title a, h1.doc-title a:visited, h1.doc-title a:hover { text-decoration: none; color: #FF5000; } /* End Typography & Colors */ /* Begin Structure */ body { margin: 0; padding: 0; } #page { background-color: white; margin: 0 auto 0 9em; padding: 0; max-width: 60em; border: 1px solid #959596; } * html #page { width: 60em; } #content { margin: 0 1em 0 3em; } #content h1 { margin-left: 0; } #footer { padding: 0 0 0 1px; margin: 0; margin-top: 1.5em; clear: both; } #footer p { margin: 1em; } /* End Structure */ /* Begin Headers */ .description { text-align: center; } /* End Headers */ /* Begin Form Elements */ #searchform { margin: 1em auto; text-align: right; } #searchform #s { width: 100px; padding: 2px; } #searchsubmit { padding: 1px; } /* End Form Elements */ /* Begin Various Tags & Classes */ acronym, abbr, span.caps { cursor: help; } acronym, abbr { border-bottom: 1px dashed #999; } blockquote { margin: 15px 30px 0 10px; padding-left: 20px; border-left: 5px solid #CCC; } blockquote cite { margin: 5px 0 0; display: block; } hr { display: none; } a img { border: none; } .navigation { display: block; text-align: center; margin-top: 10px; margin-bottom: 60px; } /* End Various Tags & Classes*/ span a { color: #CCC; } span a:hover { color: #FF5000; } #navcontainer { margin-top: 0px; padding-top: 0px; width: 100%; background-color: #CCC; text-align: right; } #navlist ul { margin-left: 0; margin-right: 5px; padding-left: 0; white-space: nowrap; } #navlist li { display: inline; list-style-type: none; } #navlist a { padding: 3px 10px; color: #fff; background-color: #999; text-decoration: none; border: 1px solid #CCC; font-weight: normal; } #navlist a:hover { color: #000; background-color: #FFF; text-decoration: none; font-weight: normal; } #navlist a:active, #navlist a.selected { padding: 3px 10px; color: #000; background-color: #EEE; text-decoration: none; border: 1px solid #CCC; font-weight: normal; }kid-0.9.6/doc/html/class-kid.BaseTemplate.html0000644000175000017500000003065710460024072021025 0ustar tstanektstanek kid.BaseTemplate -- Base class for compiled Templates.

kid-templating.org


BaseTemplate

Base class for compiled Templates.

All kid template modules expose a class named Template that extends from this class making the methods defined here available on all Template subclasses.

This class should not be instantiated directly.


Attributes

a serializer

<kid.serialization.XMLSerializer object at 0xb77cad8c>

Methods

f __init__(self) ...

Initialize a template with instance attributes specified by keyword arguments.

Keyword arguments are available to the template using self.var notation.

f write(self, file, encoding=None, fragment=0, output=None) ...

Execute template and write output to file.

file:file
A filename or a file like object (must support write()).
encoding:string
The output encoding. Default: utf-8.
fragment:bool
Controls whether prologue information (such as <?xml?> declaration and DOCTYPE should be written). Set to 1 when generating fragments meant to be inserted into existing XML documents.
output:string,`Serializer`
A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object.

f serialize(self, encoding=None, fragment=0, output=None) ...

Execute a template and return a single string.

encoding
The output encoding. Default: utf-8.
fragment
Controls whether prologue information (such as <?xml?> declaration and DOCTYPE should be written). Set to 1 when generating fragments meant to be inserted into existing XML documents.
output
A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object.

This is a convienence method, roughly equivalent to:

''.join([x for x in obj.generate(encoding, fragment, output)]

f generate(self, encoding=None, fragment=0, output=None) ...

Execute template and generate serialized output incrementally.

This method returns an iterator that yields an encoded string for each iteration. The iteration ends when the template is done executing.

encoding
The output encoding. Default: utf-8.
fragment
Controls whether prologue information (such as <?xml?> declaration and DOCTYPE should be written). Set to 1 when generating fragments meant to be inserted into existing XML documents.
output
A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object.

f __iter__(self) ...

f __unicode__(self) ...

f initialize(self) ...

f pull(self) ...

Returns an iterator over the items in this template.

f content(self) ...

f transform(self, stream=None, filters=[]) ...

Execute the template and apply any match transformations.

If stream is specified, it must be one of the following:

Element
An ElementTree Element.
ElementStream
An pull.ElementStream instance or other iterator that yields stream events.
string
A file or URL unless the string starts with '<' in which case it is considered an XML document and processed as if it had been an Element.

By default, the pull method is called to obtain the stream.

f defined(self, name) ...

f value_of(self, name, default=None) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.HTMLSerializer.html0000644000175000017500000001752210460024072021251 0ustar tstanektstanek kid.HTMLSerializer

kid-templating.org


HTMLSerializer


Attributes

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

a balanced_blocks

False

a encoding

'utf-8'

a doctype

('HTML',
 '-//W3C//DTD HTML 4.01 Transitional//EN',
 'http://www.w3.org/TR/html4/loose.dtd')

a empty_elements

set(['img', 'area', 'basefont', 'frame', 'isindex', 'meta', 'param', 'hr', 'base', 'link', 'br', 'input', 'col'])

a boolean_attributes

set(['compact', 'defer', 'checked', 'nohref', 'selected', 'ismap', 'disabled', 'noshade', 'noresize', 'multiple', 'nowrap', 'declare'])

a elements_with_pcdata

set(['fieldset', 'option', 'textarea', 'title'])

a noescape_elements

set(['style', 'script'])

Methods

f __init__(self, encoding='utf-8', doctype=None, transpose=None) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.Namespace.html0000644000175000017500000001212110460024071020334 0ustar tstanektstanek kid.Namespace

kid-templating.org


Namespace


Methods

f __init__(self, uri, prefix=None) ...

f __getitem__(self, name) ...

f __unicode__(self) ...

f __equals__(self, other) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.Serializer.html0000644000175000017500000001271610460024072020564 0ustar tstanektstanek kid.Serializer

kid-templating.org


Serializer


Attributes

a balanced_blocks

False

a encoding

'utf-8'

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

Methods

f __init__(self, encoding=None, src_encoding='utf-8') ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.XHTMLSerializer.html0000644000175000017500000002006610460024071021375 0ustar tstanektstanek kid.XHTMLSerializer

kid-templating.org


XHTMLSerializer


Attributes

a decl

1

a name

'title'

a balanced_blocks

False

a encoding

'utf-8'

a doctype

None

a empty_elements

['{http://www.w3.org/1999/xhtml}img',
 '{http://www.w3.org/1999/xhtml}area',
 '{http://www.w3.org/1999/xhtml}basefont',
 '{http://www.w3.org/1999/xhtml}frame',
 '{http://www.w3.org/1999/xhtml}isindex',
 '{http://www.w3.org/1999/xhtml}meta',
 '{http://www.w3.org/1999/xhtml}param',
 '{http://www.w3.org/1999/xhtml}hr',
 '{http://www.w3.org/1999/xhtml}base',
 '{http://www.w3.org/1999/xhtml}link',
 '{http://www.w3.org/1999/xhtml}br',
 '{http://www.w3.org/1999/xhtml}input',
 '{http://www.w3.org/1999/xhtml}col']

a elements_with_pcdata

['{http://www.w3.org/1999/xhtml}fieldset',
 '{http://www.w3.org/1999/xhtml}option',
 '{http://www.w3.org/1999/xhtml}textarea',
 '{http://www.w3.org/1999/xhtml}title']

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

Methods

f __init__(self, encoding=None, decl=None, doctype=None, namespaces=None) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.XMLSerializer.html0000644000175000017500000001465010460024071021143 0ustar tstanektstanek kid.XMLSerializer

kid-templating.org


XMLSerializer


Attributes

a decl

1

a balanced_blocks

False

a encoding

'utf-8'

a doctype

None

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

Methods

f __init__(self, encoding=None, decl=None, doctype=None, namespaces=None) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.namespace.Namespace.html0000644000175000017500000001366710460024074022312 0ustar tstanektstanek kid.namespace.Namespace

kid-templating.org


Namespace


Methods

f __init__(self, uri, prefix=None) ...

f qname(self, name) ...

f __getitem__(self, name) ...

f clarkname(self, name) ...

f __unicode__(self) ...

f __equals__(self, other) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.serialization.HTMLSerializer.html0000644000175000017500000003053210460024075024124 0ustar tstanektstanek kid.serialization.HTMLSerializer

kid-templating.org


HTMLSerializer


Attributes

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

a balanced_blocks

False

a encoding

'utf-8'

a doctype

('HTML',
 '-//W3C//DTD HTML 4.01 Transitional//EN',
 'http://www.w3.org/TR/html4/loose.dtd')

a empty_elements

set(['img', 'area', 'basefont', 'frame', 'isindex', 'meta', 'param', 'hr', 'base', 'link', 'br', 'input', 'col'])

a boolean_attributes

set(['compact', 'defer', 'checked', 'nohref', 'selected', 'ismap', 'disabled', 'noshade', 'noresize', 'multiple', 'nowrap', 'declare'])

a elements_with_pcdata

set(['fieldset', 'option', 'textarea', 'title'])

a noescape_elements

set(['style', 'script'])

Methods

f serialize(self, stream, encoding=None, fragment=0) ...

f write(self, stream, file, encoding=None, fragment=0) ...

f apply_filters(self, stream) ...

f balancing_filter(self, stream) ...

f whitespace_filter(self, stream) ...

f __init__(self, encoding='utf-8', doctype=None, transpose=None) ...

f has_only_pcdata(self, tagname) ...

f generate(self, stream, encoding=None, fragment=0) ...

Serializes an event stream to bytes of the specified encoding.

This function yields an encoded string over and over until the stream is exhausted.

f escape_cdata(text, encoding=None, escape=1) ...

Escape character data.

f escape_attrib(text, encoding=None) ...

Escape attribute value.

See the source for more information.

kid-0.9.6/doc/html/class-kid.serialization.Serializer.html0000644000175000017500000002117610460024075023443 0ustar tstanektstanek kid.serialization.Serializer

kid-templating.org


Serializer


Attributes

a balanced_blocks

False

a encoding

'utf-8'

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

Methods

f __init__(self, encoding=None, src_encoding='utf-8') ...

f has_only_pcdata(self, tagname) ...

f serialize(self, stream, encoding=None, fragment=0) ...

f write(self, stream, file, encoding=None, fragment=0) ...

f generate(self, stream, encoding=None, fragment=0) ...

f apply_filters(self, stream) ...

f balancing_filter(self, stream) ...

f whitespace_filter(self, stream) ...

See the source for more information.

kid-0.9.6/doc/html/class-kid.serialization.XMLSerializer.html0000644000175000017500000002651710460024075024030 0ustar tstanektstanek kid.serialization.XMLSerializer

kid-templating.org


XMLSerializer


Attributes

a decl

1

a balanced_blocks

False

a encoding

'utf-8'

a doctype

None

a namespaces

{'http://purl.org/atom/ns#': 'atom',
 'http://purl.org/rss/1.0/': 'rss',
 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf',
 'http://www.w3.org/1999/xhtml': 'html',
 'http://www.w3.org/XML/1998/namespace': 'xml'}

Methods

f has_only_pcdata(self, tagname) ...

f serialize(self, stream, encoding=None, fragment=0) ...

f write(self, stream, file, encoding=None, fragment=0) ...

f apply_filters(self, stream) ...

f balancing_filter(self, stream) ...

f whitespace_filter(self, stream) ...

f __init__(self, encoding=None, decl=None, doctype=None, namespaces=None) ...

f can_be_empty_element(self, ns_stack, item_name) ...

f generate(self, stream, encoding=None, fragment=0) ...

Serializes an event stream to bytes of the specified encoding.

This function yields an encoded string over and over until the stream is exhausted.

f escape_cdata(text, encoding=None) ...

Escape character data.

f escape_attrib(text, encoding=None) ...

Escape attribute value.

See the source for more information.

kid-0.9.6/doc/html/class-kid.util.QuickTextReader.html0000644000175000017500000001040610460024075022470 0ustar tstanektstanek kid.util.QuickTextReader

kid-templating.org


QuickTextReader


Methods

f __init__(self, text) ...

f read(self, amount) ...

See the source for more information.

kid-0.9.6/doc/html/gnu.html0000644000175000017500000005531510460024067015401 0ustar tstanektstanek GNU Free Documentation License

kid-templating.org


GNU Free Documentation License

Version 1.2, November 2002

<http://www.gnu.org/copyleft/fdl.html>

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.

A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  • Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
  • List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
  • State on the Title page the name of the publisher of the Modified Version, as the publisher.
  • Preserve all the copyright notices of the Document.
  • Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
  • Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
  • Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
  • Include an unaltered copy of this License.
  • Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
  • Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
  • For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
  • Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
  • Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.
  • Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
  • Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements."

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See <http://www.gnu.org/copyleft/>.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.

kid-0.9.6/doc/html/guide.html0000644000175000017500000013146310460024067015704 0ustar tstanektstanek Kid User's Guide

kid-templating.org


Kid User's Guide

Author: Ryan Tomayko
Contact: rtomayko@gmail.com
Revision: 315
Date: 2006-04-19
Copyright: 2005, Ryan Tomayko
Other Formats:Text

Kid is an XML based template language that uses embedded Python to do cool stuff. The syntax was inspired by a number of existing template languages, namely XSLT, TAL, and PHP.

This document describes the Kid Python interface, command line tools, and methods for configuring Kid in various web environments. For more information about the template language, see the Kid Language Specification.

1   Introduction

1.1   Why use Kid?

Kid was designed to simplify the process of generating and transforming dynamic well-formed XML documents using Python. While there are a myriad of tools for working with XML documents in Python, generating XML is generally tedious, error prone, or both:

  • APIs like SAX, DOM, or ElementTree can guarantee well-formed output but require that output documents be created entirely in Python.
  • Template languages like Cheetah or PTL make generating text content easy but offer little to help ensure the output is correct/well-formed. Using text based tools to generate XML can result in bad data as there are many issues with basic XML syntax and encoding that need to be understood and coded for by the programmer.
  • XSLT provides much of the functionality required to generate good XML content but requires all input to be in the form of an XML document. This brings us back to the original problem of not being able to generate XML content safely and easily.

Kid is an attempt to bring the benefits of these technologies together into a single cohesive package.

Kid also allows the programmer to exploit the structured nature of XML by writing filters and transformations that work at the XML infoset level. Kid templates use generators to produce infoset items. This allows pipelines to be created that filter and modify content as needed.

1.2   What Types of XML Documents?

Kid can be used to generate any kind of XML documents including XHTML, RSS, Atom, FOAF, RDF, XBEL, XSLT, RelaxNG, Schematron, SOAP, etc.

XHTML is generally used for examples as it is arguably the most widely understood XML vocabulary in existence today.

1.3   Template Example

Kid template files are well-formed XML documents with embedded Python used for generating and controlling dynamic content.

The following illustrates a very basic Kid Template:

<?xml version='1.0' encoding='utf-8'?>
<?python
import time
title = "A Kid Template"
?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://purl.org/kid/ns#"
>
  <head>
    <title py:content="title">
      This is replaced with the value of the title variable.
    </title>
  </head>
  <body>
    <p>
      The current time is ${time.strftime('%C %c')}.
    </p>
  </body>
</html>

Kid supports more advanced features such as conditionals (py:if), iteration (py:for), and reusable sub templates (py:def). For more information on kid template syntax, see the Kid Language Specification.

Kid templates should use the .kid file extension if importing the template module using normal Python code is desired. The Kid import hook extensions rely on the .kid file extension being present.

1.4   A Note on Template Design

It is possible to embed blocks of Python code using the <?python?> processing instruction (PI). However, the practice of embedding object model, data persistence, and business logic code in templates is highly discouraged. In most cases, these types of functionality should be moved into external Python modules and imported into the template.

Keeping large amounts of code out of templates is important for a few reasons:

  • Separation of content and logic. Templates are meant to model a document format and should not be laden with code whose main concern is something else.
  • Editors with Python support (like Emacs) will not recognize Python code embedded in Kid templates.
  • People will call you names.

That being said, circumstances requiring somewhat complex formatting or presentation logic arise often enough to incline us to include the ability to embed blocks of real code in Templates. Template languages that help by hindering ones ability to write a few lines of code when needed lead to even greater convolution and general distress.

That being said, there are some limitations on what types of usage the <?python?> PI may be put to. Specifically, you cannot generate output within a code block (without feeling dirty), and all Python blocks end with the PI.

You cannot do stuff like this:

<table>
  <?python #
  for row in rows: ?>
    <tr><td py:content="row.colums[0]">...</td></tr>
</table>
<p><?python print 'some text and <markup/> too'?></p>

This is a feature. One of the important aspects of Kid is that it guarantees well-formed XML output given a valid template. Allowing unstructured text output would make this impossible.

2   The kid package

The kid package contains functions and classes for using templates. Kid relies heavily on ElementTree and also exports much of that packages functionality.

2.1   Loading and Executing Templates

2.1.1   enable_import(suffixes=None)

The enable_import function turns on the Kid import hooks and allows Python's native import statement to be used to access template modules. The template modules are generally stored in files using a .kid file extension. The optional suffixes argument can be used to pass in a list of alternate file extensions. This is useful is you wish to put you XML templates in .html files and have them importable.

It is generally called once at the beginning of program execution, but calling multiple times has no effect adverse or otherwise.

Example:

import kid
kid.enable_import()

# or

import kid
kid.enable_import(suffixes=[".html"])

There are a few very simple rules used to determine which file to load for a particular import statement. The first file matching the criteria will be loaded even if other matching files exist down the chain. The rules are so follows: 1. look for module.kid file 2. traverse the suffixes list, if supplied, looking for module.suffix 3. look for the standard Python suffixes (.py, .pyc, etc.)

2.1.2   Template

Sometimes using Python's native import doesn't make sense for template usage. In these cases, the kid.Template function can be used to load a template module and create an instance of the module's Template class.

The kid.Template function requires one of the following arguments to be provided to establish the template:

file
The template should be loaded from the file specified. If a compiled version of template exists, it will be loaded. If not, the template is loaded and an attempt will be made to write a compiled version.
source
The template should be loaded from the string specified. There is no mechanism for caching string templates other than to keep a reference to the object returned.
name
The template should be loaded by importing a module with the specified name. This is exactly like using Python's normal import but allows template names to be specified dynamically and also doesn't require the import hook to be enabled.
import kid
template = Template(file='test.kid', foo='bar', baz='bling')
print template.serialize()
import kid
template = Template(source='<p>$foo</p>', foo='Hello World!')
print template.serialize()

2.1.3   load_template

The load_template function returns the module object for the template given a template filename. This module object can be used as if the module was loaded using Python's import statement. Use this function in cases where you need access to the template module but the template doesn't reside on Python's path.

import kid
template_module = kid.load_template('test.kid', cache=1)
template = template_module.Template(foo='bar', baz='bling')
print str(template)

Note that the Template function usually provides a better interface for creating templates as it automatically creates an instance of the Template class for the module, removing a line of code or two.

However, if you are creating templates dynamically (e.g. by loading them from a database), you may prefer to use this function in order to create them, by simply passing in the source as the first argument, and setting cache=False (so the templates modules aren't saved in sys.modules):

import kid

class TemplateManager:

    # ... other methods here

    def get_template(self, key):
        source_string = self.fetch_template_source(key)
        return kid.load_template(
            source_string, cache=False, ns={'manager':self}
        )

load_template() uses its ns keyword argument to pre-populate the template module namespace with global variables. In this example, we give the template module access to an instance of our "template manager" class in a manager variable, allowing templates to inherit from other templates loaded from the same database, using e.g.:

<root py:extends="manager.get_template('other_template')">

3   Template Classes

Kid templates are converted into normal Python modules and may be used like normal Python modules. All template modules have a uniform interface that expose a class named Template and possibly a set of functions (one for each py:def declared in the template).

3.1   Importing

Templates may be imported directly like any other Python module after the Kid import hooks have been enabled. Consider the following files in a directory on Python's sys.path:

file1.py
file2.py
file3.kid

The file1 module may import the file3 template module using the normal Python import syntax after making a call to kid.enable_import():

# enable kid import hooks
import kid
kid.enable_import()

# now import the template
import file3
print file3.serialize()

The importer checks whether a compiled version of the template exists by looking for a template.pyc file and if not found, loads the template.kid file, compiles it, and attempts to save it to template.pyc. If the compiled version cannot be saved properly, processing continues as normal; no errors or warnings are generated.

3.2   Template class

Each template module exports a class named "Template". An instance of a template is obtained in one of three ways:

  • The Template function.
  • Enabling the import hook, using Python's import to obtain the module, and then retrieving the Template class.
  • Calling the kid.load_template function and then retrieving the Template class.

The Template function is the preferred method of obtaining a template instance.

All Template classes subclass the kid.BaseTemplate class, providing a uniform set of methods that all templates expose. These methods are described in the following sections.

3.2.1   __init__(**kw)

Template instantiation takes a list of keyword arguments and maps them to attributes on the object instance. You may pass any number of keywords arguments and they are available as both instance attributes and as locals to code contained in the template itself.

For example:

from mytemplate import Template
t = Template(foo='bar', hello='world')

is equivalent to:

from mytemplate import Template
t = Template()
t.foo = 'bar'
t.hello = 'world'

And these names are available within a template as if they were locals:

<p>Hello ${hello}</p>

Note

The names source, file, and name should be avoided because they are used by the generic Template Function.

3.2.2   serialize()

Execute the template and return the result as one big string.

def serialize(encoding=None, fragment=0, output=None)

This method returns a string containing the output of the template encoded using the character encoding specified by the encoding argument. If no encoding is specified, "utf-8" is used.

The fragment argument specifies whether prologue information such as the XML declaration (<?xml ...?>) and/or DOCTYPE should be output. Set to a truth value if you need to generate XML suitable for insertion into another document.

The output argument specifies the serialization method that should be used. This can be a string or a Serializer instance.

Note

The __str__ method is overridden to use this same function so that calls like str(t), where t is a template instance, are equivalent to calling t.serialize().

3.2.3   generate()

Execute the template and generate serialized output incrementally.

def generate(encoding=None, fragment=0, output=None)

This method returns an iterator that yields an encoded string for each iteration. The iteration ends when the template is done executing.

See the serialize method for more info on the encoding, fragment, and output arguments.

3.2.4   write()

Execute the template and write output to file.

def write(file, encoding=None, fragment=0, output=None)

This method writes the processed template out to a file. If the file argument is a string, a file object is created using open(file, 'wb'). If the file argument is a file-like object (supports write), it is used directly.

See the serialize method for more info on the encoding, fragment, and output arguments.

3.2.5   transform()

This method returns a generator object that can be used to iterate over the ElementTree objects produced by template execution. For now this method is under-documented and its use is not recommended. If you think you need to use it, ask about it on the mailing list.

3.3   Serialization

The Template object's serialize, generate, and write methods take an output argument that controls how the XML Infoset items generated by a template should serialized. Kid has a modular serialization system allowing a single template to be serialized differently based on need.

The kid package exposes a set of classes that handle serialization. The Serializer class provides some base functionality but does not perform serialization; it provides useful utility services to subclasses. The XMLSerializer, HTMLSerializer, and PlainSerializer classes are concrete and can be used to serialize template output as XML or HTML, respectively.

3.3.1   XMLSerializer

The XMLSerializer has the the following options, which can be set when an instance is constructed, or afterwards as instance attributes:

encoding
The character encoding that should be used when serializing output. This can be any character encoding supported by Python.
decl
Boolean specifying whether the XML declaration should be output. Note that the fragment argument can be used to turn this off when calling the serialize, generate, or write methods.
doctype
A 3-tuple of the form (TYPE, PUBLIC, SYSTEM) that specifies a DOCTYPE that should be output. If the doctype attribute is None, no DOCTYPE is output. Note that if the fragment argument is set, no DOCTYPE will be output.

The following example creates a custom XML serializer for DocBook and uses it to serialize template output:

from kid import Template, XMLSerializer
dt = ('article', '-//OASIS//DTD DocBook XML V4.1.2//EN',
      'http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd')
serializer = XMLSerializer(encoding='ascii', decl=1, doctype=dt)
t = Template(file='example.dbk')
print t.serialize(output=serializer)

3.3.2   HTMLSerializer

The HTMLSerializer is cabable of serializing an XML Infoset using HTML 4.01 syntax. This serializer varies from the XMLSerializer as follows:

  • No <?xml ...?> declaration.
  • HTML 4.01 DOCTYPE(s).
  • Transpose element/attribute names to upper-case by default (can be configured to transpose to lowercase or to not transpose at all).
  • Injects a <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=enc"> where enc is the output encoding.
  • Outputs the following element's as "empty elements" (i.e. no closing tag): area, base, basefont, br, col, frame, hr, img, input, isindex, link, meta, param.
  • No such thing as short-form elements: <elem />. All elements (except for empty elements) must have a full end tag.
  • Does not escape reserved characters in <SCRIPT> and <STYLE> blocks. This includes less-than signs and ampersands.
  • Boolean attributes are output without a value part. For example, <OPTION SELECTED>foo</OPTION>.
  • Discards namespace information.

Much of this functionality can be controlled by setting options on the HTMLSerializer instance. These options are as follows:

encoding
The character encoding that should be used when serializing output. This can be any character encoding supported by Python.
doctype
A 3-tuple of the form (TYPE, PUBLIC, SYSTEM) that specifies a DOCTYPE that should be output. If the doctype attribute is None, no DOCTYPE is output.
transpose
This is a reference to a function that is called to transpose tag and attribute names. string.upper and string.lower are generally used here. If set to None, all tag names are output as they are in the source document.
inject_type
Boolean specifying whether a <META> tag should be inserted into the <HEAD> of the document specifying the character encoding. This is enabled by default.
empty_elements
A set containing the names (in lower case) of the elements that do not have closing tags. Set to [] to turn off empty_element processing.
noescape_elements
A set containing the names (in lower case) of elements whose content should not be escaped. This defaults to ['script', 'style']. Set to [] to turn enable escaping in all elements.
boolean_attributes
A set containing the names (in lower case) of attributes that do not require a value part. The presence of the attribute name signifies that the attribute value is set. Set to [] to disable boolean attribute processing.

3.3.3   PlainSerializer

The PlainSerializer can be used to generate non-markup, like a CSS or Javascript file. All markup that is rendered is thrown away, and entities are resolved.

When using this serializer, your template must still be valid XML. A typical pattern might be:

<css>
/* Look &amp; Feel */
body {color: #f00}
</css>

Which renders to:

/* Look & Feel */
body {color: #f00}

3.3.4   Common Output Methods

The kid.output_methods dictionary contains a mapping of names to frequently used Serializer configurations. You can pass any of these names as the output argument in Template methods.

xml

The xml output method is the default. It serializes the infoset items as well-formed XML and includes a <?xml?> declaration. The serializer is created as follows:

XMLSerializer(encoding='utf-8', decl=1)
html / html-strict

The html and html-strict output methods use the HTMLSerializer to serialize the infoset. The HTMLSerializer used has the following options set:

  • Tag and attribute names converted to uppercase (HTMLSerializer.transpose = string.upper).
  • HTML Transitional or HTML Strict DOCTYPE.

For more information on how content is serialized, see the HTMLSerializer documentation.

xhtml / xhtml-strict

The xhtml and xhtml-strict output methods use a custom XMLSerializer to serialize the infoset. The XMLSerializer used has the following options set:

  • No <?xml?> declaration.
  • XHTML Transitional or XHTML Strict DOCTYPE.
plain
The plain output method uses PlainSerializer, which takes only an encoding argument. All markup is stripped, entities are resolved, and only the resulting text is output.

The following example serializes data as HTML instead of XML:

>>> from kid import Template
>>> t = Template('<html xmlns="http://www.w3.org/1999/xhtml">'
                 '<body><p>Hello World</p><br /></body></html>')
>>> print t.serialize(output='html-strict')
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN"
                      "http://www.w3.org/TR/html4/strict.dtd">
<HTML><BODY><P>Hello World</P><BR></HTML>

Note that the DOCTYPE is output, tag names are converted to uppercase, and some elements have no end tag.

The same code can be used to output XHTML as follows:

>>> from kid import Template
>>> t = Template('<html xmlns="http://www.w3.org/1999/xhtml">'
                 '<body><p>Hello World</p><br /></body></html>')
>>> print t.serialize(output='xhtml-strict')
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body><p>Hello World</p><br /></html>

4   Template Variables

When a template is executed, all of the template instance's attributes are available to template code as local variables. These variables may be specified when the template is instantiated or by assigning attributes to the template instance directly.

The following example template relies on two arguments being provided by the code that calls the template: title and message.

message_template.kid:

<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://purl.org/kid/ns#">
  <head>
    <title>${title.upper()}</title>
  </head>
  <body>
    <h1 py:content="title">Title</h1>
    <p>
      A message from Python:
    </p>
    <blockquote py:content="message">
      Message goes here.
    </blockquote>
  </body>
</html>

The code that executes this template is responsible for passing the title and message values.

message.py:

from kid import Template
template = Template(file='message_template.kid',
                    title="Hello World",
                    message="Keep it simple, stupid.")
print template.serialize()

This should result in the following output:

<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>HELLO WORLD</title>
  </head>
  <body>
    <h1>Hello World</h1>
    <p>
      A message from Python:
    </p>
    <blockquote>
      Keep it simple, stupid.
    </blockquote>
  </body>
</html>

5   Command Line Tools

5.1   Template Compiler (kidc)

Kid templates may be compiled to Python byte-code (.pyc) files explicitly using the kidc command. kidc is capable of compiling individual files or recursively compiling all .kid files in a directory.

Use kidc --help for more information.

Note that you do not have to compile templates before using them. They are automatically compiled the first time they are used.

5.2   Run Templates (kid)

Kid templates may be executed directly without having been precompiled using the kid command as follows:

kid template-file.kid

Template output is written to stdout and may be redirected to a file or piped through XML compliant tools.

kid-0.9.6/doc/html/index.html0000644000175000017500000001564410460024265015720 0ustar tstanektstanek Kid

kid-templating.org


Kid

Pythonic, XML-based Templating

Kid is a simple template language for XML based vocabularies written in Python. It was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (see WhatsBorrowed and WhatsDifferent). For more info on current and planned features and licensing information, see AboutKid.

Download

The current stable version of Kid is 0.9.3 and is available from the following location:

http://www.kid-templating.org/dist/0.9.3/kid-0.9.3.tar.gz

You can find older and bleeding version in the dist directory.

See GettingStarted for information on installing Kid on your system.

You may also grab the project directly from subversion:

svn co svn://kid-templating.org/trunk

Documentation / Articles

Official documentation in HTML and text formats is available with the source distribution and is also available right here.

Note that the Kid Wiki contains supplementary documentation on Kid. Please consider creating your own pages if you have a useful tip to share.

Other sources of information include the mailing list archives, the Planet Kid. Older ramblings on kid can be found on Ryan Tomayko's Weblog under the tag, "kid".

Contribute

Contact

If you need help or support, please send it to the Kid mailing list:

<kid-template-discuss@lists.sourceforge.net>

kid-0.9.6/doc/html/language.html0000644000175000017500000015432110460024067016370 0ustar tstanektstanek Kid Language Specification

kid-templating.org


Kid Language Specification

Author: Ryan Tomayko
Contact: rtomayko@gmail.com
Revision: 5
Date: 2006-06-10
Copyright: 2005, Ryan Tomayko
Other Formats:Text

Kid is a simple XML based template language that uses embedded Python to do cool stuff. The syntax was inspired by a number of existing template languages, namely XSLT, TAL, and PHP.

This document describes the template language and will be most useful as reference to those developing Kid templates. For information about using templates from Python, the command line, or in web environments, see the User's Guide.

1   Synopsis

<?python
title = "A Kid Test Document"
fruits = ["apple", "orange", "kiwi", "M&M"]
from platform import system
?>
<html xmlns:py="http://purl.org/kid/ns#">
  <head>
    <title py:content="title">This is replaced.</title>
  </head>
  <body>
    <p>These are some of my favorite fruits:</p>
    <ul>
      <li py:for="fruit in fruits">
        I like ${fruit}s
      </li>
    </ul>
    <p py:if="system() == 'Linux'">
      Good for you!
    </p>
  </body>
</html>

Yields something like this:

<?xml version="1.0" encoding="utf-8"?>
<html>
  <head>
    <title>A Kid Test Document</title>
  </head>
  <body>
    <p>These are some of my favorite fruits:</p>
    <ul>
      <li>I like apples</li>
      <li>I like oranges</li>
      <li>I like kiwis</li>
      <li>I like M&amp;Ms</li>
    </ul>
    <p>
      Good for you!
    </p>
  </body>
</html>

2   The Kid Namespace

All attributes described in this document must belong to the following namespace:

http://purl.org/kid/ns#

The namespace prefix py is used throughout this document to indicate that an item belongs to the Kid/Python namespace.

3   Embedding Code Blocks (<?python?>)

The <?python?> processing instruction (PI) contains Python code and MAY occur anywhere that is legal for processing instructions to occur in an XML document.

The rules for executing code found in a <?python?> PI is as follows:

  1. <?python?> PIs located outside of the document element (e.g. root element) contain Document Level code. This code SHOULD be executed in a global, shared scope for the document. The code SHOULD be executed once when the template is loaded and shared between multiple invocations of the template.
  2. <?python?> PIs located within the document element contain Local Level code. This code is executed each time the document is processed with a local scope specific to the invocation and the shared document level global scope.

Document Level and Local Level code work exactly like Module Level and Function Level code in normal Python modules. For example, the following Kid template:

<?python
x = 0
y = 0
?>
<html xmlns:py="http://purl.org/kid/ns#">
  <?python
  x = 1
  if x == 1:
    x = 10
  ?>
  <p py:content="x"/>
  <?python
  global y
  y = 30
  ?>
  <p py:content="y"/>
</html>

May be considered equivalent to the following Python module:

x = 0
y = 0
def expand(handler):
  handler.startDocument()
  handler.startElement('html')
  x = 1
  if x == 1:
    x = 10
  handler.element('p', content=x) # output p element with x as value
  global y
  y = 30
  handler.element('p', content=y) # output p element with value of y
  handler.endElement('html')
  handler.endDocument()

<?python?> PIs may contain any legal Python language construct including functions, classes, lamda forms, etc.

<?python
class Adder:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def doit(self):
    return self.x + self.y

foo = Adder(x=400, y=20)
x = foo.doit()
?>

Single line <?python?> PIs are okay too:

<?python x = 10 ?>

4   Content Producing Constructs

There are multiple methods of generating content output from a template: py:content, py:replace, py:attrs, and ${} substitution. Each of these syntaxes have the same rules for what types of objects may result from the Python expression they contain.

str, unicode
The string is inserted as XML CDATA. That is, it is non-parsable character data that does not contain markup. The following characters are encoded as XML entities when serialized: '<', '&'. Attribute values containing content also encode the quote character: '"'.
ElementTree.Element

When an ElementTree.Element is referenced from a content producing construct, the item is inserted into the document literally, i.e. it is not encoded as text, but becomes part of the output structure.

The XML() and document() functions can be used to turn a string into structured content and to retrieve an XML document from a URL, respectively.

Note that attribute values MUST NOT reference structured content. This applies to py:attrs and using ${} substitution in attribute values.

sequence
If a sequence type (list, tuple, or other iterable) is referenced, the rules are applied to each of the items in the sequence. For example, you could reference a list containing an Element and a string.
Other
If the result of evaluating the expression is any other type, an attempt is made to coerce the value to unicode as if by calling unicode(expr) and processing continues as if the object were a string or unicode object initially.

5   Python Expression Substitution (${expr})

Attributes not belonging to the Kid namespace and text content MAY embed Python expressions by enclosing the expression within a dollar sign followed by curly braces: ${expr}. The result of evaluating the expression(s) is substituted with the rest of the attribute value or text content following rules defined for Content Producing Constructs.

<?python
verb = 'ran'
noun = 'store'
?>
<a title="I ${verb} to the ${noun}">...

... would result in:

<a title="I ran to the store">...

If an attribute value consists purely of substitution expressions and all expressions evaluate to None, the attribute is removed. This can be avoided by using expr or '' to force a zero length string to be returned instead of None. For example:

<?python
# set something to None
x = None
?>
<a title="${x}">...

... would result in:

<a>...

However, this:

<?python x = None?>
<a title="${x or ''}">...

... results in:

<a title="">...

5.1   Identifier Shortcut ($name)

For simple expressions consisting entirely variable names and object access operators (.), the curly braces may be omitted:

<a href="http://example.com/$page" title="$title">
   Dots are allowed too: $object.another.attribute
</a>

However, it is good practice to use the curly brace form as it sets the substitution off from the other text a bit more providing a stronger visual clue as to what's going on.

5.2   Escaping ($$)

$$ is an escape. $${bla} will output ${bla}.

6   Default Imports

All templates have a few default imports for convenience.

6.1   XML() function

Python Expression substitution, py:content, and py:replace encode strings as text. That is, text is encoded according to the rules of the XML specification, which includes, among other things, replacing the literal characters < and & with their encoded counterparts (&lt; &amp;). If you have XML stored as a string and want it to be output as XML and not encoded text, you need to pass the string to the XML function.

For example, let's say there is a function, hello, that returns XML data that should be embedded in template output (let's say it returns <hello>world</hello>). Consider the following:

<p>${hello()}</p>

The result would be:

<p>&lt;hello>world&lt;hello></p>

Calling the XML function would have given us the result we intended:

<p>${XML(hello())}</p>
<p><hello>world</hello></p>

The xmlns keyword parameter can be used to set the default XML namespace for the top-level elements in the supplied content:

<p>${XML(hello(), xmlns="cid:hello_example")}</p>
<p><hello xmlns="cid:hello_example">world</hello></p>

This is especially useful when including XHTML content that lacks an XML namespace declaration.

6.2   document() function

The document function loads an XML document from a file or URL allowing it to be embedded in template output:

<div py:content="document('header.html')"></div>

The document function resolves paths relative to the current template file (if the template location is available).

6.3   defined(name) and value_of(name, default) functions

defined returns True if the name exists in the Kid namespace. value_of returns either the named value or the optional default value if that name doesn't exist in the namespace. These two simple convenience functions may be more intuitive to many than hasattr(self, name) and getattr(self, name, default) which are exactly equivalent.

7   Attribute Language

7.1   Repetition/Iteration (py:for)

<element py:for="target_list in expression_list" />

Works exactly like the Python for statement.

The py:for attribute may appear on any element to signify that the element should be processed multiple times, once for each value in the sequence specified:

<?python
bottles = range(1, 101)
bottles.reverse()
?>
<p py:for="num in bottles">
   <span py:content="num">X</span> bottles of beer on the wall,
   <span py:content="num">X</span> bottles of beer on the wall,
   take one down, pass it around, <span py:content="num - 1">X - 1</span>
   bottles of beer on the wall.
</p>

The py:for attribute is the first attribute to be processed if present. All other py: attributes are processed for each iteration of the loop.

7.2   Conditionals (py:if)

<element py:if="expr" />

The py:if attribute may appear on any element to signify that the element and its decendant items should be output only if the boolean expression specified evaluates to true in Python:

<p py:if="5 * 5 == 25">
  Python seems to be handling multiplication okay.
</p>

The py:if attribute is processed after the py:for attribute and is evaluated for each iteration. If the result of evaluating expr as a boolean expression is false in Python, no further py: attributes are processed for the current iteration or, if not in a py:for, at all.

Note

Evaluated as a boolean expression in Python, None, False, [], (), {}, 0, and '' are all considered to be false.

7.3   Dynamic Content (py:content)

<element py:content="expr" />

This attribute MAY appear on any element to signify that the decendant items of the element are to be replaced with the result of evaluating expr.

<p py:content="time.strftime('%C %c')">The Time</p>

... results in:

<p>Tues, Jun 26, 2004 02:03:53 AM</p>

py:content is a Content Producing Construct and can output both character and structured data.

If expr evaluates to None the element will be output as an empty element.

<p py:content="None">i go away</p>

... results in:

<p />

7.4   Replacing Content (py:replace)

<element py:replace='expr' />

py:replace is shorthand for specifying a py:content and a py:strip="True" on the same element:

<?python
x = 10
?>
<p><span py:replace="x">...</span></p>

... results in:

<p>10</p>

... and is equivelant to specifying:

<?python #
x = 10
?>
<p><span py:strip="" py:content="x">...</span></p>

The py:replace attribute is processed after the py:for and py:if attributes. py:strip and py:content attributes are not processed and are discarded.

py:replace is a Content Producing Construct and can output both character and structured data.

If expr evaluates to None the element will be output as an empty element.

<test><p py:replace="None"><span>i go away</span></p></test>

... results in:

<test />

7.5   Stripping Tags (py:strip)

<element py:strip="expr" />

The py:strip attribute may apppear on any element to signify that the containing element should not be output. If the attribute value is blank (no expr at all) or if the result expr is a boolean expression that evaluates to true, the element is not output, but all descendant elements are processed normally. If expr is not blank and the result of evaluating expr as a boolean expression is false, processing continues as if the attribute did not exist.

The py:strip attribute MAY appear on an element with any other kid attribute. However, if both a py:replace and a py:strip exist on the same element, the py:strip attribute is ignored and discarded.

The py:strip attribute is processed after the py:for and py:if attributes. If omission is eminent, the py:content attribute is processed normally but attribute interpolation does not occur.

7.6   Dynamic Attributes (py:attrs)

<element py:attrs="expr" />

The py:attrs attribute may appear on any element to specify a set of attributes that should be set on the element when it is processed. The expression specified MUST evaluate to one of the following types of values:

dict
A dictionary with keys specifying attribute names and values specifying attribute values. These are added to the attributes of the current element by calling element.attrib.update(mapping), where element is an ElementTree Element object and mapping is the dictionary returned from the expression. Outer curly braces are not necessary to write down.
list
A list of tuples of the form (name, value) is also acceptable. Each item of the list is added to the current set of attributes by iterating over the list and calling element.set(name, value).
keyword arguments
The attributes can also be specified as comma separated keyword arguments of the form name=value.

The following lines:

<elem py:attrs="{'a':1, 'ns:b':2}" />
<elem py:attrs="'a':1, 'ns:b':2" />
<elem py:attrs="(('a',1), ('ns:b',2))" />
<elem py:attrs="a=1, ns:b=2" />

will all produce the same output:

<elem a="1" ns:b="2" />

Note that attributes whose values are None will be removed. If a blank attribute is desired, an empty string should be used.

If the expression specified is an empty dictionary or an empty list, the attributes are not modified in any way.

py:attrs is a Content Producing Construct, but can output only character data.

7.7   Named Template Functions (py:def)

<element py:def="template_name(arg_list)" />

The py:def attribute may appear on any element to create a "Named Template Function". Markup contained within an py:def element is not output during normal template expansion but can be referenced from other Content Producing Constructs to insert the markup at the point referenced.

Like normal Python functions, Named Template Functions have an optional argument list that may use all of the jazzy features of Python argument lists like variable and keyword arguments.

Named Template Functions are invoked exactly like normal Python functions. They are generally invoked from Content Producing Constructs like py:content or ${} substitution.

Here we will define two Named Template Functions: display_list and display_dict. The first function takes a sequence and the second a mapping. We can invoke these functions from the same template by invoking them from a content producing construct:

<html xmlns:py="http://purl.org/kid/ns#">
   <body>
      <ul py:def="display_list(seq)">
         <li py:for="item in seq" py:content="item" />
      </ul>

      <table py:def="display_dict(mapping)">
         <tr>
            <th>Key</th>
            <th>Value</th>
         </tr>
         <tr py:for="key, value in mapping.items()">
            <td py:content="key" />
            <td py:content="value" />
         </tr>
      </table>

      ${display_list(['apple', 'orange', 'kiwi'])}

      <div py:replace="display_dict({'x' : 'y', 'p' : 'q'})">
         Key/Value Table replaces this text
      </div>
   </body>
</html>

Serialized as XML this becomes something like:

<?xml version="1.0" encoding="utf-8"?>
<html>
   <body>
      <ul>
         <li>apple</li><li>orange</li><li>kiwi</li>
      </ul>
      <table>
         <tr>
            <th>Key</th>
            <th>Value</th>
         </tr>
         <tr>
            <td>x</td>
            <td>y</td>
         </tr>
         <tr>
            <td>p</td>
            <td>q</td>
         </tr>
      </table>
   </body>
</html>

7.8   Match Templates (py:match)

<element py:match="expr" />

The py:match attribute may appear on any element to create a "Match Template". Markup contained within a Match Template element is not output during normal template expansion. Instead, these constructs set up filters for expansion output that are capable of transforming content as it is generated.

Match Templates are generally used to insert content dynamically based on patterns in template expansion or to provide "custom tag" functionality similar to that found in JSP taglibs or XSLT.

A Match Template has two parts: the match expression part (expr) and the body part (the element and it's descendants).

Match Templates are processed as follows:

  1. Each element that is output from a template goes through the Match Template Filter.
  2. The Match Template Filter visits each of the Match Templates defined in the current template and the templates the current template extends in the order that they are defined and evaluates the associated match expression.
  3. If the match expression returns true as a boolean expression, the match template's body is expanded and replaces the original element and all of its descendants.

In both the match expression and in the match template's body, the item name is bound to the Element that is being output. However, there are some limitations to what can be accessed at each phase:

  1. During match expression evaluation, only the item Element and none of its descendants are available. This means that match expressions are limited to testing matches based on the immediate Element's tag and attributes [1].
  2. During match template expansion (that is, when the match expression is true), the element's descendants are available and may be referenced from Content Producing Constructs to output bits and pieces of the matched items structure.

When matching the item.tag you need to keep your namespaces in mind. A common problem is to use the expression item.tag == 'body' when the document has a default namespace declared. When the default namespace is declared the XML parser will rename the tags using clark notation. So the correct expression would be something like item.tag == '{http://www.w3.org/1999/xhtml}body'.

[1]This is due to the streaming nature of the Kid processor. During normal template expansion, the entire tree is never fully retained in memory.

7.8.1   Example

The following simple example shows how to create a custom tag <greeting> that outputs one of two provided values based on the time of day the template is expanded:

<?xml version="1.0" encoding="utf-8"?>
<?python
from time import localtime
def timeofday():
    """Get time of day ('am' or 'pm')"""
    return localtime().tm_hour < 12 and 'am' or 'pm'
?>
<html xmlns:py="http://purl.org/kid/ns#">
  <!-- define the greeting match template -->
  <span py:match="item.tag == 'greeting'"
        py:replace="item.get(timeofday())">
  </span>

  <head>
    <title>Time of day demo</title>
  </head>
  <body>
    <p>
      Good <greeting am="Morning!" pm="Afternoon" />
    </p>
  </body>
</html>

An important thing to note is that the py:match expression and the match template body have access to the <greeting> element via the variable item. The item.get(timeofday()) bit retrieves the value of the am attribute or the pm attribute based on what is returned from the timeofday function.

At 9:00 AM, output from this template would look like this:

<html>
  <head>
    <title>Time of day demo</title>
  </head>
  <body>
    <p>
      Good Morning!
    </p>
  </body>
</html>

The obvious question at this point is how to reuse Match Templates? The example above demonstrates the use of a Match Template from the same main template but it is often desirable to have "libraries" of Match Templates that could be used by multiple individual templates. The answer is to have the main template extend a common template containing the Match Templates needed. We can rewrite the above example as two separate templates: main.kid and common.kid.

The common template would look like this:

<?xml version="1.0" encoding="utf-8"?>
<?python
from time import localtime
def timeofday():
    """Get time of day ('am' or 'pm')"""
    return localtime().tm_hour < 12 and 'am' or 'pm'
?>
<html xmlns:py="http://purl.org/kid/ns#">
  <!-- define the greeting match template -->
  <span py:match="item.tag == 'greeting'"
        py:replace="item.get(timeofday())">
  </span>
</html>

And the main template would look like this:

<?xml version="1.0" encoding="utf-8"?>
<html py:extends="'common.kid'">
  <head>
    <title>Time of day demo</title>
  </head>
  <body>
    <p>
      Good <greeting am="Morning!" pm="Afternoon" />
    </p>
  </body>
</html>

When a template extends another template (or set of templates), all of the Match Templates and Named Template Functions of the extended templates are available as if they were defined locally.

Warning

Match templates are an experimental feature. Syntax and semantics may change significantly or be removed entirely in future release. Actually, this statement applies to many aspects of Kid but this one is especially unstable.

7.9   Template Reuse (py:extends)

<root py:extends="template1, template2, ...">

The py:extends attribute may appear on the root element to specify that the template should inherit the Named Template Functions and Match Templates defined in another template (or set of templates). If a py:extends attribute is specified, it MUST be on the root element of the document.

The py:extends may contain a list of Python expressions separated by commas that reference templates. The rules for what types of values may be specified are:

string

The name of a template file, relative to the current template file.

Example:

<html py:extends="'common.kid'" />
module or Template class

The py:extends variable references a module or a Template class. If a module is referenced, an attempt is made to find a class named Template belonging to the that module.

Example:

<?python
import common
?>
<html py:extends="common" ...

Multiple templates may be referenced by separating each by a comma. The following example references templates common and forms, imported using the import hooks and a template filename named other.kid:

<?python
import common, forms
?>
<html py:extends="common, forms, 'other.kid'" ...

7.9.1   Example

For example, there is a template named common.kid that defines a template function, display_errors, and a match template that converts <b> elements to <strong> elements with uppercase content:

<html xmlns:py="http://purl.org/kid/ns#">

  <ul py:def="display_errors(errors)">
    <li py:for="error in errors" py:content="error" />
  </ul>

  <strong py:match="item.tag == 'b'"
    py:content="item.text.upper()" />

</html>

The functions and match templates may be imported into another template by referencing them with py:extends:

<html py:extends="'common.kid'"
      xmlns:py="http://purl.org/kid/ns#">
  <head>
    <title>Errors</title>
  </head>
  <body>
    <p>The following <b>errors</b> were found:</p>
    ${ display_errors(["Field is required", "Must be phone number.."]) }
  </body>
</html>

The <b>errors</b> item is transformed to <strong>ERRORS</strong> and the error list is displayed. Both the match template and the named template function are available in the derived template as if they were defined locally.

7.10   Layout Templates (py:layout)

<root py:layout="base_layout">

The py:layout attribute may appear on the root element to specify that a content template should use the referenced template as a layout template. This allows separation of individual page content from site-wide layout elements such as headers, menus, footers, etc. Match Templates, Named Template Functions, and layout parameters defined in a content template will be applied to the layout template. If a py:layout attribute is specified, it MUST be on the root element of the document.

The py:layout attribute may contain a single Python expression that references a layout template. The rules for what types of values may be specified are:

string

The name of a template file, relative to the current template file.

Example:

<html py:layout="'base_layout.kid'" />
module or Template class

The py:layout variable references a module or a Template class. If a module is referenced, an attempt is made to find a class named Template belonging to the that module.

Example:

<?python
import base_layout
?>
<html py:extends="base_layout" ...

7.10.1   Example

For example, here is a base template named base_layout.kid that contains header, content, and footer sections:

<html xmlns:py="http://purl.org/kid/ns#">

  <head>
    <title>App Name - ${page_title}</title>

    <link href="layout.css" type="text/css" rel="stylesheet" />
    ${page_specific_css()}
  </head>

  <body>
    <h1>Now viewing: ${page_title} of App Name</h1>

    <content>Default content</content>

    <div class="footer">Page Footer Text</div>
  </body>

</html>

Note how some sections were left to be filled in by the content template. Page-specific functions, match templates, and layout parameters may be defined in a separate template and then applied to the base template with py:layout:

<?python
layout_params['page_title'] = "Content Page 1 of 10"
?>
<html py:layout="'base_layout.kid'"
      xmlns:py="http://purl.org/kid/ns#">

  <link py:def="page_specific_css()"
    href="layout.css" type="text/css" rel="stylesheet" />

  <div py:match="item.tag == 'content'">
    <ul>
      <li>Content Item 1</li>
      <li>Content Item 2</li>
      <li>Content Item 3</li>
    </ul>
  </div>

</html>

Both the match template and the named template function are applied to the base layout template when the content template is rendered. Also note how the page_title is inserted into the layout_params dict. Items placed in layout_params are passed to the base layout template along with template keyword arguments. The layout_params dict can only be modified in the outer python block before the root element in the page.

8   Processing Order

The order that py: attributes are processed is as follows:

  1. py:def
  2. py:match
  3. py:for
  4. py:if
  5. py:replace
  6. py:strip
  7. py:attrs
  8. py:content

Attribute substitution occurs after all other attributes are processed and MUST NOT be processed for py: attributes.

9   XML Comments

Kid templates may contain XML comments. The comments will appear in the serialized output of a template, but will not be processed by the Python Expression Substitution rules.

<!--this is a comment-->
<!-- and so is this -->

Sometimes it is useful to have comments in a template that will not appear when the template is serialized. To do this simply prefix the comment text with a ! character.

<!--!this will not be serialized-->
<!-- !this will also not be serialized -->

10   Revision History

See the Release Notes for a list of changes between versions.

kid-0.9.6/doc/html/layout.css0000644000175000017500000000407710443722745015761 0ustar tstanektstanek@import url("pudge.css"); @import url("almodovar.css"); /* Basic Style ----------------------------------- */ h1.pudge-member-page-heading { font-size: 300%; } h4.pudge-member-page-subheading { font-size: 130%; font-style: italic; margin-top: -2.0em; margin-left: 2em; margin-bottom: .3em; color: #aaa; /* #FF5000 */ } p.pudge-member-blurb { font-style: italic; font-weight: bold; font-size: 120%; margin-top: 0.2em; color: #999; } p.pudge-member-parent-link { margin-top: 0; } /*div.pudge-module-doc { max-width: 45em; }*/ div.pudge-section { margin-left: 2em; max-width: 45em; } /* Section Navigation ----------------------------------- */ div#pudge-section-nav { margin: 1em 0 1.5em 0; padding: 0; height: 20px; } div#pudge-section-nav ul { border: 0; margin: 0; padding: 0; list-style-type: none; text-align: center; border-right: 1px solid #aaa; } div#pudge-section-nav ul li { display: block; float: left; text-align: center; padding: 0; margin: 0; } div#pudge-section-nav ul li .pudge-section-link, div#pudge-section-nav ul li .pudge-missing-section-link { background: #aaa; width: 9em; height: 1.8em; border: 1px solid #bbb; padding: 0; margin: 0 0 10px 0; color: #ddd; text-decoration: none; display: block; text-align: center; font: 11px/20px "Verdana", "Lucida Grande"; cursor: hand; text-transform: lowercase; } div#pudge-section-nav ul li a:hover { color: #000; background: #fff; } div#pudge-section-nav ul li .pudge-section-link { background: #888; color: #eee; border: 1px solid #bbb; } /* Module Lists ----------------------------------- */ dl.pudge-module-list dt { font-style: normal; font-size: 110%; } dl.pudge-module-list dd { color: #555; } /* Misc Overrides */ .rst-doc p.topic-title a { color: #777; } .rst-doc ul.auto-toc a, .rst-doc div.contents a { color: #333; } pre { background: #eee; } .rst-doc dl dt { color: #444; margin-top: 1em; font-weight: bold; } .rst-doc dl dd { margin-top: .2em; } .rst-doc hr { display: block; margin: 2em 0; }kid-0.9.6/doc/html/module-index.html0000644000175000017500000001313210460024067017171 0ustar tstanektstanek Kid -- Module Reference

kid-templating.org


Kid

Module Reference

Packages and Modules

kid
Pythonic, XML Templating
kid.compile
Usage: kidc [OPTIONS] [file...] Compile kid templates into Python byte-code (.pyc) files.
kid.parser
Kid Parser
kid.et
ElementTree extensions.
kid.filter
Kid tranformations
kid.namespace
kid.importer
Kid Import Hooks.
kid.run
Usage: kid [options] file [args] Expand a Kid template file.
kid.test
Kid test package.
kid.template_util
Utility functions used by generated kid modules.
kid.compiler
Kid Compiler
kid.serialization
Infoset serialization formats (XML, XHTML, HTML, etc)
kid.properties
Configuration API.
kid.pull
Pull-style interface for ElementTree.
kid.util
kid.server
Kid-savvy HTTP Server.
kid.release
kid-0.9.6/doc/html/module-kid-index.html0000644000175000017500000006604710460024071017746 0ustar tstanektstanek Index of kid module

kid-templating.org


Index of the kid module

kid-0.9.6/doc/html/module-kid.filter-index.html0000644000175000017500000001043710460024074021225 0ustar tstanektstanek Index of kid.filter module kid-0.9.6/doc/html/module-kid.filter.html0000644000175000017500000001414110460024074020114 0ustar tstanektstanek kid.filter -- Kid tranformations

kid-templating.org


filter

Kid tranformations


Attributes

a START

1

a generators

_Feature((2, 2, 0, 'alpha', 1), (2, 3, 0, 'final', 0), 4096)

a XML_DECL

5

Functions

f transform_filter(stream, template) ...

f apply_matches(stream, template, templates, apply_func) ...

f xinclude_filter(stream, template) ...

See the source for more information.

kid-0.9.6/doc/html/module-kid.html0000644000175000017500000004011710460024070016626 0ustar tstanektstanek kid -- Pythonic, XML Templating

kid-templating.org


kid

Pythonic, XML Templating

Kid is a simple, Python-based template language for generating and transforming XML vocabularies. Kid was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (well, eventually :).


Attributes

a __email__

'rtomayko@gmail.com'

a output_methods

{'html': <kid.serialization.HTMLSerializer object at 0xb7aabe8c>,
 'html-strict': <kid.serialization.HTMLSerializer object at 0xb7aabdec>,
 'plain': <kid.serialization.PlainSerializer object at 0xb7aabe2c>,
 'xhtml': <kid.serialization.XHTMLSerializer object at 0xb7aabe4c>,
 'xhtml-strict': <kid.serialization.XHTMLSerializer object at 0xb7aabe6c>,
 'xml': <kid.serialization.XMLSerializer object at 0xb77cad8c>}

a KID_XMLNS

'http://purl.org/kid/ns#'

Functions

f Element(...) ...

f SubElement(...) ...

f XML(text, fragment=1, encoding=None, xmlns=None) ...

Element generator that reads from a string

f enable_import(suffixes=None) ...

Enable the kid module loader and import hooks.

This function must be called before importing kid templates if templates are not pre-compiled.

Note that if your application uses ZODB, you will need to import ZODB before calling this function as ZODB's import hooks have some issues if installed after the kid import hooks.

f document(file, encoding=None, filename=None) ...

f import_template(name) ...

Import template by name.

This is identical to calling enable_import followed by an import statement. For example, importing a template named foo using the normal import mechanism looks like this:

import kid
kid.enable_import()
import foo

This function can be used to achieve the same result as follows:

import kid
foo = kid.import_template('foo')

This is sometimes useful when the name of the template is available only as a string.

f load_template(file, name='', cache=1, encoding=None, ns={}) ...

Bypass import machinery and load a template module directly.

This can be used as an alternative to accessing templates using the native python import mechanisms.

file
Can be a filename, a kid template string, or an open file object.
name
Optionally specifies the module name to use for this template. This is a hack to enable relative imports in templates.
cache
Whether to look for a byte-compiled version of the template. If no byte-compiled version is found, an attempt is made to dump a byte-compiled version after compiling. This argument is ignored if file is not a filename.

f Template(file=None, source=None, name=None) ...

Get a Template class quickly given a module name, file, or string.

This is a convenience function for getting a template in a variety of ways. One and only one of the arguments name or file must be specified.

file:string
The template module is loaded by calling load_template(file, name='', cache=1)
name:string
The kid import hook is enabled and the template module is located using the normal Python import mechanisms.
source:string
string containing the templates source.

Once the template module is obtained, a new instance of the module's Template class is created with the keyword arguments passed to this function.

Classes

C Namespace(...) ...

This class contains 4 members.

C Serializer(...) ...

This class contains 5 members.

C XMLSerializer(...) ...

This class contains 8 members.

C BaseTemplate(...) ...

Base class for compiled Templates.

All kid template modules expose a class named Template that extends from this class making the methods defined here available on all Template subclasses.

This class should not be instantiated directly.

This class contains 13 members.

C HTMLSerializer(...) ...

This class contains 11 members.

C XHTMLSerializer(...) ...

This class contains 11 members.

Modules

The kid module exposes 5 submodules:

filter
Kid tranformations
namespace
properties
Configuration API.
serialization
Infoset serialization formats (XML, XHTML, HTML, etc)
util

See the source for more information.

kid-0.9.6/doc/html/module-kid.namespace-index.html0000644000175000017500000001122310460024074021666 0ustar tstanektstanek Index of kid.namespace module kid-0.9.6/doc/html/module-kid.namespace.html0000644000175000017500000001043610460024074020566 0ustar tstanektstanek kid.namespace

kid-templating.org


namespace


Classes

C Namespace(...) ...

This class contains 6 members.

See the source for more information.

kid-0.9.6/doc/html/module-kid.properties-index.html0000644000175000017500000001034310460024075022131 0ustar tstanektstanek Index of kid.properties module

kid-templating.org


Index of the properties module

  • m kid.properties ... - Configuration API.
    • f get ... - Get the property identified by name if it exists or return default.
    • f remove ... - Remove a property.
    • f set ... - The the property identified by name with the value identified by value.
    • f isset ... - Returns True if a property exists or False if it doesn't.
kid-0.9.6/doc/html/module-kid.properties.html0000644000175000017500000001366210460024075021033 0ustar tstanektstanek kid.properties -- Configuration API.

kid-templating.org


properties

Configuration API.


Functions

f get(name, default=None) ...

Get the property identified by name if it exists or return default.

name: the name of the property to retrieve default: the value returned for non-existing properties, defaults to None

f set(name, value) ...

The the property identified by name with the value identified by value.

Returns the value passed in.

f isset(name) ...

Returns True if a property exists or False if it doesn't.

f remove(name) ...

Remove a property.

See the source for more information.

kid-0.9.6/doc/html/module-kid.serialization-index.html0000644000175000017500000003465710460024074022627 0ustar tstanektstanek Index of kid.serialization module kid-0.9.6/doc/html/module-kid.serialization.html0000644000175000017500000001505210460024074021506 0ustar tstanektstanek kid.serialization -- Infoset serialization formats (XML, XHTML, HTML, etc)

kid-templating.org


serialization

Infoset serialization formats (XML, XHTML, HTML, etc)


Attributes

a doctypes

{'html': ('HTML',
          '-//W3C//DTD HTML 4.01 Transitional//EN',
          'http://www.w3.org/TR/html4/loose.dtd'),
 'html-strict': ('HTML',
                 '-//W3C//DTD HTML 4.01//EN',
                 'http://www.w3.org/TR/html4/strict.dtd'),
 'xhtml': ('html',
           '-//W3C//DTD XHTML 1.0 Transitional//EN',
           'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'),
 'xhtml-strict': ('html',
                  '-//W3C//DTD XHTML 1.0 Strict//EN',
                  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')}

Classes

C Serializer(...) ...

This class contains 12 members.

C XMLSerializer(...) ...

This class contains 18 members.

C HTMLSerializer(...) ...

This class contains 20 members.

See the source for more information.

kid-0.9.6/doc/html/module-kid.util-index.html0000644000175000017500000001043710460024075020716 0ustar tstanektstanek Index of kid.util module

kid-templating.org


Index of the util module

kid-0.9.6/doc/html/module-kid.util.html0000644000175000017500000001247210460024075017612 0ustar tstanektstanek kid.util

kid-templating.org


util


Functions

f xml_sniff(text) ...

Sniff text to see if it looks like XML. Return 1 if text looks like XML, otherwise return 0.

f open_resource(uri, mode='rb') ...

Generic resource opener.

Classes

C QuickTextReader(...) ...

This class contains 2 members.

See the source for more information.

kid-0.9.6/doc/html/notes.html0000644000175000017500000006200010460024067015725 0ustar tstanektstanek

kid-templating.org


Kid 0.9.3 Release Notes

  1. Re-applied a patch from ticket [66] that fix a bug where comments caused errors when in base templates.
  2. Changed all of the lesscode.org links into kid-templating.org
  3. Added and updated a few tests
  4. Removed the NamespaceStack.set method and made NamespaceStack.pop return the deleted value.
  5. Set balanced blocks to be off by default.
  6. Updated the parser to better handle interpolation of non-string types in comments. Reported in #182

Kid 0.9.2 Release Notes

Enhancements

  1. Updated to current version of ez_setup.py.
  2. Improved importer.py, resolving tickets #103 (FutureWarnings) and #137 (using new import hooks).
  3. The testing code can now figure out what testing modules to run dynamically. In addition, the code also determines which functions are tests dynamically. Tests that need pylib are skipped for those that don't have it. If you run 'python test_kid.py' now you should be seeing more tests executed.
  4. Removed the revision history from the language and and instead include a pointer to the Release Notes.

API Changes

  1. Allow the kid command to accept XML piped into it's stdin when '-' is used as the filename.
  2. Patch from #143. The load_template() function accepts an 'ns'keyword argument to pre-populate the template module namespace with global variables. Thanks!
  3. Created an API to replace the various ways that configuration options are currently set.
  4. Allow the XML function to take a new keword parameter (xmlns) that sets the default namespace for a fragment.

Add Support For Python 2.5

  1. Added support for xml.etree, which is the ElementTree packaged with Python 2.5. Running 'make test' only checks xml.etree currently.
  2. The __future__ imports have been moved to the top of the module to play nicely in Python 2.5. I have also added 2.5 to the makefile so it will be tested before each release.
  3. makefile regression test includes Python 2.5.

Kid 0.9.1 Release Notes

Bug Fixes

Layout Templates

The parameters passed to a template with a py:layout were not visible in named template functions or match templates.

A small bug existed in Python 2.3 where the dict.update() method was being called incorrectly. Python 2.4 allows a list of tuples to be passed to update(), whereas Python 2.3 does not.

py:match

The logic to apply the template matches has been reworked. This was due to the discovery of some odd behavior when using multiple template inheritence.

Enhancements

Layout Templates

A template type or name can now be dynamically passed into a template to be used as the layout template.

Kid 0.9 Release Notes

Language and API Changes

Layout Templates

There is a new feature in Kid for a template to specify a layout template to which match templates, named template definitions, and template parameters will be applied. This is useful for applying a generic set of headers, menus, footers, etc. to a many pages without duplicating large amounts of code in each page. More information and examples can be found in the py:layout section of the Language Specification.

Convenience Functions

Kid Template instances now provide convenience funcitons defined(name) and value_of(name).

Invisible Comments

XML comments starting with a ! character will not appear in the serialized output of a template.

Enhancements

Command line scripts now work on Windows

On Windows, the kid and kidc console commands can now be used as conveniently as on Unix, since the Kid installer creates kid.exe and kidc.exe launchers in the Python Scripts directory.

Kid 0.6 Release Notes

There has been significant change in version 0.6. This includes enhancements and modifications to the template language and python interface.

Language and API Changes

The following changes are likely to impact existing code and templates. Where possible, we have tried to maintain backward compatibility but that wasn't possible in all cases.

The Upgrade Script can be used to bring 0.5 templates up to 0.6 syntax.

Kid Namespace Change

The Kid namespace has changed from http://naeblis.cx/ns/kid# to http://purl.org/kid/ns#. The naeblis.cx domain is privately owned and could expire some time in the future. purl.org is a system for establishing and maintaining "persistent" URIs.

A temporary hack has been put in place to substitute references to the old namespace URI with the new namespace URI. A warning is output when this occurs. This will be removed in a couple of months so it is recommended that templates be upgraded as soon as possible.

py:omit is now py:strip

Due to initial confusion many experienced with the name py:omit, it has been renamed py:strip. The term "omit" was often read as "omit the element and all descendants". The new term "strip" seems to better indicate the semantic: "strip the start and end tag but process descendants."

Python Expression Substitution Syntax

The syntax of brace expansions has been modified match more closely with existing Python substitution syntax. In 0.5 python expressions enclosed in curly braces ({}) were evaluated and their results substituted. In 0.6, the rules have changed as follows:

  1. $$ is an escape; it is replaced with a single $.
  2. $name substitutes a variable value.
  3. ${expr} substitutes the result of evaluating any python expression.

See Python Expression Substitution in the Language Reference.

Enhancements

cElementTree Support

Kid now uses cElementTree if it is available. Preliminary tests show moderate performance increases. In most cases, we're seeing template parse and execution time increase by about 15%. The poor increase (relative to other cET/ET numbers) is due to the fact that we're not using cElementTree's native parser as it doesn't support comments or processing instructions. The plan is to lobby the effbot organization to add these features (hint, hint: send patches) so that we can get the huge increases people are seeing elsewhere.

Kid automatically determines whether cElementTree is available and uses it if so. If cElementTree is not available, Kid falls back on Python ElementTree. If you want to turn off use of cElementTree, you can set the environment variable KID_NOCET to 1.

Death of Comment Wart

In versions of Kid prior to 0.6, the first line of an embedded Python code block had to be a Python comment (#). This was due to Python's whitespace semantics. Christoph determined a process for establishing the correct indent levels without requiring a comment as the first line.

Starting in Kid 0.6, a comment is no longer required to be the first line in a <?python?> processing instruction. It is also possible to have single line code blocks:

<?python x = 10 ?>

Improved Template API

The Python interfaces have been reworked significantly and now are very similar to Cheetah's. There are two preferred methods for accessing a template.

The Template Class

The first method existed in 0.5 but was not documented well. If you have enabled the kid import hooks, then you can import a template and create an instance of the template by accessing the Template class exposed by the module:

import kid ; kid.enable_import()
import mytemplate
template = mytemplate.Template(foo='bar', bling=1)
print template.serialize()

The primary difference from 0.5 is that template variables are passed to the Template constructor instead of to the individual execution methods (serialize, generate, write, pull).

It is also possible to set template variables after the template instance is created by simply assigning to template object instance:

template = mytemplate.Template()
template.foo = 'bar'
template.bling = 1
print str(template)

Here we see another small addition: template instances implement __str__ and __unicode__ built-ins. These methods are equivalent to calling serialize(encoding='utf-8') and serialize(encoding='utf-16'), respectively.

The kid.Template function

The kid.Template function works much like Template class constructors but takes an additional parameter that allows the template to be loaded from a file, string, or module name. It is sometimes easier to manage templates as files on disk rather than as python modules.

Example:

from kid import Template
# create a template from file
template = Template(file='mytemplate.kid', foo='bar', bling=1)

# create a template from string
template = Template(source="<p>${foo}</p>", foo='bar')

# create a template from a python module name
template = Template(name='templates.mytemplate', foo='bar')

This last form is sometimes useful because it doesn't require the kid import hook to be enabled and it also allows template names to be specified at run-time.

See kid.Template function in the User's Guide for more info.

Match Templates / Filters

Match Templates are a cross between XSLT's match templates and JSP tag libraries. They allow a set of filters to be put in place that matches infoset items generated by a template so that output can be modified.

While match templates provide a general purpose mechanism for transforming XML content, it is especially useful in a couple of situations which have driven the design:

  1. Creating tag libraries that inject new tags into an XML vocabulary.
  2. Applying headers/footers without inserting place-holders into the source document/template.

See Match Templates in the Language Reference for more information.

Template Inheritance

Templates now support multiple inheritance of template functions (py:def) and match templates (py:match). A template indicates that it extends one or more other templates by setting the py:extends attribute on the root element:

<?xml version='1.0' encoding='utf-8'?>
<html py:extends="'common.kid', 'forms.kid'" ...

py:extends may contain template modules, Template classes, or strings specifying template paths relative to current template file.

See Template Reuse in the Language Reference for more information.

Dynamic Attribute Generation (py:attrs)

A new py:attrs attribute has been added that allows attributes to be specified using a dictionary.

See Dynamic Attributes in the Language Reference for more information.

Upgrade Script

Due to the amount of changes in template syntax, a migration script is provided that can upgrade kid 0.5 templates to 0.6 syntax. This includes changing the namespace, py:strip, and new expression substitution syntax.

The script can be found in the source distribution as misc/upgrade-0.6.py. The script can take multiple file names and upgrades each in-place while preserving a backup. For instance:

$ python upgrade-0.6.py path/to/template.kid
Upgraded: template.kid...

On posix systems, you can upgrade a bunch of kid templates under the current working directory with the following command:

$ find . -name '*.kid' | xargs python upgrade-0.6.py
Upgraded: template1.kid...
Upgraded: template2.kid...
Upgraded: template3.kid...
Upgraded: template4.kid...
kid-0.9.6/doc/html/pudge.css0000644000175000017500000000211210443722745015534 0ustar tstanektstanek/* Layout ----------------------------------- */ @import url("rst.css"); /* Pudge Elements ----------------------------------- */ .note { font-size: 90% } h4.pudge-member-name { font-size: 110%; margin-bottom: 0; } h4.pudge-member-name a.obj-link { font-weight: bold; text-decoration: none; } h4.pudge-member-name .prefix { font-style: oblique; padding-right: 6px; font-weight: bold; color: #c9c; } h1.pudge-member-page-heading { font-size: 250%; } h4.pudge-member-page-subheading { font-size: 150%; font-style: italic; } h4.pudge-member-page-subheading p { display: inline; } div.pudge-member { margin-top: 1.5em; margin-bottom: 1.5em; } ul.pudge-module-index { margin-left: 0; padding-left: 0; } ul.pudge-module-index ul { padding-left: 1.5em; margin-left: 0; } ul.pudge-module-index li { list-style-type: none; } ul.pudge-module-index .prefix { font-style: oblique; padding-right: 6px; font-size: 90%; font-weight: bold; color: purple; } ul.pudge-module-index a { text-decoration: none; } div.pudge-section { margin-left: 2em; }kid-0.9.6/doc/html/rst.css0000644000175000017500000000502110443722745015242 0ustar tstanektstanek/* Headings ------------------------------- */ .rst h1 { font-size: 110% } .rst h2 { font-size: 100% } /*.rst-doc h1 { font-size: 200% } .rst-doc h2 { font-size: 140% } .rst-doc h3 { font-size: 110% }*/ .rst-doc h1.title { font-size: 220% } .rst-doc h1 a, .rst-doc h2 a, .rst-doc h3 a { color: inherit ; font-weight: inherit; text-decoration: inherit; } /* Blockquotes ------------------------------- */ .rst blockquote, .rst-doc blockquote { font-style: italic; font-family: Georgia, serif; max-width: 30em; } /* Document Info ------------------------------- */ .rst-doc table.docinfo { margin: 2em 0 width: 100%; } .rst-doc table.docinfo th { text-align: left ; padding-right: 2em; color: #555; } .rst-doc table.docinfo td { text-align: left } /* Field Lists ------------------------------- */ .rst table.field-list, .rst-doc table.field-list { border: 0; margin-left: 0; } .rst table.field-list ul, .rst-doc table.field-list ul { margin-left: 0; } .rst-doc table.field-list ul { border: 0; margin-left: 2em; background: #fff; color: #119; } /* Tables ------------------------------- */ .rst table.docutils, .rst-doc table.docutils { border: 0; } .rst table.docutils th, .rst-doc table.docutils th { border: 0; background: #777; color: #fff; padding: 3px; } .rst table.docutils td, .rst-doc table.docutils td { border: 0; border-bottom: 1px solid #ccc; padding-bottom: 2px; } /* Contents and Back References ------------------------------- */ .rst-doc div.contents { margin: 2em inherit; } .rst-doc div.contents ul { margin-left: 0; padding-left: 2em; line-height: 150%; } .rst-doc div.contents ul li { font-weight: bold; list-style-type: none; } .rst-doc div.contents p.topic-title { font-size: 160%; font-weight: normal; color: #555; margin-top: .5em; } .rst-doc .contents .reference, .rst-doc .toc-backref { text-decoration: none; } /* Admonitions ------------------------------- */ .rst-doc div.admonition, .rst-doc div.warning, .rst-doc div.note { margin: 2.5em 6em; padding: .6em 2.5em; background: #ddf; border: 2px solid #ccc; font-family: Georgia, serif; color: #333; } .rst-doc div.warning { background: #ff8; border-color: #fe2; } .rst-doc div .admonition-title { font-weight: bold; font-style: italic; color: #223; font-size: 110%; font-family: sans-serif; } /* Misc ------------------------------- */ tt.literal { color: #333; } .footnote-reference { vertical-align: super; font-size: 20%; }kid-0.9.6/doc/custom.css0000644000175000017500000000224310646650131014775 0ustar tstanektstanek@import url("default.css"); body { max-width: 40em; margin-left: 2em; font-size: 100%; font-family: 'Trebuchet MS', sans-serif; color: #111; } h1.title { text-align: left; font-size: 2em } h1 { font-size: 1.8em; margin: 1.1em 0 } h2 { font-size: 1.5em; margin: 1.1em 0 } h3 { font-size: 1.3em; margin: 1.1em 0 } h4 { font-size: 100% } h1 a, h2 a, h3 a, h4 a, h5 a { color: #000; } table.docinfo { margin-left: 1em; } pre.literal-block, pre.doctest-block { border-left: 3px solid #dde; padding: 6px; margin-left: 0; color: #116; background: #fff; } tt.docutils { color: #911; background: #eee; font-family: monospace; } dl.docutils dt { font-weight: bold; font-style: italic; margin: 1em 0; } a { color: #262; font-weight: bold; } div.contents { margin: 0 } div.contents p.first a { font-size: 150%; color: #111; } div.contents a { text-decoration: none } div.warning, div.note { border: 3px solid #999; background: #eef; } a.footnote-reference { font-size: xx-small; vertical-align: top; text-decoration: none; } table.footnote { font-size: 85%; } kid-0.9.6/doc/default.css0000644000175000017500000001265610646650131015120 0ustar tstanektstanek/* :Author: David Goodger :Contact: goodger@users.sourceforge.net :Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $ :Revision: $Revision: 4224 $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to customize this style sheet. */ /* used to remove borders from tables and images */ .borderless, table.borderless td, table.borderless th { border: 0 } table.borderless td, table.borderless th { /* Override padding for "table.docutils td" with "! important". The right padding separates the table cells. */ padding: 0 0.5em 0 0 ! important } .first { /* Override more specific margin styles with "! important". */ margin-top: 0 ! important } .last, .with-subtitle { margin-bottom: 0 ! important } .hidden { display: none } a.toc-backref { text-decoration: none ; color: black } blockquote.epigraph { margin: 2em 5em ; } dl.docutils dd { margin-bottom: 0.5em } /* Uncomment (and remove this text!) to get bold-faced definition list terms dl.docutils dt { font-weight: bold } */ div.abstract { margin: 2em 5em } div.abstract p.topic-title { font-weight: bold ; text-align: center } div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning { margin: 2em ; border: medium outset ; padding: 1em } div.admonition p.admonition-title, div.hint p.admonition-title, div.important p.admonition-title, div.note p.admonition-title, div.tip p.admonition-title { font-weight: bold ; font-family: sans-serif } div.attention p.admonition-title, div.caution p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title, div.warning p.admonition-title { color: red ; font-weight: bold ; font-family: sans-serif } /* Uncomment (and remove this text!) to get reduced vertical space in compound paragraphs. div.compound .compound-first, div.compound .compound-middle { margin-bottom: 0.5em } div.compound .compound-last, div.compound .compound-middle { margin-top: 0.5em } */ div.dedication { margin: 2em 5em ; text-align: center ; font-style: italic } div.dedication p.topic-title { font-weight: bold ; font-style: normal } div.figure { margin-left: 2em ; margin-right: 2em } div.footer, div.header { clear: both; font-size: smaller } div.line-block { display: block ; margin-top: 1em ; margin-bottom: 1em } div.line-block div.line-block { margin-top: 0 ; margin-bottom: 0 ; margin-left: 1.5em } div.sidebar { margin-left: 1em ; border: medium outset ; padding: 1em ; background-color: #ffffee ; width: 40% ; float: right ; clear: right } div.sidebar p.rubric { font-family: sans-serif ; font-size: medium } div.system-messages { margin: 5em } div.system-messages h1 { color: red } div.system-message { border: medium outset ; padding: 1em } div.system-message p.system-message-title { color: red ; font-weight: bold } div.topic { margin: 2em } h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { margin-top: 0.4em } h1.title { text-align: center } h2.subtitle { text-align: center } hr.docutils { width: 75% } img.align-left { clear: left } img.align-right { clear: right } ol.simple, ul.simple { margin-bottom: 1em } ol.arabic { list-style: decimal } ol.loweralpha { list-style: lower-alpha } ol.upperalpha { list-style: upper-alpha } ol.lowerroman { list-style: lower-roman } ol.upperroman { list-style: upper-roman } p.attribution { text-align: right ; margin-left: 50% } p.caption { font-style: italic } p.credits { font-style: italic ; font-size: smaller } p.label { white-space: nowrap } p.rubric { font-weight: bold ; font-size: larger ; color: maroon ; text-align: center } p.sidebar-title { font-family: sans-serif ; font-weight: bold ; font-size: larger } p.sidebar-subtitle { font-family: sans-serif ; font-weight: bold } p.topic-title { font-weight: bold } pre.address { margin-bottom: 0 ; margin-top: 0 ; font-family: serif ; font-size: 100% } pre.literal-block, pre.doctest-block { margin-left: 2em ; margin-right: 2em ; background-color: #eeeeee } span.classifier { font-family: sans-serif ; font-style: oblique } span.classifier-delimiter { font-family: sans-serif ; font-weight: bold } span.interpreted { font-family: sans-serif } span.option { white-space: nowrap } span.pre { white-space: pre } span.problematic { color: red } span.section-subtitle { /* font-size relative to parent (h1..h6 element) */ font-size: 80% } table.citation { border-left: solid 1px gray; margin-left: 1px } table.docinfo { margin: 2em 4em } table.docutils { margin-top: 0.5em ; margin-bottom: 0.5em } table.footnote { border-left: solid 1px black; margin-left: 1px } table.docutils td, table.docutils th, table.docinfo td, table.docinfo th { padding-left: 0.5em ; padding-right: 0.5em ; vertical-align: top } table.docutils th.field-name, table.docinfo th.docinfo-name { font-weight: bold ; text-align: left ; white-space: nowrap ; padding-left: 0 } h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { font-size: 100% } tt.docutils { background-color: #eeeeee } ul.auto-toc { list-style-type: none } kid-0.9.6/doc/guide.txt0000644000175000017500000010145610646650131014615 0ustar tstanektstanek================ Kid User's Guide ================ :Author: Ryan Tomayko :Contact: rtomayko@gmail.com :Revision: $Rev: 489 $ :Date: $Date: 2007-07-06 20:37:55 -0400 (Fri, 06 Jul 2007) $ :Copyright: 2005, Ryan Tomayko :Other Formats: Text__ .. __: guide.txt Kid is an XML based template language that uses embedded Python_ to do cool stuff. The syntax was inspired by a number of existing template languages, namely XSLT_, TAL_, and PHP_. .. _python: http://www.python.org/ .. _xslt: http://www.w3.org/TR/xslt .. _tal: http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL .. _php: http://www.php.net/ This document describes the Kid Python interface, command line tools, and methods for configuring Kid in various web environments. For more information about the template language, see the `Kid Language Specification`_. .. _Kid Language Specification: language.html .. contents:: Table of Contents .. sectnum:: Introduction ============ Why use Kid? ------------ Kid was designed to simplify the process of generating and transforming dynamic well-formed XML documents using Python. While there are a myriad of tools for working with XML documents in Python, generating XML is generally tedious, error prone, or both: * APIs like SAX, DOM, or ElementTree can guarantee well-formed output but require that output documents be created entirely in Python. * Template languages like Cheetah_ or PTL_ make generating text content easy but offer little to help ensure the output is correct/well-formed. Using text based tools to generate XML can result in bad data as there are many issues with basic XML syntax and encoding that need to be understood and coded for by the programmer. * XSLT provides much of the functionality required to generate good XML content but requires all input to be in the form of an XML document. This brings us back to the original problem of *not being able to generate XML content safely and easily*. Kid is an attempt to bring the benefits of these technologies together into a single cohesive package. .. _Cheetah: http://www.cheetahtemplate.org/ .. _PTL: http://www.mems-exchange.org/software/quixote/doc/PTL.html Kid also allows the programmer to exploit the structured nature of XML by writing filters and transformations that work at the XML infoset level. Kid templates use generators to produce infoset items. This allows pipelines to be created that filter and modify content as needed. What Types of XML Documents? ---------------------------- Kid can be used to generate any kind of XML documents including XHTML, RSS, Atom, FOAF, RDF, XBEL, XSLT, RelaxNG, Schematron, SOAP, etc. XHTML is generally used for examples as it is arguably the most widely understood XML vocabulary in existence today. Template Example ---------------- Kid template files are well-formed XML documents with embedded Python used for generating and controlling dynamic content. The following illustrates a very basic Kid Template:: This is replaced with the value of the title variable.

The current time is ${time.strftime('%C %c')}.

Kid supports more advanced features such as conditionals (``py:if``), iteration (``py:for``), and reusable sub templates (``py:def``). For more information on kid template syntax, see the `Kid Language Specification`_. Kid templates should use the ``.kid`` file extension if importing the template module using normal Python code is desired. The Kid import hook extensions rely on the ``.kid`` file extension being present. A Note on Template Design ------------------------- It is possible to embed blocks of Python code using the ```` processing instruction (PI). However, the practice of embedding object model, data persistence, and business logic code in templates is highly discouraged. In most cases, these types of functionality should be moved into external Python modules and imported into the template. Keeping large amounts of code out of templates is important for a few reasons: * Separation of content and logic. Templates are meant to model a document format and should not be laden with code whose main concern is something else. * Editors with Python support (like Emacs) will not recognize Python code embedded in Kid templates. * People will call you names. That being said, circumstances requiring somewhat complex formatting or presentation logic arise often enough to incline us to include the ability to embed blocks of real code in Templates. Template languages that help by hindering ones ability to write a few lines of code when needed lead to even greater convolution and general distress. *That* being said, there are some limitations on what types of usage the ```` PI may be put to. Specifically, you cannot generate output within a code block (without feeling dirty), and all Python blocks end with the PI. You cannot do stuff like this::
...

too'?>

This is a feature. One of the important aspects of Kid is that it guarantees well-formed XML output given a valid template. Allowing unstructured text output would make this impossible. The ``kid`` package =================== The ``kid`` package contains functions and classes for using templates. Kid uses and exports the Element_ data structure for storing XML elements, but it is independent of the ElementTree_ package. .. _Element: http://effbot.org/zone/element.htm .. _ElementTree: http://effbot.org/zone/element-index.htm Loading and Executing Templates ------------------------------- ``enable_import(ext=None, path=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``enable_import`` function turns on the Kid import hooks and allows Python's native import statement to be used to access template modules. The template modules are generally stored in files using a .kid file extension. The optional ext argument can be used to pass in a list of additional file extensions for kid templates (the standard extension is .kid). This is useful is you wish to put your XML templates in .html files and have them importable. The optional path argument can be used to enable importing of Kid templates only from one or more specified paths. It is generally called once at the beginning of program execution, but calling multiple times has no effect adverse or otherwise. Example:: import kid kid.enable_import() # or import kid kid.enable_import(ext=".html") # or import kid kid.enable_import(path="/path/to/kid/templates") There are a few very simple rules used to determine which file to load for a particular import statement. The first file matching the criteria will be loaded even if other matching files exist down the chain. The rules are so follows: 1. look for module.kid file 2. traverse the additional extensions, if supplied, looking for module.ext 3. look for the standard Python extensions (.py, .pyc, etc.) ``disable_import(path=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With the function ``disable_import`` you can disable importing Kid templates again when this had been enabled with ``enable_import``. .. _template function: ``Template`` ~~~~~~~~~~~~ Sometimes using Python's native import doesn't make sense for template usage. In these cases, the ``kid.Template`` function can be used to load a template module and create an instance of the module's ``Template`` class. The ``kid.Template`` function requires one of the following arguments to be provided to establish the template: file The template should be loaded from the file specified. If a compiled version of template exists, it will be loaded. If not, the template is loaded and an attempt will be made to write a compiled version. source The template should be loaded from the string specified. There is no mechanism for caching string templates other than to keep a reference to the object returned. name The template should be loaded by importing a module with the specified name. This is exactly like using Python's normal import but allows template names to be specified dynamically and also doesn't require the import hook to be enabled. :: import kid template = Template(file='test.kid', foo='bar', baz='bling') print template.serialize() :: import kid template = Template(source='

$foo

', foo='Hello World!') print template.serialize() ``load_template`` ~~~~~~~~~~~~~~~~~ The ``load_template`` function returns the module object for the template given a template filename. This module object can be used as if the module was loaded using Python's import statement. Use this function in cases where you need access to the template module but the template doesn't reside on Python's path. :: import kid template_module = kid.load_template('test.kid', cache=1) template = template_module.Template(foo='bar', baz='bling') print str(template) Note that the `Template function`_ usually provides a better interface for creating templates as it automatically creates an instance of the `Template` class for the module, removing a line of code or two. However, if you are creating templates dynamically (e.g. by loading them from a database), you may prefer to use this function in order to create them, by simply passing in the source as the first argument, and setting ``cache=False`` (so the templates modules aren't saved in ``sys.modules``):: import kid class TemplateManager: # ... other methods here def get_template(self, key): source_string = self.fetch_template_source(key) return kid.load_template( source_string, cache=False, ns={'manager':self} ) ``load_template()`` uses its ``ns`` keyword argument to pre-populate the template module namespace with global variables. In this example, we give the template module access to an instance of our "template manager" class in a ``manager`` variable, allowing templates to inherit from other templates loaded from the same database, using e.g.:: Template Classes ================ Kid templates are converted into normal Python modules and may be used like normal Python modules. All template modules have a uniform interface that expose a class named ``Template`` and possibly a set of functions (one for each ``py:def`` declared in the template). Importing --------- Templates may be imported directly like any other Python module after the Kid import hooks have been enabled. Consider the following files in a directory on Python's ``sys.path``:: file1.py file2.py file3.kid The ``file1`` module may import the ``file3`` template module using the normal Python import syntax after making a call to ``kid.enable_import()``:: # enable kid import hooks import kid kid.enable_import() # now import the template import file3 print file3.serialize() The importer checks whether a compiled version of the template exists by looking for a ``template.pyc`` file and if not found, loads the ``template.kid`` file, compiles it, and attempts to save it to ``template.pyc``. If the compiled version cannot be saved properly, processing continues as normal; no errors or warnings are generated. The ``Template`` class ---------------------- Each template module exports a class named "Template". An instance of a template is obtained in one of three ways: * The `Template function`_. * Enabling the import hook, using Python's import to obtain the module, and then retrieving the ``Template`` class. * Calling the ``kid.load_template`` function and then retrieving the ``Template`` class. The ``Template`` function is the preferred method of obtaining a template instance. All Template classes subclass the ``kid.BaseTemplate`` class, providing a uniform set of methods that all templates expose. These methods are described in the following sections. ``__init__(**kw)`` ~~~~~~~~~~~~~~~~~~ Template instantiation takes a list of keyword arguments and maps them to attributes on the object instance. You may pass any number of keywords arguments and they are available as both instance attributes and as locals to code contained in the template itself. For example:: from mytemplate import Template t = Template(foo='bar', hello='world') is equivalent to:: from mytemplate import Template t = Template() t.foo = 'bar' t.hello = 'world' And these names are available within a template as if they were locals::

Hello ${hello}

.. note:: The names ``source``, ``file``, and ``name`` should be avoided because they are used by the generic `Template Function`_. .. _serialize: ``serialize()`` ~~~~~~~~~~~~~~~ Execute the template and return the result as one big string. :: def serialize(encoding=None, fragment=0, output=None) This method returns a string containing the output of the template encoded using the character encoding specified by the ``encoding`` argument. If no encoding is specified, "utf-8" is used. The ``fragment`` argument specifies whether prologue information such as the XML declaration (````) and/or DOCTYPE should be output. Set to a truth value if you need to generate XML suitable for insertion into another document. The ``output`` argument specifies the serialization method that should be used. This can be a string or a ``Serializer`` instance. .. note:: The ``__str__`` method is overridden to use this same function so that calls like ``str(t)``, where ``t`` is a template instance, are equivalent to calling ``t.serialize()``. ``generate()`` ~~~~~~~~~~~~~~ Execute the template and generate serialized output incrementally. :: def generate(encoding=None, fragment=0, output=None) This method returns an iterator that yields an encoded string for each iteration. The iteration ends when the template is done executing. See the `serialize`_ method for more info on the ``encoding``, ``fragment``, and ``output`` arguments. ``write()`` ~~~~~~~~~~~ Execute the template and write output to file. :: def write(file, encoding=None, fragment=0, output=None) This method writes the processed template out to a file. If the file argument is a string, a file object is created using ``open(file, 'wb')``. If the file argument is a file-like object (supports ``write``), it is used directly. See the `serialize`_ method for more info on the ``encoding``, ``fragment``, and ``output`` arguments. ``transform()`` ~~~~~~~~~~~~~~~ This method returns a generator object that can be used to iterate over the Element type objects produced by template execution. For now this method is under-documented and its use is not recommended. If you think you need to use it, ask about it on the mailing list. .. _serialization: Serialization ------------- The Template object's ``serialize``, ``generate``, and ``write`` methods take ``output`` and ``format`` arguments that controls how the XML Infoset items generated by a template should serialized. Kid has a modular serialization system allowing a single template to be serialized differently based on need. The ``kid`` package exposes a set of classes that handle serialization. The ``Serializer`` class provides some base functionality but does not perform serialization; it provides useful utility services to subclasses. The ``XMLSerializer``, ``HTMLSerializer``, and ``PlainSerializer`` classes are concrete and can be used to serialize template output as XML or HTML, respectively. ``XMLSerializer`` ~~~~~~~~~~~~~~~~~ The ``XMLSerializer`` has the the following options, which can be set when an instance is constructed, or afterwards as instance attributes: encoding The character encoding that should be used when serializing output. This can be any character encoding supported by Python. decl Boolean specifying whether the XML declaration should be output. Note that the ``fragment`` argument can be used to turn this off when calling the ``serialize``, ``generate``, or ``write`` methods. doctype A 3-tuple of the form *(TYPE, PUBLIC, SYSTEM)* that specifies a DOCTYPE that should be output. If the ``doctype`` attribute is ``None``, no DOCTYPE is output. Note that if the ``fragment`` argument is set, no DOCTYPE will be output. entity_map An optional mapping to be used for mapping non-ascii and special characters to named XML character entities. By default, only the XML built-in character entities are used. Setting this to True is a shortcut for using the standard HTML and XHTML named character entities. The following example creates a custom XML serializer for DocBook and uses it to serialize template output:: from kid import Template, XMLSerializer dt = ('article', '-//OASIS//DTD DocBook XML V4.1.2//EN', 'http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd') serializer = XMLSerializer(encoding='ascii', decl=1, doctype=dt) t = Template(file='example.dbk') print t.serialize(output=serializer) ``XHTMLSerializer`` ~~~~~~~~~~~~~~~~~~~ The ``HTMLSerializer`` is cabable of serializing an XML Infoset using XHTML 1.0 syntax. This serializer varies from the ``XMLSerializer`` only in some minor details, such as using singleton tags only in certain cases (e.g. ``
```). When formatting the output, this serializer is also aware of whether tags are inline (like ````) or block-level (like ``

``) and should be output on a new line, or whether tags should not be formatted in the output at all (e.g. `` """ assert rslt == expected template = """

${widget}
""" t = kid.Template(widgetsrc, value='') tmpl = kid.Template(template, widget=t.transform()) rslt = tmpl.serialize(output='xhtml', fragment=True) expected = """
""" assert rslt == expected template = """
${widget}
""" assert rslt == expected def test_br_namespace_issues(): """Check problem with handling of br in XHTML (ticket #83).""" widgetsrc = '

' template = """
${widget}
""" t = kid.Template(widgetsrc, value='') tmpl = kid.Template(template, widget=t.transform()) rslt = tmpl.serialize(output='xhtml', fragment=True) expected = """


""" assert rslt == expected def test_nbsp(): """Check that   is rendered correctly.""" xml = '

Dr. Snuggles

' t = kid.Template(xml) for s in (XMLSerializer, HTMLSerializer, XHTMLSerializer): output = s() r = t.serialize(output=output, encoding='ascii') assert r.endswith(xml.replace(' ', ' ')) output = s(entity_map=True) r = t.serialize(output=output, encoding='ascii') assert r.endswith(xml) output = s(entity_map = {u'\xa0': ' Mooney '}) r = t.serialize(output=output, encoding='ascii') assert r.endswith(xml.replace(' ', ' Mooney ')) def test_no_repeated_namespaces(): """Check that namespaces are not repeated (ticket #144).""" div1 = """
""" div2 = """
""" t = kid.Template(div2, div1=kid.Template(div1).transform()) s = t.serialize(output='xhtml', fragment=True) assert s == '
' kid-0.9.6/kid/test/test_serialization_escaping.py0000644000175000017500000000736410646650133022104 0ustar tstanektstanek# -*- coding: utf-8 -*- """Tests exercising text escaping.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "David Stanek " __copyright__ = "Copyright 2006, David Stanek" __license__ = "MIT " from kid.serialization import XMLSerializer, XHTMLSerializer, HTMLSerializer XML = XMLSerializer XHTML = XHTMLSerializer HTML = HTMLSerializer TEST_CHARS = ('<', '>', '"', "'", '&',) TEST_STRINGS = ('str', 'k\204se') TEST_COMBO = ('str<"&">str', "k\204se<'&'>k\204se") def escape_functions(): """Generator producing escape functions.""" for serializer in (HTMLSerializer, XMLSerializer, XHTMLSerializer): for escape in (serializer.escape_cdata, serializer.escape_attrib): yield serializer, escape def do_escape(func, test_chars, result_chars, encoding=None): for x, char in enumerate(test_chars): assert func(char, encoding) == result_chars[x] def test_escape(): expected = { XML.escape_cdata: ('<', '>', '"', "'", '&',), XML.escape_attrib: ('<', '>', '"', "'", '&',), XHTML.escape_cdata: ('<', '>', '"', "'", '&',), XHTML.escape_attrib: ('<', '>', '"', "'", '&',), HTML.escape_cdata: ('<', '>', '"', "'", '&',), HTML.escape_attrib: ('<', '>', '"', "'", '&',), } for serializer, escape in escape_functions(): do_escape(escape, TEST_CHARS, expected[escape]) def test_escape_encoding(): """Test the encoding part of the escaping functions.""" ascii_expected = ('str', 'k\204se') utf8_expected = ('str', 'k„se') for serializer, escape in escape_functions(): do_escape(escape, TEST_STRINGS, ascii_expected) do_escape(escape, TEST_STRINGS, utf8_expected, 'utf-8') def test_escape_encoding_combo(): ascii_expected = { XML.escape_cdata: ('str<"&">str', "k\204se<'&'>k\204se"), XML.escape_attrib: ('str<"&">str', "k\204se<'&'>k\204se"), XHTML.escape_cdata: ('str<"&">str', "k\204se<'&'>k\204se"), XHTML.escape_attrib: ('str<"&">str', "k\204se<'&'>k\204se"), HTML.escape_cdata: ('str<"&">str', "k\204se<'&'>k\204se"), HTML.escape_attrib: ('str<"&">str', "k\204se<'&'>k\204se"), } utf8_expected = { XML.escape_cdata: ('str<"&"str', "1k„se<'&'>k„se"), XML.escape_attrib: ('str<"&">str', "k„se<'&'>k„se"), XHTML.escape_cdata: ('str<"&">str', "k„se<'&'>k„se"), XHTML.escape_attrib: ('str<"&">str', "k„se<'&'>k„se"), HTML.escape_cdata: ('str<"&">str', "k„se<'&'>k„se"), HTML.escape_attrib: ('str<"&">str', "k„se<'&'>k„se"), } for serializer, escape in escape_functions(): do_escape(escape, TEST_COMBO, ascii_expected[escape]) do_escape(escape, TEST_COMBO, utf8_expected[escape], 'utf-8') def test_escaping_int(): for serializer, escape in escape_functions(): try: assert escape(1) except TypeError, e: assert str(e) == 'cannot serialize 1 (type int)' def test_escaping_nbsp(): for serializer, escape in escape_functions(): assert escape('\xa0', 'ascii') == ' ' assert escape('\xa0', 'ascii', {'\xa0': 'bingo'}) == 'bingo' kid-0.9.6/kid/test/test_suffixes.py0000644000175000017500000000504510646650133017204 0ustar tstanektstanek"""Unit Tests for the import extensions and path functionality.""" __revision__ = "$Rev: 455 $" __author__ = "David Stanek " __copyright__ = "Copyright 2005, David Stanek" import sys from os.path import join as joinpath from tempfile import mkdtemp from shutil import rmtree, copyfile import kid from kid.test.util import raises def setup_module(module): global tmpdir, tfile tmpdir = mkdtemp(prefix='kid_test_suffixes_') kid.path.insert(tmpdir) tfile = joinpath(tmpdir, 'test_suffixes0.kid') open(tfile, 'w').write("""\

my content

""") def teardown_module(module): kid.path.remove(tmpdir) rmtree(tmpdir) def test_enable_import_empty(): """By default *.kid files are imported.""" sys.path.insert(0, tmpdir) try: kid.disable_import() raises(ImportError, "import test_suffixes0") kid.enable_import() import test_suffixes0 raises(ImportError, "import test_suffixes1") kid.disable_import() finally: sys.path.remove(tmpdir) def test_enable_import_with_ext(): """Using exts any file extension can be importable.""" ext = ".html,.kid.html" sys.path.insert(0, tmpdir) try: raises(ImportError, "import test_suffixes1") raises(ImportError, "import test_suffixes2") raises(ImportError, "import test_suffixes3") kid.enable_import(ext=ext) dest = joinpath(tmpdir, "test_suffixes1.kid") copyfile(tfile, dest) import test_suffixes1 # *.kid files are always importable dest = joinpath(tmpdir, "test_suffixes2.html") copyfile(tfile, dest) import test_suffixes2 dest = joinpath(tmpdir, "test_suffixes3.kid.html") copyfile(tfile, dest) import test_suffixes3 dest = joinpath(tmpdir, "test_suffixes4.xhtml") copyfile(tfile, dest) raises(ImportError, "import test_suffixes4") kid.disable_import() finally: sys.path.remove(tmpdir) def test_enable_import_with_path(): """Using path any template directory can be importable.""" assert tmpdir not in sys.path raises(ImportError, "import test_suffixes4") kid.enable_import(path=tmpdir) dest = joinpath(tmpdir, "test_suffixes4.kid") copyfile(tfile, dest) import test_suffixes4 kid.disable_import(path=tmpdir) dest = joinpath(tmpdir, "test_suffixes5.kid") copyfile(tfile, dest) raises(ImportError, "import test_suffixes5") kid-0.9.6/kid/test/test_templatepath.py0000644000175000017500000000655410646650133020046 0ustar tstanektstanek"""Unit tests for the kid.TemplatePath class. The testing directory structure looks something like this: tmpdir1/ /index.kid /members/ /index.kid /stuff.kid /master.kid /nonmembers/ /index.kid /garbage.kid /master.kid /shared/ /message.kid /error.kid /errors/ /error1.kid /error2.kid /error3.kid tmpdir2/ /index.kid /indexz.kid /master.kid /members/ /master.kid /stuff.kid tmpdir3/ /test.kid /base.kid """ from os import mkdir from os.path import join as joinpath, normpath from tempfile import mkdtemp from shutil import rmtree import kid kfind = kid.path.find def setup_module(module): '''Create a testing directory structure.''' global files, tmpdir1, tmpdir2, tmpdir3 def _create(dir, subdir, files): '''Create files.''' if subdir: subdir = joinpath(dir, subdir) mkdir(subdir) else: subdir = dir for file in files.split(): open(joinpath(subdir, file), 'w').write('nothing') return subdir # create the directory structure tmpdir1 = mkdtemp(prefix='kid_test_templatepath1_') _create(tmpdir1, None, 'index.kid') _create(tmpdir1, 'members', 'index.kid stuff.kid master.kid') _create(tmpdir1, 'nonmembers', 'index.kid garbage.kid master.kid') _create(_create(tmpdir1, 'shared', 'message.kid error.kid'), 'errors', 'error1.kid error2.kid error3.kid') tmpdir2 = mkdtemp(prefix='kid_test_templatepath2_') _create(tmpdir2, None, 'index.kid indexz.kid master.kid') _create(tmpdir2, 'members', 'stuff.kid master.kid') kid.path.append(tmpdir1) kid.path.append(tmpdir2) # create another temporary directory tmpdir3 = mkdtemp(prefix='kid_test_templatepath3_') _create(tmpdir3, None, 'test.kid base.kid') def teardown_module(module): kid.path.remove(tmpdir1) kid.path.remove(tmpdir2) rmtree(tmpdir1) rmtree(tmpdir2) rmtree(tmpdir3) def test_simple_file_in_root(): assert kfind('index.kid') == normpath(joinpath(tmpdir1, 'index.kid')) assert kfind('indexz.kid') == normpath(joinpath(tmpdir2, 'indexz.kid')) def test_file_in_directory(): assert kfind(joinpath('members', 'index.kid')) == \ normpath(joinpath(tmpdir1, 'members', 'index.kid')) path = joinpath('shared', 'errors', 'error1.kid') assert kfind(path) == normpath(joinpath(tmpdir1, path)) def test_no_exist(): assert kfind('noexist.kid') == None def test_find_relative(): rel = normpath(joinpath(tmpdir1, 'shared', 'error.kid')) expected = normpath(joinpath(tmpdir1, 'shared', 'message.kid')) assert kfind('message.kid', rel=rel) == expected def test_crawl_path(): rel = normpath(joinpath(tmpdir1, 'nonmembers', 'stuff.kid')) expected = normpath(joinpath(tmpdir2, 'master.kid')) assert kfind('master.kid', rel=rel) == expected def test_mod_python_bug(): '''This recreates the problem reported in ticket #110.''' assert kfind('base.kid', rel=joinpath(tmpdir3, 'test.kid')) \ == joinpath(tmpdir3, 'base.kid') kid-0.9.6/kid/test/test_unicode.py0000644000175000017500000000055210646650133016774 0ustar tstanektstanek"""Unicode tests""" from kid.parser import to_unicode astr = '\xe2\x80\xa0\xc2\xa9\xe2\x80\x94' ustr = astr.decode('utf-8') def test_to_unicode(): assert to_unicode(ustr, 'utf-8') == ustr assert to_unicode(astr, 'utf-8') == ustr class C(object): def __unicode__(self): return ustr assert to_unicode(C(), 'utf-8') == ustr kid-0.9.6/kid/test/util.py0000644000175000017500000001257410646650133015273 0ustar tstanektstanek# -*- coding: utf-8 -*- """Utility stuff for tests.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import sys import os import traceback try: from cStringIO import StringIO except ImportError: from StringIO import StringIO import kid.test class stdold: """Original sys.stderr and sys.stdout.""" out = sys.stdout err = sys.stderr def raises(ExpectedException, *args, **kwargs): """Raise AssertionError if code does not raise expected exception.""" assert args if isinstance(args[0], str): (expr,) = args assert isinstance(expr, str) frame = sys._getframe(1) loc = frame.f_locals.copy() loc.update(kwargs) try: exec expr in frame.f_globals, loc except ExpectedException, e: return e except Exception, e: pass else: e = None else: func, args = args[0], args[1:] assert callable(func) try: func(*args, **kwargs) except ExpectedException, e: return e except Exception, e: pass else: e = None expr = ["%r" % x for x in args] expr.extend(["%s=%r" % x for x in kwargs.items()]) expr = '%s(%s)' % (func.__name__, ', '.join(expr)) if e: e = 'raised %s instead of' % e.__class__ else: e = 'did not raise' raise AssertionError('%s %s %s' % (expr, e, ExpectedException)) def dot(): stdold.err.write('.') def skip(): stdold.err.write('s') def come_on_guido_this_is_just_wrong(name): mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod def get_funcs(mod): """Return a list of test functions for the given module object.""" funcs = [] for name in dir(mod): if name[:4] == 'test': attr = getattr(mod, name) if callable(attr): funcs.append(attr) return funcs def run_suite(tests, stop_first=True): """Run tests given a list of modules that export __test__ variables.""" try: os.mkdir(kid.test.output_dir) except OSError: e = sys.exc_info()[1] if int(e.errno) != 17: raise bad = [] kid.test.basic_tests = 1 test_cnt = skip_cnt = bad_cnt = 0 from time import time start = time() # run over modules... for module_name in tests: try: mod = come_on_guido_this_is_just_wrong(module_name) except ImportError, e: if 'No module named py' not in str(e): raise skip_cnt += 1 skip() continue # you don't have pylib - so i won't run these tests #if not hasattr(mod, '__tests__'): # raise '%r does not export a __tests__ variable.' % module_name if hasattr(mod, 'setup_module'): mod.setup_module(mod) try: # run each test... for test in get_funcs(mod): test_cnt += 1 sys.stdout, sys.stderr = StringIO(), StringIO() try: test() except: bad_cnt += 1 asserr = isinstance(sys.exc_info()[0], AssertionError) ftype = asserr and 'F' or 'E' buf = StringIO() traceback.print_exc(file=buf) stdold.err.write(ftype) bad.append((test, ftype, sys.exc_info(), \ (sys.stdout.getvalue(), sys.stderr.getvalue()))) if stop_first: sys.stdout, sys.stderr = stdold.out, stdold.err sys.stderr.write( '*\n\bBailing after %d tests\n\n' % test_cnt) out, err = bad[-1][3] if out: sys.stderr.write( '-- sys.stdout:\n%s\n' % out.strip()) if err: sys.stderr.write( '-- sys.stderr:\n%s\n' % err.strip()) raise else: dot() sys.stdout, sys.stderr = stdold.out, stdold.err finally: if hasattr(mod, 'teardown_module'): mod.teardown_module(mod) done = time() sys.stderr.write('\n') for test, ftype, exc_info, (out, err) in bad: sys.stderr.write('\n%s: %s\n' % ({'F': 'Failure', 'E': 'Error'}.get(ftype, 'Bad'), test.__doc__ or test.__name__)) if out: sys.stderr.write( '-- sys.stdout:\n%s\n' % out.strip()) if err: sys.stderr.write( '-- sys.stderr:\n%s\n' % err.strip()) traceback.print_exception( exc_info[0], exc_info[1], exc_info[2], 15, sys.stderr) sys.stderr.write('\nTests: %d (+%d extended) OK (%g seconds)\n' % (test_cnt, kid.test.additional_tests, done - start)) if skip_cnt: sys.stderr.write('Skipped tests (need py lib): %d\n' % skip_cnt) if bad_cnt: sys.stderr.write('Bad tests: %d\n' % bad_cnt) kid-0.9.6/kid/__init__.py0000644000175000017500000004067510646650134015102 0ustar tstanektstanek# -*- coding: utf-8 -*- """Pythonic, XML Templating Kid is a simple, Python-based template language for generating and transforming XML vocabularies. Kid was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (well, eventually :). """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" from kid import release __version__ = release.version __author__ = release.author __email__ = release.email __copyright__ = release.copyright __license__ = release.license import sys, os assert sys.hexversion >= 0x02030000, "Kid templates need Python 2.3 or later" from kid.util import xml_sniff, QuickTextReader from kid.namespace import Namespace from kid.codewriter import KID_XMLNS, raise_template_error from kid.compiler import KID_EXT from kid.element import Element, SubElement, Comment, \ ProcessingInstruction, Fragment from kid.parser import ElementStream, XML, document, _coalesce from kid.filter import transform_filter from kid.serialization import Serializer, PlainSerializer, \ XMLSerializer, HTMLSerializer, XHTMLSerializer from kid.format import Format, output_formats import kid.template_util as template_util __all__ = ['KID_XMLNS', 'BaseTemplate', 'Template', 'enable_import', 'import_template', 'load_template', 'Element', 'SubElement', 'XML', 'document', 'Namespace', 'Serializer', 'XMLSerializer', 'HTMLSerializer', 'XHTMLSerializer', 'output_methods', 'Format', 'output_formats', 'filter', 'format', 'namespace', 'serialization', 'util'] assume_encoding = sys.getdefaultencoding() def enable_import(ext=None, path=None): """Enable the kid module loader and import hooks. This function must be called before importing kid templates if templates are not pre-compiled. """ import kid.importer kid.importer.install(ext, path) def disable_import(path=None): """Disable the kid module loader and import hooks again.""" import kid.importer kid.importer.uninstall(path) # Turn on import hooks if KID_IMPORT variables are set if os.environ.get('KID_IMPORT'): enable_import(os.environ.get('KID_IMPORT_EXT')) if os.environ.get('KID_IMPORT_PATH'): enable_import(os.environ.get('KID_IMPORT_EXT'), os.environ['KID_IMPORT_PATH']) def import_template(name, encoding=None): """Import template by name. This is identical to calling `enable_import` followed by an import statement. For example, importing a template named foo using the normal import mechanism looks like this:: import kid kid.enable_import() import foo This function can be used to achieve the same result as follows:: import kid foo = kid.import_template('foo') This is sometimes useful when the name of the template is available only as a string. """ enable_import() mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) if encoding: mod.encoding = encoding return mod def load_template(file, name='', cache=True, encoding=None, ns={}, entity_map=None, exec_module=None): """Bypass import machinery and load a template module directly. This can be used as an alternative to accessing templates using the native python import mechanisms. file Can be a filename, a kid template string, or an open file object. name Optionally specifies the module name to use for this template. This is a hack to enable relative imports in templates. cache Whether to look for a byte-compiled version of the template. If no byte-compiled version is found, an attempt is made to dump a byte-compiled version after compiling. This argument is ignored if file is not a filename. entity_map Entity map to be used when parsing the template. exec_module If you want full control over how the template module is executed, you can provide this callable that will be called with the template module and the code to be executed as parameters, after the code has been compiled and the module has been created. """ if isinstance(file, basestring): if xml_sniff(file): fo = QuickTextReader(file) filename = '' else: fo = None filename = file else: fo = file filename = '' import kid.importer as importer if filename != '': abs_filename = path.find(filename) if not abs_filename: raise template_util.TemplateNotFound( "%s (in %s)" % (filename, ', '.join(path.paths))) filename = abs_filename name = importer.get_template_name(name, filename) if sys.modules.has_key(name): return sys.modules.get(name) import kid.compiler as compiler if filename == '': code = compiler.compile(fo, filename, encoding, entity_map) else: template = compiler.KidFile(filename, force=False, encoding=encoding, entity_map=entity_map) code = template.compile(dump_code=cache, dump_source=os.environ.get('KID_OUTPUT_PY')) mod = importer._create_module(code, name, filename, store=cache, ns=ns, exec_module=exec_module) return mod # create some default serializers... output_methods = { 'xml': XMLSerializer(decl=True), 'wml': XMLSerializer(decl=True, doctype='wml'), 'xhtml-strict': XHTMLSerializer(decl=False, doctype='xhtml-strict'), 'xhtml': XHTMLSerializer(decl=False, doctype='xhtml'), 'xhtml-frameset': XHTMLSerializer(decl=False, doctype='xhtml-frameset'), 'html-strict': HTMLSerializer(doctype='html-strict'), 'html': HTMLSerializer(doctype='html'), 'html-frameset': HTMLSerializer(doctype='html-frameset'), 'html-quirks': HTMLSerializer(doctype='html-quirks'), 'html-frameset-quirks': HTMLSerializer(doctype='html-frameset-quirks'), 'HTML-strict': HTMLSerializer(doctype='html-strict', transpose=True), 'HTML': HTMLSerializer(doctype='html', transpose=True), 'HTML-frameset': HTMLSerializer(doctype='html-frameset', transpose=True), 'HTML-quirks': HTMLSerializer(doctype='html-quirks', transpose=True), 'HTML-frameset-quirks': HTMLSerializer(doctype='html-frameset-quirks', transpose=True), 'plain': PlainSerializer()} def Template(file=None, source=None, name=None, encoding=None, **kw): """Get a Template class quickly given a module name, file, or string. This is a convenience function for getting a template in a variety of ways. One and only one of the arguments name or file must be specified. file:string The template module is loaded by calling ``load_template(file, name='', cache=True)`` name:string The kid import hook is enabled and the template module is located using the normal Python import mechanisms. source:string string containing the templates source. Once the template module is obtained, a new instance of the module's Template class is created with the keyword arguments passed to this function. """ if name: mod = import_template(name, encoding=encoding) elif file is not None: mod = load_template(file, name=name, encoding=encoding) elif source is not None: mod = load_template(QuickTextReader(source), name=name or hex(id(source)), encoding=encoding) else: raise template_util.TemplateError( "Must specify one of name, file, or source.") try: mod.Template.module = mod except Exception: raise template_util.TemplateImportError( "Template could not be initialized.") return mod.Template(**kw) class BaseTemplate(object): """Base class for compiled Templates. All kid template modules expose a class named ``Template`` that extends from this class making the methods defined here available on all Template subclasses. This class should not be instantiated directly. """ # the serializer to use when writing output serializer = output_methods['xml'] def __init__(self, *args, **kw): """ Initialize a template with instance attributes specified by keyword arguments. Keyword arguments are available to the template using self.var notation. """ for k in kw: # check that reserved keywords such as 'content' are not used if hasattr(BaseTemplate, k): raise template_util.TemplateAttrsError( "Keyword argument %r is a reserved name." % k) self.__dict__.update(kw) self._filters = [transform_filter] self._layout_classes = [] def write(self, file, encoding=None, fragment=False, output=None, format=None): """ Execute template and write output to file. file:file A filename or a file like object (must support write()). encoding:string The output encoding. Default: utf-8. fragment:bool Controls whether prologue information (such as declaration and DOCTYPE should be written). Set to True when generating fragments meant to be inserted into existing XML documents. output:string,`Serializer` A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object. """ serializer = self._get_serializer(output) try: return serializer.write(self, file, encoding, fragment, format) except Exception: raise_template_error(module=self.__module__) def serialize(self, encoding=None, fragment=False, output=None, format=None): """ Execute a template and return a single string. encoding The output encoding. Default: utf-8. fragment Controls whether prologue information (such as declaration and DOCTYPE should be written). Set to True when generating fragments meant to be inserted into existing XML documents. output A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object. This is a convienence method, roughly equivalent to:: ''.join([x for x in obj.generate(encoding, fragment, output)] """ serializer = self._get_serializer(output) try: return serializer.serialize(self, encoding, fragment, format) except Exception: raise_template_error(module=self.__module__) def generate(self, encoding=None, fragment=False, output=None, format=None): """ Execute template and generate serialized output incrementally. This method returns an iterator that yields an encoded string for each iteration. The iteration ends when the template is done executing. encoding The output encoding. Default: utf-8. fragment Controls whether prologue information (such as declaration and DOCTYPE should be written). Set to True when generating fragments meant to be inserted into existing XML documents. output A string specifying an output method ('xml', 'html', 'xhtml') or a Serializer object. """ serializer = self._get_serializer(output) try: return serializer.generate(self, encoding, fragment, format) except Exception: raise_template_error(module=self.__module__) def __iter__(self): return iter(self.transform()) def __str__(self): return self.serialize() def __unicode__(self): return unicode(self.serialize(encoding='utf-16'), 'utf-16') def initialize(self): pass def pull(self): """Returns an iterator over the items in this template.""" # create stream and apply filters self.initialize() stream = ElementStream(_coalesce(self.content(), self._get_assume_encoding())) return stream def _pull(self): """Generate events for this template. Compiled templates implement this method. """ return [] def content(self): from inspect import getmro visited = self._layout_classes mro = list(getmro(self.__class__)) mro.reverse() for c in mro: if c.__dict__.has_key('layout') and c not in visited: visited.insert(0, c) return c.__dict__['layout'](self) return self._pull() def transform(self, stream=None, filters=[]): """ Execute the template and apply any match transformations. If stream is specified, it must be one of the following: Element A kid.Element. ElementStream An `pull.ElementStream` instance or other iterator that yields stream events. string A file or URL unless the string starts with '<' in which case it is considered an XML document and processed as if it had been an Element. By default, the `pull` method is called to obtain the stream. """ if stream is None: stream = self.pull() elif isinstance(stream, basestring): if xml_sniff(stream): stream = XML(stream, fragment=False) else: stream = document(stream) elif hasattr(stream, 'tag'): stream = ElementStream(stream) else: stream = ElementStream.ensure(stream) for f in filters + self._filters: stream = f(stream, self) return stream def _get_match_templates(self): # XXX: use inspect instead of accessing __mro__ directly try: rslt = self._match_templates_cached except AttributeError: rslt = [] mro = self.__class__.__mro__ for C in mro: try: templates = C._match_templates except AttributeError: continue rslt += templates self._match_templates_cached = rslt return rslt def _get_serializer(self, serializer): if serializer is None: return self.serializer elif isinstance(serializer, basestring): return output_methods[serializer] else: return serializer def _get_assume_encoding(self): global assume_encoding if hasattr(self, "assume_encoding"): return self.assume_encoding else: return assume_encoding def defined(self, name): return hasattr(self, name) def value_of(self, name, default=None): return getattr(self, name, default) class TemplatePath(object): """Finding templates on a list of paths.""" def __init__(self, paths=None): """Initialize with path list.""" if isinstance(paths, basestring): paths = paths.split(os.pathsep) elif paths is None: paths = [] paths.append(os.getcwd()) self.paths = [] for path in paths: self.append(path) def _cleanse_path(self, path): """Normalize path.""" return os.path.abspath(os.path.normpath(os.path.expanduser(path))) def insert(self, path, pos=0): """Insert path to list if not already there.""" path = self._cleanse_path(path) if path not in self.paths: self.paths.insert(pos, path) def append(self, path): """Append path to list if not already there.""" path = self._cleanse_path(path) if path not in self.paths: self.paths.append(path) def remove(self, path): """Remove path from list.""" path = self._cleanse_path(path) self.paths = [p for p in self.paths if p != path] def find(self, path, rel=None): """Find file relative to path list and rel.""" path = os.path.normpath(path) if rel: rel = [os.path.dirname(rel)] else: rel = [] for p in self.paths + rel: p = os.path.join(p, path) if os.path.exists(p): return p if not p.endswith(KID_EXT): p += KID_EXT if os.path.exists(p): return p path = TemplatePath() kid-0.9.6/kid/codewriter.py0000644000175000017500000007262010646650134015505 0ustar tstanektstanek# -*- coding: utf-8 -*- """KidWriter Write Python source code from XML. """ __revision__ = "$Rev: 496 $" __date__ = "$Date: 2007-07-15 18:14:35 -0400 (Sun, 15 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import sys, re from os.path import splitext from traceback import extract_tb, format_exception_only from kid import __version__, Namespace from kid.parser import document, START, END, TEXT, XML_DECL, DOCTYPE, LOCATION from kid.element import namespaces, Comment, ProcessingInstruction __all__ = ['KID_XMLNS', 'KID_PREFIX', 'kidns', 'raise_template_error'] # the Kid XML namespace KID_XMLNS = "http://purl.org/kid/ns#" KID_PREFIX = 'py' kidns = Namespace(KID_XMLNS) QNAME_FOR = kidns['for'] QNAME_IF = kidns['if'] QNAME_DEF = kidns['def'] QNAME_SLOT = kidns['slot'] QNAME_CONTENT = kidns['content'] QNAME_REPLACE = kidns['replace'] QNAME_MATCH = kidns['match'] QNAME_STRIP = kidns['strip'] QNAME_ATTRIBUTES = kidns['attrs'] QNAME_EXTENDS = kidns['extends'] QNAME_LAYOUT = kidns['layout'] # deprectaed QNAME_OMIT = kidns['omit'] QNAME_REPEAT = kidns['repeat'] # the Kid processing instruction name KID_PI = 'python' KID_ALT_PI = 'py' KID_OLD_PI = 'kid' def parse(source, encoding=None, filename=None, entity_map=None): doc = document(source, encoding=encoding, filename=filename, entity_map=entity_map) return KidWriter(doc, encoding, filename).parse() def parse_file(filename, encoding=None, entity_map=None): """Parse the file specified. filename -- the name of a file. fp -- an optional file like object to read from. If not specified, filename is opened. """ source = open(filename, 'rb') try: return parse(source, encoding, filename, entity_map) finally: source.close() def error_location(filename, encoding=None, entity_map=None, lineno=None): if lineno: try: source = open(filename, 'rb') try: doc = document(source, encoding=encoding, filename=filename, entity_map=entity_map, debug=True) writer = KidWriter(doc, encoding, filename, lineno) return writer.parse() finally: source.close() except Exception: pass def TemplateExceptionError(error, add_message): """Get exception with additional error message.""" Error = error.__class__ class TemplateExceptionError(Error): def __init__(self): for arg in dir(error): if not arg.startswith('_'): setattr(self, arg, getattr(error, arg)) def __str__(self): return str(error) + '\n' + add_message TemplateExceptionError.__name__ = Error.__name__ TemplateExceptionError.__module__ = Error.__module__ return TemplateExceptionError() def raise_template_error(module=None, filename=None, encoding=None): """Raise template error along with additional context information. If the module containing the erroneous code has been compiled from a Kid template, try to compile that template with additional debug information, and display the location in the Kid template file corresponding to the erroneous code. """ if module and not (filename and encoding): if module in sys.modules: mod = sys.modules[module] if hasattr(mod, 'encoding'): encoding = mod.encoding if hasattr(mod, 'kid_file'): filename = mod.kid_file if not filename or filename == '': raise if not encoding: encoding = 'utf-8' py_file = splitext(filename)[0] + '.py' exc_type, exc_value = sys.exc_info()[:2] if exc_type == SyntaxError: tb = [(py_file, exc_value.lineno)] else: tb = extract_tb(sys.exc_info()[2]) tb.reverse() for t in tb: if py_file != t[0] or not t[1]: continue location = error_location(filename, encoding, lineno=t[1]) if not location: continue (start_line, start_col), (end_line, end_col) = location if start_line > end_line: continue s = [] if not end_col and end_line > start_line: end_line -= 1 end_col = -1 if start_line == end_line: s.append('on line %d' % start_line) if start_col == end_col: s.append(', column %d' % start_col) elif start_col: if end_col > start_col: s.append(' between columns %d and %d' % (start_col, end_col)) else: s.append(' after column %d' % start_col) elif end_col > 0: s.append(' before column %d' % end_col) else: s.append('between line %d' % start_line) if start_col: s.append(', column %d' % start_col) s.append(' and line %d' % end_line) if end_col > 0: s.append(', column %d' % end_col) if s: s = ''.join(s) try: start_line -= 1 end_line -= 1 error_line, error_text = [], [] for line, text in enumerate(open(filename)): if line < start_line: continue text = text.rstrip() if text: if line == start_line and start_col: if text[:start_col].rstrip(): text = text[start_col:].lstrip() if text: text = '... ' + text if line == end_line and end_col > 0: if text[end_col:].lstrip(): if end_col > 75: end_col = 75 text = text[:end_col].rstrip() if text: text += ' ...' else: text = text[:end_col].rstrip() if len(text) > 79: text = text[:75].rstrip() + ' ...' if text: if len(error_line) < 3: error_line.append(line) error_text.append(text) else: error_line[2] = line error_text[2] = text if line >= end_line: break if not error_line: raise LookupError, 'error line not found' if len(error_line) == 2: if error_line[1] - error_line[0] > 1: error_text.insert(1, '...') elif len(error_line) == 3: if error_line[2] - error_line[0] > 2: error_text[1] = '...' s = [s + ':'] + error_text except Exception, e: s = [s, '(cannot acquire source text: %s)' % str(e)] s.insert(0, 'Error location in template file %r' % filename) break else: s = ['Error in code generated from template file %r' % filename] s = ''.join(format_exception_only(exc_type, exc_value)[:-1]) + '\n'.join(s) if isinstance(exc_type, str): exc_type += '\n' + s else: exc_value = TemplateExceptionError(exc_value, s) exc_type = exc_value.__class__ raise exc_type, exc_value, sys.exc_info()[2] class KidWriter(object): def __init__(self, stream, encoding=None, filename=None, lineno=None): self.stream = stream self.encoding = encoding or 'utf-8' self.filename = filename self.depth = 0 self.lineno = lineno self.location = None self.locations = [] self.module_code = self.codegen() self.class_code = self.codegen() self.expand_code = self.codegen(level=1) self.end_module_code = self.codegen() self.module_defs = [] self.inst_defs = [] def codegen(self, code=None, level=0, tab='\t'): if self.lineno: return LocationGenerator(code, self.getloc) else: return CodeGenerator(code, level, tab) def getloc(self): return self.location def parse(self): self.begin() self.proc_stream(self.module_code) self.end() parts = [] parts += self.module_code.code for c in self.module_defs: parts += c.code parts += self.class_code.code parts += self.expand_code.code for c in self.inst_defs: parts += c.code parts += self.end_module_code.code if self.lineno: lineno = self.lineno - 1 if not 0 <= lineno < len(parts): return None pos = parts[lineno] if not pos: return None pos, is_start = pos if not 0 <= pos < len(self.locations): return None start_loc = self.locations[pos] pos += is_start and 1 or -1 if 0 <= pos < len(self.locations): end_loc = self.locations[pos] else: end_line = start_loc[0] if is_start: end_line += 1 end_loc = (end_line, 0) if not is_start: start_loc, end_loc = end_loc, start_loc return start_loc, end_loc return '\n'.join(parts) def begin(self): code = self.module_code # Start with PEP 0263 encoding declaration code.line('# -*- coding: %s -*-' % self.encoding, '# Kid template module', # version against which the file has been compiled 'kid_version = %r' % __version__, # source from which the file has been compiled 'kid_file = %r' % self.filename, # imports 'import kid', 'from kid.template_util import *', 'import kid.template_util as template_util', '_def_names = []', # default variables (can be overridden by template) 'encoding = "%s"' % self.encoding, 'doctype = None', 'omit_namespaces = [kid.KID_XMLNS]', 'layout_params = {}', # module methods 'def pull(**kw): return Template(**kw).pull()', "def generate(encoding=encoding, fragment=False," " output=None, format=None, **kw):" " return Template(**kw).generate(encoding=encoding," " fragment=fragment, output=output, format=format)", "def serialize(encoding=encoding, fragment=False," " output=None, format=None, **kw):" " return Template(**kw).serialize(encoding=encoding," " fragment=fragment, output=output, format=format)", "def write(file, encoding=encoding, fragment=False," " output=None, format=None, **kw):" " return Template(**kw).write(file, encoding=encoding," " fragment=fragment, output=output, format=format)", 'def initialize(template): pass', 'BaseTemplate = kid.BaseTemplate') # expand code code = self.expand_code code.start_block('def initialize(self):') code.line('rslt = initialize(self)', 'if rslt != 0: super(Template, self).initialize()') code.end_block() code.start_block('def _pull(self):') # XXX hack: nasty kluge for making kwargs locals code.line("exec template_util.get_locals(self, locals())", 'current, ancestors = None, []', 'if doctype: yield DOCTYPE, doctype') code = self.end_module_code code.line('') def end(self): self.expand_code.end_block() def proc_stream(self, code): for ev, item in self.stream: if ev == START: if item.tag == Comment: text = item.text.strip() if text.startswith('!'): continue # swallow comment if code is self.module_code: line = self.expand_code.line else: line = code.line if text.startswith('[') or text.startswith('', 'exec') # if it works, line does not start new block except SyntaxError: # unexpected EOF while parsing? try: # try to compile the whole block block = '\n'.join(lines) + '\n' compile(block, '', 'exec') # if it works, line does not start new block except IndentationError: # expected an indented block? # so try to add some indentation: lines2 = lines[:1] + [tab + line for line in lines[1:]] block = '\n'.join(lines2) + '\n' # try again to compile the whole block: compile(block, '', 'exec') lines = lines2 # if it works, keep the indentation except: pass # leave it as it is except: pass # leave it as it is return lines kid-0.9.6/kid/compile.py0000644000175000017500000000613710646650133014765 0ustar tstanektstanek#!/usr/bin/env python # -*- coding: utf-8 -*- # This module provides the "kidc" command """Usage: kidc [OPTIONS] [file...] Compile kid templates into Python byte-code (.pyc) files. OPTIONS: -f, --force Force compilation even if .pyc file already exists. -s, --source Generate .py source files along with .pyc files. This is sometimes useful for debugging. -d, --strip-dest-dir Strips the supplied path from the beginning of source filenames stored for error messages in the generated .pyc files The file list may have files and/or directories. If a directory is specified, all .kid files found in the directory and any sub-directories are compiled. """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import sys from os.path import isdir from getopt import getopt, GetoptError as gerror try: from os import EX_OK, EX_DATAERR, EX_USAGE except ImportError: EX_OK, EX_DATAERR, EX_USAGE = 0, 1, 2 import kid.compiler def main(): # get options try: opts, args = getopt(sys.argv[1:], 'fshd=', ['force', 'source', 'help', 'strip-dest-dir=']) except gerror, e: sys.stderr.write(str(e) + '\n') sys.stdout.write(__doc__) sys.exit(EX_USAGE) force = source = False strip_dest_dir = None for o, a in opts: if o in ('-f', '--force'): force = True elif o in ('-s', '--source'): source = True elif o in ('-h', '--help'): sys.stdout.write(__doc__) sys.exit(EX_OK) elif o in ('-d', '--strip-dest-dir'): strip_dest_dir = a files = args if not files: sys.stderr.write('kidc: No kid template specified.\n') sys.stderr.write(" Try 'kidc --help' for usage information.\n") sys.exit(EX_USAGE) # a quick function for printing results def print_result(res): stat, filename = res if stat == True: msg = 'compile: %s\n' % filename elif stat == False: msg = 'fresh: %s\n' % filename else: msg = 'error: %s (%s)\n' % (filename, stat) sys.stderr.write(msg) # run through files and compile err = False for f in files: if isdir(f): for res in kid.compiler.compile_dir(f, force=force, source=source, strip_dest_dir=strip_dest_dir): if res[0] not in (True, False): err = True print_result(res) else: try: stat = kid.compiler.compile_file(f, force=force, source=source, strip_dest_dir=strip_dest_dir) except Exception, e: stat, err = e, True print_result((stat, f)) # exit with error status if one compilation failed sys.exit(err and EX_DATAERR or EX_OK) if __name__ == '__main__': main() kid-0.9.6/kid/compiler.py0000644000175000017500000001717210646650134015151 0ustar tstanektstanek# -*- coding: utf-8 -*- """Kid Compiler Compile XML to Python byte-code. """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import os import os.path import imp import stat import struct import marshal import kid from kid.codewriter import raise_template_error __all__ = ['KID_EXT', 'compile', 'compile_file', 'compile_dir'] # kid filename extension KID_EXT = ".kid" def actualize(code, dict=None): """Run code with variables in dict, updating the dict.""" if dict is None: dict = {} exec code in dict return dict _py_compile = compile def py_compile(code, filename='', kind='exec'): """The Python built-in compile function with safeguard.""" if type(code) == unicode: # unicode strings may not have a PEP 0263 encoding declaration if code.startswith('# -*- coding: '): # we want the line numbering to match with the source file, # so we only remove the magic word in the comment line: code = '# -*-' + code[13:] return _py_compile(code, filename, 'exec') def compile(source, filename='', encoding=None, entity_map=None): """Compiles Kid XML source to a Python code object. source -- A file like object - must support read. filename -- An optional filename that is used """ # XXX all kinds of work to do here catching syntax errors and # adjusting line numbers... py = kid.codewriter.parse(source, encoding, filename, entity_map) return py_compile(py, filename) _timestamp = lambda filename : os.stat(filename)[stat.ST_MTIME] class KidFile(object): magic = imp.get_magic() def __init__(self, kid_file, force=False, encoding=None, strip_dest_dir=None, entity_map=None): self.kid_file = kid_file self.py_file = os.path.splitext(kid_file)[0] + '.py' self.strip_dest_dir = strip_dest_dir self.pyc_file = self.py_file + 'c' self.encoding = encoding self.entity_map = entity_map fp = None if force: stale = True else: stale = False try: fp = open(self.pyc_file, "rb") except IOError: stale = True else: if fp.read(4) != self.magic: stale = True else: mtime = struct.unpack(' 0 and name != os.curdir and name != os.pardir \ and os.path.isdir(fullname) and not os.path.islink(fullname): for res in compile_dir(fullname, maxlevels - 1, force, source, encoding, strip_dest_dir, entity_map): yield res kid-0.9.6/kid/element.py0000644000175000017500000001212110646650133014754 0ustar tstanektstanek# -*- coding: utf-8 -*- """A partial implementation of ElementTree and some extensions.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import re __all__ = ['Element', 'SubElement', 'Comment', 'ProcessingInstruction', 'Fragment', 'QName', 'namespaces', 'escape_map', 'encode_entity', 'raise_serialization_error'] class Element(object): """A class representing an XML element.""" text = None tail = None def __init__(self, tag, attrib={}, **extra): attrib = attrib.copy() attrib.update(extra) self.tag = tag self.attrib = attrib self._children = [] def __repr__(self): return "" % (self.tag, id(self)) # Methods for dealing with children - a list interface def __len__(self): return len(self._children) def __getitem__(self, index): return self._children[index] def __setitem__(self, index, element): assert isinstance(element, Element) self._children[index] = element def __delitem__(self, index): del self._children[index] def __getslice__(self, start, stop): return self._children[start:stop] def __setslice__(self, start, stop, elements): for element in elements: assert isinstance(element, Element) self._children[start:stop] = list(elements) def __delslice__(self, start, stop): del self._children[start:stop] def append(self, element): assert isinstance(element, Element) self._children.append(element) def insert(self, index, element): assert isinstance(element, Element) self._children.insert(index, element) def remove(self, element): assert isinstance(element, Element) self._children.remove(element) def getchildren(self): return self._children def clear(self): self.attrib.clear() self._children = [] self.text = self.tail = None # Methods for dealing with attributes - a dictionary like interface def get(self, key, value=None): return self.attrib.get(key, value) def set(self, key, value): self.attrib[key] = value def keys(self): return self.attrib.keys() def items(self): return self.attrib.items() def SubElement(parent, tag, attrib={}, **extra): attrib = attrib.copy() attrib.update(extra) element = Element(tag, attrib) parent.append(element) return element def Comment(text=None): """Comment element factory.""" elem = Element(Comment) elem.text = text return elem def ProcessingInstruction(target, text=None): """PI element factory.""" elem = Element(ProcessingInstruction) elem.text = target if text: elem.text += " " + text return elem def Fragment(text=''): """XML fragment factory. Fragments hold TEXT and children but do not have a tag or attributes. """ elem = Element(Fragment) elem.text = text return elem class QName: def __init__(self, text_or_uri, tag=None): if tag: text_or_uri = "{%s}%s" % (text_or_uri, tag) self.text = text_or_uri def __str__(self): return self.text def namespaces(elem, remove=False): """Get the namespace declarations for an Element. This function looks for attributes on the Element provided that have the following characteristics: * Begin with 'xmlns:' and have no namespace URI. * Are named 'xmlns' and have no namespace URI. The result is a dictionary containing namespace prefix -> URI mappings. Default namespace attributes result in a key of ''. If remove is truthful, namespace declaration attributes are removed from the passed in Element. """ names = {} for k in elem.keys(): if k.startswith('xmlns:'): names[k[6:]] = elem.get(k) if remove: del elem.attrib[k] elif k == 'xmlns': names[''] = elem.get(k) if remove: del elem.attrib[k] return names escape_map = { "&": "&", "<": "<", ">": ">", '"': """, } re_escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) def encode_entity(text, pattern=re_escape, entities=None): if entities is None: entities = escape_map # map reserved and non-ascii characters to XML entities def escape_entities(m, entities=entities): out = [] for char in m.group(): text = entities.get(char) if text is None: text = "&#%d;" % ord(char) out.append(text) return ''.join(out) try: return pattern.sub(escape_entities, text).encode('ascii') except TypeError: raise_serialization_error(text) def raise_serialization_error(text): raise TypeError( "cannot serialize %r (type %s)" % (text, type(text).__name__) ) kid-0.9.6/kid/filter.py0000644000175000017500000000471510646650135014624 0ustar tstanektstanek# -*- coding: utf-8 -*- """Kid tranformations""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " from kid.parser import ElementStream, START, XML_DECL, document, _coalesce from kid.namespace import Namespace from kid.template_util import generate_content __all__ = ['transform_filter'] def transform_filter(stream, template): templates = template._get_match_templates() def apply_func(item): return transform_filter(generate_content(item), template) stream = ElementStream.ensure(stream) return ElementStream(apply_matches(stream, template, templates, apply_func)) def apply_matches(stream, template, templates, apply_func): for ev, item in stream: if ev == START: matched = False for i in range(0, len(templates)): match, call = templates[i] if match(item): item = stream.expand() newstream = _coalesce(call(template, item, apply_func), template._get_assume_encoding()) if len(templates) < 2: for ev, item in newstream: yield ev, item else: for ev, item in apply_matches( ElementStream(newstream), template, templates[:i] + templates[i+1:], apply_func): yield ev, item matched = True break if matched: continue yield ev, item # XXX haven't tested this yet.. def xinclude_filter(stream, template): xi = Namespace('http://www.w3.org/2001/XInclude') include = xi.include fallback = xi.fallback for ev, item in stream: if ev == START and item.tag == include: item = item.expand() href = item.get('href') try: doc = document(href, template._get_assume_encoding()) except: fallback_elm = item.find(fallback) for ev, item in ElementStream(fallback_elm).strip(1): yield ev, item else: for ev, item in doc: if ev != XML_DECL: yield ev kid-0.9.6/kid/format.py0000644000175000017500000005254410646650133014630 0ustar tstanektstanek# -*- coding: utf-8 -*- """Infoset serialization format styles. This modules provides methods assisting the serialization module in formatting the text content of serialized infosets. The methods for "educating" and "stupefying" typographic characters have been inspired by John Gruber's "SmartyPants" project (http://daringfireball.net/projects/smartypants/, see also http://web.chad.org/projects/smartypants.py/). """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Christoph Zwerschke (cito@online.de)" __copyright__ = "Copyright 2006, Christoph Zwerschke" __license__ = "MIT " import re __all__ = ['Format', 'output_formats'] class Format(object): """Formatting details for Serializers.""" # Default values for some parameters: wrap = 80 indent = '\t' min_level, max_level = 1, 8 tabsize = 8 apostrophe = u'\u2019' squotes = u'\u2018\u2019' dquotes = u'\u201c\u201d' dashes = u'\u2013\u2014' ellipsis = u'\u2026' # Regular expressions used by the Format class: re_whitespace = re.compile(r'[ \t\n\r]+') re_leading_blanks = re.compile(r'^[ \t]+', re.MULTILINE) re_trailing_blanks = re.compile(r'[ \t]+$', re.MULTILINE) re_duplicate_blanks = re.compile(r'[ \t]{2,}') re_duplicate_newlines = re.compile(r'\n[ \t\n\r]*\n') re_whitespace_with_newline = re.compile(r'[ \t]*\n[ \t\n\r]*') re_indentation = re.compile(r'\n[ \t]*') re_squotes = re.compile(r"'") re_dquotes = re.compile(r'"') re_sbackticks = re.compile(r"`") re_dbackticks = re.compile(r"(? width > 0: t.append('\n') offset = indent + len(word) t.append(word) for word in s: offset += len(word) + 1 if offset <= width: t.append(' ') else: t.append('\n') offset = indent + len(word) t.append(word) return ''.join(t) # Auxiliary functions for indentation and word wrapping def indent_width(indent, tabsize=tabsize): """Calculate width of indentation.""" if indent.startswith('\t'): width = len(indent) indent = indent.lstrip('\t') width -= len(indent) width *= tabsize width += len(indent) else: width = len(indent) return width indent_width = staticmethod(indent_width) def new_offset(s, offset=0): """Calculate new offset after appending a string.""" n = s.rfind('\n') if n < 0: offset += len(s) else: offset = Format.indent_width(s[n+1:]) return offset new_offset = staticmethod(new_offset) # create some predefined serialization formats... output_formats = { 'default': Format(no_empty_lines=True), 'straight': Format(), 'compact': Format(simple_whitespace=True), 'newlines': Format(simple_whitespace=True, indent=''), 'pretty': Format(simple_whitespace=True, indent='\t'), 'wrap': Format(wrap=True, indent=''), 'nice': Format(no_empty_lines=True, nice=True), 'ugly': Format(no_empty_lines=True, ugly=True), 'named': Format(no_empty_lines=True, named=True), 'compact+named': Format(simple_whitespace=True, named=True), 'newlines+named': Format(simple_whitespace=True, indent='', named=True), 'pretty+named': Format(simple_whitespace=True, indent='\t', named=True), 'wrap+named': Format(wrap=True, indent='', named=True), 'compact+nice': Format(simple_whitespace=True, nice=True), 'newlines+nice': Format(simple_whitespace=True, indent='', nice=True), 'pretty+nice': Format(simple_whitespace=True, indent='\t', nice=True), 'wrap+nice': Format(wrap=True, indent='', nice=True), 'nice+named': Format(no_empty_lines=True, nice=True, named=True), 'compact+named+nice': Format(simple_whitespace=True, nice=True, named=True), 'newlines+named+nice': Format(simple_whitespace=True, indent='', nice=True), 'pretty+named+nice': Format(simple_whitespace=True, indent='\t', nice=True, named=True), 'wrap+named+nice': Format(wrap=True, indent='', nice=True, named=True), } kid-0.9.6/kid/importer.py0000644000175000017500000001712210646650134015173 0ustar tstanektstanek# -*- coding: utf-8 -*- """Kid Import Hooks. When installed, these hooks allow importing .kid files as if they were Python modules. Notes: We use new import hooks instead of the old ihooks module, because ihooks is incompatible with Python eggs. We allow importing from one or more specified paths for Kid templates, or importing from sys.path. In the latter case, we use an importer on meta_path because importers on path_hook do not fall back to the built-in import in Python >= 2.5 (this worked in Python 2.3 and 2.4). """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com); Christoph Zwerschke (cito@online.de)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko; 2006 Christoph Zwerschke" __license__ = "MIT " import sys import time import new from os import environ, extsep, pathsep from os.path import exists, join as joinpath, isdir from kid import __version__ from kid.codewriter import raise_template_error from kid.compiler import KidFile, KID_EXT from kid.template_util import TemplateImportError __all__ = ['install', 'uninstall', 'import_template', 'get_template_name'] def install(ext=None, path=None): """Install importer for Kid templates. ext can be one or more extensions as list or comma separated string path can be one or more paths as list or pathsep separated string """ if ext: if isinstance(ext, basestring): exts = ext.split(',') else: exts = list(ext) for ext in exts: if not ext.startswith(extsep): raise Exception, "Illegal exception: " + ext if KID_EXT in exts: exts.remove(KID_EXT) else: exts = [] exts.insert(0, KID_EXT) if path: # install path hook if isinstance(path, basestring): paths = path.split(pathsep) else: paths = list(path) # Install special Kid template paths, because since Python 2.5, # path hooks do not fall back to the built-in import any more. ext = ','.join(exts) kidpaths = [] syspath = sys.path for path in paths: kidpath = 'kid::%s::' % path syspath = [path for path in syspath if not path.startswith(kidpath)] kidpaths.append(kidpath + ext) sys.path = kidpaths + syspath if kidpaths: if not KidImporter in sys.path_hooks: sys.path_hooks.insert(0, KidImporter) else: # install meta hook for all sys paths for importer in sys.meta_path: if isinstance(importer, KidImporter): importer.exts = exts break else: importer = KidImporter(ext=exts) sys.meta_path.insert(0, importer) def uninstall(path=None): """Uninstall importer for Kid templates. path can be one or more paths as list or pathsep separated string """ if path: # uninstall path hook if isinstance(path, basestring): paths = path.split(pathsep) else: paths = list(path) syspath = [] remove_hook = True for path in sys.path: p = path.split(':') if len(p) >= 5 and \ p[0] == 'kid' and not p[1] and not p[-2]: if ':'.join(p[2:-2]) in paths: continue remove_hook = False syspath.append(path) sys.path = syspath if remove_hook: if KidImporter in sys.path_hooks: sys.path_hooks = [hook for hook in sys.path_hooks if hook != KidImporter] sys.path_importer_cache.clear() else: # uninstall meta hook for all sys paths sys.meta_path = [importer for importer in sys.meta_path if not isinstance(importer, KidImporter)] def import_template(name, filename, force=False): if not force and name and sys.modules.has_key(name): return sys.modules[name] template = KidFile(filename) code = template.compile(dump_source=environ.get('KID_OUTPUT_PY')) module = _create_module(code, name, filename) return module def get_template_name(name, filename): if name: return name else: return 'kid.util.template_%x' % (hash(filename) + sys.maxint + 1) def _create_module(code, name, filename, store=True, ns={}, exec_module=None): for recompiled in range(2): name = get_template_name(name, filename) mod = new.module(name) mod.__file__ = filename mod.__ctime__ = time.time() mod.__dict__.update(ns) try: if exec_module: exec_module(mod, code) else: exec code in mod.__dict__ except Exception: if store: sys.modules[name] = mod raise_template_error(module=name, filename=filename) if getattr(mod, 'kid_version', None) == __version__: break # the module has been compiled against an old Kid version, # recompile to ensure compatibility and best performance if recompiled: # already tried recompiling, to no avail raise TemplateImportError('Cannot recompile template file' ' %r for Kid version %s' % (filename, __version__)) template = KidFile(filename) template.stale = True template._python = template._code = None code = template.compile(dump_source=environ.get('KID_OUTPUT_PY')) if store: sys.modules[name] = mod return mod class KidImporter(object): """Importer for Kid templates via sys.path_hooks or sys.meta_path.""" def __init__(self, path=None, ext=None): if path: # initialized via sys.path_hooks # check for special path format: # path = kid::/path/to/templates::.ext1,.ext2 p = path.split(':') if len(p) >= 5 and \ p[0] == 'kid' and not p[1] and not p[-2]: path = ':'.join(p[2:-2]) exts = p[-1].split(',') if exts: for ext in exts: if not ext.startswith(extsep): break else: if isdir(path): self.path = path self.exts = exts return raise ImportError else: # initialize for use via sys.meta_path if ext: if isinstance(ext, basestring): exts = ext.split(',') else: exts = list(ext) for ext in exts: if not ext.startswith(extsep): raise ImportError else: raise ImportError self.path = None self.exts = exts def find_module(self, fullname, path=None): name = fullname.split('.')[-1] if self.path: if path: raise ImportError else: paths = [self.path] else: paths = sys.path if path: paths = path + paths for path in paths: if isdir(path): path = joinpath(path, name) for ext in self.exts: if exists(path + ext): self.filename = path + ext return self return None def load_module(self, fullname): return import_template(fullname, self.filename, force=True) kid-0.9.6/kid/namespace.py0000644000175000017500000000321510646650134015264 0ustar tstanektstanek# -*- coding: utf-8 -*- """Namespace handling.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " __all__ = ['Namespace', 'xml', 'xhtml', 'atom', 'rdf', 'rss', 'nons'] namespaces = {} class Namespace(object): def __init__(self, uri, prefix=None): self.uri = uri self.prefix = prefix if prefix: namespaces[uri] = prefix def qname(self, name): if self.prefix: return '%s:%s' % (self.prefix, name) else: return name def clarkname(self, name): if self.uri: return '{%s}%s' % (self.uri, name) else: return name __getattr__ = clarkname __getitem__ = clarkname def __str__(self): return self.uri def __unicode__(self): return unicode(self.uri) def __repr__(self): return 'Namespace(%r, %r)' % (self.uri, self.prefix) def __equals__(self, other): if isinstance(other, basestring): return self.uri == other elif isinstance(other, Namespace): return self.uri == other.uri else: return False xml = Namespace('http://www.w3.org/XML/1998/namespace', 'xml') xhtml = Namespace('http://www.w3.org/1999/xhtml', 'html') atom = Namespace('http://purl.org/atom/ns#', 'atom') rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf') rss = Namespace('http://purl.org/rss/1.0/', 'rss') nons = Namespace(None, None) kid-0.9.6/kid/options.py0000644000175000017500000000373110646650133015025 0ustar tstanektstanek# -*- coding: utf-8 -*- """Configuration API.""" import release __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "David Stanek " __copyright__ = "Copyright 2006, David Stanek" __license__ = release.license __all__ = ['Options'] _prefix = "kid:" class Options(object): def __init__(self, options={}, **extra): self._options = {} for name, value in options.items(): self.set(name, value) for name, value in extra.items(): self.set(name, value) def isset(self, name): """Returns True if a option exists or False if it doesn't. name: the option to check """ return self._options.has_key(self.__prefix(name)) def get(self, name, default=None): """Get the value of an option. name: the option to retrieve default: returned for non-existing properties, defaults to None """ return self._options.get(self.__prefix(name), default) def set(self, name, value): """Set the value of an option. name: the option to set value: the value to be set for the option Returns the value passed in. """ self._options[self.__prefix(name)] = value return value def remove(self, name): """Remove an option.""" if self.isset(name): del self._options[self.__prefix(name)] def __getitem__(self, name): if not self.isset(name): raise KeyError, "no option %s" % name return self.get(name) def __setitem__(self, name, value): self.set(name, value) def __delitem__(self, name): if not self.isset(name): raise KeyError, "no option %s" % name self.remove(name) def __prefix(self, name): """Add the prefix if it does not already exist.""" if not name.startswith(_prefix): name = _prefix + name return name kid-0.9.6/kid/parser.py0000644000175000017500000003601210646650134014625 0ustar tstanektstanek# -*- coding: utf-8 -*- """Pull-style interface for ElementTree.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import htmlentitydefs from xml.parsers import expat from kid.element import Element, Comment, ProcessingInstruction from kid.util import open_resource, QuickTextReader, get_expat_error __all__ = ['ElementStream', 'XML', 'document', 'Parser', 'ExpatParser', 'START', 'END', 'TEXT', 'COMMENT', 'PI', 'XML_DECL', 'DOCTYPE', 'LOCATION'] # This is the default entity map: default_entity_map = {} default_external_dtd = [] for k, v in htmlentitydefs.name2codepoint.items(): default_entity_map[k] = unichr(v) default_external_dtd.append('' % (k, v)) default_external_dtd = '\n'.join(default_external_dtd) class InvalidStreamState(Exception): def __init__(self, msg="Invalid stream state."): Exception.__init__(self, msg) def XML(text, fragment=True, encoding=None, xmlns=None, entity_map=None): """Convert XML string into an ElementStream.""" if text.startswith('%s' % (xmlns, text) else: text = '%s' % text if isinstance(text, unicode): encoding = 'utf-16' text = text.encode(encoding) p = Parser(QuickTextReader(text), encoding, entity_map) return ElementStream(_coalesce(p, encoding=encoding)).strip() else: if isinstance(text, unicode): encoding = 'utf-16' text = text.encode(encoding) p = Parser(QuickTextReader(text), encoding, entity_map) return ElementStream(_coalesce(p, encoding=encoding)) def document(file, encoding=None, filename=None, entity_map=None, debug=False): """Convert XML document into an Element stream.""" if not hasattr(file, 'read'): if filename is None: filename = file file = open_resource(file, 'rb') else: if filename is None: filename = '' p = Parser(file, encoding, entity_map, debug) p._filename = filename return ElementStream(_coalesce(p, encoding=encoding)) class ElementStream(object): """Provides a pull/streaming interface to ElementTree. Instances of this class are iterable. Most methods of the class act on the Element that is currently being visited. """ def __init__(self, stream, current=None): """Create an ElementStream. stream - an iterator that returns ElementStream events. current - If an Element is provided in this parameter than it is yielded as the first element in the stream. """ if hasattr(stream, 'tag') and hasattr(stream, 'attrib'): stream = self._pull(stream, tail=True) self.current = None self._iter = self._track(iter(stream), current) def __iter__(self): return self._iter def expand(self): """Expand the current item in the stream as an Element. In the case where there is no current element and no single root element, this will return a list of Elements. """ current = self.current if current is None: current = [] stack = [current] this, last = current, None for ev, item in self._iter: if ev == START: current, last = item, None stack[-1].append(current) stack.append(current) elif ev == END: last = stack.pop() assert last is item if not stack: break elif ev == TEXT: if last is not None: last.tail = item elif not isinstance(current, list): current.text = item if isinstance(this, list) and len(this) == 1: this = this[0] return this def strip(self, levels=1): """Return new ElementStream with first element level(s) stripped.""" def strip(depth): for ev, item in self._iter: if ev == END: depth -= 1 if depth == 0: break elif depth < 0: raise InvalidStreamState() if depth >= levels: yield ev, item if ev == START: depth += 1 depth = self.current is not None and 1 or 0 return ElementStream(strip(depth)) def eat(self): """Eat the current element and all decendant items.""" depth = self.current is not None and 1 or 0 for ev, item in self._iter: if ev == START: depth += 1 elif ev == END: depth -= 1 if depth == 0: break return self def _pull(self, elem, tail=False): """Make a stream from an Element.""" orig = elem elem = Element(orig.tag, dict(orig.attrib)) ## XXX: find a better way if elem.tag in (Comment, ProcessingInstruction): elem.text = orig.text orig.text = None yield START, elem if orig.text: yield TEXT, orig.text for child in orig.getchildren(): for event in self._pull(child, tail=True): yield event yield END, elem if tail and orig.tail: yield TEXT, orig.tail def _track(self, stream, current=None): """Track current item in stream.""" if current is not None: self.current = current yield START, current for p in stream: ev, item = p if ev == START: self.current = item elif ev == END: self.current = None yield ev, item def ensure(cls, stream, current=None): """Ensure the stream is an ElementStream.""" if isinstance(stream, cls): return stream else: return cls(stream, current) ensure = classmethod(ensure) def to_unicode(value, encoding): if isinstance(value, unicode): return value if hasattr(value, '__unicode__'): return unicode(value) if not isinstance(value, str): value = str(value) return unicode(value, encoding) def _coalesce(stream, encoding): """Coalesces TEXT events and namespace events. Fold multiple sequential TEXT events into a single event. The 'encoding' attribute is for the source strings. """ textbuf = [] namespaces = [] last_ev = None stack = [None] for ev, item in stream: if ev == TEXT: textbuf.append(item) last_ev = TEXT continue if last_ev == TEXT: text = u"" for value in textbuf: text += to_unicode(value, encoding) textbuf = [] if text: yield TEXT, text if ev == START: attrib = item.attrib for prefix, uri in namespaces: if prefix: attrib['xmlns:%s' % prefix] = uri else: attrib['xmlns'] = uri namespaces = [] current = item stack.append(item) elif ev == END: current = stack.pop() elif ev == START_NS: prefix, uri = item namespaces.append((prefix, uri)) continue elif ev == END_NS: continue yield ev, item if last_ev == TEXT: text = u"" for value in textbuf: text += to_unicode(value, encoding) if text: yield TEXT, text # Common Events START = 1 END = 2 TEXT = 3 DOCTYPE = 4 XML_DECL = 5 # These events aren't used after initial parsing START_NS = 10 END_NS = 11 PI = 12 COMMENT = 13 # This is for forwarding the location in the XML document LOCATION = 20 def Parser(source, encoding=None, entity_map=None, debug=False): return ExpatParser(source, encoding, entity_map, debug) # Most of the following copied from ElementTree.XMLTreeBuilder. # Differences from ElementTree implementation: # # * Specialized for generator based processing. Elements are built # using a iterator approach instead of the TreeBuilder approach. # # * Support for DOCTYPE, Comment, and Processing Instruction nodes. class ExpatParser(object): def __init__(self, source, encoding=None, entity_map=None, debug=False): if hasattr(source, 'read'): filename = '' else: filename = source source = open(source, 'rb') self._filename = filename self._source = source self._encoding = encoding self._parser = parser = expat.ParserCreate(encoding, "}") self._queue = [] try: self._parser.CurrentLineNumber except AttributeError: # Expat in Python < 2.4 does not provide the location, # silently switch off the debug mode in this case debug = False if debug: self.push = self._push_location else: self.push = self._push self.debug = debug # callbacks parser.DefaultHandler = self._default parser.StartElementHandler = self._start parser.EndElementHandler = self._end parser.CharacterDataHandler = self._data parser.ProcessingInstructionHandler = self._pi parser.CommentHandler = self._comment parser.StartNamespaceDeclHandler = self._start_ns parser.EndNamespaceDeclHandler = self._end_ns parser.XmlDeclHandler = self._xmldecl_handler parser.StartDoctypeDeclHandler = self._doctype_handler # attributes # (these should all become customizable at some point) parser.buffer_text = True parser.ordered_attributes = False parser.specified_attributes = True self._doctype = None if entity_map: self.entity = entity_map else: self.entity = default_entity_map self.external_dtd = default_external_dtd # setup entity handling parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS) parser.ExternalEntityRefHandler = self._buildForeign parser.UseForeignDTD() def _buildForeign(self, context, base, systemId, publicId): import StringIO parseableFile = StringIO.StringIO(default_external_dtd) original_parser = self._parser self._parser = self._parser.ExternalEntityParserCreate(context) self._parser.ParseFile(parseableFile) self._parser = original_parser return True def _push(self, ev, stuff): self._queue.append((ev, stuff)) def _push_location(self, ev, stuff): self._push(LOCATION, (self._parser.CurrentLineNumber, self._parser.CurrentColumnNumber)) self._push(ev, stuff) def _expat_stream(self): bufsize = 4 * 1024 # 4K feed = self.feed read = self._source.read more = True while more: while more and not self._queue: data = read(bufsize) if data == '': self.close() more = False else: feed(data) for item in self._queue: yield item self._queue = [] def __iter__(self): clarknames = {} def clarkname(key): try: name = clarknames[key] except KeyError: if "}" in key: name = "{" + key else: name = key clarknames[key] = name return name stack = [] current = None for ev, stuff in self._expat_stream(): if ev == TEXT: yield TEXT, stuff elif ev == START: tag, attrib = stuff tag = clarkname(tag) attrib = dict([(clarkname(key), value) for key, value in attrib.items()]) parent = current current = Element(tag, attrib) stack.append(current) yield START, current elif ev == END: current = stack.pop() assert clarkname(stuff) == current.tag parent = len(stack) and stack[-1] or None yield END, current elif ev == COMMENT: current = Comment(stuff) yield START, current yield END, current elif ev == PI: current = ProcessingInstruction(*stuff) yield START, current yield END, current else: yield ev, stuff def feed(self, data, isfinal=False): try: self._parser.Parse(data, isfinal) except expat.ExpatError, e: e.filename = self._filename e.source = self._source try: e = 'Error parsing XML%s:\n%s%s' % ( e.filename and e.filename != '' and (' file %r' % e.filename) or '', get_expat_error(e), str(e)) except Exception: pass raise expat.ExpatError(e) def close(self): if hasattr(self, '_parser'): try: self.feed('', True) # end of data finally: del self._parser # get rid of circular references def _start(self, tag, attrib): self.push(START, (tag, attrib)) def _data(self, text): self.push(TEXT, text) def _end(self, tag): self.push(END, tag) def _default(self, text): if text.startswith('&'): # deal with undefined entities try: self.push(TEXT, self.entity[text[1:-1]]) except KeyError: raise expat.error("undefined entity %s: line %d, column %d" % (text, self._parser.ErrorLineNumber, self._parser.ErrorColumnNumber)) else: # XXX not sure what should happen here. # This gets: \n at the end of documents?, " import warnings warnings.warn("kid.pull has been superseded by kid.parser", DeprecationWarning) from kid.parser import *kid-0.9.6/kid/release.py0000644000175000017500000000146110646651363014756 0ustar tstanektstanek#!/usr/bin/env python # -*- coding: utf-8 -*- """Pythonic, XML Templating Kid is a simple, Python-based template language for generating and transforming XML vocabularies. Kid was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (well, eventually :). """ __revision__ = "$Rev: 497 $" __date__ = "$Date: 2007-07-16 14:48:50 -0400 (Mon, 16 Jul 2007) $" version = "0.9.6" author = "Ryan Tomayko" email = "rtomayko@gmail.com" copyright = "Copyright 2004-2006, Ryan Tomayko, " \ "David Stanek, Christoph Zwerschke, Daniel Miller" license = "MIT" # http://www.opensource.org/licenses/mit-license.php long_description = '\n'.join(__doc__.splitlines()[1:]).strip() kid-0.9.6/kid/run.py0000644000175000017500000001073410646650134014140 0ustar tstanektstanek#!/usr/bin/env python # -*- coding: utf-8 -*- # This module provides the "kid" command """Usage: kid [options] file [args] Expand a Kid template file. OPTIONS: -e enc, --encoding=enc Specify the output character encoding. Default: utf-8 -o outfile, --output=outfile Specify the output file. Default: standard output -s host:port, --server=host:port Specify the server address if you want to start the HTTP server. Instead of the Kid template, you can specify a base directory. -h, --help Print this help message and exit. -V, --version Print the Kid version number and exit. file: filename of the Kid template to be processed or "-" for reading the template from stdin. args: key=value or other arguments passed to the template. """ __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import sys from os.path import dirname, abspath from getopt import getopt, GetoptError as gerror try: from os import EX_OK, EX_DATAERR, EX_USAGE except ImportError: EX_OK, EX_DATAERR, EX_USAGE = 0, 1, 2 import kid def main(): # get options try: opts, args = getopt(sys.argv[1:], 'e:o:s:hV', ['encoding=', 'output=', 'server=', 'help', 'version']) except gerror, e: sys.stderr.write(str(e) + '\n') sys.stdout.write(__doc__) sys.exit(EX_USAGE) enc = 'utf-8' outfile = server = None for o, a in opts: if o in ('-e', '--encoding'): enc = a elif o in ('-o', '--output'): outfile = a elif o in ('-s', '--server'): server = a elif o in ('-h', '--help'): sys.stdout.write(__doc__) sys.exit(EX_OK) elif o in ('-V', '--version'): from kid import __version__ sys.stdout.write('Kid %s\n' % __version__) sys.exit(EX_OK) if server is None: if args: # get template file f = args.pop(0) sys.argv = [f] if f != '-': # make sure template dir is on sys.path path = abspath(dirname(f)) if not path in sys.path: sys.path.insert(0, path) else: f = sys.stdin.read() # get arguments for the template file kw = {} while args: a = args.pop(0).split('=', 1) if len(a) > 1: kw[a[0]] = a[1] else: sys.argv.append(a[0]) # do not run as __main__ module sys.modules['__kid_main__'] = sys.modules['__main__'] __name__ = '__kid_main__' del sys.modules['__main__'] # load kid template as __main__ module module = kid.load_template(f, name='__main__', cache=False) # execute the template and write output if not outfile: outfile = sys.stdout module.write(outfile, encoding=enc, **kw) else: sys.stderr.write('kid: No template file specified.\n') sys.stderr.write(" Try 'kid --help' for usage information.\n") sys.exit(EX_USAGE) else: if len(args) < 2: if outfile: stderr = file(outfile, 'a', 1) sys.stderr = stderr sys.stdout.write('Starting HTTP server ...\n') if args: # get base directory basedir = args.pop(0) from os import chdir chdir(basedir) from os import getcwd basedir = getcwd() sys.stdout.write('Base directory: %s\n' % basedir) if outfile: sys.stdout.write('Server log: %s\n' % outfile) if server == '-': server = 'localhost' sys.argv[1:] = [server] from kid.server import main main() if outfile: sys.stderr = sys.__stderr__ stderr.close() else: sys.stderr.write('kid: Server does not need additional arguments.\n') sys.stderr.write(" Try 'kid --help' for usage information.\n") sys.exit(EX_USAGE) if __name__ == '__main__': main() kid-0.9.6/kid/serialization.py0000644000175000017500000010037710646650135016215 0ustar tstanektstanek# -*- coding: utf-8 -*- """Infoset serialization formats (XML, XHTML, HTML, etc)""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import htmlentitydefs try: set except NameError: # fallback for Python 2.3 from sets import Set as set from kid.element import Element, Comment, ProcessingInstruction, \ Fragment, QName, namespaces, encode_entity, raise_serialization_error import kid.namespace as namespace from kid.parser import START, END, TEXT, COMMENT, PI, _coalesce from kid.format import Format, output_formats __all__ = ['doctypes', 'Serializer', 'XMLSerializer', 'HTMLSerializer'] # bring in well known namespaces xml_uri = namespace.xml.uri xhtml_uri = namespace.xhtml.uri # This is the default entity map: default_entity_map = {} for k, v in htmlentitydefs.codepoint2name.items(): default_entity_map[unichr(k)] = "&%s;" % v # Some common doctypes. # You can pass doctype strings from here or doctype tuples to Serializers. doctypes = { 'wml': ('wml', "-//WAPFORUM//DTD WML 1.1//EN", "http://www.wapforum.org/DTD/wml_1.1.xml"), 'xhtml-strict': ('html', "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"), 'xhtml': ('html', "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"), 'xhtml-frameset': ('html', "-//W3C//DTD XHTML 1.0 Frameset//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"), 'html-strict': ('HTML', "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd"), 'html': ('HTML', "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"), 'html-frameset': ('HTML', "-//W3C//DTD HTML 4.01 Frameset//EN", "http://www.w3.org/TR/html4/frameset.dtd"), 'html-quirks': ('HTML', '-//W3C//DTD HTML 4.01 Transitional//EN'), 'html-frameset-quirks': ('HTML', "-//W3C//DTD HTML 4.01 Frameset//EN") } class Serializer(object): namespaces = namespace.namespaces src_encoding = encoding = 'utf-8' format = output_formats['default'] formatted = False inline = False def __init__(self, encoding=None, src_encoding=None, formatted=None, inline=None, format=None): """Initialize Serializer. You can change the following parameters: encoding: the output encoding src_encoding: the source encoding formatted: whether all tags should be considered formatted inline: whether all tags should be considered inline format: format to be applied (string or instance of Format) """ if encoding is not None: self.encoding = encoding if src_encoding is not None: self.src_encoding = src_encoding if formatted is not None: self.formatted = formatted if inline is not None: self.inline = inline if format is not None: self.format = format self.format = self._get_format(format) def _get_format(self, format): if format is None: return self.format elif isinstance(format, basestring): return output_formats[format] else: return format def is_formatted(self, tagname): return self.formatted def is_inline(self, tagname): return self.inline def serialize(self, stream, encoding=None, fragment=False, format=None): try: text = ''.join(self.generate(stream, encoding, fragment, format)) except TypeError: # workaround for bug 905389 in Python < 2.5 text = ''.join(tuple( self.generate(stream, encoding, fragment, format))) if not fragment: text = Format.strip(text) return text def write(self, stream, file, encoding=None, fragment=False, format=None): needs_closed = False if not hasattr(file, 'write'): needs_closed = True file = open(file, 'wb') try: write = file.write for text in self.generate(stream, encoding, fragment, format): write(text) finally: # only close a file if it was opened locally if needs_closed: file.close() def generate(self, stream, encoding=None, fragment=False, format=None): pass def apply_filters(self, stream, format=None): stream = _coalesce(stream, self.src_encoding) if format: stream = self.format_stream(stream, format) return stream def format_stream(self, stream, format): """Apply format to stream. Note that this method is unaware of the serialization of the tags and does only take into account the text inside the stream. So the results may sometimes differ from what you expect when formatting the complete serialized output. """ filter_text = format.filter indent, wrap = format.indent, format.wrap if indent is not None: indent_lines = format.indent_lines lstrip_blanks = format.lstrip_blanks rstrip_blanks = format.rstrip_blanks lstrip_lines = format.lstrip_lines min_level, max_level = format.min_level, format.max_level indent_level = [] new_line = False if wrap is not None: wrap_lines = format.wrap_lines indent_width, new_offset = format.indent_width, format.new_offset offset = 0 formatted = 0 text = last_char = '' for ev, item in stream: if ev == TEXT: text += item else: if ev in (START, END): tag = item.tag if not formatted: text = filter_text(text, last_char) if indent is None: if wrap is not None: text = wrap_lines(text, wrap, offset) else: level = len(indent_level) if max_level and level > max_level: level = max_level if min_level: level -= min_level if level < 0: level = 0 if wrap is not None: text = wrap_lines(text, wrap, offset, indent_width(level*indent)) if '\n' in text and indent_level: indent_level[-1] = True if new_line: if lstrip_blanks(text)[:1] != '\n': text = '\n' + lstrip_blanks(text) offset = 0 new_line = False if tag == Comment or not self.is_inline(tag): if ev == START: if indent_level: if rstrip_blanks(text)[-1:] != '\n': text = rstrip_blanks(text) + '\n' text = indent_lines(text, level*indent) indent_level[-1] = True elif text: text = lstrip_lines(text) if tag != Comment \ and not self.is_formatted(tag): indent_level.append(False) else: if indent_level: if indent_level.pop(): if rstrip_blanks(text)[-1:] == '\n': text = rstrip_blanks(text)[:-1] text = indent_lines(text, level*indent) text = rstrip_blanks(text) + '\n' level = len(indent_level) if max_level and level > max_level: level = max_level if min_level: level -= min_level if level < 0: level = 0 text += level*indent elif text: text = lstrip_lines(text) new_line = True elif text: text = indent_lines(text, level*indent) if tag == Comment or self.is_formatted(tag): if ev == START: formatted += 1 elif formatted: formatted -= 1 new_line = True yield TEXT, text if wrap is not None: offset = new_offset(text, offset) last_char = text[-1:] text = '' yield ev, item if text: if not formatted: text = filter_text(text, last_char) if wrap is not None: text = wrap_lines(text, wrap, offset) if indent is None: if wrap is not None: text = wrap_lines(text, wrap, offset) else: level = len(indent_level) if max_level and level > max_level: level = max_level if min_level: level -= min_level if level < 0: level = 0 if wrap is not None: text = wrap_lines(text, wrap, offset, indent_width(level*indent)) if rstrip_blanks(text)[-1:] == '\n': text = text[:-1] text = indent_lines(text, level*indent) yield TEXT, text class XMLSerializer(Serializer): decl = True doctype = None entity_map = None def __init__(self, encoding=None, decl=None, doctype=None, entity_map=None, namespaces=None, formatted=None, inline=None, format=None): """Initialize XMLSerializer. You can change the following parameters: encoding: the output encoding decl: add xml declaration at the beginning (True/False) doctype: add doctype (None, string, tuple) entity_map: use named entities for output (True/False or mapping) namespaces: mapping of namespaces formatted: whether all tags should be considered formatted inline: whether all tags should be considered inline format: format to be applied (string or instance of Format) """ Serializer.__init__(self, encoding=encoding, format=format, formatted=formatted, inline=inline) if decl is not None: self.decl = decl if doctype is not None: self.doctype = doctype if entity_map is not None: self.entity_map = entity_map if namespaces is not None: self.namespaces = namespaces def can_be_empty_element(self, item_name): return True def generate(self, stream, encoding=None, fragment=False, format=None): """Serializes an event stream to bytes of the specified encoding. This function yields an encoded string over and over until the stream is exhausted. """ decl = self.decl doctype = self.doctype encoding = encoding or self.encoding or 'utf-8' entity_map = self.entity_map format = self._get_format(format) if format: if format.decl is not None: decl = format.decl if format.doctype is not None: doctype = format.doctype if format.entity_map is not None: entity_map = format.entity_map if entity_map == True: # if True, use default HTML entity map entity_map = default_entity_map elif entity_map == False: entity_map = None if isinstance(doctype, basestring): # allow doctype strings doctype = doctypes[self.doctype] escape_cdata = XMLSerializer.escape_cdata escape_attrib = XMLSerializer.escape_attrib lastev = None stream = iter(stream) names = NamespaceStack(self.namespaces) if not fragment: if decl: yield '\n' % encoding if doctype is not None: yield serialize_doctype(doctype) + '\n' text = None for ev, item in self.apply_filters(stream, format): if ev in (START, END) and item.tag == Fragment: continue elif ev == TEXT: if text is not None: text = u''.join([text, item]) else: text = item continue if lastev == START: if ev == END and (not text or not (Format.strip(text) or self.is_formatted(item.tag))) \ and self.can_be_empty_element(item.tag): yield ' />' lastev = END text = None names.pop() continue yield ">" if text: yield escape_cdata(text, encoding, entity_map) text = None if ev == START: if item.tag == Comment: yield "" % item.text.encode(encoding) lastev = COMMENT continue elif item.tag == ProcessingInstruction: yield "" % item.text.encode(encoding) lastev = PI continue else: current_names = names.current names.push(namespaces(item, remove=True)) qname = names.qname(item.tag, default=True) yield "<" + qname.encode(encoding) for k, v in item.attrib.items(): k = names.qname(k, default=False).encode(encoding) v = escape_attrib(v, encoding) yield ' %s="%s"' % (k, v) for prefix, uri in names.current.items(): if prefix not in current_names \ or current_names[prefix] != uri: v = escape_attrib(uri, encoding) if prefix: k = 'xmlns:' + prefix.encode(encoding) else: k = 'xmlns' yield ' %s="%s"' % (k, v) elif ev == END and item.tag not in ( Comment, ProcessingInstruction): qname = names.qname(item.tag, default=True) yield "" % qname.encode(encoding) names.pop() lastev = ev if fragment and text: yield escape_cdata(text, encoding, entity_map) return def escape_cdata(text, encoding=None, entity_map=None): """Escape character data.""" try: if encoding: try: text = text.encode(encoding) except UnicodeError: return encode_entity(text, entities=entity_map) text = text.replace("&", "&") text = text.replace("<", "<") except (TypeError, AttributeError): raise_serialization_error(text) return text escape_cdata = staticmethod(escape_cdata) def escape_attrib(text, encoding=None, entity_map=None): """Escape attribute value.""" try: if encoding: try: text = text.encode(encoding) except UnicodeError: return encode_entity(text, entities=entity_map) text = text.replace("&", "&") text = text.replace("<", "<") text = text.replace("\"", """) except (TypeError, AttributeError): raise_serialization_error(text) return text escape_attrib = staticmethod(escape_attrib) class HTMLBased(object): """Mixin class for HTML based serializers.""" inject_type = None empty_elements = set([ 'area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param']) formatted_elements = set([ 'code', 'kbd', 'math', 'pre', 'script', 'textarea']) inline_elements = set(['a', 'abbr', 'acronym', 'b', 'basefont', 'bdo', 'big', 'br', 'cite', 'code', 'dfn', 'em', 'font', 'i', 'img', 'input', 'kbd', 'label', 'q', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var']) def can_be_empty_element(self, tag): return self.tagname(tag) in self.empty_elements def is_formatted(self, tag): return self.tagname(tag) in self.formatted_elements def is_inline(self, tag): return self.tagname(tag) in self.inline_elements def is_escape(self, tag): return self.tagname(tag) not in self.noescape_elements def inject_meta_content_type(self, stream, encoding): """Injects a meta tag for the content-type.""" return self.inject_meta_tags(stream, [{'http-equiv': 'content-type', 'content': 'text/html; charset=%s' % encoding}]) def inject_meta_tags(self, stream, taglist): """Injects meta tags at the start of the head section. If meta tags already exist at that position, they are kept. Expects a list of meta-tag attributes with content keys. The attribute names and values must be given in lower case. """ done = False meta_tag = None for ev, item in stream: if not done: if ev in (START, END): tag = self.tagname(item.tag) if meta_tag: if item.tag == meta_tag: if ev == START: for attributes in taglist: for attrib, value in item.items(): attrib = attrib.lower() if attrib == 'content': continue if attrib not in attributes: break value = value.lower() if attributes[attrib] != value: break else: # that meta tag exists already attributes['content'] = None break else: for attributes in taglist: if attributes['content'] is None: continue meta_item = Element(meta_tag, **attributes) yield START, meta_item yield END, meta_item yield TEXT, '\n' done = True elif tag == 'head' and ev == START: meta_tag = item.tag[:-4] + 'meta' yield ev, item class HTMLSerializer(HTMLBased, Serializer): doctype = doctypes['html'] transpose = False inject_type = True entity_map = None noescape_elements = set([ 'script', 'style']) boolean_attributes = set( ['selected', 'checked', 'compact', 'declare', 'defer', 'disabled', 'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap']) def __init__(self, encoding='utf-8', doctype=None, transpose=False, inject_type=None, entity_map=None, format=None): """Initialize HTMLSerializer. You can change the following parameters: encoding: the output encoding doctype: add doctype (None, string, tuple) transpose: alter tag names (None, True/False, callable) inject_type: inject content type (True/False) entity_map: use named entities for output (True/False or mapping) format: format to be applied (string or instance of Format) """ Serializer.__init__(self, encoding=encoding, format=format) if doctype is not None: self.doctype = doctype self.transpose = transpose if inject_type is not None: self.inject_type = inject_type if entity_map is not None: self.entity_map = entity_map def tagname(tag): """Remove namespace from tag and make it lowercase.""" if isinstance(tag, basestring): if tag.startswith('{'): tag = tag.split('}', 1)[-1] tag = tag.lower() return tag tagname = staticmethod(tagname) def is_escape(self, tag): return self.tagname(tag) not in self.noescape_elements def is_boolean_attribute(self, attribute): return attribute in self.boolean_attributes def generate(self, stream, encoding=None, fragment=False, format=None): """Serializes an event stream to bytes of the specified encoding. This function yields an encoded string over and over until the stream is exhausted. """ doctype = self.doctype encoding = encoding or self.encoding or 'utf-8' entity_map = self.entity_map transpose = self.transpose inject_type = self.inject_type format = self._get_format(format) if format: if format.doctype is not None: doctype = format.doctype if format.entity_map is not None: entity_map = format.entity_map if format.transpose is not None: transpose = format.transpose if format.inject_type is not None: inject_type = format.inject_type if entity_map == True: # if True, use default HTML entity map entity_map = default_entity_map elif entity_map == False: entity_map = None if isinstance(doctype, basestring): # allow doctype strings doctype = doctypes[self.doctype] if transpose is not None: if not callable(transpose): if transpose: transpose = lambda s: s.upper() else: transpose = lambda s: s.lower() escape_cdata = HTMLSerializer.escape_cdata escape_attrib = HTMLSerializer.escape_attrib names = NamespaceStack(self.namespaces) def grok_name(tag): if tag[0] == '{': uri, localname = tag[1:].split('}', 1) else: uri, localname = None, tag if uri and uri != xhtml_uri: qname = names.qname(tag, default=False) else: qname = localname if transpose: qname = transpose(qname) return uri, localname, qname current = None stack = [current] stream = iter(stream) if not fragment and doctype is not None: yield serialize_doctype(doctype) + '\n' if inject_type and encoding: stream = self.inject_meta_content_type(stream, encoding) for ev, item in self.apply_filters(stream, format): if ev == TEXT and item: escape = self.is_escape(current) yield escape_cdata(item, encoding, entity_map, escape) elif ev == START: if item.tag == Comment: yield "" % item.text.encode(encoding) continue elif item.tag == ProcessingInstruction: yield "" % item.text.encode(encoding) continue elif item.tag == Fragment: continue else: names.push(namespaces(item, remove=True)) tag = item.tag qname = grok_name(tag)[2] # push this name on the stack so we know where we are current = qname.lower() stack.append(current) yield "<" + qname.encode(encoding) attrs = item.attrib.items() if attrs: for k, v in attrs: q = grok_name(k)[2] lq = q.lower() if lq == 'xml:lang': continue if self.is_boolean_attribute(lq): # XXX: what if v is 0, false, or no. # should we omit the attribute? yield ' %s' % q.encode(encoding) else: yield ' %s="%s"' % ( q.encode(encoding), escape_attrib(v, encoding, entity_map)) yield ">" elif ev == END and item.tag not in ( Comment, ProcessingInstruction, Fragment): current = stack.pop() if not self.can_be_empty_element(current): tag = item.tag qname = grok_name(tag)[2] yield "" % qname.encode(encoding) current = stack[-1] names.pop() def escape_cdata(text, encoding=None, entity_map=None, escape=True): """Escape character data.""" try: if encoding: try: text = text.encode(encoding) except UnicodeError: return encode_entity(text, entities=entity_map) if escape: text = text.replace("&", "&") text = text.replace("<", "<") except (TypeError, AttributeError): raise_serialization_error(text) return text escape_cdata = staticmethod(escape_cdata) def escape_attrib(text, encoding=None, entity_map=None): """Escape attribute value.""" try: if encoding: try: text = text.encode(encoding) except UnicodeError: return encode_entity(text, entities=entity_map) text = text.replace("&", "&") text = text.replace("\"", """) except (TypeError, AttributeError): raise_serialization_error(text) return text escape_attrib = staticmethod(escape_attrib) class XHTMLSerializer(HTMLBased, XMLSerializer): doctype = doctypes['xhtml'] inject_type = True def __init__(self, encoding='utf-8', decl=None, doctype=None, inject_type=None, entity_map=None, namespaces=None, format=None): """Initialize XHTMLSerializer.""" XMLSerializer.__init__(self, encoding=encoding, decl=decl, doctype=doctype, entity_map=entity_map, namespaces=namespaces, format=format) if inject_type is not None: self.inject_type = inject_type def tagname(tag): """Remove namespace from tag.""" if isinstance(tag, basestring) and tag.startswith('{%s}' % xhtml_uri): tag = tag.split('}', 1)[-1] return tag tagname = staticmethod(tagname) def generate(self, stream, encoding=None, fragment=False, format=None): encoding = encoding or self.encoding or 'utf-8' inject_type = self.inject_type format = self._get_format(format) if format: if format.inject_type is not None: inject_type = format.inject_type if inject_type and encoding: stream = self.inject_meta_content_type(stream, encoding) return XMLSerializer.generate(self, stream, encoding=encoding, fragment=fragment, format=format) class PlainSerializer(Serializer): def generate(self, stream, encoding=None, fragment=False, format=None): """Generate only the text content.""" encoding = encoding or self.encoding or 'utf-8' for ev, item in self.apply_filters(stream, format): if ev == TEXT: yield item class NamespaceStack: """Maintains a stack of namespace prefix to URI mappings.""" def __init__(self, default_map=namespace.namespaces): self.stack = [] self.default_map = default_map self.push() self.ns_count = 0 def push(self, names=None): if names is None: names = {} self.current = names self.stack.insert(0, self.current) def pop(self): names = self.stack.pop(0) if self.stack: self.current = self.stack[0] return names def resolve_prefix(self, uri, default=True): """Figure out prefix given a URI.""" if uri == xml_uri: return 'xml' # first check if the default is correct is_default = None prefix = None for names in self.stack: for p, u in names.items(): if default and is_default is None and not p: # this is the current default namespace is_default = (u == uri) if (default and is_default) or prefix: break if u == uri and p: prefix = p if is_default is not None: break if default and is_default == True: return '' elif prefix: return prefix else: return None def resolve_uri(self, prefix): """Figure out URI given a prefix.""" if prefix == 'xml': return xml_uri for names in self.stack: uri = names.get(prefix) if uri: return uri return None def qname(self, cname, default=False): if isinstance(cname, QName): cname = cname.text if cname[0] != '{': # XXX: need to make sure default namespace is "no-namespace" return cname uri, localname = cname[1:].split('}', 1) prefix = self.resolve_prefix(uri, default) if prefix is None: # see if we have it in our default map prefix = self.default_map.get(uri) if prefix is not None: self.current[prefix] = uri else: if default and not self.current.has_key(''): prefix = '' self.current[prefix] = uri else: self.ns_count += 1 # XXX : need to check for collisions here. prefix = 'ns%d' % self.ns_count self.current[prefix] = uri if prefix != '': return '%s:%s' % (prefix, localname) else: return localname def serialize_doctype(doctype): if isinstance(doctype, basestring): return doctype elif len(doctype) == 1: return '' % doctype elif len(doctype) == 2: return '' % doctype else: return '' % doctype kid-0.9.6/kid/server.py0000644000175000017500000002120710646650134014637 0ustar tstanektstanek# -*- coding: utf-8 -*- """Kid-savvy HTTP Server. Written by Christoph Zwerschke based on CGIHTTPServer 0.4. This module builds on SimpleHTTPServer by implementing GET and POST requests to Kid templates. In all cases, the implementation is intentionally naive -- all requests are executed by the same process and sychronously. Code to create and run the server looks like this: from kid.server import HTTPServer host, port = 'localhost', 8000 HTTPServer((host, port)).serve_forever() This serves files and kid templates from the current directory and any of its subdirectories. If you want the server to be accessible via the network, use your local host name or an empty string as the host. (Security warning: Don't do this unless you are inside a firewall.) You can also call the test() function to run the server, or run this module as a script, providing host and port as command line arguments. The Kid templates have access to the following predefined objects: FieldStorage (access to GET/POST variables) environ (CGI environment) request (the request handler object) Here is a simple Kid template you can use to test the server: Python Expression Evaluator

${FieldStorage.getvalue('expr')} = ${eval(FieldStorage.getvalue('expr'))}

Enter a Python expression:

""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Christoph Zwerschke (cito@online.de)" __copyright__ = "Copyright 2005, Christoph Zwerschke" __license__ = "MIT " import os.path from urllib import unquote from BaseHTTPServer import HTTPServer as BaseHTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler from cgi import FieldStorage from kid import load_template __all__ = ["HTTPServer", "HTTPRequestHandler"] default_host = 'localhost' default_port = 8000 class HTTPRequestHandler(SimpleHTTPRequestHandler): """Complete HTTP server with GET, HEAD and POST commands. GET and HEAD also support running Kid templates. The POST command is *only* implemented for Kid templates.""" def do_POST(self): """Serve a POST request implemented for Kid templates.""" if self.is_kid(): self.run_kid() else: self.send_error(501, "Can only POST to Kid templates") def send_head(self): """Version of send_head that supports Kid templates.""" if self.is_kid(): return self.run_kid() else: return SimpleHTTPRequestHandler.send_head(self) def is_kid(self): """Test whether self.path corresponds to a Kid template. The default implementation tests whether the path ends with one of the strings in the list self.kid_extensions. """ path = self.path i = path.rfind('?') if i >= 0: path, query = path[:i], path[i+1:] else: query = '' for x in self.kid_extensions: if path.endswith(x): self.cgi_info = path, query return True return False kid_extensions = ['.kid', '.kid.html'] def run_kid(self): """Execute a Kid template.""" scriptname, query = self.cgi_info scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such Kid template (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "Kid template is not a plain file (%r)" % scriptname) return env = {} env['SERVER_SOFTWARE'] = self.version_string() env['SERVER_NAME'] = self.server.server_name env['GATEWAY_INTERFACE'] = 'CGI/1.1' env['SERVER_PROTOCOL'] = self.protocol_version env['SERVER_PORT'] = str(self.server.server_port) env['REQUEST_METHOD'] = self.command uqpath = unquote(scriptname) env['PATH_INFO'] = uqpath env['PATH_TRANSLATED'] = self.translate_path(uqpath) env['SCRIPT_NAME'] = scriptname if query: env['QUERY_STRING'] = query host = self.address_string() if host != self.client_address[0]: env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env['AUTH_TYPE'] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(':') if len(authorization) == 2: env['REMOTE_USER'] = authorization[0] if self.headers.typeheader is None: env['CONTENT_TYPE'] = self.headers.type else: env['CONTENT_TYPE'] = self.headers.typeheader length = self.headers.getheader('content-length') if length: env['CONTENT_LENGTH'] = length accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(accept) ua = self.headers.getheader('user-agent') if ua: env['HTTP_USER_AGENT'] = ua co = filter(None, self.headers.getheaders('cookie')) if co: env['HTTP_COOKIE'] = ', '.join(co) self.send_response(200, "Script output follows") # Execute template in this process try: template_module = load_template(scriptfile, cache=True) template = template_module.Template( request=self, environ=env, FieldStorage=FieldStorage(self.rfile, environ=env)) s = str(template) self.send_header("Content-type", "text/html") self.send_header("Content-Length", str(len(s))) self.end_headers() self.wfile.write(s) except Exception, e: self.log_error("Kid template exception: %s", str(e)) else: self.log_message("Kid template exited OK") class HTTPServer(BaseHTTPServer): def __init__(self, server_address=None, RequestHandlerClass=HTTPRequestHandler): if server_address is None: server_address = (default_host, default_port) BaseHTTPServer.__init__(self, server_address, HTTPRequestHandler) def test(server_address=None, HandlerClass=HTTPRequestHandler, ServerClass=HTTPServer, protocol="HTTP/1.0"): """Test the HTTP request handler class.""" HandlerClass.protocol_version = protocol server = ServerClass(server_address, HandlerClass) sa = server.socket.getsockname() print "Serving HTTP on", sa[0], "port", sa[1], "..." server.serve_forever() def main(): """This runs the Kid-savvy HTTP server. Provide host and port as command line arguments. The current directory serves as the root directory. """ from sys import argv, exit if len(argv) > 3: print "Usage:", argv[0], "[host]:[port]" exit(2) if len(argv) < 2: server_address = (default_host, default_port) else: if len(argv) == 3: host = argv[1] port = argv[2] else: host = argv[1].split(':', 1) if len(host) < 2: host = host[0] if host.isdigit(): port = host host = '' else: port = None else: host, port = host if port: if port.isdigit(): port = int(port) else: print "Bad port number." exit(1) else: port = default_port server_address = (host, port) test(server_address) if __name__ == '__main__': main() kid-0.9.6/kid/template_util.py0000644000175000017500000002425410646650134016206 0ustar tstanektstanek# -*- coding: utf-8 -*- """Utility functions used by generated kid modules.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " import inspect import sys from types import TypeType, ModuleType, ClassType, GeneratorType import itertools # these are for use by template code import kid from kid.parser import XML, document, ElementStream, START, END, TEXT, \ START_NS, COMMENT, PI, DOCTYPE, XML_DECL, to_unicode from kid.element import Element, SubElement, Comment, ProcessingInstruction __all__ = ['XML', 'document', 'ElementStream', 'Element', 'SubElement', 'Comment', 'ProcessingInstruction', 'START', 'END', 'TEXT', 'START_NS', 'COMMENT', 'PI', 'DOCTYPE', 'XML_DECL'] class TemplateError(Exception): pass class TemplateNotFound(TemplateError): pass class TemplateImportError(TemplateError): pass class TemplateDictError(TemplateError): pass class TemplateAttrsError(TemplateError): pass class TemplateExtendsError(TemplateError): pass class TemplateLayoutError(TemplateError): pass _local_excludes = ['generate', 'module', 'parser', 'serialize', 'transform', 'write'] def get_locals(inst, _locals=None): if _locals is None: _locals = {} ls = [] local_excludes = _local_excludes # local copy for var, value in inspect.getmembers(inst): if not var.startswith('_') and not var in local_excludes \ and var not in _locals: ls.append('%s=self.%s' % (var, var)) return ';'.join(ls) def get_base_class(thing, from_file=None, arg=None): """Get template base class for thing, raising an exception on error.""" if thing is None: return kid.BaseTemplate if isinstance(thing, TypeType): return thing elif isinstance(thing, ModuleType): try: cls = thing.Template except AttributeError: cls = None if (isinstance(cls, TypeType) and issubclass(cls, kid.BaseTemplate) and cls != kid.Template): return cls thing = repr(thing) if arg: thing = arg else: try: thing = thing.__name__ except AttributeError: thing = repr(thing) raise TemplateNotFound( '%s is a module without Template class' % thing) elif isinstance(thing, basestring): try: path = kid.path.find(thing, from_file) except Exception: path = None if not path: if arg: thing = arg raise TemplateNotFound('Template file %r not found' % thing) try: mod = kid.load_template(path) except Exception: mod = None if not mod: raise TemplateNotFound('Could not open %r' % path) try: cls = mod.Template except AttributeError: cls = None if (isinstance(cls, TypeType) and issubclass(cls, kid.BaseTemplate) and cls != kid.Template): return cls raise TemplateNotFound('%r does not contain a template class' % path) thing = repr(thing) if arg: thing = '%s (%s)' % (arg, thing) raise TemplateNotFound('%s is not a Template class' % thing) def base_class(arg, globals, locals): """Get base class for argument with graceful exception handling.""" try: from_file = globals['__file__'] thing = eval(arg, globals, locals) return get_base_class(thing, from_file, arg) except Exception, e: errors = [str(e)] # try again without evaluating the argument (forgotten quotes etc.) try: return get_base_class(arg, from_file, arg) except Exception, e: errors.append(str(e)) # reraise the original problem when we tried to evaluate the thing errors = '\n'.join(filter(bool, errors)) or arg raise TemplateNotFound, errors def base_class_extends(extends, globals, locals, all_extends=None): """Get Template base class for 'extends'.""" try: return base_class(extends, globals, locals) except Exception, e: raise TemplateExtendsError((str(e) + '\nwhile processing extends=%r' % (all_extends or extends)).lstrip()) def base_class_layout(layout, globals, locals): """Get Template base class for 'layout'.""" try: return base_class(layout, globals, locals) except Exception, e: raise TemplateLayoutError((str(e) + '\nwhile processing layout=%r' % layout).lstrip()) def make_attrib(attrib, encoding=None): """Generate unicode strings in dictionary.""" if attrib is None: return {} if encoding is None: encoding = sys.getdefaultencoding() for (k, v) in attrib.items(): if v is not None: try: v = generate_attrib(v, encoding) except TemplateAttrsError: raise TemplateAttrsError('Illegal value for attribute "%s"' % k.encode('raw_unicode_escape')) if v is None: del attrib[k] else: attrib[k] = v return attrib def generate_attrib(attrib, encoding): """Generate unicode string from attribute.""" if attrib is None: return None elif isinstance(attrib, basestring): return to_unicode(attrib, encoding) elif isinstance(attrib, ElementStream): text = [] for ev, item in attrib: if ev == TEXT: text.append(to_unicode(item, encoding)) else: raise TemplateAttrsError if text: return ''.join(text) else: return None elif hasattr(attrib, '__iter__'): # if we get any other iterable, join the strings together: text = [] for item in attrib: if item is not None: item = generate_attrib(item, encoding) if item is not None: text.append(item) if text: return ''.join(text) else: return None else: return to_unicode(attrib, encoding) def generate_content(content): """Generate ElementStream from content.""" if content is None: return [] elif isinstance(content, basestring): return [(TEXT, content)] elif isinstance(content, (ElementStream, kid.BaseTemplate)): return content elif isinstance(content, GeneratorType): return ElementStream(content) elif hasattr(content, 'tag') and hasattr(content, 'attrib'): # if we get an Element back, make it an ElementStream return ElementStream(content) elif hasattr(content, '__iter__'): # if we get any other iterable, chain the contents together: return itertools.chain(*itertools.imap(generate_content, content)) else: return [(TEXT, unicode(content))] def filter_names(names, omit_list): for ns in names.keys(): if ns in omit_list: del names[ns] return names def update_dict(a, args, globals, locals): """Update dictionary a from keyword argument string args.""" try: b = eval('%s' % args, globals, locals) if not isinstance(b, dict): b = dict(b) except Exception: try: b = eval('dict(%s)' % args, globals, locals) except SyntaxError: # TypeErrror could happen with Python versions < 2.3, because # building dictionaries from keyword arguments was not supported. # Kid requires a newer Python version, so we do not catch this. # SyntaxError can happen if one of the keyword arguments is # the same as a Python keyword (e.g. "class") or if it is # a qualified name containing a namespace prefixed with a colon. # In these cases we parse the keyword arguments manually: try: try: from cStringIO import StringIO except ImportError: from StringIO import StringIO from tokenize import generate_tokens from token import NAME, OP depth, types, parts = 0, [], [] for token in generate_tokens(StringIO(args).readline): type_, string = token[:2] if type_ == OP: if string == '=': if depth == 0: if len(types) > 0 \ and types[-1] == NAME and parts[-1]: if len(types) > 2 \ and types[-2] == OP and parts[-2] == ':' \ and types[-3] == NAME and parts[-3]: parts[-3:] = ["'%s'" % ''.join(parts[-3:])] else: parts[-1] = "'%s'" % parts[-1] string = ':' elif string in '([{': depth += 1 elif depth > 0 and string in ')]}': depth -= 1 types.append(type_) parts.append(string) b = eval('{%s}' % ''.join(parts), globals, locals) except Exception: b = None if not isinstance(b, dict): raise for k in b.keys(): if b[k] is None: del b[k] if k in a: del a[k] a.update(b) return a def update_attrs(attrib, attrs, globals, locals): """Update attributes from attrs string args.""" try: return update_dict(attrib, attrs, globals, locals) except Exception, e: raise TemplateAttrsError((str(e) + '\nwhile processing attrs=%r' % attrs).lstrip()) def make_updated_attrib(attrib, attrs, globals, locals, encoding=None): """"Generate unicode strings in updated dictionary.""" return make_attrib(update_attrs(attrib, attrs, globals, locals), encoding) kid-0.9.6/kid/util.py0000644000175000017500000000720710646650135014313 0ustar tstanektstanek# -*- coding: utf-8 -*- """Utility functions for Kid.""" __revision__ = "$Rev: 492 $" __date__ = "$Date: 2007-07-06 21:38:45 -0400 (Fri, 06 Jul 2007) $" __author__ = "Ryan Tomayko (rtomayko@gmail.com)" __copyright__ = "Copyright 2004-2005, Ryan Tomayko" __license__ = "MIT " from urllib import splittype class QuickTextReader(object): def __init__(self, text): self.text = text self.len = len(self.text) self.pos = 0 self.lines = None def __iter__(self): while 1: if self.lines is None: self.lines = self.text.splitlines(True) if not self.lines: break yield self.lines.pop(0) def close(self): self.text = None self.pos = self.len = 0 self.lines = None def read(self, size=None): if size is not None: try: size = int(size) except: size = None else: if not 0 <= size < self.len: size = None pos = self.pos if size is None: self.pos = self.len return self.text[pos:] else: self.pos += size if self.pos > self.len: self.pos = self.len return self.text[pos:self.pos] def seek(self, offset, whence=0): if whence: if whence == 2: self.pos = self.len - offset else: self.pos += offset else: self.pos = offset self.lines = None if self.pos < 0: self.pos = 0 elif self.pos > self.len: self.pos = self.len def tell(self): return self.pos def next(self): if not self.lineno: self.lines = self.splitlines(True) self.lineno += 1 if not self.lines: raise StopIteration return self.lines.pop(0) def xml_sniff(text): """Sniff text to see if it looks like XML. Return True if text looks like XML, otherwise return False. """ for x in text: if x in '\t\r\n ': continue elif x == '<': return True else: return False def open_resource(uri, mode='rb'): """Generic resource opener.""" scheme, rest = splittype(uri) if not scheme or (len(scheme) == 1 and rest.startswith('\\')): return open(uri, mode) else: import urllib2 return urllib2.urlopen(uri) def get_expat_error(error): """Return text showing the position of an Expat error.""" source, lineno, offset = error.source, error.lineno, error.offset if lineno < 1: lineno = 1 offset = 0 source.seek(0) nlines = 0 for line in source: lineno -= 1 nlines += 1 if not lineno: break else: offset = 0 if nlines: if nlines == 1: if line.startswith('\xef\xbb\xbf'): line = line[3:] if line: if offset < 0: offset = 0 elif offset > len(line): offset = len(line) if offset > 75: if len(line) - offset > 37: line = line[offset-38:offset+38] offset = 38 else: offset -= len(line) - 76 line = line[-76:] else: line = line[:76] if line: line = '%s\n%%%ds\n' % (line.rstrip(), offset + 1) line = line % '^' return line kid-0.9.6/kid.egg-info/0000755000175000017500000000000010646655235014456 5ustar tstanektstanekkid-0.9.6/kid.egg-info/PKG-INFO0000644000175000017500000000232710646655235015557 0ustar tstanektstanekMetadata-Version: 1.0 Name: kid Version: 0.9.6 Summary: A simple and pythonic XML template language Home-page: http://www.kid-templating.org Author: Ryan Tomayko Author-email: rtomayko@gmail.com License: MIT Download-URL: http://www.kid-templating.org/dist/0.9.6/kid-0.9.6.tar.gz Description: Kid is a simple, Python-based template language for generating and transforming XML vocabularies. Kid was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (well, eventually :). Keywords: xml template html web Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Text Processing :: Markup :: XML kid-0.9.6/kid.egg-info/SOURCES.txt0000644000175000017500000000741410646655235016350 0ustar tstanektstanekCOPYING ChangeLog HISTORY MANIFEST.in README RELEASING ez_setup.py kid-env.sh makefile run_tests.py setup.cfg setup.py work.sh bin/kid bin/kidc doc/custom.css doc/default.css doc/guide.txt doc/index.txt doc/language.txt doc/makefile doc/notes.txt doc/html/almodovar.css doc/html/class-kid.BaseTemplate.html doc/html/class-kid.HTMLSerializer.html doc/html/class-kid.Namespace.html doc/html/class-kid.Serializer.html doc/html/class-kid.XHTMLSerializer.html doc/html/class-kid.XMLSerializer.html doc/html/class-kid.namespace.Namespace.html doc/html/class-kid.serialization.HTMLSerializer.html doc/html/class-kid.serialization.Serializer.html doc/html/class-kid.serialization.XMLSerializer.html doc/html/class-kid.util.QuickTextReader.html doc/html/gnu.html doc/html/guide.html doc/html/index.html doc/html/language.html doc/html/layout.css doc/html/module-index.html doc/html/module-kid-index.html doc/html/module-kid.filter-index.html doc/html/module-kid.filter.html doc/html/module-kid.html doc/html/module-kid.namespace-index.html doc/html/module-kid.namespace.html doc/html/module-kid.properties-index.html doc/html/module-kid.properties.html doc/html/module-kid.serialization-index.html doc/html/module-kid.serialization.html doc/html/module-kid.util-index.html doc/html/module-kid.util.html doc/html/notes.html doc/html/pudge.css doc/html/rst.css doc/html/kid/__init__.py.html doc/html/kid/compile.py.html doc/html/kid/compiler.py.html doc/html/kid/et.py.html doc/html/kid/filter.py.html doc/html/kid/importer.py.html doc/html/kid/namespace.py.html doc/html/kid/parser.py.html doc/html/kid/properties.py.html doc/html/kid/pull.py.html doc/html/kid/release.py.html doc/html/kid/run.py.html doc/html/kid/serialization.py.html doc/html/kid/server.py.html doc/html/kid/template_util.py.html doc/html/kid/util.py.html doc/html/kid/test/__init__.py.html examples/basic/README examples/basic/self.kid examples/basic/sysinfo.kid examples/basic/tutorial.kid examples/basic/tutorial2.kid examples/cgi/README examples/cgi/kid_handler.cgi examples/cgi/sysinfo.kid kid/__init__.py kid/codewriter.py kid/compile.py kid/compiler.py kid/element.py kid/filter.py kid/format.py kid/importer.py kid/namespace.py kid/options.py kid/parser.py kid/pull.py kid/release.py kid/run.py kid/serialization.py kid/server.py kid/template_util.py kid/util.py kid.egg-info/PKG-INFO kid.egg-info/SOURCES.txt kid.egg-info/dependency_links.txt kid.egg-info/entry_points.txt kid.egg-info/top_level.txt kid/test/__init__.py kid/test/test_attribute_interpolation.py kid/test/test_codewriter.py kid/test/test_comment.py kid/test/test_compiler.py kid/test/test_element.py kid/test/test_error.py kid/test/test_extended_layout.py kid/test/test_extends.py kid/test/test_format.py kid/test/test_kid.py kid/test/test_kid_lang.py kid/test/test_layout.py kid/test/test_match.py kid/test/test_namespace.py kid/test/test_options.py kid/test/test_parser.py kid/test/test_scope.py kid/test/test_serialization.py kid/test/test_serialization_escaping.py kid/test/test_suffixes.py kid/test/test_templatepath.py kid/test/test_unicode.py kid/test/util.py misc/upgrade-0.6.py test/__init__.py test/basic-test.html.kid test/blocks.py test/context.kid test/include-me.xml test/layout.kid test/serialization.kid test/template-test.html.kid test/templates.kid test/test_attribute_interpolation.kid test/test_attrs.kid test/test_backward.kid test/test_comment_pi.kid test/test_content.kid test/test_content_interpolation.kid test/test_content_structure.kid test/test_def.kid test/test_encoding.kid test/test_entities.kid test/test_extends.kid test/test_if.kid test/test_kid_pi.kid test/test_layout_page.kid test/test_match.kid test/test_match_parent.kid test/test_namespaces.kid test/test_omit.kid test/test_repeat.kid test/test_replace.kid test/test_strip.kid test/test_xml_encoding.kid test/test_xml_func.kid kid-0.9.6/kid.egg-info/dependency_links.txt0000644000175000017500000000000110646655235020524 0ustar tstanektstanek kid-0.9.6/kid.egg-info/entry_points.txt0000644000175000017500000000007610646655235017757 0ustar tstanektstanek[console_scripts] kidc = kid.compile:main kid = kid.run:main kid-0.9.6/kid.egg-info/top_level.txt0000644000175000017500000000000410646655235017202 0ustar tstanektstanekkid kid-0.9.6/misc/0000755000175000017500000000000010646655235013150 5ustar tstanektstanekkid-0.9.6/misc/upgrade-0.6.py0000755000175000017500000000263610646650131015452 0ustar tstanektstanek#!/usr/bin/env python """usage: %s file... Upgrades a kid template from version 0.5 to 0.6. The previous version of each file is backed up to "file-0.5". It is recommended that """ import sys import re from os.path import exists from shutil import move, copymode ns_exp = re.compile(r'http://naeblis.cx/ns/kid#') omit_exp = re.compile(r'py:omit=') brace_exp = re.compile(r""" (? This is replaced.

py:content

py:repeat

These are some things I like to eat:

  • A fruit

py:if (False value)

You shouldn't see anything after this paragraph..

This should not be output or put out.

py:if (True value)

You should see something after this paragraph..

This should be output.

attribute interpolation

The title attribute should read: "This should read like a normal sentence."

The title attribute of this element shouldn't be output at all

py:strip

The containing <div> should be omitted.
The containing <div> should not be omitted.
The containing <div> should be omitted.

py:repeat (with nesting)

kid-0.9.6/test/blocks.py0000644000175000017500000000354010646650131015013 0ustar tstanektstanek""" A bunch of code blocks for testing indentation detection.. """ blocks = [] def block(text, expect=None): blocks.append( (text.strip(), (expect or text).strip()) ) block(""" # comment """) block(""" call() """) block(""" \t\t\t# comment """, """ # comment """) block(""" \t\t\tcall() """, """ call() """) block(""" if test: \tprint 'bla' """) block(""" if test: \t\t\t\t\tprint 'bla' """, """ if test: \tprint 'bla' """) block(""" if test: print 'bla' """, """ if test: \tprint 'bla' """) block(""" if test: print 'bla' """, """ if test: \tprint 'bla' """) block(""" if test: \t\t\t\t\tprint 'for' else: \t\t\t\t\tprint 'bla' """) block(""" if test: print 'bla' """, """ if test: \tprint 'bla'""") block(""" if x: print 'foo' else: print 'bar' """,""" if x: print 'foo' else: print 'bar' """) block(""" if x: \tprint 'foo' \tif y: \t\tprint 'bar' """) block(""" import bla bla.bla() """) block(""" # if x: print 'bla' """) block(""" if f(x, \ty) == 1: \tprint 'bla' """) block(""" if f(x, y) == 1: print 'bla' """, """ if f(x, \ty) == 1: \tprint 'bla' """) block(""" if f(x) == 1: # bla print 'bla' """, """ if f(x) == 1: # bla \tprint 'bla' """) block(""" if "#": pass""", """ if "#": \tpass """) block(""" try: \ttest() except: \toops() """) block(""" class x: pass""", """ class x: \tpass """) block(""" # ignore comments \t\twhile something: \t\t\tdo(something) \t\telse: \t\t\tsleep() """, """ # ignore comments while something: \tdo(something) else: \tsleep() """) block(""" \t\t\t\t\t \tclass x: \t\t\t\t\t \t\tpass \t\t\t\t\t \texit(1) """, """ class x: \tpass exit(1) """) block(""" \tif this: \t\tdo(that) \telse # oops \t\tforgot(something) """, """ if this: \tdo(that) else # oops \tforgot(something) """) block(""" elif something: pass""") block(""" else: pass""") block(""" except: pass""") block(""" if1: pass""") kid-0.9.6/test/context.kid0000644000175000017500000000050510646650131015337 0ustar tstanektstanek

should be 10

10

should be bla bla

bla bla

kid-0.9.6/test/include-me.xml0000644000175000017500000000010110646650131015716 0ustar tstanektstanek

included from external file.

cool

kid-0.9.6/test/layout.kid0000644000175000017500000000124610646650131015173 0ustar tstanektstanek
Incorrect content...
This is the ${title} This is the correct title This body content should not be displayed
This is the correct content!
${xinput("toast")}
kid-0.9.6/test/serialization.kid0000644000175000017500000000013210646650131016524 0ustar tstanektstanek kid-0.9.6/test/template-test.html.kid0000644000175000017500000000056010646650131017407 0ustar tstanektstanek

Bla Bla

""
kid-0.9.6/test/templates.kid0000644000175000017500000000076510646650131015661 0ustar tstanektstanek

This is a test

kid-0.9.6/test/test_attribute_interpolation.kid0000644000175000017500000000205210646650131021663 0ustar tstanektstanek

string test

string test

int test

int test

float test

float test

mixed test

mixed test

Remove and blank attr test

Remove and blank attr test

Escape test

Escape test

Escape test

Escape test

kid-0.9.6/test/test_attrs.kid0000644000175000017500000000263010646650131016050 0ustar tstanektstanek

harmless attrs test

harmless attrs test

offensive attrs test with Python keywords

offensive attrs test with Python keywords

attrs test with qualified names

attrs test with qualified names

kid-0.9.6/test/test_backward.kid0000644000175000017500000000043610646650131016473 0ustar tstanektstanek test

test

test

kid-0.9.6/test/test_comment_pi.kid0000644000175000017500000000127610646650131017052 0ustar tstanektstanek
<div><!-- check that comments pass through --></div>
kid-0.9.6/test/test_content.kid0000644000175000017500000000573610646650131016377 0ustar tstanektstanek we'll stop here, thanks.." tmpl = kid.Template(source=some_xml) ?> test with a module-level variable this is some text test with a module-level function this is some function test with empty content expression test with None

Here's some embedded structure too. This should not show up in the output document.

This shouldn't either.

some text
int test 1234 float test 1234.5678 unicode test †©— quick < CDATA test cação cação cação wrapped with ${unicode(msg2, 'iso8859-1')} other text wrapped with â other text False ${value_of("fizzyfish", "extra fizzy")} extra fizzy

we'll stop here, thanks..

kid-0.9.6/test/test_content_interpolation.kid0000644000175000017500000000474310646650131021343 0ustar tstanektstanek ${test1} test1 value ${test2()} test2 value ${None} ${'test4'} test4 ${1234} 1234 ${1234.5678} 1234.5678 ${[1,2,3]} 123 ${(4,5,6)} 456 ${u'†©—'} †©— quick < CDATA test hello ${'there'} this is ${None} a multi-part $test1 hello there this is a multi-part test1 value test $$escaping of $$ signs. test $$escaping of $$ signs. ${1+2+3}pack 6pack em${}p${ }ty empty $s ${'world'} ${s + ' world'} $$ $$ $$ $ $ $ $$ $$ $$ ${'$ $ $ $ $ $ $ $ $'} $$s $s $$$s $$$ ${'$s hello $hello $$'} es ist schon ${int(str(6-1))} vor ${3 + 4 + 5} aber ${s.replace('e', 'a')}! es ist schon 5 vor 12 aber hallo! ${msg} cação ${unicode(msg_utf8, 'utf-8')} cação ${unicode(msg_iso, 'iso8859-1')} cação kid-0.9.6/test/test_content_structure.kid0000644000175000017500000000153310646650131020506 0ustar tstanektstanek world" from kid import Element, SubElement test_elm = Element("elmo") test_elm.set("oscar", "grouch") SubElement(test_elm, "inner").text = "test" ?> test including a file

included from external file.

cool

test with XML string world Test Element type test
kid-0.9.6/test/test_def.kid0000644000175000017500000000304710646650131015454 0ustar tstanektstanek

This is a test

hello world?

Some Fruit

orange
A juicy fruit from Florida mostly.
m&m's
melts in your mouth not in your hand.
apple
A red fruit that hurts my teeth.

a test paragraph

a test paragraph

${ inline_test() } and then ${'some'}

a test paragraph

and then some

${x}

,

! Hello, World! kid-0.9.6/test/test_encoding.kid0000644000175000017500000000060510646650131016501 0ustar tstanektstanek ${var} ${var} kid-0.9.6/test/test_entities.kid0000644000175000017500000000042010646650131016532 0ustar tstanektstanek Uses   and other entities: © › — Uses   and other entities: © › — kid-0.9.6/test/test_extends.kid0000644000175000017500000000124110646650131016362 0ustar tstanektstanek

a test paragraph

${inline_test()} and then ${'some'}

a test paragraph

and then some
This content should be copied
second parent - first parent - This content should be copied
kid-0.9.6/test/test_if.kid0000644000175000017500000000043010646650131015305 0ustar tstanektstanek

test1

test1

test1

kid-0.9.6/test/test_kid_pi.kid0000644000175000017500000000272510646650131016157 0ustar tstanektstanek some stuff global scope some stuff global scope some stuff local scope some stuff local scope some stuff pass kid-0.9.6/test/test_layout_page.kid0000644000175000017500000000044510646650131017226 0ustar tstanektstanek
This is the correct content!
kid-0.9.6/test/test_match.kid0000644000175000017500000000260210646650131016006 0ustar tstanektstanek
${[item.text, item.getchildren()]}
This content will be copied. This content will be copied.

]]>

Foo: ${item.get('bar')}

first parent - ${[item.text, item.getchildren()]}

Foo: baz

]]>
${apply(item.getchildren())}
bla bla

Foo: bling

bla bla
]]>
kid-0.9.6/test/test_match_parent.kid0000644000175000017500000000044310646650131017360 0ustar tstanektstanek
second parent - ${[item.text, item.getchildren()]}
kid-0.9.6/test/test_namespaces.kid0000644000175000017500000000173710646650131017041 0ustar tstanektstanek bar" ?> some text some text some text some text ${XML(include_common)} bar kid-0.9.6/test/test_omit.kid0000644000175000017500000000111510646650131015660 0ustar tstanektstanek

outer p is omitted

outer p is omitted

outer p is omitted

outer p is omitted

outer p is not omitted

outer p is not omitted

kid-0.9.6/test/test_repeat.kid0000644000175000017500000000172710646650131016201 0ustar tstanektstanek
  • A fruit
  • apple
  • orange
  • kiwi
  • M&M
  • 1

    • 11
    • 12
  • 2

    • 21
    • 22
kid-0.9.6/test/test_replace.kid0000644000175000017500000000201710646650131016325 0ustar tstanektstanek we'll stop here, thanks.." tmpl = kid.Template(source=some_xml) def f(): return None ?>

this should be replaced

this is some text

this should go away

this should go away

will be replaced

we'll stop here, thanks..

we'll stop here, thanks.. kid-0.9.6/test/test_strip.kid0000644000175000017500000000341110646650131016052 0ustar tstanektstanek

abc

abc

abc

abc

abc

abc

abc

abc

abc

abc

ac

ac

ac

ac

abc

abc

abc

abc

abc

abc

abc

abc

kid-0.9.6/test/test_xml_encoding.kid0000644000175000017500000000057510646650131017367 0ustar tstanektstanek µ¹è»¾ýáí $e kid-0.9.6/test/test_xml_func.kid0000644000175000017500000000213610646650131016527 0ustar tstanektstanek ') ?> ') ?> abc ${test_xml_global()} abc ${test_xml_local()} abc ${test_xml_template()} kid-0.9.6/COPYING0000644000175000017500000000207210646650135013243 0ustar tstanektstanekCopyright (c) 2004-2005 Ryan Tomayko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. kid-0.9.6/ChangeLog0000644000175000017500000004442410646650131013765 0ustar tstanektstanek2005-10-12 12:12 kdangoor * Multiple match rules can now run against a single element. 2005-01-26 08:20 rtomayko * ChangeLog: release 0.5 2005-01-26 08:20 rtomayko * examples/basic/sysinfo.kid: Updated example for recent changes.. 2005-01-26 08:15 rtomayko * HISTORY: [no log message] 2005-01-26 08:10 rtomayko * doc/index.txt, doc/kid-spec.txt, doc/tutorial.txt, kid/__init__.py, kid/parser.py, examples/basic/sysinfo.kid, examples/cgi/sysinfo.kid, test/basic-test.html.kid, test/context.kid, test/template-test.html.kid, test/templates.kid, test/test_attribute_interpolation.kid, test/test_attrs.kid, test/test_content.kid, test/test_content_interpolation.kid, test/test_content_structure.kid, test/test_def.kid, test/test_if.kid, test/test_kid_pi.kid, test/test_omit.kid, test/test_repeat.kid, test/test_replace.kid: Renamed the kid PI to python. Use py: instead of kid: for namespace prefixes. 2005-01-26 07:37 rtomayko * kid/parser.py: Fixed bad dict call. Added call to _k_dict from kid:attrs. 2005-01-26 07:36 rtomayko * kid/util.py: Added python < 2.3 compatible _k_dict function.. 2005-01-26 07:32 rtomayko * test/test_attrs.kid: Added kid:attrs test.. 2005-01-26 07:22 rtomayko * kid/parser.py: Applied kid:attrs patch from Christoph Zwerschke 2005-01-26 06:30 rtomayko * doc/style.xsl: Damn sourceforge logo was wrong.. 2005-01-26 06:29 rtomayko * kid/parser.py, kid/util.py, test_kid.py, test/test_content_interpolation.kid, test/test_def.kid: Added support for brace interpolation with text content. 2005-01-26 06:26 rtomayko * makefile: Add python 2.4 to tests 2005-01-22 01:12 rtomayko * ChangeLog: updated ChangeLog 2005-01-22 01:12 rtomayko * kid/__init__.py: release 0.4.2 2005-01-22 01:11 rtomayko * ChangeLog: [no log message] 2005-01-22 01:11 rtomayko * setup.py: Oops.. erase all evidence of urlgrabber theft :) 2005-01-22 01:11 rtomayko * MANIFEST.in: Update MANIFEST to include all tests 2005-01-22 00:50 rtomayko * ChangeLog, kid/__init__.py: release 0.4.2 2005-01-22 00:49 rtomayko * examples/basic/README: Updated for API changes. 2005-01-22 00:49 rtomayko * TODO: [no log message] 2005-01-20 10:06 rtomayko * HISTORY, TODO: Updated for 0.4.3 2005-01-20 10:06 rtomayko * README: Updates for website changes and what not. 2005-01-19 06:28 rtomayko * kid/util.py: Added _k_filter_names utility function. Used by omit namespace logic. 2005-01-19 06:27 rtomayko * kid/parser.py: Added omit namespace support. the kid namespace is now omitted as well. 2005-01-19 06:25 rtomayko * kid/compiler.py: Write python source files as utf-8. 2005-01-19 06:24 rtomayko * pulltree.py: Add end-of-line after DOCTYPE declaration. 2005-01-19 05:59 rtomayko * pulltree.py: Remove print.. 2005-01-19 05:53 rtomayko * test/test_content.kid: Added a quick DOCTYPE test.. 2005-01-19 05:52 rtomayko * kid/parser.py: Added DOCTYPE support.. 2005-01-19 05:52 rtomayko * pulltree.py: Added support for DOCTYPE declarations (kind of. it's really not correct at all but should work for most kid cases. still, i feel dirty.) 2005-01-19 04:19 rtomayko * kid/util.py: Coerce attribute interpolated items to unicode before using. 2005-01-19 04:18 rtomayko * test/test_attribute_interpolation.kid: Added attribute interpolation tests. 2005-01-19 04:11 rtomayko * kid/parser.py: Fixes to accept extended unicode characters in templates. 2005-01-19 04:10 rtomayko * test_kid.py: Make template tests first class (they get dots). 2005-01-19 03:40 rtomayko * test/test_content_structure.kid: Added test for XML() function. 2005-01-19 03:37 rtomayko * makefile: Remove needless comments.. 2005-01-19 03:36 rtomayko * test_kid.py: Use os.path.join instead of platform dependant paths. Added test to check that .pyc files are being generated properly. 2005-01-19 03:35 rtomayko * kid/importer.py: Fix to generate .pyc files (for real this time). Also added KID_OUTPUT_PY environment variable. When set, .py source is generated along with the .pyc file. 2005-01-19 03:34 rtomayko * makefile: Clean more stuff. 2005-01-19 03:34 rtomayko * TODO: [no log message] 2005-01-17 04:14 rtomayko * doc/: index.txt, makefile, style.xsl: Changes for sourceforge project move.. 2005-01-17 04:14 rtomayko * TODO: Added attribute interpolation bug.. 2005-01-14 16:12 rtomayko * HISTORY: Minor change.. 2005-01-14 16:12 rtomayko * TODO: [no log message] 2005-01-12 13:03 rtomayko * setup.py: Move to Alpha 2005-01-12 12:58 rtomayko * setup.py: Better download link 2005-01-12 11:32 rtomayko * ChangeLog: updated ChangeLog 2005-01-12 11:31 rtomayko * TODO, HISTORY: [no log message] 2005-01-12 11:29 rtomayko * doc/tutorial.txt: Updated tutorial for interface changes. 2005-01-12 10:45 rtomayko * ChangeLog: updated ChangeLog 2005-01-12 10:45 rtomayko * kid/__init__.py: release 0.4.1 2005-01-12 10:43 rtomayko * kid/compiler.py: Aplying patch from Ross Burton to fix pyc file genration bug. 2005-01-12 10:42 rtomayko * bin/kid, kid/parser.py: Fixed double-output bug when using kid command. (Ross Burton) 2005-01-11 04:25 rtomayko * ChangeLog: updated ChangeLog 2005-01-11 04:25 rtomayko * kid/__init__.py: release 0.4 2005-01-11 04:22 rtomayko * HISTORY: Updated for 0.4 2005-01-11 04:22 rtomayko * kid/__init__.py: Clean up some rogue doc.. 2005-01-11 04:07 rtomayko * pulltree.py, test_kid.py, kid/__init__.py, kid/parser.py: Renamed the following methods: encode() -> serialize() serialize() -> generate() expand() -> pull() 2005-01-11 03:11 rtomayko * kid/parser.py: Added enumerate function for Python < 2.3 2005-01-11 02:59 rtomayko * ChangeLog: [no log message] 2005-01-11 02:58 rtomayko * test/test_content_structure.kid: Not sure wtf I was doing here. 2005-01-11 02:58 rtomayko * doc/: makefile, style.xsl: Added history to site. 2005-01-11 02:56 rtomayko * kid/parser.py: Added parse() and parse_file() methods. Generated Template class subclass BaseTemplate. You can set this in a template to use a different base class. 2005-01-11 02:55 rtomayko * kid/: compiler.py, importer.py: Simplified modules. Got rid of some cruft that was left around from code lifted from Quixote. 2005-01-11 02:53 rtomayko * kid/__init__.py: Major interface changes: import_template() - like using import statement but with ihooks crap. load_template() - load a template module from file instead of importing. Template() - function calls load_template and returns the template's main class. BaseTemplate - class that acts as the base-class for all generated templates. Automatically call enable_import() if KID_IMPORT environment variable is set. 2005-01-11 02:50 rtomayko * test_kid.py: Added exec() hack tests. Added tests for kid.load_template and kid.import_template Added test for outputting short-form elements. 2005-01-11 02:49 rtomayko * bin/kid: Updated for 0.4 interface changes. 2005-01-11 02:12 rtomayko * TODO: [no log message] 2004-12-30 19:20 rtomayko * bin/kid: Fixed SyntaxError: __name__ referenced before assignment. Thanks Ross Burton 2004-12-29 14:26 rtomayko * test/: templates.kid, test_def.kid: kid:def test cases.. 2004-12-29 07:19 rtomayko * kid/util.py: Minor speed up.. 2004-12-29 07:18 rtomayko * doc/kid-spec.txt, kid/parser.py, HISTORY: First crack at name-based templating. The kid:def attribute can be used to create a named template. Markup in an kid:def isn't executed as part of the normal template but can be called in kid:content or imported into other templates. woot! 2004-12-28 17:51 rtomayko * test_kid.py, doc/kid-spec.txt, kid/parser.py: Handle escaping attribute value templates. Use double curly braces. Also add unit tests for interpolation functions. 2004-12-28 17:49 rtomayko * bin/kid: Only process __main__ stuff if this script is called as __main__ 2004-12-27 05:54 rtomayko * HISTORY, ChangeLog: [no log message] 2004-12-27 05:53 rtomayko * test_kid.py, bin/kid, bin/kidc, kid/__init__.py, kid/importer.py, kid/parser.py: Generated templates subclass kid.Template. Various refactoring into class 2004-12-27 05:53 rtomayko * examples/basic/sysinfo.kid: repeat is not for.. 2004-12-24 11:05 rtomayko * test_kid.py, test/context.kid: Tests for kwarg context. 2004-12-24 11:03 rtomayko * kid/: parser.py, __init__.py: expand methods now take keyword args instead of a context dict. Anything passed in the keyword args dict is scoped in locally. 2004-12-24 11:02 rtomayko * kid/compiler.py: compiler.compile is not the same as the compile builtin. this was causing some problems with scoping of local variables. 2004-12-24 11:01 rtomayko * kid/importer.py: Remove unneeded debug statement. 2004-12-22 17:05 rtomayko * setup.py: Oops. missed license stuff in distutils script.. 2004-12-22 17:05 rtomayko * HISTORY: Move things around a bit.. 2004-12-22 07:28 rtomayko * ChangeLog: updated ChangeLog 2004-12-22 07:28 rtomayko * kid/__init__.py: release 0.3 2004-12-22 06:57 rtomayko * kid/parser.py: Changes for pulltree.eat modifications.. 2004-12-22 06:57 rtomayko * doc/: about.txt, index.txt: Documentation updates for license change. 2004-12-22 06:56 rtomayko * pulltree.py: Fixed problem with character data not making it into ElementTree. Removed __iter__ from PullElement. This is causing problems somewhere but I don't have time to track it down atm. expand and eat now assume that the start element event has not arrived. depth argument can be provided to get old-style functionality.. 2004-12-22 06:54 rtomayko * test/test_replace.kid: Added kid:replace test.. 2004-12-22 06:53 rtomayko * makefile: More clean files.. 2004-12-22 06:52 rtomayko * HISTORY, TODO: [no log message] 2004-12-22 06:52 rtomayko * README: sugar.. 2004-12-18 00:19 rtomayko * HISTORY: Added notes about kid:replace 2004-12-18 00:16 rtomayko * kid/parser.py: Support for kid:replace 2004-12-18 00:16 rtomayko * pulltree.py: Fixed bad variable name in XML() function.. 2004-12-18 00:15 rtomayko * TODO: [no log message] 2004-12-18 00:05 rtomayko * HISTORY, doc/kid-spec.txt, doc/tutorial.txt: Documentation updates for kid:repeat to kid:for name change. 2004-12-18 00:00 rtomayko * kid/parser.py, test/test_repeat.kid: kid:repeat changed to to kid:for 2004-12-17 23:37 rtomayko * kid/parser.py: Add from __future__ import generators to generated code. Needed for Python lt 2.3 compatibility. 2004-12-17 23:35 rtomayko * test_kid.py: __file__ doesn't work on __main__ modules in Python lt 2.3 2004-12-17 23:32 rtomayko * README, TODO, kid/__init__.py, kid/compiler.py, kid/parser.py: More from __future__ import generators for Python lt 2.3 2004-12-17 23:31 rtomayko * test/include-me.xml: file to include in tests. 2004-12-17 23:30 rtomayko * pulltree.py: Add from __future__ import generators for Python 2.2 2004-12-17 22:53 rtomayko * COPYING: Sucks.. 2004-12-17 22:53 rtomayko * HISTORY: Added HISTORY as ChangeLog is too verbose and crazy to read sanely 2004-12-17 22:43 rtomayko * makefile, pulltree.py, test_kid.py, bin/kid, bin/kidc, kid/__init__.py, kid/compiler.py, kid/importer.py, kid/parser.py, kid/util.py: Standardizing on four-space indent. Prelimenary license changes. 2004-12-16 22:21 rtomayko * ChangeLog, TODO: [no log message] 2004-12-15 11:02 rtomayko * TODO: [no log message] 2004-12-14 06:09 rtomayko * test/test_content_structure.kid: Test for bringing in external content. 2004-12-14 05:37 rtomayko * makefile: Add examples to clean files.. 2004-12-14 05:36 rtomayko * kid/: parser.py, util.py: First crack at support for structured content. 2004-12-14 05:35 rtomayko * pulltree.py: Add pull function for turning Elements into streams. Don't require an element be passed to expand or eat. 2004-12-14 05:32 rtomayko * TODO: [no log message] 2004-12-14 02:31 rtomayko * kid/parser.py: Fixed generated code referencing kid.pulltree instead of pulltree. 2004-12-14 02:26 rtomayko * setup.py: Fix bad package name in py_modules 2004-12-14 02:25 rtomayko * pulltree.py, setup.py, kid/__init__.py, kid/parser.py, kid/pulltree.py: Move pulltree.py to top-level module 2004-12-14 02:23 rtomayko * TODO: Updated for recent changes.. 2004-12-14 01:56 rtomayko * test_kid.py, test/test_content.kid, test/test_repeat.kid: Actual check that output matches expected output in tests. 2004-12-14 01:55 rtomayko * kid/: __init__.py, parser.py, pulltree.py, util.py: Rewrite internals to use ElementTree/pulltree so we can do something sane wrt templating. 2004-12-02 06:50 rtomayko * setup.py: Missed a comma in setup.py. Was causing trove classifiers to collapse. 2004-12-02 06:47 rtomayko * ChangeLog: updated ChangeLog 2004-12-02 06:47 rtomayko * bin/kid, kid/__init__.py: Ran tests, found bugs, fixed bugs, releasing for real this time. 2004-12-02 06:40 rtomayko * setup.py: oops. didn't mean to ucase the package name.. 2004-12-02 06:39 rtomayko * ChangeLog: updated ChangeLog 2004-12-02 06:39 rtomayko * kid/__init__.py: release 0.2 2004-12-02 06:39 rtomayko * makefile: don't verify the tag hasn't been used. 2004-12-02 06:38 rtomayko * setup.py: Should be good for PyPI registration.. I think. 2004-12-02 06:19 rtomayko * README: Added some information to the README.. 2004-12-02 06:17 rtomayko * ChangeLog: updated ChangeLog 2004-12-02 06:16 rtomayko * MANIFEST.in: Really add ChangeLog this time.. 2004-12-02 06:15 rtomayko * ChangeLog, MANIFEST.in, kid/__init__.py: Added examples and ChangeLog 2004-12-02 06:10 rtomayko * doc/: style.css, style.xsl: Added the sourceforge.net logo.. 2004-12-02 06:10 rtomayko * doc/: kid-spec.txt, tutorial.txt: Updated the spec and stubbed some content into the tutorial (which isn't really a tutorial..) 2004-12-02 03:21 rtomayko * examples/basic/: README, sysinfo.kid: Added basic example illustrating various kid usage from commandline and from within python. 2004-12-02 02:57 rtomayko * examples/cgi/: README, kid_handler.cgi, sysinfo.kid: Added CGI demo. It's no more than a proof-of-concept to be honest. 2004-12-02 02:46 rtomayko * kid/util.py: the expand function of template modules can now take a ContentHandler, a file like object, or None (in which case a buffer is created and the result is returned as a string) 2004-12-02 02:44 rtomayko * kid/parser.py: Change name of output ContentHandler from output to _out to try to reduce the chance of name collision. 2004-12-02 02:43 rtomayko * kid/__init__.py: Allow SAX content handlers to be passed to expand_template 2004-12-02 02:42 rtomayko * bin/kidc: Minor fixup to error handling and usage. 2004-12-02 02:41 rtomayko * work.sh: bash script to source when testing out of working directory. 2004-12-02 02:40 rtomayko * makefile: make doc before releasing so that the html files go out in the distribution. 2004-12-02 02:37 rtomayko * bin/kid: Run templates from the command line without compiling. 2004-12-01 09:18 rtomayko * TODO: [no log message] 2004-12-01 09:17 rtomayko * setup.py: Added download link 2004-12-01 09:15 rtomayko * setup.py: Better trove classifiers. Removed doc files 2004-12-01 09:05 rtomayko * MANIFEST.in: Added doc files and kidc to MANIFEST 2004-12-01 08:59 rtomayko * makefile: Don't clean release by default. Added fullclean target for cleaning everything. 2004-11-30 06:40 rtomayko * doc/kid-spec.txt: Fixed bug in language spec. 2004-11-30 06:40 rtomayko * doc/index.txt: Changed download location.. 2004-11-30 06:24 rtomayko * ChangeLog: updated ChangeLog 2004-11-30 06:23 rtomayko * ChangeLog: release 0.1.1 2004-11-30 06:23 rtomayko * makefile: Don't check ChangeLog in pre-release-test.. 2004-11-30 06:22 rtomayko * kid/__init__.py: Version update.. 2004-11-30 06:21 rtomayko * doc/index.txt: Add download location and note about being early.. 2004-11-30 06:02 rtomayko * doc/: about.txt, index.txt, makefile, style.css, style.xsl: Tidy up documentation a bit 2004-11-29 09:10 rtomayko * makefile, doc/makefile: I think make publish is finally working for pushing out site content. 2004-11-29 09:10 rtomayko * TODO: [no log message] 2004-11-29 08:03 rtomayko * doc/: index.txt, kid-spec.txt, makefile, style.css, style.xsl, tutorial.txt: Some work on documentation.. 2004-11-28 22:29 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 22:29 rtomayko * kid/__init__.py: release 0.1 2004-11-28 22:28 rtomayko * kid/: compiler.py, parser.py: Fixed some fairly obvious and stupid problems due to splitting compiler and parser up into two modules. 2004-11-28 22:27 rtomayko * makefile: test target should be working now. 2004-11-28 22:18 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 22:18 rtomayko * kid/__init__.py: release 0.0.1 2004-11-28 22:17 rtomayko * makefile: makefile is halfway sane now. 2004-11-28 22:09 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 22:09 rtomayko * makefile: release 0.0 2004-11-28 22:01 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 22:01 rtomayko * makefile: release 0.0 2004-11-28 21:59 rtomayko * .cvsignore: Ignore release and export directories 2004-11-28 21:57 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 21:57 rtomayko * makefile: release 0.0 2004-11-28 21:54 rtomayko * ChangeLog: updated ChangeLog 2004-11-28 21:54 rtomayko * ChangeLog, makefile, kid/__init__.py: release 0.0 2004-11-28 21:51 rtomayko * ChangeLog: [no log message] 2004-11-28 21:46 rtomayko * COPYING, MANIFEST.in, README, TODO, makefile, setup.py, test_kid.py, bin/kidc, doc/index.txt, doc/kid-spec.txt, doc/tutorial.txt, kid/__init__.py, kid/compiler.py, kid/importer.py, kid/parser.py, kid/util.py, test/__init__.py, test/basic-test.html.kid, test/template-test.html.kid, test/test_content.kid, test/test_if.kid, test/test_kid_pi.kid, test/test_omit.kid, test/test_repeat.kid: Initial import into sourceforge repository. Old history can be found at the following: http://naeblis.cx/cvs/kid/ kid-0.9.6/HISTORY0000644000175000017500000003011410646650135013272 0ustar tstanektstanekKid Version History =================== 2005-03-14 0.6.3 ----------------- * Fixed issue introduced with py:extends that broke kid on Python 2.2. See: * Fixed various issues with HTML output methods including incorrect DOCTYPEs, attribute casing, etc. See: * Applied Tim Gerla's patch to add a ``--strip-dest-dir`` option that acts like the argument with same name in Python proper. This is mainly useful for package maintainers. See: 2005-03-09 0.6.2 ----------------- * Fixed bug with short-form elements (
) not being output properly. Long form was always being used. * Added support for custom serialization routines including XHTML and HTML. See: * Fixed bug where ElementTree objects passed into kid were being modified (children removed) during template execution. See: * This file is now included the source distribution again. See: * Fixed various unicode related issues (mainly with the XML() function). See: 2005-03-06 0.6.1 ----------------- * Fixed bug (again) with comments and PIs not making it through to output. * Fixed bug with text content being dropped when passed to the XML() function. * No longer escaping ( > | ' | " ) in output (except in attributes where quotes are escaped. * Fixed bug with doc not shipping with css files. * Namespace prefix generation and handling should be working well at this point. 2005-03-05 0.6 --------------- For detailed information see: * Namespace URI changed from "http://naeblis.cx/ns/kid#" to "http://purl.org/kid/ns#". * py:omit is now py:strip. * Expression substitution changed from {} to ${} and $name. * Python interface is more like Cheetah. * Support for cElementTree. * Template inheritence (py:extends). * Match Templates (py:match) * Comment wart is no longer. * ElementTree objects can be referenced directly in content constructs. * Major updates to documentation. 2005-02-14 0.5.2 ----------------- * Fixed bug with namespace prefix being stripped in xml:* attributes (such as xml:lang). This could sometimes result in ill-formed XML. * Examples have been brought up to date. * Added functionality to kid command line script. (Christoph Zwerschke) 2005-02-11 0.5.1 ----------------- * Fixed problem with brace interpolation sometimes not working in text content due to pulltree reporting text in multiple hunks. * Should be able to build RPMs with `python setup.py bdist_rpm` now. * Comments and Processing Instructions should now be passed through properly. These were previously being omitted from output. There may be an argument in the future that turns comment output off. * Template modules used to import various names from ElementTree and pulltree into the module namespace. This can cause problems if a template imports other stuff with the same name. The Element and ElementTree imports have been changed to _Element and _ElementTree to avoid clashing. (Christoph Zwerschke) * Add support for specifying a character encoding when loading kid templates. (Christoph Zwerschke) * Fixed bug in kid:attrs where python reserved words could not be used as keyword arguments. (Christoph Zwerschke) 2005-01-26 0.5 --------------- * Changed `` processing instruction name to ``. Not sure why I didn't think of this in the beginning. Note that `` is still supported but deprecated. I may leave it in forever just in case there's ever a clash with another `` PI. * Changed stuff everywhere to use `py:` as namespace prefix instead of `kid:`. * Applied `py:attrs` patch from Christoph Zwerschke. More detail on this in the following thread: The concept is identical to `tal:attributes` with minor syntax differences. For example: Will result in the following output: * Allow brace interpolation in normal text content. This isn't set in stone but there's been enough requests for it and I've found myself wanting something less verbose than `kid:content`. the current time is: {time.strftime('%C %c')} Yields something like this: the current time is: 20 Wed Jan 26 01:49:56 2005 This can serve as a terse alternative for clumsy situations like the following: the curent time is: 2005-01-18 0.4.2 ----------------- * Fixed `.pyc` file generation on import for real this time (thanks: Christoph Zwerschke). * Fixed problem with using non-string values in attribute value templates "{}". For instance, `` would fail with a type error. (thanks: Dagur Páll Ammendrup) * Added support for DOCTYPE declarations. They were being chopped previously making it impossible to generate validating.. well.. anything.. (thanks: Dagur Páll Ammendrup) * Added support for omitting namespace declarations used in the source template. A template can set the `omit_namespaces` variable to a list of namespace URIs that should be omitted. The following example results in the `xmlns:kid` and `xmlns:x` declarations being dropped: ... The `omit_namespaces` variable is set to `['http://purl.org/kid/ns#']` by default, hence the weird appending of the additional namespaces to exclude to the list. (thanks: Christoph Zwerschke) * Setting the environment variable KID\_OUTPUT\_PY to something True will dump out `.py` source files along side of `.pyc` files when templates are imported. * Make `test_kid.py` portable for upcoming Windows testing. This mostly consisted of getting rid of hard coded path separators. * Added a few unicode tests to make sure there isn't any funny business with unicode in templates. 2005-01-12 0.4.1 ----------------- * Fixed bad output when running templates with the `kid` command. There was a print statment in there that shouldn't have been and the template was being executed twice. (thanks: Ross Burton) * Fixed compiler not outputting `.pyc` files correctly. (thanks: Ross Burton) * Updated tutorial documentation. 2005-01-10 0.4 --------------- * Initial crack at reusable templates (damn if that word doesn't mean five things in this system. are you guys confused yet?). See the kid language spec on the `kid:def` attribute. It provides the equivalent of a Python function. * Templates now extend the base class: `kid.BaseTemplate`. When you import a kid template module, a class named `Template` is available from the module. You can pass keyword arguments to the Template class constructor and have them be accessible to all template expansion performed on the instance. The template code accesses these variables by using `this`. * The following methods are available on Template instances and template modules: * `serialize(encoding='utf-8', **kw)` - Execute the template and return a string. * `generate(encoding='utf-8', **kw)` - Like `serialize()` but returns a generator that continuously yields a string until the template is finished. * `write(file, encoding='utf-8', **kw)` - Execute the template and write output to the specified filename or file like object. * `pull(**kw)` - Generator that yields pulltree events for each infoset item generated by the template. * Template methods now take keyword args. Any arguments passed are available by name in the template as local variables. * Added support for escaping curly braces in attributes. Works like XSLT: '{{' and '}}'. Note also that you don't _need_ to escape braces unless you have both ends: {example}. If you just have a single open or a single close brace, you shouldn't need to escape anything. It won't hurt anything if you do however. 2004-12-21 0.3 --------------- A couple quirks have been straightened out since 0.2 but the primary reason I'm putting out a new release now is because of a license change. Kid is now licensed under an MIT style license. All versions prior to 0.3 are licensed under the GPL. This is due to a couple of reasons: * I stole a bit of code from Quixote, which is licensed under a GPL incompatible license. * I plan on using/distributing various GPL and non-GPL licensed libraries with systems that use Kid. Quite a bit else has shifted underneath the hood during this release. I tried to implement XSLT-like templating but found that it was going to be extremely messy to implement on top of SAX (if possible at all). That combined with an absolute refusal on the part of the stingy author to bring in `xml.dom` in any way led to [effbot's ElementTree][et], which is completely in line with Kid's goals around simplicity. This opened a few doors for new features in this release but mostly just took up a lot of time. Here's the full list of major modifications since 0.2: * Rewrite parser to be [ElementTree][et] based instead of SAX based. This is in preparation for templating. Note that this means Kid now requires ElementTree where before it used only modules from the standard library. * `document()` function for bringing in external XML content from a file or URL. Acts *kind of* like the XSLT's `document` XPath extension function sans relative URI resolution and the ability to resolve multiple resources. * `XML()` function for bringing in XML content that is a string. Basic usage is to wrap XML() around a well-formed XML string returned from a python module function call. * New pulltree module provides a streaming pull interface to ElementTree. [Check it out!][pulltree] `pulltree.py` is not dependent on Kid at all. I may split it out into a separate project if there's interest. * Support for `kid:replace`. (I thought I added this in 0.1) * Tests are now actually validating that output is matching expected output. * Tests pass on Python 2.2. * `kid:repeat` is now `kid:for`. Templates that used `kid:repeat` will break under this version. * Starting with 0.3, Kid will be licensed under the "MIT License" as specified [here](http://www.opensource.org/licenses/mit-license.php). This is due to license compatibility issues with the ElementTree package, compatibility issues with a bit of code taken from Quixote in `kid/importer.py`, and to ensure we have the ability to distribute Kid with applications written atop Quixote. Note: the GPL isn't viral - everything else is viral :( [pulltree]: http://cvs.sourceforge.net/viewcvs.py/splice/kid/pulltree.py?view=markup "pulltree.py" [et]: http://effbot.org/zone/element-index.htm "ElementTree Overview" 2004-12-01 0.2 --------------- Initial public release. * Added documentation. * Makefile is halfway useful. * Broke up kid.py into three separate modules and placed in a kid package. * distutils install. * kidc command for compiling templates. * kid command for running templates from the command line. * Added basic and cgi examples under `examples` directory. 2004-11-29 0.1 --------------- Barely useful. No documentation. * Supports the following attributes: kid:content, kid:if, kid:repeat, kid:omit. * `` processing instruction for embedding code blocks. kid-0.9.6/MANIFEST.in0000644000175000017500000000032210646650135013742 0ustar tstanektstanekinclude README COPYING HISTORY include run_tests.py recursive-include test *.kid *.py *.xml include misc/upgrade-0.6.py include ez_setup.py recursive-include doc * recursive-include examples *.cgi *.kid README kid-0.9.6/README0000644000175000017500000000366410646650131013074 0ustar tstanektstanekKid === About ----- Kid is a simple Python based template language for XML vocabularies. It was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out. Copyright and License --------------------- Kid is Copyright (c) 2004-2005, Ryan Tomayko and is licensed under a standard MIT license. For more information on copying see the file ``COPYING`` in source distribution. System Requirements -------------------- Kid has been tested with Python 2.3, 2.4 and 2.5 on Linux, Windows XP and Mac OS X. Install ------- Extract the source tarball, change into the newly created directory, and execute `setup.py`. Something like the following should do:: $ gzip -dc kid-0.x.tar.gz | tar xvf - $ cd kid-0.x $ python setup.py install Without any extra arguments to ``setup.py``, this will install the following items: 1. Python libraries to your site-packages directory. 2. The ``kidc`` and ``kid`` commands to your "scripts" directory. This is usually ``/usr/local/bin`` under Linux. Use ``python setup.py install --help`` for information on tweaking the install. More ---- Documentation specific to this release in both text and HTML formats can be found under the doc directory or on the web at: http://www.kid-templating.org/doc/kid/ More info can be found on the Kid project site, which includes a wiki and bug/enhancement tracker: http://www.kid-templating.org To ask questions, discuss Kid usage, join the mailing list: http://lists.sourceforge.net/lists/listinfo/kid-template-discuss Read my weblog: http://naeblis.cx/rtomayko/ Authors/Contributors -------------------- * Ryan Tomayko (Original author of the Kid project) * David Stanek (Coding, current project maintainer) * Christoph Zwerschke (Coding) * Ross Burton (Debian package maintainer) kid-0.9.6/RELEASING0000644000175000017500000001077210646650135013452 0ustar tstanektstanek===================== KID RELEASE CHECKLIST ===================== These notes describe the general procedure for releasing new version of Kid. Pre-requisites -------------- Make sure the following packages are installed on your system: * Python 2.3, Python 2.4 and Python 2.5 * elementtree * setuptools * docutils * buildutils * pudge * py.test Most of the utility packages can be installed using ``easy_install``. For ``buildutils`` and ``pudge``, it's recommended that you grab the latest revisions from subversion: $ easy_install http://lesscode.org/svn/pudge/trunk $ easy_install http://lesscode.org/svn/buildutils/trunk Since some of the tests require py.test, this should be installed as well (see http://codespeak.net/py/current/doc/getting-started.html). Release Procedure ----------------- 1. Run Tests Check that all tests are passing: $ make test The tests are run for all Python versions 2.3, 2.4 and 2.5. I generally run tests on the following systems when possible: * Debian * SuSE Linux * Fedora Core 4 * FreeBSD * Mac OS X / 10.4+ * Windows XP (run the tests manually) If possible, run the TurboGears nosetests with the new Kid version to make sure nothing ha been broken. 2. Update the ez_setup.py script with the latest version from http://peak.telecommunity.com/dist/ez_setup.py 3. Bump version number in ``kid/release.py`` and ``doc/index.txt``, and ``kid.egg-info/PKG_INFO``. Also change download URL and possibly other meta data in ``kid.egg-info/PKG_INFO``. 4. Update build notes Update ``doc/notes.txt`` with release notes. 5. Commit / Tag After committing release related changes, make a note of the current changeset revision and then tag it: $ svn cp -m 'tagging [changeset] for VERSION release' \ svn://kid-templating.org/trunk \ svn://kid-templating.org/tags/VERSION 6. Build Distributables Make sure you have recent versions of setuptools and buildutils installed for Python 2.3, 2.4 and 2.5. $ pbu -i2.3,2.4,2.5 sdist bdist_egg You should now have ``dist/kid-VERSION.tar.gz``, ``dist/kid-VERSION-py2.3.egg``, ``dist/kid-VERSION-py2.4.egg`` and ``dist/kid-VERSION-py2.5.egg``. This is generally all I release. I like to scan the file contents just to make sure nothing funny made its way into the dist process: $ tar tzf dist/kid-VERSION.tar.gz | less $ ls -1 dist/kid-0.9-*.egg | xargs -n1 unzip -l | less Now it is time to push to the CheeseShop: $ pbu -i2.3,2.4,2.5 sdist bdist_egg upload 7. Generate Checksums This is important for package maintainers. Most package repositories hold the policy that upstream distributables MUST include checksums and many require checksums to be signed. $ pbu checksum --sign (Leave off the --sign option if you're not setup with GPG.) This generates a `dist/kid-VERSION.sha` file and a `dist/kid-VERSION.sha.asc` file if the checksums are signed. 8. Publish Distributables Copy the entire dist directory to kid-templating.org: $ scp -rp dist kid-templating.org:/srv/kid-templating.org/www/htdocs/dist/VERSION Any release (major, minor, build, nightly) should have its own directory. Don't copy new distributables into existing dist directories. i.e., VERSION may be 0.9, 0.9a1, 0.9.5, 20060101, etc... Check that the files made it up properly and are accessible via HTTP: $ links http://www.kid-templating.org/dist/VERSION/ or perhaps: $ curl http://www.kid-templating.org/dist/VERSION/kid-VERSION.sha NOTE: This process was automated through ``pbu`` at one point but I can't seem to get it working properly. I'll get it figured out and update this doc accordingly. 9. Build documentation Build the docs using buildutils/pudge: $ pbu pudge Files generated by pudge are placed under the ``doc/html`` directory. 10. Publish Docs Transfer the files generated under ``doc/html`` to kid-templating.org: $ scp -r doc/*.txt doc/html/* kid-templating.org:/srv/kid-templating.org/www/htdocs/ Check and update the wiki pages at http://www.kid-templating.org/trac/wiki/, particularly make sure that this page is up to date: http://www.kid-templating.org/trac/wiki/GettingStarted kid-0.9.6/ez_setup.py0000644000175000017500000002106410646650131014416 0ustar tstanektstanek#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c6" DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', } import sys, os def _validate_md5(egg_name, data): if egg_name in md5_data: from md5 import md5 digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ try: import setuptools if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) except ImportError: egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg import pkg_resources try: pkg_resources.require("setuptools>="+version) except pkg_resources.VersionConflict, e: # XXX could we install in a subprocess here? print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first.\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': # tell the user to uninstall obsolete version use_setuptools(version) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re from md5 import md5 for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) kid-0.9.6/kid-env.sh0000755000175000017500000000450610646650135014110 0ustar tstanektstanek#!/bin/bash # kid-evn.sh is a very useful shell script to setup a testing environment # for Kid development and testing. # $Author: dstanek $ # $Rev: 435 $ # $Date: 2006-11-26 04:50:31 -0500 (Sun, 26 Nov 2006) $" KIDHOME=$HOME/src/kid PY23SRC=$KIDHOME/python/Python-2.3.5.tar.bz2 PY23DIST=http://www.python.org/ftp/python/2.3.6/Python-2.3.6.tar.bz2 PY24SRC=$KIDHOME/python/Python-2.4.3.tar.bz2 PY24DIST=http://www.python.org/ftp/python/2.4.4/Python-2.4.4.tar.bz2 PY25SRC=$KIDHOME/python/Python-2.5.tar.bz2 PY25DIST=http://www.python.org/ftp/python/2.5/Python-2.5.tar.bz2 PATH=$KIDHOME/bin:${PATH} EZSETUP=$KIDHOME/bin/ez_setup.py EZSETUPDIST=http://peak.telecommunity.com/dist/ez_setup.py function install_python { DIST_PATH=`dirname ${1}` DIST_FILE=`basename ${1}` VERSION=`echo ${1} | sed -s 's/.*Python-\(.\..\).*/\1/'` ( cd $DIST_PATH cd `tar vxjf $DIST_FILE | tail -n 1 | sed -s 's/\(\.*\)\/.*/\1/'` ./configure --prefix=$KIDHOME make make install ) python$VERSION $EZSETUP easy_install-$VERSION setuptools easy_install-$VERSION docutils easy_install-$VERSION elementtree easy_install-$VERSION celementtree } echo "Setting up ${KIDHOME}" [ ! -e $KIDHOME ] && mkdir $KIDHOME [ ! -e $KIDHOME/python ] && mkdir $KIDHOME/python [ ! -e $KIDHOME/bin ] && mkdir $KIDHOME/bin [ ! -e $EZSETUP ] && wget -O $EZSETUP $EZSETUPDIST #echo "Installing Python2.3 in ${KIDHOME}" #[ ! -e $PY23SRC ] && wget -O $PY23SRC $PY23DIST #install_python $PY23SRC #echo "Installing Python2.4 in ${KIDHOME}" #[ ! -e $PY24SRC ] && wget -O $PY24SRC $PY24DIST #install_python $PY24SRC echo "Installing Python2.5 in ${KIDHOME}" [ ! -e $PY25SRC ] && wget -O $PY25SRC $PY25DIST install_python $PY25SRC echo "Setting up the release environment" easy_install-2.5 http://lesscode.org/svn/pudge/trunk easy_install-2.5 http://lesscode.org/svn/buildutils/trunk #install_python $PY23 #python2.3 ${EZSETUP} #easy_install-2.3 setuptools #easy_install-2.3 docutils ##easy_install-2.3 kid #install_python $PY25 #python2.5 ${EZSETUP} #easy_install-2.5 setuptools #easy_install-2.5 docutils ##easy_install-2.5 kid #install_python $PY24 #python2.4 ${EZSETUP} #easy_install-2.4 setuptools #easy_install-2.4 docutils ##easy_install-2.4 kid #easy_install-2.4 http://lesscode.org/svn/pudge/trunk #easy_install-2.4 http://lesscode.org/svn/buildutils/trunk kid-0.9.6/makefile0000644000175000017500000000621110646650135013707 0ustar tstanektstanekPACKAGE = kid PYTHON = python2.4 PY_MODULE = $(PACKAGE) SVN_ROOT = svn://www.kid-templating.org/ DIST_DEST = kid-templating.org:/srv/kid-templating.org/www/htdocs/dist/$(PACKAGE)/ CLEANFILES = MANIFEST build dist export daily release ChangeLog.bak \ *.pyc kid/*.pyc bin/*.pyc \ test/*.pyc test/*.out test/*test*.py \ test/templates.py test/serialization.py test/context.py \ .*.html doc/*.html doc/.*.html \ examples/*/*.html examples/basic/*.py RM = /bin/rm -rf # pudge documentation utility PUDGE = KID_OUTPUT_PY=1 $(PYTHON) ../pudge/bin/pudge # browser open support BROWSER = open VERSION = $(shell $(PYTHON) -c 'import $(PY_MODULE); print $(PY_MODULE).__version__') DATE = $(shell $(PYTHON) -c 'import $(PY_MODULE); print $(PY_MODULE).__date__[7:17]') SVN_TAG = $(SVN_ROOT)/tags/release-$(VERSION) SVN_BRANCH = $(shell svn info | grep '^URL:' | cut -f2 -d' ') PYTHON23 = $(shell /usr/bin/which python2.3 2>/dev/null | egrep -v '^no ') PYTHON24 = $(shell /usr/bin/which python2.4 2>/dev/null | egrep -v '^no ') PYTHON25 = $(shell /usr/bin/which python2.5 2>/dev/null | egrep -v '^no ') CVS2CL = $(shell /usr/bin/which cvs2cl 2>/dev/null | egrep -v '^no ') TESTPYTHONS = $(PYTHON23) $(PYTHON24) $(PYTHON25) default: @echo TARGETS: ChangeLog daily release clean test doc ChangeLog: FORCE $(CVS2CL) -S --utc dist: FORCE scp -p release/$(PACKAGE)-* $(DIST_DEST) release: FORCE pre-release-test svn copy "$(SVN_BRANCH)" "$(SVN_TAG)" -m "Release $(VERSION) Tag" $(RM) export mkdir export -mkdir release cd export; svn export $(SVN_TAG) $(PACKAGE) cd export/$(PACKAGE); $(MAKE) doc cd export/$(PACKAGE); \ $(PYTHON) setup.py sdist --force-manifest ; \ $(PYTHON) setup.py bdist_rpm ; \ $(PYTHON) setup.py bdist_wininst mv export/$(PACKAGE)/dist/* release/ pre-release-test: FORCE @echo "version = $(VERSION), date = $(DATE), tag = $(SVN_TAG)" #test $(DATE) = `date +'%Y-%m-%d'` # verify release date is set to today ! svn status | egrep '^M ' | egrep -v -e '__init__.py' -e 'ChangeLog' -e 'makefile' daily: FORCE doc $(RM) export mkdir export -mkdir release cd export; svn export $(SVN_BRANCH) $(PACKAGE) NOW_DATE=`date +'%Y\\/%m\\/%d'`; \ NOW_VERSION=`date +'%Y%m%d'`; \ echo $$NOW_DATE $$NOW_VERSION; \ OLD=export/$(PACKAGE)/$(PY_MODULE)/__init__.py.old; \ NEW=export/$(PACKAGE)/$(PY_MODULE)/__init__.py; \ mv $$NEW $$OLD; \ sed -e "s/__version__.*/__version__ = '$$NOW_VERSION'/" \ -e "s/__date__.*/__date__ = '$$NOW_DATE'/" < $$OLD > $$NEW; cd export/$(PACKAGE); $(MAKE) doc cd export/$(PACKAGE); \ $(PYTHON) setup.py sdist --force-manifest ; \ $(PYTHON) setup.py bdist_rpm ; \ $(PYTHON) setup.py bdist_wininst mv export/$(PACKAGE)/dist/* release/ clean: FORCE cd doc ; $(MAKE) clean $(RM) $(CLEANFILES) fullclean: FORCE clean $(RM) release test: FORCE @for PYTHONBIN in $(TESTPYTHONS); do \ echo "Testing with $$PYTHONBIN"; \ $$PYTHONBIN run_tests.py; \ echo ""; \ done doc: FORCE cd doc ; $(MAKE) all pudge: FORCE -mkdir -p build/doc $(PUDGE) --dest=build/doc $(PACKAGE) -$(BROWSER) build/doc/index.html publish: FORCE cd doc ; $(MAKE) publish FORCE: kid-0.9.6/run_tests.py0000755000175000017500000000237610646650135014622 0ustar tstanektstanek#!/usr/bin/env python """Runs the suite of Kid tests. For best results, run with py.test as follows: py.test -xl Or run with nose using the following command: nosetests -xd py.test and nose provide nicer tracebacks and inspect variables when assertions fail. You can also run this test suite directly by: python run_tests.py -x You can omit the -x option in all of the above commands if you do not want the testing to stop after the first failed test. (In order to run the tests, you need to install ElementTree in Python versions < 2.5.) """ import sys from os.path import dirname, abspath, join as joinpath, exists if __name__ == '__main__': __file__ = sys.argv[0] base_dir = abspath(dirname(__file__)) if not base_dir in sys.path: sys.path.insert(1, base_dir) test_dir = joinpath(base_dir, 'test') assert exists(test_dir), "Test template directory missing." assert not exists(joinpath(base_dir, 'build')) \ and not exists(joinpath(base_dir, 'dist')), \ "Please remove build and dist directories before testing." import kid.test kid.test.template_package = 'test.' kid.test.template_dir = test_dir kid.test.output_dir = test_dir def run_suite(args): kid.test.run_suite(args) if __name__ == '__main__': run_suite(sys.argv[1:]) kid-0.9.6/setup.cfg0000644000175000017500000000107010646655235014034 0ustar tstanektstanek[pudge] syndication_url = http://planet.kid-templating.org/rss20.xml license = gnu title = "Kid Template" dest = doc/html docs = doc/guide.txt doc/index.txt doc/language.txt doc/notes.txt modules = kid theme = lesscode.org mailing_list_url = http://lists.sourceforge.net/lists/listinfo/kid-template-discuss blog_url = http://planet.kid-templating.org/ organization = kid-templating.org organization_url = http://www.kid-templating.org/ trac_url = http://www.kid-templating.org/trac/ [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [publish] make-dirs = 1 kid-0.9.6/setup.py0000755000175000017500000000263610646650131013727 0ustar tstanektstanek#!/usr/bin/env python # bootstrap setuptools if necessary from ez_setup import use_setuptools use_setuptools() import os execfile(os.path.join("kid", "release.py")) from setuptools import setup, find_packages setup( name="kid", version=version, description= "A simple and pythonic XML template language", author=author, author_email=email, license=license, long_description=long_description, keywords = "xml template html web", url = "http://www.kid-templating.org", download_url = "http://www.kid-templating.org/dist/%s/kid-%s.tar.gz" % \ (version, version), entry_points = { 'console_scripts': [ 'kid = kid.run:main', 'kidc = kid.compile:main', ], }, py_modules=[], packages=["kid", 'kid.test'], install_requires=[], classifiers = [ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Text Processing :: Markup :: XML' ]) kid-0.9.6/work.sh0000755000175000017500000000061610646650131013527 0ustar tstanektstanek# (@) bash # source this into your shell to use a working directory. # note: that your working directory (pwd) needs to be the same # directory as this script for this to work properly. function addpath() { m=$(echo "$1" | egrep "(^|:)$2(:|$)") [ -n "$m" ] && echo "$1" || echo "$2:$1" } dn=$(pwd) PYTHONPATH=$(addpath $PYTHONPATH $dn) PATH=$(addpath $PATH "$dn/bin") export PATH PYTHONPATH kid-0.9.6/PKG-INFO0000644000175000017500000000232710646655235013316 0ustar tstanektstanekMetadata-Version: 1.0 Name: kid Version: 0.9.6 Summary: A simple and pythonic XML template language Home-page: http://www.kid-templating.org Author: Ryan Tomayko Author-email: rtomayko@gmail.com License: MIT Download-URL: http://www.kid-templating.org/dist/0.9.6/kid-0.9.6.tar.gz Description: Kid is a simple, Python-based template language for generating and transforming XML vocabularies. Kid was spawned as a result of a kinky love triangle between XSLT, TAL, and PHP. We believe many of the best features of these languages live on in Kid with much of the limitations and complexity stamped out (well, eventually :). Keywords: xml template html web Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Text Processing :: Markup :: XML