****************
Setting up PyXWF
****************
PyXWF currently requires a dedicated webserver with
`WSGI `_ support. Many widely-used
webservers (at least Apache and lighttpd) support WSGI using a module.
In addition to the python code, you'll have a repository with content, which is
where you put all the data which belongs to the site. We call this the
*data directory*, while the directory where PyXWF resides is the
*PyXWF directory*.
Creating the sitemap and initial data
=====================================
All those files referenced in this section are available in an example form in
the PyXWF repository, in the subdirectory ``misc/example``. You may use these
as a reference to build your own customized website.
PyXWF requires at least one file, the so called ``sitemap.xml`` (although you
can choose a different name). This is an XML file where the whole configuration
for PyXWF goes. It usually resides in the root of the *data directory*.
This is how a bare ``sitemap.xml`` looks (it won't work)::
My fancy PyXWF site
PyXWF.Nodes.Directory
We'll use this as a basement for our walk through the configuration process.
Before we go on, I'll leave a few words on how we at PyXWF think about XML
namespaces, as what we're doing here may seem a bit weird to you if you know
XML (if you don't, you probably should read up on XML anyways, cause most of
PyXWF happens in XML and Python).
PyXWF is really modular, as you might guess from the snippet above, even the
most basic elements like a directory in a site structure are plugins. To keep
the plugins separated from each other in the sitemap XML, each plugin has to
use its own XML namespace.
This brings you to a dilemma when it comes to find the root of the tree in the
sitemap XML: because you _cannot_ know its namespace. Someone could decide to
put a Transform node at the root or just a single page or a remote redirect.
So we have to scan through the whole ```` node and find a child with the
XML local-name *tree*. This is the only place in PyXWF itself where the
local-name of a node matters.
The ``@template`` attribute on the ```` node by the way states the
default template used to render web pages. We'll talk about templates later,
namely when we create the file referenced there.
Adding a home page
------------------
As mentioned previously, this sitemap will not work in PyXWF. You'll recieve
an error message which tells you that the ``dir:tree`` node needs an index
node.
So let's add one::
This won't work on it's own, we have to add two other things. First, the
``page`` namespace prefix needs to be resolved. We do that by adding the
declaration to the ```` node::
And we also need to load the plugin by adding another ```` tag::
PyXWF.Nodes.Directory
PyXWF.Nodes.Page
Now let's add source file for the home page. As you might guess, the
``@src`` attribute of a ```` references the file in which the
node looks for the source of the document to display. All paths are relative
to the *data directory*. So we create a ``home.xml`` file, which has to look
like this to satisfy the ``application/x-pywebxml`` content type set in
``@type``::
Home page
Welcome to my website!
I just set up PyXWF and want to play around.
The root element of a PyWebXML document must be a ```` node in
the namespace given above. We usually choose the ``py:`` prefix to reference
this namespace (for more elements and attributes which can be used in that
namespace have a look at the respective documentation). For more information
about PyWebXML documents see :ref:``. The only thing you need
to know now is that you can use arbitary XHTML (and anything you can use in
XHTML) inside the ```` element. It will be displayed on page, a correct
template presumed.
Adding a template
-----------------
Templates in PyXWF are XSL transformations. If you don't know anything about
these, you're probably lost. We cannot help you there, you maybe should get some
resources on these.
I won't paste a whole default template here. Instead, i'll describe in short
what the outermost template must do to create a proper website.
* The input of the transformation is always a valid ``py:page`` tree.
* The output of the transformation must be a valid ``py:page`` tree.
* The ``h:body`` of the ``py:page`` tree should contain the whole body which
should appear in the HTML output.
* The ``py:meta`` element should contain a ``py:title`` element which will map
to the HTML title.
* The ``py:meta`` element can also contain as many ``py:link`` and
``h:meta`` elements neccessary to describe your page. Please see the
``py:link`` documentation on how to include javascript files.
Setting up WSGI
===============
As mentioned before, PyXWF connects to the Web using WSGI. Here are the
neccessary configuration steps to get it to work.
Create the WSGI script
----------------------
You may want to have a look at ``examples/start/pyxwf.py`` from the PyXWF
repository to see how a WSGI script might look. Most important is to set up the
path to the *data directory* properly, and make sure that PyXWF is in your
python path.
We'll go through it here anyways. It's basically a normal python script, which
is set up for use with WSGI (see the
`PEP-3333 `_ for more info about
WSGI itself). A very simplistic approach might look like this and we'll call
this file **pyxwf.py**::
#!/usr/bin/python2
# encoding=utf-8
from __future__ import unicode_literals, print_function
import sys
import os
import logging
# you can configure logging here as you wish. This is the recommended
# configuration for testing (disable DEBUG-logging on the cache, it's rather
# verbose and not particularily helpful at the start)
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("PyXWF.Cache").setLevel(logging.INFO)
conf = {
"pythonpath": ["/path/to/pyxwf"],
"datapath": "/path/to/site"
}
try:
sys.path.extend(conf["pythonpath"])
except KeyError:
pass
os.chdir(conf["datapath"])
import PyXWF.WebBackends.WSGI as WSGI
sitemapFile = os.path.join(conf["datapath"], "sitemap.xml")
application = WSGI.WSGISite(
sitemapFile,
default_url_root=conf.get("urlroot")
)
The *datapath* in the *conf* dictionary refers to the directory in which PyXWF
will look for all files. In fact, all references to files inside the
``sitemap.xml`` are relative to that path. Later on in the snippet above, we
also look for the ``sitemap.xml`` itself in that location. Note that you have
to add the path to the ``PyXWF`` package to your pythonpath (if you have not
already done this globally).
Test it quickly (without dedicated webserver)
---------------------------------------------
For this, PyXWF comes with a script called ``serve.py``. It'll help you to run
test your website as soon as you have a WSGI script running. This will break
though as soon as you have static content which is served from outside of
PyXWF. But for the start, it's fine. It's basic use is pretty simple (and
``./serve.py -h`` will tell you more). Just navigate to the PyXWF directory and
do::
./serve.py /path/to/pyxwf.py
(you created the file ``pyxwf.py`` in the previous step!) This will spam some
log messages. After it quiets down, you'll be able to access your site using
the URL http://localhost:8080/.
As soon as you need static files (images, CSS, …), you'll want to use a
dedicated webserver for that, as PyXWF does not deliver such files by default.
The next section deals with setting up PyXWF with Apache, but you're free to
skip this in favour of finding out how awesome PyXWF really is.
You can in fact also run the examples delivered with PyXWF using ``serve.py``,
for example::
./serve.py examples/start/pyxwf.py
``mod_wsgi`` with Apache
------------------------
We are using a configuration similar to this one for zombofant.net::
WSGIApplicationGroup %{GLOBAL}
WSGIScriptAlias / /path/to/zombofant/data/pyxwf.py
# access to static files via Apache, PyXWF won't do that
Alias /css /path/to/zombofant/data/css
Alias /img /path/to/zombofant/data/img
Actually, thats all you need. Read up on
`WSGI configuration `_
to see how to adapt this to your needs if it doesn't work out of the box.
Before you cheer in happiness, a word of warning. The directive
``WSGIApplicationGroup`` is required for PyXWF to work properly with ``lxml``,
but may also break having multiple PyXWF sites on one server. The solution
is to use one ``WSGIProcessGroup`` for each site. I might write another section
about this, but for the basic setup the above snippet is okay, so I'll leave
that for later.