Package: xhpy
XHPyextends Python syntax such that XML document
fragments become valid Python expressions. It is based offXHP, a similar framework for PHP.AdvantagesSimplicity: write UI logic in a simple, expressive syntax without the need for external
templates or templating languages.Flexibility: use Python expressions freely within XHPy tags, and vice-versa.Security: benefit from automatic escaping of text within XHPy tags.Reusability: build reusable components by subclassing :x:element.An exampleIn bar.py:from xhpy.init import register_xhpy_module
register_xhpy_module('foo')
import fooIn foo.py:from xhpy.pylib import *
class :ui:foo(:x:element):
  attribute list bar
  category %flow
  def render(self):
    a = <ul />
    for b in self.getAttribute('bar'):
      a.appendChild(<li>{b}</li>)
    return a
print <div class="baz"><ui:foo bar={range(3)} /></div>We can now run bar.py as a normal Python script:$ python bar.py
<div class="baz"><ul><li>0</li><li>1</li><li>2</li></ul></div>Congratulations! You just wrote your first snippet of XHPy.SyntaxXHPy adds some new syntax to Python. Line by line replay time!from xhpy.init import register_xhpy_moduleThis initializes XHPy and allows you to register modules to be interpreted as XHPy.register_xhpy_module('foo')Now thefoomodule infoo.pywill be interpreted as XHPy when imported.
Iffoowere a package, all of its submodules would also be registered; this is
useful for registering UI libraries.import fooTo actually use XHPy, however, you will probably want the core library:from xhpy.pylib import *Now you have access to all the standard HTML 4.0 elements, the:x:elementbase class
(this is what you build custom components on top of!), and some utilities.class :ui:foo(:x:element):Making new components is easy: just subclass:x:element. For your component class to be
registered, it must start with:- this clearly distinguishes your components from
ordinary Python classes.attribute list barThis is an attribute declaration, meaning that:ui:fooallows bar attributes on<ui:foo>tags. Note the<ui:foo bar={range(3)} />later on - like XHP, XHPy uses XML attribute syntax.category %flowThis is a category declaration -:ui:foois part of the%flowcategory. Categories are
primarily useful as a way of identifying elements that are similar without using
inheritance; for example, the<a>tag in pylib.html haschildren (pcdata | %flow)*indicating that its children must either contain text or be of the%flowcategory. (So
we can put<ui:foo>inside<a>!)def render(self):When you print an:x:element(or callstron it), therender()method is invoked; this
is where you put your UI logic.a = <ul />
for b in self.getAttribute('bar'):
    a.appendChild(<li>{b}</li>)
return aHere,<ui:foo>is a thin wrapper around<ul>that allows you to construct an unordered
list out of a Python list. Standard HTML elements like<ul>and<li>are automatically
rendered - except that, in XHPy, you can use Python expressions within tags, so that{b}is replaced by the value of b. Note the use ofgetAttribute()andappendChild():self.getAttribute('bar')fetches the value of attributebar(in this case,range(3)), whereasa.appendChild(<li>{b}</li>)adds<li>{b}</li>as a child ofa = <ul />.XHPy is largely based off XHP; for more details on the latter, see theXHP wiki. The syntax has been adapted for
Python; in particular:there are no semicolons;XHPy class names may be used anywhere ordinary Python classes can;XHPy tags ignore internal whitespace, but must externally obey indentation and
line continuation rules.More on the last point:def foo(href):
  return <a href={href}></a>

def bar(href):
  return\
  <a href={href}></a>are valid, whereasdef foo(href):
  return\
    <a href={href}>
    </a>is not, as it introduces an extra dedent after</a>.How it worksWhen youimport xhpy.initXHPy installs animport hook.
This hook traps subsequent import statements, running them through a preprocessor
that parses a superset of Python. This preprocessor translates XHPy tags and class
names to valid Python, then executes the translated code in module scope.This is similar to how XHP works, except:with, e.g.,pythonenv, you can always use
XHPy even without access to system-wide Python package installation directories;by default, Python compiles bytecode .pyc files from your modules, so the
preprocessing only needs to be done once when a module is first imported.