skip to navigation
skip to content

xhpy 0.8

XHP for Python

Latest Version: 0.83

XHPy: XHP for Python
====================

`XHPy <https: github.com="" candu="" xhpy="">`_ extends Python syntax such that XML document
fragments become valid Python expressions. It is based off
`XHP <https: github.com="" facebook="" xhp="">`_, a similar framework for PHP.

Advantages
----------
- *Simplicity*: 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 example
----------
In bar.py:

::

from xhpy.init import register_xhpy_module
register_xhpy_module('foo')
import foo

In 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.

Syntax
------

XHPy adds some new syntax to Python. Line by line replay time!

::

from xhpy.init import register_xhpy_module

This initializes XHPy and allows you to register modules to be interpreted as XHPy.

::

register_xhpy_module('foo')

Now the ``foo`` module in ``foo.py`` will be interpreted as XHPy when imported.
If ``foo`` were a package, all of its submodules would also be registered; this is
useful for registering UI libraries.

::

import foo

To 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:element`` base 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 bar

This is an attribute declaration, meaning that ``:ui:foo`` allows bar attributes on ``<ui:foo>``
tags. Note the

::

<ui:foo bar="{range(3)}"/>

later on - like XHP, XHPy uses XML attribute syntax.

::

category %flow

This is a category declaration - ``:ui:foo`` is part of the ``%flow`` category. Categories are
primarily useful as a way of identifying elements that are similar without using
inheritance; for example, the ``<a>`` tag in pylib.html has

::

children (pcdata | %flow)*

indicating that its children must either contain text or be of the ``%flow`` category. (So
we can put ``<ui:foo>`` inside ``<a>``!)

::

def render(self):

When you print an ``:x:element`` (or call ``str`` on it), the ``render()`` 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 a

Here, ``<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 of ``getAttribute()`` and ``appendChild()``:

::

self.getAttribute('bar')

fetches the value of attribute ``bar`` (in this case, ``range(3)``), whereas

::

a.appendChild(<li>{b}</li>)

adds ``<li>{b}</li>`` as a child of ``a = <ul/>``.

XHPy is largely based off XHP; for more details on the latter, see the
`XHP wiki <https: github.com="" facebook="" xhp="" wiki="" `_.="" the="" syntax="" has="" been="" adapted="" for<br="">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, whereas

::

def foo(href):
return\
<a href="{href}">
</a>

is not, as it introduces an extra dedent after ``</a>``.

How it works
------------
When you

::

import xhpy.init

XHPy installs an `import hook <http: www.python.org="" dev="" peps="" pep-0302=""/>`_.
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 <http: pypi.python.org="" pypi="" virtualenv="">`_, 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.  
File Type Py Version Uploaded on Size
xhpy-0.8.tar.bz2 (md5) Source 2011-02-15 20KB
xhpy-0.8.tar.gz (md5) Source 2011-02-15 22KB
xhpy-0.8.zip (md5) Source 2011-02-15 34KB