New and hot, part 2: First Pyramid setup
This is part 2 of my March 9th 2011 Confoo presentation. Refer to the Table of Contents for the other parts.
Pyramid installation
Setup of the "Foo" pyramid application
We'll install those packages:
- pyramid: the web framework.
- mongokit: which brings in pymongo, the low-level mongo driver.
- kombu: for AMQP/RabbitMQ communication. To be used later on.
- redis: to access a Redis server. Used in the last part of this presentation.
- pyramid_socketio: pyramid and Socket.IO integration for real-time apps. This will bring in all the Gevent machinery. We'll use that later on also.
First, we setup the virtual environment:
$ cd ~ $ virtualenv --distribute env $ . env/bin/activate
NOTE: each time you will see that(env)prompt prefix, it means we're in the virtual environment. To activate it (after a reboot or whatever), run. env/bin/activateagain.
Then install what we need, create a new template and install it in the environment (in development mode):
(env)$ pip install pyramid mongokit kombu pyramid_socketio redis (env)$ paster create -t pyramid_starter Foo ... (env)$ python setup.py develop (env)$ paster serve --reload development.ini
You'll notice that Pyramid was made to use the same Paste server and configuration that we were used to in Pylons 1.0. Let's have a look at the default page at: http://127.0.0.1:6543. Needless to say that it is much prettier than before! We can have a sneak peek at the documentation to notice it is very extensive and beautifully laid out.
Exploring the directory layout
(env)$ cd Foo (env)$ find . . ./templates ./templates/mytemplate.pt ./static ./static/pyramid.png ./static/pyramid-small.png ./static/transparent.gif ./static/headerbg.png ./static/middlebg.png ./static/favicon.ico ./static/footerbg.png ./static/ie6.css ./static/pylons.css ./resources.py ./__init__.py ./views.py ./tests.py
A notable difference with the original Pylons 1.0, is that Pyramid doesn't impose any structure to the directories you layout. It can easily create a one-file application, as well as allow you to lay your files in the way that fits best with your project. This is very refreshing.
In the pyramid_starter template, the model.py was renamed to resources.py, but you could rename it as you wish. Simply tweak __init__.py accordingly.
The static/ directory contains all the static files, and replaces the public/ directory of Pylons 1.0.
templates/ is our old templates holder, with snippets of HTML in the templating language you like the most. Pyramid isn't stubborn about the templating language you choose - or decide not to choose. It'll run the templating engine you want, based on the extension of your template files. So you can have many templating languages in the same project. By default, it uses the Chameleon templating engine, an XML-based Zope Page Template and Genshi template compiler.
The central part of the projet is in __init__.py... the foo module itself. That's where all the config and wires are tied in. We'll add a couple of config items in here in a moment.
Notice in the __init__.py file that there's nothing about sessions (Beaker) and not much about databases. That's because they're pluggable, and we'll add them as required. Fear not, everything is thoroughly documented.
Adding Mako support
I love Mako, so we'll tack on Mako support:
def main(global_config, **settings): ... config.add_renderer('.html', 'pyramid.mako_templating.renderer_factory') ...
This will make all future rendering of .html files use the Mako rendering engine. I used .html just for convenience. You might want to use the .mako extension if you want to integrate with other components well.
You'll want to add those config in development.ini to have the templates compiled once. mako.directories is required for Mako to work.
### inside Foo/development.ini [app:Foo] ... mako.directories = foo:templates #mako.module_directory = %(here)s/data/templates ...
The second mako.module_directory is used to write compiled Mako files. Make sure to use this in production, as it speeds things up a lot.
Writing our first view
This year, I'm not going to demonstrate Mako, so I'll simply load the excellent and highly recommended HTML5 boiler-plate (by Paul Irish) directly into my templates dir.
$ cd ~/Foo $ git clone ~/build/html5-boilerplate $ cp -r html5-boilerplate/* foo/static $ # We'll put index.html in the templates/ dir though.. $ mv foo/static/index.html foo/templates
We will need to tweak the HTML5 boilerplate so that the URLs pointing to our scripts and resources use Pyramid's routing. Get the full patch here. This is a sneak peek:
--- a/foo/templates/index.html +++ b/foo/templates/index.html @@ -26,18 +26,18 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Place favicon.ico & apple-touch-icon.png in the root of your domain and delete these references --> - <link rel="shortcut icon" href="/favicon.ico"> - <link rel="apple-touch-icon" href="/apple-touch-icon.png"> + <link rel="shortcut icon" href="${request.static_url('foo:static/favicon.ico')}"> + <link rel="apple-touch-icon" href="${request.static_url('foo:static/apple-touch-icon.png')}">
You can apply it this way:
(env)$ cd ~/Foo (env)$ patch -p1
and paste the patch in, then hit Ctrl+D.
We'll also add a little style in foo/static/css/style.css after the CSS resets. There's a specially marked section for you:
In the demonstration, I'm actually using a stripped-down version of the html5 boilerplate (it's a yasnippet for Emacs).
/* Primary Styles Author: Alexandre Bourget */ div#container { margin: 0 auto; width: 800px; border: 1px solid #aaa; border-radius: 10px; padding: 10px; -webkit-box-shadow: 5px 5px 5px #ddd; } h1 { text-shadow: 2px 2px 2px #ddd; font-size: 22px; margin-bottom: 10px; } footer { font-size: 10px; text-align: center; margin-top: 15px; } iframe { width: 780px; height: 70px; border: 1px solid black; } div#graph { width: 750px; height: 300px; } div#video { text-align: center; } video { width: 640px; height: 480px; }
We'll go in index.html and add some hello world or something:
...
<header>
<h1>Hello Excellent World!</h1>
</header>
...
Now let's add the required calls to show that on the front-page:
In views.py:
from pyramid.view import view_config @view_config(route_name="home", renderer="index.html") def home(request): return {'boo': 'ahh'}
In __init__.py:
def main(...): ... config.add_route('home', '') config.scan('foo.views') ...
and hop! http://localhost:6543 should now answer the call
That's it for now! But what if we could actually do someting interesting, like dragging a video file from the desktop and have it encoded on the server-side so that it could be played back via the web ? We'll do just that in our next episode!
If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at contact@savoirfairelinux.com mentioning this blog.
UPDATE May 3rd 2011: Simplified the Mako integration (from 2 lines to one).
