XHPy extends Python syntax such that XML document fragments become valid Python expressions. It is based off 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. 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, 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. 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.
Release files for xhpy 0.83
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distributions (sdists)
| File | Size | Uploaded | |
|---|---|---|---|
| xhpy-0.83.zip | 39.0 kB | Details | |
| xhpy-0.83.tar.gz | 25.1 kB | Details | |
| xhpy-0.83.tar.bz2 | 22.5 kB | Details |
Release files / xhpy-0.83.zip
| Download URL | xhpy-0.83.zip |
|---|---|
| Size | 39.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c2511ffc421ae14304692b34ea148e3438ec74bb4ed1434483c50ceac20ef0c
|
|
BLAKE2b-256 checksum How to use checksums |
db2aad9a1d4984cb64fbd826eda113a9e19d155895f68105a3fc2c06ce57ca5b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Release files / xhpy-0.83.tar.gz
| Download URL | xhpy-0.83.tar.gz |
|---|---|
| Size | 25.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c727980266ed576fccdc757589d246f09a025180ca70b33f445bf60a3aadf9d5
|
|
BLAKE2b-256 checksum How to use checksums |
dd247fd8a68272332d2cc9b83a876372c03f005ce0ffff580d47bafa8653c1fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Release files / xhpy-0.83.tar.bz2
| Download URL | xhpy-0.83.tar.bz2 |
|---|---|
| Size | 22.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9cfdc65ebc61a33557343764da0db90b1b60ed4484c5f14cc410e61c1832a04b
|
|
BLAKE2b-256 checksum How to use checksums |
93636e15b88439e23c575b91bcfbefe4ca9269c5f74a194e1e33f2d277a01524
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |