Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unofficial deformdemo #92

Merged
merged 11 commits into from
Oct 31, 2020
5 changes: 5 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
2.0.15 (unreleased)
-------------------

- Added unofficial deformdemo. This provides a space for contributors to add
their widgets without requiring tests, especially when the functional tests
cannot pass using Selenium. [sydoluciani]
https://github.com/Pylons/deformdemo/pull/92

- Changed dateparts widget to use ``type="number"`` instead of default `text`.
https://github.com/Pylons/deform/issues/442

Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
graft deformdemo
graft unofficial-deformdemo

include *.py
include *.sh
Expand Down
10 changes: 8 additions & 2 deletions deformdemo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2892,13 +2892,19 @@ def translator(term):
return get_localizer(get_current_request()).translate(term)

# Configure renderer
configure_zpt_renderer(("deformdemo:custom_widgets",), translator)

configure_zpt_renderer(
("deformdemo:custom_widgets", "unofficial-deformdemo:custom_widgets"),
translator,
)
config.add_static_view("static_deform", "deform:static")
config.add_route(
"unofficial-deformdemo", "/unofficial-deformdemo*traverse"
)
config.add_route("deformdemo", "*traverse")

def onerror(*arg):
pass

config.scan("deformdemo", onerror=onerror)
config.include("..unofficial-deformdemo")
return config.make_wsgi_app()
9 changes: 6 additions & 3 deletions deformdemo/templates/index.pt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
<div metal:fill-slot="main" tal:omit-tag="">
<div class="page-header">
<h1><a href="https://docs.pylonsproject.org/projects/deform/en/latest/">Deform</a> is a Python library for generating HTML
forms<br/><small>Each link on the left demonstrates a capability</small>
forms.<br/>
<small>Each link on the left demonstrates a capability.</small>
</h1>
</div>

<div class="well">

<p>The <a href="/">official Deform Demo</a> supports tested and documented widgets.
The <a href="/unofficial-deformdemo">unofficial Deform Demo</a> provides a space for contributors to add custom widgets that are not supported with the usual rigorous tests and documentation that is required by the Pylons Project.</p>
<p>
This demo is written using <a
href="https://trypyramid.com/">Pyramid</a>. Note that Deform does
not depend on any particular web framework,
we just had to write a demo application in <em>something</em>.
not depend on any particular web framework.
We had to write a demo application in <em>something</em>.
If you would like to run this demo application locally,
please read the <a href="https://github.com/Pylons/deformdemo">README
file for installation of this application</a>.
Expand Down
11 changes: 8 additions & 3 deletions deformdemo/templates/main.pt
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,14 @@

<div class="navbar navbar-default" role="navigation">
<div class="container">
<a class="navbar-brand" href="/"><span class="glyphicon glyphicon-info-sign"></span>
<span i18n:translate=""> Deform Demo</span>
</a>
<ul class="nav nav-pills">
<li class="nav-item active">
<a class="nav-link active" href="/"><span i18n:translate="">Deform Demo</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/unofficial-deformdemo"><span i18n:translate="">Unofficial Deform Demo</span></a>
</li>
</ul>
</div>
</div>

Expand Down
231 changes: 231 additions & 0 deletions unofficial-deformdemo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-

""" A Pyramid app that demonstrates various Deform widgets and
capabilities and which provides a functional test suite """

import inspect
import logging
import pprint
import sys

import colander
from pyramid.i18n import TranslationStringFactory
from pyramid.i18n import get_locale_name
from pyramid.renderers import get_renderer
from pyramid.response import Response
from pyramid.view import view_config
from pyramid.view import view_defaults

import deform
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import PythonLexer


log = logging.getLogger(__name__)


PY3 = sys.version_info[0] == 3
PY38MIN = sys.version_info[0] == 3 and sys.version_info[1] >= 8

if PY3:

def unicode(val, encoding="utf-8"):
return val


_ = TranslationStringFactory("unofficial-deformdemo")

formatter = HtmlFormatter(nowrap=True)
css = formatter.get_style_defs()

# the zpt_renderer above is referred to within the demo.ini file by dotted name


class demonstrate(object):
def __init__(self, title):
self.title = title

def __call__(self, method):
method.demo = self.title
return method


# Py2/Py3 compat
# http://stackoverflow.com/a/16888673/315168
# eliminate u''
def my_safe_repr(obj, context, maxlevels, level, sort_dicts=True):

if type(obj) == unicode:
obj = obj.encode("utf-8")

# Python 3.8 changed the call signature of pprint._safe_repr.
# by adding sort_dicts.
if PY38MIN:
return pprint._safe_repr(obj, context, maxlevels, level, sort_dicts)
else:
return pprint._safe_repr(obj, context, maxlevels, level)


@view_defaults(route_name="unofficial-deformdemo")
class UnofficialDeformDemo(object):
def __init__(self, request):
self.request = request
self.macros = get_renderer("templates/main.pt").implementation().macros

def render_form(
self,
form,
appstruct=colander.null,
submitted="submit",
success=None,
readonly=False,
is_i18n=False,
):

captured = None

if submitted in self.request.POST:
# the request represents a form submission
try:
# try to validate the submitted values
controls = self.request.POST.items()
captured = form.validate(controls)
if success:
response = success()
if response is not None:
return response
html = form.render(captured)
except deform.ValidationFailure as e:
# the submitted values could not be validated
html = e.render()

else:
# the request requires a simple form rendering
html = form.render(appstruct, readonly=readonly)

if self.request.is_xhr:
return Response(html)

code, start, end = self.get_code(2)
locale_name = get_locale_name(self.request)

reqts = form.get_widget_resources()

printer = pprint.PrettyPrinter()
printer.format = my_safe_repr
output = printer.pformat(captured)
captured = highlight(output, PythonLexer(), formatter)

# values passed to template for rendering
return {
"form": html,
"captured": captured,
"code": code,
"start": start,
"end": end,
"is_i18n": is_i18n,
"locale": locale_name,
"demos": self.get_demos(),
"title": self.get_title(),
"css_links": reqts["css"],
"js_links": reqts["js"],
}

def get_code(self, level):
frame = sys._getframe(level)
lines, start = inspect.getsourcelines(frame.f_code)
end = start + len(lines)
code = "".join(lines)
if not PY3:
code = unicode(code, "utf-8")
return highlight(code, PythonLexer(), formatter), start, end

@view_config(name="thanks.html", route_name="unofficial-deformdemo")
def thanks(self):
return Response(
"<html><body><p>Thanks!</p><small>"
'<a href="..">Up</a></small></body></html>'
)

@view_config(name="allcode",
renderer="templates/code.pt",
route_name="unofficial-deformdemo")
def allcode(self):
params = self.request.params
start = params.get("start")
end = params.get("end")
hl_lines = None
if start and end:
start = int(start)
end = int(end)
hl_lines = list(range(start, end))
code = open(inspect.getsourcefile(self.__class__), "r").read()
code = code.encode("utf-8")
formatter = HtmlFormatter(
linenos="table",
lineanchors="line",
cssclass="hightlight ",
hl_lines=hl_lines,
)
html = highlight(code, PythonLexer(), formatter)
return {"code": html, "demos": self.get_demos()}

def get_title(self):
# gross hack; avert your eyes
frame = sys._getframe(3)
attr = frame.f_locals["attr"]
inst = frame.f_locals["inst"]
method = getattr(inst, attr)
return method.demo

@view_config(name="pygments.css", route_name="unofficial-deformdemo")
def cssview(self):
response = Response(body=css, content_type="text/css")
response.cache_expires = 360
return response

@view_config(renderer="templates/index.pt",
route_name="unofficial-deformdemo")
def index(self):
return {"demos": self.get_demos()}

def get_demos(self):
def predicate(value):
if getattr(value, "demo", None) is not None:
return True

demos = inspect.getmembers(self, predicate)
L = []
for name, method in demos:
url = self.request.resource_url(
self.request.root, name, route_name="unofficial-deformdemo"
)
L.append((method.demo, url))
L.sort()
return L

# Unofficial Deform Demo Forms Start Here.

@view_config(name="textinput",
renderer="templates/form.pt",
route_name="unofficial-deformdemo")
@demonstrate("Text Input Widget")
def textinput(self):
class Schema(colander.Schema):
text = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=100),
widget=deform.widget.TextInputWidget(),
description="Enter some text",
)

schema = Schema()
form = deform.Form(schema, buttons=("submit",))

return self.render_form(form)


def includeme(config):

config.scan("unofficial-deformdemo")
6 changes: 6 additions & 0 deletions unofficial-deformdemo/templates/code.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div metal:use-macro="view.macros['master']">
<div metal:fill-slot="main">
<h2>Module Code</h2>
<span tal:replace="structure code"/>
</div>
</div>
46 changes: 46 additions & 0 deletions unofficial-deformdemo/templates/form.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<div metal:use-macro="view.macros['master']"
i18n:domain="deformdemo">
<div metal:fill-slot="main">
<div class="btn-group" tal:condition="is_i18n|False">
<a tal:attributes="class locale == 'en' and 'active btn btn-default' or 'btn btn-default'" href="${request.path_url}?_LOCALE_=en">English</a>
<a tal:attributes="class locale == 'de' and 'active btn btn-default' or 'btn btn-default'" href="${request.path_url}?_LOCALE_=de">Deutsch</a>
<a tal:attributes="class locale == 'nl' and 'active btn btn-default' or 'btn btn-default'" href="${request.path_url}?_LOCALE_=nl">Nederlands</a>
<a tal:attributes="class locale == 'ru' and 'active btn btn-default' or 'btn btn-default'" href="${request.path_url}?_LOCALE_=ru">Russian</a>
<a tal:attributes="class locale == 'es' and 'active btn btn-default' or 'btn btn-default'" href="${request.path_url}?_LOCALE_=es">Español</a>
<br />
<br />
</div>


<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Demo: ${title}</h3>
</div>
<div class="panel-body">
<div id="form" tal:content="structure form"/>
</div>
</div>

<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Captured submission</h3>
</div>
<div class="panel-body">
<pre style="border: none; background-color: #FFF" class="highlight" id="captured" tal:content="structure captured"/>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Code <a href="${request.resource_url(request.root, 'allcode', query={'start':start, 'end':end}, anchor='line-%s' % start)}"><small>
(click to show in context)</small></a>
</h3>
</div>
<div class="panel-body highlight">
<pre style="border: none; background-color: #FFF" tal:content="structure code"/>
</div>
</div>
</div>
</div>

Loading