Skip to content

Commit

Permalink
Attempt to integrate formhelpers with pyramid
Browse files Browse the repository at this point in the history
  • Loading branch information
tholo committed Sep 21, 2011
0 parents commit 08a59ac
Show file tree
Hide file tree
Showing 17 changed files with 633 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
@@ -0,0 +1,8 @@
/.coverage
/build/
/cover/
/coverage.xml
/data/
/dist/
/*.egg-info
*.pyc
4 changes: 4 additions & 0 deletions CHANGES.rst
@@ -0,0 +1,4 @@
0.0
---

- Initial version
2 changes: 2 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include formhelpers2 *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml
8 changes: 8 additions & 0 deletions README.rst
@@ -0,0 +1,8 @@
============
formhelpers2
============

formhelpers2 is an attempt to use Mike Bayer's formhelpers_ with Pyramid_.

.. _formhelpers: http://techspot.zzzeek.org/2008/07/01/better-form-generation-with-mako-and-pylons
.. _Pyramid: http://pyramid.org
51 changes: 51 additions & 0 deletions development.ini
@@ -0,0 +1,51 @@
[app:main]
use = egg:formhelpers2

pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.debug_templates = true
pyramid.default_locale_name = en
pyramid.includes = pyramid_debugtoolbar

mako.preprocessor = formhelpers2:mako.process_tags
mako.directories = formhelpers2:templates
#mako.module_directory = %(here)s/data/templates
mako.strict_undefined = true

[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 6543

# Begin logging configuration

[loggers]
keys = root, formhelpers2

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_formhelpers2]
level = DEBUG
handlers =
qualname = formhelpers2

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

# End logging configuration
17 changes: 17 additions & 0 deletions formhelpers2/__init__.py
@@ -0,0 +1,17 @@
from pyramid.config import Configurator
from pyramid.session import UnencryptedCookieSessionFactoryConfig

def main(global_config, **settings):
"""
This function returns a Pyramid WSGI application.
"""

my_session_factory = UnencryptedCookieSessionFactoryConfig('formhelpers2')
config = Configurator(settings=settings,
session_factory=my_session_factory)

config.add_static_view('static', 'formhelpers2:static')

config.scan()

return config.make_wsgi_app()
86 changes: 86 additions & 0 deletions formhelpers2/mako.py
@@ -0,0 +1,86 @@
import re


class Form(object):
class FormContext(object):
pass

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

def validate(self, data):
return self.schema.deserialize(data)

def render(self, data=None, errors=None, context=None, **kw):
if not context:
context = self.FormContext()
if not data:
data = self.schema.serialize()

setattr(context, self.name, dict(data.iteritems()))

if errors:
if hasattr(context, 'errors'):
context.errors.update(errors)
else:
context.errors = errors

for key, val in kw.items():
setattr(context, key, val)

return context


tag_regexp = re.compile(r'<(\/)?%(\w+):(\w+)\s*(.*?)(\/)?>', re.S)
attr_regexp = re.compile(
r"\s*(\w+)\s*=\s*(?:(?<!\\)'(.*?)(?<!\\)'|(?<!\\)\"(.*?)(?<!\\)\")")
expr_regexp = re.compile(r'\${(.+?)}')


def process_tags(source):
"""Convert tags of the form <nsname:funcname attrs> into a <%call> tag.
This is a quick regexp approach that can be replaced with a full blown
XML parsing approach, if desired.
"""
def process_exprs(t):
m = re.match(r'^\${(.+?)}$', t)
if m:
return m.group(1)

att = []

def replace_expr(m):
att.append(m.group(1))
return "%s"

t = expr_regexp.sub(replace_expr, t)
if att:
return "'%s' %% (%s)" % (t.replace("'", r"\'"), ",".join(att))
else:
return "'%s'" % t.replace("'", r"\'")

def cvt(match):
if bool(match.group(1)):
return "</%call>"

ns = match.group(2)
fname = match.group(3)
attrs = match.group(4)

attrs = dict([(key, process_exprs(val1 or val2))
for key, val1, val2 in attr_regexp.findall(attrs)])
args = attrs.pop("args", "")

attrs = ",".join(["%s=%s" % (key, value)
for key, value in attrs.iteritems()])

if bool(match.group(5)):
return """<%%call expr="%s.%s(%s)" args=%s/>""" % (
ns, fname, attrs, args)
else:
return """<%%call expr="%s.%s(%s)" args=%s>""" % (
ns, fname, attrs, args)
return tag_regexp.sub(cvt, source)
21 changes: 21 additions & 0 deletions formhelpers2/static/style.css
@@ -0,0 +1,21 @@
body { background-color: #fff; color: #333; }

body, p {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
line-height: 18px;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
line-height: 13px;
}

a { color: #000; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }

.error-message{
color:red;
}
20 changes: 20 additions & 0 deletions formhelpers2/subscribers.py
@@ -0,0 +1,20 @@
from pyramid.events import BeforeRender
from pyramid.events import NewRequest
from pyramid.events import subscriber
from pyramid.httpexceptions import HTTPForbidden

from webhelpers.html import tags


@subscriber(BeforeRender)
def add_renderer_globals(event):
event['h'] = tags


@subscriber(NewRequest)
def csrf_validation(event):
request = event.request
if request.method == 'POST':
token = request.POST.get('_csrf')
if token is None or token != request.session.get_csrf_token():
raise HTTPForbidden('Cross Site Request Forgery detected')
48 changes: 48 additions & 0 deletions formhelpers2/templates/comment.mako
@@ -0,0 +1,48 @@
<%namespace name="form" file="/form_tags.mako"/>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Mako Form Helpers</title>
<link rel="stylesheet" href="${request.static_url('formhelpers2:static/style.css')}" type="text/css" />
</head>
<body>

<h3>Using Mako Helpers</h3>

<%form:form name="comment_form" controller="comment" action="post">
<div style="display: none;">
<input type="hidden" name="_csrf" value="${request.session.get_csrf_token()}" />
</div>
<table>
<tr>
<th colspan="2">Submit your Comment</th>
</tr>
<tr>
<td>Your Name:</td>
<td><%form:text name="name"/></td>
</tr>
<tr>
<td>How did you hear about this site ?</td>
<td>
<%form:select name="heard" options="${heard_choices}">
<%form:option value="">None</%form:option>
</%form:select>
</td>
</tr>
<tr>
<td>Comment:</td>
<td><%form:textarea name="comment"/></td>
</tr>
<tr>
<td colspan="2"><%form:submit/></td>
</tr>
</table>
</%form:form>

</body>
</html>

0 comments on commit 08a59ac

Please sign in to comment.