Mercurial > genshi > genshi-test
changeset 4:f8612f05af99
Added first stab of an implementation of the !TurboGears [http://www.turbogears.org/docs/plugins/template.html plugin API for template engines], and also a !TurboGears-based example using this plugin. Both written by Matt Good.
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/examples/turbogears/README.txt @@ -0,0 +1,4 @@ +MarkupTest + +This is a TurboGears (http://www.turbogears.org) project. It can be +started by running the start-markuptest.py script. \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/examples/turbogears/dev.cfg @@ -0,0 +1,64 @@ +[global] +# This is where all of your settings go for your development environment +# Settings that are the same for both development and production +# (such as template engine, encodings, etc.) all go in +# markuptest/config/app.cfg + +# DATABASE + +# pick the form for your database +# sqlobject.dburi="postgres://username@hostname/databasename" +# sqlobject.dburi="mysql://username:password@hostname:port/databasename" +# sqlobject.dburi="sqlite:///file_name_and_path" + +# If you have sqlite, here's a simple default to get you started +# in development +sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" + + +# if you are using a database or table type without transactions +# (MySQL default, for example), you should turn off transactions +# by prepending notrans_ on the uri +# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" + +# for Windows users, sqlite URIs look like: +# sqlobject.dburi="sqlite:///drive_letter:/path/to/file" + + +# SERVER + +# Some server parameters that you may want to tweak +# server.socket_port=8080 + +# Enable the debug output at the end on pages. +# log_debug_info_filter.on = False + +server.environment="development" +autoreload.package="markuptest" + +# Set to True if you'd like to abort execution if a controller gets an +# unexpected parameter. False by default +tg.strict_parameters = True + +# LOGGING +# Logging configuration generally follows the style of the standard +# Python logging module configuration. Note that when specifying +# log format messages, you need to use *() for formatting variables. +# Deployment independent log configuration is in markuptest/config/log.cfg +[logging] + +[[loggers]] +[[[markuptest]]] +level='DEBUG' +qualname='markuptest' +handlers=['debug_out'] + +[[[allinfo]]] +level='INFO' +handlers=['debug_out'] + +[[[access]]] +level='INFO' +qualname='turbogears.access' +handlers=['access_out'] +propagate=0
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/config/app.cfg @@ -0,0 +1,44 @@ +[global] +# The settings in this file should not vary depending on the deployment +# environment. dev.cfg and prod.cfg are the locations for +# the different deployment settings. Settings in this file will +# be overridden by settings in those other files. + +# The commented out values below are the defaults + +# VIEW + +# which view (template engine) to use if one is not specified in the +# template name +# tg.defaultview = "kid" +tg.defaultview = "markup" +markup.search_path = ["%(current_dir_uri)s"] +markup.outputformat = "xml" + +# The following kid settings determine the settings used by the kid serializer. + +# One of (html|xml|json) +# kid.outputformat="html" + +# kid.encoding="utf-8" + +# The sitetemplate is used for overall styling of a site that +# includes multiple TurboGears applications +# tg.sitetemplate="<packagename.templates.templatename>" + +# Allow every exposed function to be called as json, +# tg.allow_json = False + +# Set to True if you'd like all of your pages to include MochiKit +# tg.mochikit_all = False + +# Set to True if the scheduler should be started +# tg.scheduler = False + +[/static] +static_filter.on = True +static_filter.dir = "%(top_level_dir)s/static" + +[/favicon.ico] +static_filter.on = True +static_filter.file = "%(top_level_dir)s/static/images/favicon.ico"
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/config/log.cfg @@ -0,0 +1,29 @@ +# LOGGING +# Logging is often deployment specific, but some handlers and +# formatters can be defined here. + +[logging] +[[formatters]] +[[[message_only]]] +format='*(message)s' + +[[[full_content]]] +format='*(asctime)s *(name)s *(levelname)s *(message)s' + +[[handlers]] +[[[debug_out]]] +class='StreamHandler' +level='DEBUG' +args='(sys.stdout,)' +formatter='full_content' + +[[[access_out]]] +class='StreamHandler' +level='INFO' +args='(sys.stdout,)' +formatter='message_only' + +[[[error_out]]] +class='StreamHandler' +level='ERROR' +args='(sys.stdout,)'
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/controllers.py @@ -0,0 +1,17 @@ +import logging + +import cherrypy + +import turbogears +from turbogears import controllers, expose, validate, redirect + +from markuptest import json + +log = logging.getLogger("markuptest.controllers") + +class Root(controllers.RootController): + @expose(template="markuptest.templates.welcome") + def index(self): + import time + log.debug("Happy TurboGears Controller Responding For Duty") + return dict(now=time.ctime())
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/json.py @@ -0,0 +1,13 @@ +# This module provides helper functions for the JSON part of your +# view, if you are providing a JSON-based API for your app. + +# Here's what most rules would look like: +# @jsonify.when("isinstance(obj, YourClass)") +# def jsonify_yourclass(obj): +# return [obj.val1, obj.val2] +# +# The goal is to break your objects down into simple values: +# lists, dicts, numbers and strings + +from turbojson.jsonify import jsonify +
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/release.py @@ -0,0 +1,13 @@ +# Release information about MarkupTest + +version = "1.0" + +# description = "Your plan to rule the world" +# author = "Your Name Here" +# email = "YourEmail@YourDomain" +# copyright = "Vintage 2006 - a good year indeed" + +# if it's open source, you might want to specify these +# url = "http://yourcool.site/" +# download_url = "http://yourcool.site/download" +# license = "MIT"
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..332557bc307647601389c14939be0671c62efcd7 GIT binary patch literal 1081 zc$@(_1jhSENk%w1VGsZi0Ow5rU0q$8Llvf`rg3p`iHV7;tE=$v@Z{v=e0+SkxVY1i zVbjyo_xJa<wzj;CZl9l@FD)+J-QCTjjjXJ!)3l`g{QT+H&GPc{larIe!omUq0>s3` z%*@QbzP_%muFlTRuXR$eu&|(@pvlR}#>U39w6vL-ncLgj_sv?eva+bCsJgnky}iAU zFbC)7=g`p5RFNg6++fty)Q5+M+-+j?^z?2p6YHcgZ*Feo?Dc7BY3=j=*}=5d*4FCk z>e$%WkZD%6mVNm6_)$?&^5)=2M@NQ3Cg0!R!<&WI$-#kvfuvL_*WKs;|Nrdl>}F<W zU|?W#K`zUCEy(zUpiLrIS68xvQ~L0KtY$%`S~AAV)!X3f;_2^~cW1SLV})BtxxUBm z;@k83{l24+&C=ZVqLJCp%W$nEK5Q|VY&!Lhf^bkt<jugQs<QX}|J>Ek`SkLhzMN`o zagv9Jfw4^C=I!{dq?(?k?eOvV@$SCE%$}mDz_6m><mR%rzv=J#-{Rzqjg9Q(;$mfK z^Y-}Y?C$*k|I^pog~2`A-QSOokLc^{jgW+Hadvllfcy9L&cwdJuSos-`tbDjtFO0p zb#|ept&WkH?)CZH*wuoCi}?Hf=HJ}X*y2o0O;c4_wyC4p+ueGDL!^du9X1y8^YdI^ zWBvU4`}+Ct^Y-1};1d%RczAgF`1t4V^M#3z<KyG;@$v2L?M_frU0`IhGA?h2ZaO+T zl9rwI?die6!K0(2QBzmI*0#&b%chcw%1}t}@9*yJ?)&@u%F4>Xz`*|g{`&g*;^N}L z#?NMGZT|oN|Nj2#@%%wTLjL~$`T6<%{r&p;`}Xzq`~Cj#^77Hr)zs3`*VNL(wyegx zwdmZ{ok<+e(bVDL;o;)r_4W1k_V)Mo_07%AQ&Us!?(OO6>Few3%*VrGV`a<B%z<-r z>+9-gXJ=SgSXx?J$iKM${{4J^g{GvV9UL4aBO}Yu&APj}r>CXM&&=!Z@#5p;>gwsi zzrDi2z?Pb!A^sIZa%Ew3Wn>_CX>@2HRA^-&M@dak04x9i000mG5C8xO{s5aaVb<i0 z86g#fn0Yf$pu=TIf&{^44x2<I@f->~md%O-2S^lHv64-i!($A}fp9Pe9y&;49CUHQ z;Fz%>4uYhycVZEqMJMv5!5PGul{9Hmczdy=sTptC(pZr~t<X_bM_SNOBc;U=RZ?9E z0oUaVAapIHDCi2Q&zCMWqEU;orVlzBRIpHKfzHL6DA9}ovGL`{i7_^8v>0<D!WSDr zniz=^rOUZ%@Umriv8YQFBSs9N8<nOqtUi5Q!0KW|DkNw%%=G~h<;xc!x1#{r=c0x& zV->;$iDIKRaU;LNRWRnT0wg0}PMk>e#R#Md8k<DBu;`nt8nR#pExHiRVL$*o*j18l
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bc9c79cc6141a67a21edaffc9a068ebd0899eb46 GIT binary patch literal 4010 zc$@*M4^{AqP)<h;3K|Lk000e1NJLTq006)M002Y?0{{R3;3LZW00004XF*Lt007q5 z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#08mU+Ma8Cw z#Jjb~$jJKo`nj5ib2u0H`1qH4X~&#%rH5>*YDvbIYV`E<X)_hsrE}TY+3e%qs$@W> zcS*)_N8;Vt-{0T4i*l)rclP%7^78WR?CkR9;P$YDnnM-rm~X_Hf?6gCgI!D3*xIvn zQ{CO&=H}+Sp@`Jf)V8Uj(#^}_=IZF^=*z;rmu*C&dQ{-x;HiUM_4)eK$-?jO@apR7 z<mBY{qkG-JvF`5f`10?CI~CW_&C9c*gkn+KzOIE;I)`9P+TP*8i&nFebA%}X)YjPU z@$=c$(Yvv%yMs#N;^K%#A=iRgifvuIyu9Y<>4`B0d{{=xteoB8;=Pe*n1FP(i(`00 zCd0L>(Y~|l?(u6oA$UtP`27CBuA8AxB)zPixrJ$+S~$(6kGzasu$G0tl6vUv@2XQK zf<Yddc2u&Ke3525zqYcTaYMR>Q>0ljtdM-Vqm<d)-psL?&&tP?X;JIu<F})cyMbcz z^!4N9<)us>#KFMX+T796(dp~%*3;2vD+#Qelyox?%EiL-_V~t;T(y5=&(hTV{{OkB zo72X-v!k2Uw4&C#tI^Wbv{xzO<KwuMbg+e7v!9Tzjc&Y{b);`p#h`tyqn+v4&xvMK z!iiAi=I7YUzk5<WxQ=Dos(rA5QG{t*U@jAjXji_TfBF0Uzp0e}|Nqj|)#A#&wV8jh zeog4<>dCvVzK(S3?e5yiz@JVdkvR$b{r=6)&)weN*q>+N;^X!7@z~DD_xk&9Kqikt z9OvrnwqG-EM=`>±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 QYybcN07*qoM6N<$f~epMssI20
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/templates/login.html @@ -0,0 +1,115 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://purl.org/kid/ns#" + xmlns:xi="http://www.w3.org/2001/XInclude"> + +<xi:include href="master.html" /> + +<head> + <meta content="text/html; charset=UTF-8" + http-equiv="content-type" py:replace="''"/> + <title>Login</title> + <style type="text/css"> + #loginBox + { + width: 30%; + margin: auto; + margin-top: 10%; + padding-left: 10%; + padding-right: 10%; + padding-top: 5%; + padding-bottom: 5%; + font-family: verdana; + font-size: 10px; + background-color: #eee; + border: 2px solid #ccc; + } + + #loginBox h1 + { + font-size: 42px; + font-family: "Trebuchet MS"; + margin: 0; + color: #ddd; + } + + #loginBox p + { + position: relative; + top: -1.5em; + padding-left: 4em; + font-size: 12px; + margin: 0; + color: #666; + } + + #loginBox table + { + table-layout: fixed; + border-spacing: 0; + width: 100%; + } + + #loginBox td.label + { + width: 33%; + text-align: right; + } + + #loginBox td.field + { + width: 66%; + } + + #loginBox td.field input + { + width: 100%; + } + + #loginBox td.buttons + { + text-align: right; + } + + </style> +</head> + +<body> + <div id="loginBox"> + <h1>Login</h1> + <p>$message</p> + <form action="$previous_url" method="POST"> + <table> + <tr> + <td class="label"> + <label for="user_name">User Name:</label> + </td> + <td class="field"> + <input type="text" id="user_name" name="user_name"/> + </td> + </tr> + <tr> + <td class="label"> + <label for="password">Password:</label> + </td> + <td class="field"> + <input type="password" id="password" name="password"/> + </td> + </tr> + <tr> + <td colspan="2" class="buttons"> + <input type="submit" name="login" value="Login"/> + </td> + </tr> + </table> + + <input py:if="forward_url" type="hidden" name="forward_url" + value="$forward_url"/> + + <input py:for="name,value in original_parameters.items()" + type="hidden" name="$name" value="$value"/> + </form> + </div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/templates/master.html @@ -0,0 +1,40 @@ +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://purl.org/kid/ns#" + xmlns:xi="http://www.w3.org/2001/XInclude" + py:strip=""> +<xi:include href="sitetemplate.html"><xi:fallback/></xi:include> + +<head py:match="head"> + <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> + <title py:replace="''">Your title goes here</title> + ${select('*/*')} + <style type="text/css"> + #pageLogin + { + font-size: 10px; + font-family: verdana; + text-align: right; + } + </style> +</head> + +<body py:match="body"> + <div py:if="tg.config('identity.on', False) and not logging_in" + id="pageLogin"> + <span py:if="tg.identity.anonymous"> + <a href="/login">Login</a> + </span> + <span py:if="not tg.identity.anonymous"> + Welcome ${tg.identity.user.display_name}. + <a href="/logout">Logout</a> + </span> + </div> + + <div py:if="tg_flash" class="flash" py:content="tg_flash"></div> + + ${select('*')} + + <p align="center"><img src="/static/images/tg_under_the_hood.png" alt="TurboGears under the hood"/></p> +</body> + +</html>
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/templates/welcome.html @@ -0,0 +1,35 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://purl.org/kid/ns#" + xmlns:xi="http://www.w3.org/2001/XInclude"> +<xi:include href="master.html" /> + +<head> + <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> + <title>Welcome to TurboGears</title> +</head> + +<body> + <p>Congratulations, your TurboGears application is running as of <span py:replace="now">now</span>.</p> + + <h2>Are you ready to Gear Up?</h2> + + <p>Take the following steps to dive right in:</p> + + <ol> + <li>Edit your project's model.py to create SQLObjects representing the data you're working with</li> + <li>Edit your dev.cfg file to point to the database you'll be using</li> + <li>Run "<code>tg-admin sql create</code>" to create the tables in the database</li> + <li>Edit controllers.py to add the functionality to your webapp</li> + <li>Change the master.kid template to have the headers and footers for your application.</li> + <li>Change welcome.kid (this template) or create a new one to display your data</li> + <li>Repeat steps 4-6 until done.</li> + <li><b>Profit!</b></li> + </ol> + + <p>If you haven't already, you might check out some of the <a href="http://www.turbogears.org/docs/" >documentation</a>.</p> + + <p>Thanks for using TurboGears! See you on the <a href="http://groups.google.com/group/turbogears" >mailing list</a> and the "turbogears" channel on irc.freenode.org!</p> + +</body> +</html>
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/tests/test_controllers.py @@ -0,0 +1,16 @@ +from turbogears import testutil +from markuptest.controllers import Root +import cherrypy + +cherrypy.root = Root() + +def test_method(): + "the index method should return a string called now" + import types + result = testutil.call(cherrypy.root.index) + assert type(result["now"]) == types.StringType + +def test_indextitle(): + "The mainpage should have the right title" + testutil.createRequest("/") + assert "<TITLE>Welcome to TurboGears</TITLE>" in cherrypy.response.body[0]
new file mode 100644 --- /dev/null +++ b/examples/turbogears/markuptest/tests/test_model.py @@ -0,0 +1,23 @@ +# If your project uses a database, you can set up database tests +# similar to what you see below. Be sure to set the db_uri to +# an appropriate uri for your testing database. sqlite is a good +# choice for testing, because you can use an in-memory database +# which is very fast. + +from turbogears import testutil +# from markuptest.model import YourDataClass, User + +# database.set_db_uri("sqlite:///:memory:") + +# class TestUser(testutil.DBTest): +# def get_model(self): +# return User +# +# def test_creation(self): +# "Object creation should set the name" +# obj = User(user_name = "creosote", +# email_address = "spam@python.not", +# display_name = "Mr Creosote", +# password = "Wafer-thin Mint") +# assert obj.display_name == "Mr Creosote" +
new file mode 100644 --- /dev/null +++ b/examples/turbogears/sample-prod.cfg @@ -0,0 +1,66 @@ +[global] +# This is where all of your settings go for your production environment. +# You'll copy this file over to your production server and provide it +# as a command-line option to your start script. +# Settings that are the same for both development and production +# (such as template engine, encodings, etc.) all go in +# markuptest/config/app.cfg + +# DATABASE + +# pick the form for your database +# sqlobject.dburi="postgres://username@hostname/databasename" +# sqlobject.dburi="mysql://username:password@hostname:port/databasename" +# sqlobject.dburi="sqlite:///file_name_and_path" + +# if you are using a database or table type without transactions +# (MySQL default, for example), you should turn off transactions +# by prepending notrans_ on the uri +# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" + +# for Windows users, sqlite URIs look like: +# sqlobject.dburi="sqlite:///drive_letter|/path/to/file" + + +# SERVER + +server.environment="production" + +# Sets the number of threads the server uses +# server.thread_pool = 1 + +# if this is part of a larger site, you can set the path +# to the TurboGears instance here +# server.webpath="" + +# Set to True if you'd like to abort execution if a controller gets an +# unexpected parameter. False by default +# tg.strict_parameters = False + +# LOGGING +# Logging configuration generally follows the style of the standard +# Python logging module configuration. Note that when specifying +# log format messages, you need to use *() for formatting variables. +# Deployment independent log configuration is in markuptest/config/log.cfg +[logging] + +[[handlers]] + +[[[access_out]]] +# set the filename as the first argument below +args="('server.log',)" +class='FileHandler' +level='INFO' +formatter='message_only' + +[[loggers]] +[[[markuptest]]] +level='ERROR' +qualname='markuptest' +handlers=['error_out'] + +[[[access]]] +level='INFO' +qualname='turbogears.access' +handlers=['access_out'] +propagate=0
new file mode 100644 --- /dev/null +++ b/examples/turbogears/setup.py @@ -0,0 +1,62 @@ +from setuptools import setup, find_packages +from turbogears.finddata import find_package_data + +import os +execfile(os.path.join("markuptest", "release.py")) + +setup( + name="MarkupTest", + version=version, + + # uncomment the following lines if you fill them out in release.py + #description=description, + #author=author, + #author_email=email, + #url=url, + #download_url=download_url, + #license=license, + + install_requires = [ + "TurboGears >= 0.9a7dev-r1517", + ], + scripts = ["start-markuptest.py"], + zip_safe=False, + packages=find_packages(), + package_data = find_package_data(where='markuptest', + package='markuptest'), + keywords = [ + # Use keywords if you'll be adding your package to the + # Python Cheeseshop + + # if this has widgets, uncomment the next line + # 'turbogears.widgets', + + # if this has a tg-admin command, uncomment the next line + # 'turbogears.command', + + # if this has identity providers, uncomment the next line + # 'turbogears.identity.provider', + + # If this is a template plugin, uncomment the next line + # 'python.templating.engines', + + # If this is a full application, uncomment the next line + # 'turbogears.app', + ], + classifiers = [ + 'Development Status :: 3 - Alpha', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Framework :: TurboGears', + # if this is an application that you'll distribute through + # the Cheeseshop, uncomment the next line + # 'Framework :: TurboGears :: Applications', + + # if this is a package that includes widgets that you'll distribute + # through the Cheeseshop, uncomment the next line + # 'Framework :: TurboGears :: Widgets', + ], + test_suite = 'nose.collector', + ) +
new file mode 100755 --- /dev/null +++ b/examples/turbogears/start-markuptest.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +import pkg_resources +pkg_resources.require("TurboGears") + +import turbogears +import cherrypy +cherrypy.lowercase_api = True + +from os.path import * +import sys + +# first look on the command line for a desired config file, +# if it's not on the command line, then +# look for setup.py in this directory. If it's not there, this script is +# probably installed +if len(sys.argv) > 1: + turbogears.update_config(configfile=sys.argv[1], + modulename="markuptest.config") +elif exists(join(dirname(__file__), "setup.py")): + turbogears.update_config(configfile="dev.cfg", + modulename="markuptest.config") +else: + turbogears.update_config(configfile="prod.cfg", + modulename="markuptest.config") + +from markuptest.controllers import Root + +turbogears.start_server(Root())
new file mode 100644 --- /dev/null +++ b/markup/plugin.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006 Mattew Good +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://projects.edgewall.com/trac/. + +import os +from pkg_resources import resource_filename + +from markup.template import Context, Template, TemplateLoader + + +class TemplateEnginePlugin(object): + + def __init__(self, extra_vars_func=None, options=None): + if options is None: + options = {} + # TODO get loader_args from the options dict + + self.loader = TemplateLoader(auto_reload=True) + self.options = options + self.get_extra_vars = extra_vars_func + + def load_template(self, templatename): + """Find a template specified in python 'dot' notation.""" + divider = templatename.rfind('.') + if divider >= 0: + package = templatename[:divider] + basename = templatename[divider + 1:] + '.html' + fullpath = resource_filename(package, basename) + dirname, templatename = os.path.split(fullpath) + self.loader.search_path.append(dirname) # Kludge + + return self.loader.load(templatename) + + def render(self, info, format='html', fragment=False, template=None): + """Renders the template to a string using the provided info.""" + return self.transform(info, template).render(method=format) + + def transform(self, info, template): + "Render the output to Elements" + if not isinstance(template, Template): + template = self.load_template(template) + + data = {} + if self.get_extra_vars: + data.update(self.get_extra_vars()) + data.update(info) + + ctxt = Context(**data) + return template.generate(ctxt)
--- a/setup.py +++ b/setup.py @@ -21,5 +21,9 @@ license='BSD', url='http://markup.cmlenz.net/', packages=find_packages(exclude=['*.tests*']), test_suite = 'markup.tests.suite', - zip_safe = True + zip_safe = True, + entry_points = """ + [python.templating.engines] + markup = markup.plugin:TemplateEnginePlugin + """, )