Author Archives: Kevin

About Kevin

I'm a web developer living and working in Nashville, Tennessee, USA. I work with Plone and Django.

Date Constraint for XForms in Open Data Kit

Had some trouble Googling this little nugget, so I thought I might share it here.

If you want to constrain a date field in Open Data Kit by a specific date (i.e. “The date must be before 12/15/2000”), here’s the syntax:

<bind nodeset="/demographics/dob"
      type="date"
      constraint=". &lt; date('2000-12-15')"
      jr:constraintMsg="Date of Birth must be before 12/15/2000"
      />

Don’t forget the quotes inside the parentheses.

Benchmarking Plone 3.3.5 with ApacheBench

Ever wondered what a good caching policy can do for your site’s performance? I’m deep in the throws of a ground-up Plone installation behind Apache, and I’ll be using CacheFu and Varnish to speed up the site. As I go along I’ll run ApacheBench at major milestones to see what difference they’re making.

The Command

ApacheBench comes installed with Apache, so no need to add anything new. To benchmark my site, I’ll run the following command:

ab -n 100 -c 3 http://127.0.0.1:8080/Plone/front-page

That’s 100 total requests, no more than 3 at the same time.

Initial Data

Here are the results from the “Welcome to Plone” page on a freshly created Plone site.

Server Software:        Zope/(unreleased
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /Plone/front-page
Document Length:        21120 bytes

Concurrency Level:      3
Time taken for tests:   34.529235 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      2140200 bytes
HTML transferred:       2112000 bytes
Requests per second:    2.90 [#/sec] (mean)
Time per request:       1035.877 [ms] (mean)
Time per request:       345.292 [ms] (mean, across all concurrent requests)
Transfer rate:          60.53 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   4.4      0      32
Processing:   263 1021 3556.2    528   34526
Waiting:      261 1019 3553.4    523   34494
Total:        263 1022 3557.4    528   34526

Percentage of the requests served within a certain time (ms)
50%    528
66%    553
75%    564
80%    575
90%    667
95%    967
98%   8281
99%  34526
100% 34526 (longest request)

Next, let’s see what happens when we add content.

With Data, Running on the Bare Zope Server

Since the site is running on ZEO, I decided to temporarily leave one client running on the bare Zope application server and set up one behind Apache. Here’re the stats for the non-Apache client.

Server Software:        Zope/(unreleased
Server Hostname:        127.0.0.1
Server Port:            8081

Document Path:          /Plone/
Document Length:        26136 bytes

Concurrency Level:      3
Time taken for tests:   42.539567 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      2641800 bytes
HTML transferred:       2613600 bytes
Requests per second:    2.35 [#/sec] (mean)
Time per request:       1276.187 [ms] (mean)
Time per request:       425.396 [ms] (mean, across all concurrent requests)
Transfer rate:          60.63 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   15 115.0      0     991
Processing:   408 1247 221.9   1221    2181
Waiting:       10 1235 253.2   1219    2179
Total:        820 1263 189.2   1221    2181

Percentage of the requests served within a certain time (ms)
 50%   1221
 66%   1225
 75%   1227
 80%   1231
 90%   1409
 95%   1596
 98%   2181
 99%   2181
 100%   2181 (longest request)

With Data, Running Behind Apache

… and here’s what I got on the client running behind Apache. I hadn’t spent any time on caching yet.

Server Software:        Zope/(unreleased
Server Hostname:        **************************
Server Port:            80

Document Path:          /
Document Length:        25745 bytes

Concurrency Level:      3
Time taken for tests:   46.875144 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      2602800 bytes
HTML transferred:       2574500 bytes
Requests per second:    2.13 [#/sec] (mean)
Time per request:       1406.254 [ms] (mean)
Time per request:       468.751 [ms] (mean, across all concurrent requests)
Transfer rate:          54.21 [Kbytes/sec] received

Connection Times (ms)
 min  mean[+/-sd] median   max
Connect:        0   12  87.6      0     740
Processing:   719 1385 2949.9    899   24272
Waiting:      264 1377 2935.4    899   24271
Total:        719 1397 2978.6    901   24272

Percentage of the requests served within a certain time (ms)
 50%    901
 66%    934
 75%    988
 80%   1031
 90%   1453
 95%   1954
 98%  19548
 99%  24272
 100%  24272 (longest request)

With Data, from my local machine

This is what it looks like from my local machine.

Server Software:        Apache/2.2.3
Server Hostname:        ***********************
Server Port:            80

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      3
Time taken for tests:   3.004 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Non-2xx responses:      100
Total transferred:      25500 bytes
HTML transferred:       0 bytes
Requests per second:    33.29 [#/sec] (mean)
Time per request:       90.124 [ms] (mean)
Time per request:       30.041 [ms] (mean, across all concurrent requests)
Transfer rate:          8.29 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       26   44  13.6     39     101
Processing:    27   45  14.8     40     100
Waiting:       26   45  14.9     40     100
Total:         54   89  22.1     85     161

Percentage of the requests served within a certain time (ms)
  50%     85
  66%     95
  75%    101
  80%    108
  90%    122
  95%    137
  98%    143
  99%    161
 100%    161 (longest request)

Accessing the new model instance with Django’s “post_save” signal

I’d been wracking my brain for a few hours before I finally went back to the Django signals documentation and looked up how to get to the newly created instance with Django’s ‘post_save’ signal. I’m not sure if johnboxall’s django-paypal signal example is out of date or simply erroneous, but it’s not the right way to do it. I’d expected the sender itself to be the new instance. Instead, this:

def notify_on_payment(sender, **kwargs):
  print "We got it"
  ipn_obj = sender
  print ipn_obj

post_save.connect(notify_on_payment, sender=PayPalIPN)

got me this:

We got it
<class 'paypal.standard.ipn.models.PayPalIPN'>

…plus a big fat error page in the browser.

Note: I couldn’t get the payment_was_successful signal to work at all, so I rolled my own.

The <class> bit is NOT the newly created instance, but the class itself. Django did not like me trying to access the ‘id’ of a Model class.

Long story short, the actual instance is passed as a keyword argument. Here’s how to get to it:

def notify_on_payment(sender, **kwargs):
  print "We got it"
  ipn_obj = kwargs['instance']
  print ipn_obj

Here’s the output:

We got it
<IPN: Recurring > #This is the get_display for this particular Model

Much better :). I can now access fields on that instance using dot notation.

I’d be interested in knowing whether the example on johnboxall’s page is outdated or wrong. It would seem reasonable to me for the sender to be the newly created instance to send the signal. I am, however, usually wrong about these things. Any ideas?

Getting django-syncr running on WebFaction

I’m working on a Django installation at WebFaction that will be needing the special magnificence that is django-syncr. It’s got a few other dependencies, so I thought I’d record the steps I needed to take to get it up and running.

ElementTree

You don’t need this unless you’re using Python 2.4 or earlier, but if you do: http://effbot.org/zone/element-index.htm

django-tagging

Get it here: http://code.google.com/p/django-tagging/

OR…. just easy_install it :). I’m on Python 2.5, so SSH into your server and:

easy_install-2.5 django-tagging

God bless setuptools.

python-twitter

If you want to get your Twitter feed into your Django database, you’re gonna need python-twitter. And for python-twitter, you’re gonna need simplejson. Let’s get that first. If you’re still SSH’d in:

easy_install-2.5 simplejson

Now for python-twitter:

easy_install-2.5 python-twitter

Do you want the Flickr support?

Flickr won’t release the actual photo or allow it to be embedded using the API (as far as I can tell). I don’t really see any need for all the Flickr metadata to live in my database without the image, so I’m skipping it.

Installing django-syncr itself

django-syncr isn’t in PyPI yet, so we’ll have to download and install it the old-fashioned setuptools way:

cd ~/webapps/djangoapp/
mkdir src
cd src
svn checkout http://django-syncr.googlecode.com/svn/trunk/ syncr
cd ..
easy_install-2.5 src/syncr

I pulled up out of the ‘src’ directory so easy_install would no exactly what ‘syncr’ I was talking about.

Including django-syncr in your Installed Apps

You’ll need to edit your settings.py file to tell django you’d like to use the new apps you just easy_installed. Get to your settings.py file and open it with your favorite editor:

cd ~/webapps/djangoapp/myproject/
emacs settings.py

Added the following lines (between the ellipses) to your ‘INSTALLED_APPS’:

INSTALLED_APPS = (
    ...
    'tagging',
    'syncr.youtube',
    'syncr.twitter',
    ...
)

In my particular case, I’ve added it after a bunch of Satchmo stuff but before my own app.

Syndb and restart

That’s it for the tricky stuff. If you’ve done everything right you should be able to sync the database no problem (now is a great time to back up your data, by the way):

python2.5 manage.py syncdb

Then restart your server…

../apache2/bin/restart

and check your admin site for the new tables.

Installing Satchmo on Snow Leopard

Django is my framework of choice for non-CMS web applications, and that makes Satchmo my choice for eCommerce. It’s a great library, even if it does have a million dependencies. On the bright side, I’ve used many of it’s dependencies in other projects, so look at installing these as a chance to learn more about Python.

This tutorial is based on the excellent instructions at the Satchmo Project site.

Installing Dependencies

If you’re going to use Satchmo, you’ve of course got to have Django. See my Django installation tutorial.

Remember how I said that I like to keep Libraries in my user folder? Here’s my first official renege. I don’t want to keep up with all these dependencies, so I’m going to allow easy_install to install these libraries in my Python 2.6 SITE-PACKAGES whenever possible.

Installing easy_install

Here are the official instructions, written for the slightly more advanced user. Here’s what I did:

  1. Download the SetupTools Python egg for our version of Python (2.6, the default on Snow Leopard)
  2. Run the egg as a Shell script with the following Terminal command:
    sudo sh /Users/kevin/Downloads/setuptools-0.6c11-py2.6.egg
  3. Type in your password when your asked for it

That’s it. easy_install is installed as a part of setuptools, and you can run it directly from Terminal by typing ‘easy_install’

Installing the other dependencies

These are generally straightforward with easy_install. Use the command below the name of each library to install. Notes included where I ran into trouble.

Pycrypto

easy_install pycrypto

ReportLab

There’s a link to the 2.5 egg on the Satchmo install site, but that doesn’t help us much. Here’s how to get ReportLab for Python 2.6 (you’ll need GCC, which is a part of XCode):

  1. Download the latest ReportLab tarball from the ReportLab site.
  2. Move the tarball into your user folder and un-tar it
  3. cd
    mv Downloads/ReportLab_2_3.tar.gz ReportLab_2_3.tar.gz
    tar xzvf ReportLab_2_3.tar.gz
  4. Move into the new directory and type the following command to install it:
  5. cd ReportLab_2_3
    python setup.py install

After running this I got the following error:

########## SUMMARY INFO #########
################################################
#Attempting install of _rl_accel, sgmlop & pyHnj
#extensions from '/Users/kevin/ReportLab_2_3/src/rl_addons/rl_accel'
################################################
################################################
#Attempting install of _renderPM
#extensions from '/Users/kevin/ReportLab_2_3/src/rl_addons/renderPM'
# installing without freetype no ttf, sorry!
################################################

Not sure what’s going on here, but I’ll ignore this for now.

TRML2PDF

easy_install http://www.satchmoproject.com/snapshots/trml2pdf-1.2.tar.gz

django-registration

easy_install django-registration

PyYAML

easy_install PyYAML

Python Imaging Library (PIL)

sudo easy_install --find-links=http://download.zope.org/distribution PILwoTk

Django-Threaded-Multihost

  1. Download the django-threaded-multihost tarball from GoSatchmo
  2. Move the tarball into your user folder and un-tar it
  3. cd
    mv Downloads/django-threaded-multihost-1.3-2.tar.gz django-threaded-multihost-1.3-2.tar.gz
    tar xzvf django-threaded-multihost-1.3-2.tar.gz
  4. Move into the new directory and type the following command to install it:
  5. cd django-threaded-multihost-1.3-2
    python setup.py install

Django-App-Plugins

  1. This one’s a little funky. We’re going to need a place for this to live. Make a new directory ‘/Users/kevin/src/django/plugins/’
    mkdir ~/src/django/plugins
  2. Move to the new directory and checkout django-app-plugins from Subversion
  3. cd ~/src/django/plugins
    svn checkout http://django-app-plugins.googlecode.com/svn/trunk/ django-app-plugins-read-only
  4. Create a symbolic link to the SITE-PACKAGES directory from django-app-plugins/app_plugins
    cd /Library/Python/2.6/site-packages/
    ln -s /Users/kevin/src/django/plugins/django-app-plugins-read-only/app_plugins .

SORL-Thumbnail

This package is kept in a Mercurial repository. You’ll have to download and install Mercurial. Here’s the Mercurial Installer for Snow Leopard.

  1. Move to your newly created ‘plugins’ directory and checkout SORL-Thumbnail with Mercurial
    cd ~/src/django/plugins
    hg clone https://sorl-thumbnail.googlecode.com/hg/ sorl-thumbnail
  2. Create a symbolic link to your SITE-PACKAGES directory for SORL-Thumbnail
    cd /Library/Python/2.6/site-packages/
    ln -s /Users/kevin/src/django/plugins/sorl-thumbnail/sorl .

signals-ahoy

  1. Move to your newly created ‘plugins’ directory and checkout signals-ahoy with Mercurial
    cd ~/src/django/plugins
    hg clone http://bitbucket.org/bkroeze/django-signals-ahoy/
  2. Create a symbolic link to your SITE-PACKAGES directory for django-signals-ahoy/signals-ahoy
    cd /Library/Python/2.6/site-packages/
    ln -s /Users/kevin/src/django/plugins/django-signals-ahoy/signals_ahoy .

Sphinx

sudo easy_install sphinx

Docutils

sudo easy_install docutils

Installing Satchmo

Still with me? I want to install Satchmo the same way I installed Django. I’ll be installing it in it’s own directory in ‘src’, though it is technically a plugin. I might be using different versions of Satchmo in the future. I also want to be able to browse the source without too much trouble.

  1. Checkout Satchmo into your ‘src’ directory
    cd ~/src
    mdkir satchmo
    cd satchmo
    hg clone http://bitbucket.org/chris1610/satchmo/ satchmo-trunk
  2. Add ‘satchmo-trunk/satchmo/apps’ to your Python path. I did this by adding it to my .bash_profile. Either edit or create yours, in the root your user directory, to include this line:
    export PYTHONPATH="$PYTHONPATH:/Users/kevin/src/satchmo/satchmo-trunk/satchmo/apps"

At this point, Satchmo is installed. You should be able to import Satchmo from the Python 2.6 interpreter:

>>> import satchmo_store

… and you can now run pre-exisiting Satchmo projects on your iMac.

In GenericSetup, a Page isn’t a “Page”

Here’s a little gotcha I just ran into again recently. I’ve got a new folderish Plone content type that I’m working on, to which I’d like to be able to add plain-old Pages. At first, my profiles/default/types/NewFolderish.xml looked like this:

...
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
  <element value="Link" />
  <element value="Page" /> <!-- WRONG -->
</property>
...

Well, that didn’t allow me to add a page to a New Folderish content type.  Here’s why: for GenericSetup, you have to identify a content type by it’s meta_type. For most default content types, it’s what you’d expect. For Page and Collection, it’s not. Here’s the correct profiles/default/types/NewFolderish.xml

...
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
  <element value="Link" />
  <element value="Document" /> <!-- CORRECT -->
</property>
...

To allow a Page

  <element value="Document" />

To allow a Collection

  <element value="Topic" />

Happy Ploning!

Installing Django (1.1) and MySQL on Snow Leopard

A few days ago I posted my misadventures in setting up a Plone 3 buildout on Snow Leopard. That (fingers crossed) was a lot more complicated than getting Django going. However, I’ll also be installing MySQL (my database of choice) as a backend database. I’ll be foregoing Apache and mod_wsgi, as this is just a development instance.

Most of this is based on the excellent instructions available at the Django site

Working With What We’ve Got

The Macintosh Operating System, being the forward thinking platform that it is, already has Python 2.5 and 2.6 installed. Python 2.6 is the default (it’s the interpreter that starts when you type ‘python’ into the Terminal), and we’ll be sticking with that. It also includes Subversion, which we’ll use to download and update the Django trunk.

Where To Put Django

As my coding style has developed, I’ve gravitated more toward keeping Python libraries that need close management in my ‘home’ folder (/Users/kevin/ on my machine) and using symbolic links to get it on my Python path. It appears to me that everything installed under ‘/Library/’ is laid out quite nicely without any of my assistance, thank you very much.

Besides not wanting to play around with the system folders, there are a couple advantages to installing like this. First, I’ll want to update my Django installation as new code comes out, and it’s simpler to find stuff in your home folder. Second, keeping packages like Django in your home folder makes browsing the source code (a must in Open Source) much simpler.

You’ll see me use easy_install to get stuff for Pythons 2.5 and 2.6, but as a general rule if I have to manually install it it’s going in my home folder. For an alternative approach (i.e. installing Django in the local site-packages directory) see this post.

Getting MySQL

To paraphrase Billy Bob Thornton from The Bad News Bears, developing in Django without a database is kind of like kissing your sister. Let’s install MySQL.

There are lots of ways to install MySQL, including compiling and installing from source. As this is a Django development machine, I feel comfortable simply using an installer package. To my surprise, MySQL as of today doesn’t have a specific 10.6 installer package on their downloads page. No matter, we’ll just grab the 64-bit version for Mac OS X 5.

  1. Go to http://dev.mysql.com/downloads/mysql/5.5.html#downloads (for MySQL 5.5, the most current recommended version)
  2. Find the “Mac OS X 10.5 (x86_64)” under “Mac OS (package format)” and click “Pick a mirror”
  3. MySQL/Sun Microsystems will want to know everything about you. Go ahead and register.
  4. Pick a site, download the package, and double click to open the package
  5. Click “mysql-5.5.0-m2-osx10.5-x86_64.pkg” to begin the install
  6. OPTIONAL: click “mySQLStartupItem.pkg” to have MySQL start when you start your system
  7. Head’s Up!

    I don’t want MySQL running all the time, so I’m not going to install the MySQL Startup Item. That means that I’ll have to START MYSQL FROM TERMINAL EVERY TIME I WANT TO USE IT. I’ll show you how to make this simple a bit further down.

  8. OPTIONAL: click “MySQL.prefPane” to install a Preference Pane in the System Preference for MySQL (I didn’t do this either)
  9. Using your favorite text editor, create a new document called “.bash_profile” in your home directory (yes, the dot is supposed to be there). We’re going to add the MySQL directory to the PATH, allowing you to run MySQL commands by typing one string into the terminal (not the entire path). Add the following line to “.bash_profile” and save it.
  10. export PATH="$PATH:/usr/local/mysql/bin"
  11. You’ll need a root password for MySQL. Type the following command into Terminal, replacing “superduper” with a password you’ll remember
  12. mysqladmin -u root password superduper

To start MySQL, type the following into your Terminal

sudo mysqld_safe

You’ll be prompted for your system password. Enter it and MySQL will start running. You’ll need to leave a Terminal tab open to leaveit running. To stop MySQL, type Control+Z from the Terminal tab it’s running from. Now for Django itself.

Installing MySQLdb

MySQLdb is the Python library that let’s us manipulate a MySQLdb with Python code.

  1. Download the MySQLdb tarball from SourceForge.net
  2. Move the tarball to your user directory and un-tar it
    cd
    mv Downloads/MySQL-python-1.2.3c1.tar.gz MySQL-python-1.2.3c1.tar.gz
    tar xzvf MySQL-python-1.2.3c1.tar.gz
  3. Change into the directory your just created and install the library
    cd MySQL-python-1.2.3c1
    python setup.py install

Installing Django 1.1

Most of the Django sites I’ve installed at at version 1.1, but not all. I’ll also probably want to run the development version at some point as well. I’m going to set up the directories around Django with that in mind.

  1. Open Terminal, and create the following directory structure (some of which will already exist): /Users/kevin/src/django/core/. Working in our home directory…
    mkdir src
    cd src
    mkdir django
    cd django
    mkdir core
    cd core
  2. Download the latest stable version of Django 1.1 (it’s a tar.gz file, AKA a ‘tarball’)
  3. Unpack the Django tarball into the directory you created in step 1. Working in the ‘core’ directory…
    tar xzvf /Users/kevin/Downloads/Django-1.1.1.tar.gz
  4. Change into the directory you created in step 3
    cd Django-1.1.1
  5. Here is where I start deviating a little from the norm. I want to keep this code in my home directory, so I’m going to create a symbolic link to my Python SITE-PACKAGES directory that points to this version of Django. First, find your Site-Packages directory by typing this into Terminal
    python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

    In my case, this returned:

    /Library/Python/2.6/site-packages

    So, to make the symbolic link (from within the Django-1.1.1 directory), I type:

    ln -s $PWD/django /Library/Python/2.6/site-packages/django

    (change the path to match your own SITE-PACKAGES directory)

  6. I’m going to want django-admin.py in my path (and you will too). Create a symbolic link to /usr/local/bin:
    sudo ln -s /Users/kevin/src/django/core/Django-1.1.1/django/bin/django-admin.py /usr/local/bin
  7. Check that you’ve installed Django correctly by starting the Python Interpreter (type ‘python’ into the command line) and try importing Django
    >>> import django

    No errors = awesomeness

This method installing Django 1.1.1 as my default Django (the Django I get when I type ‘django’ into a Python Interpreter). If you wanted to simultaneously run a different version of Django, repeat this process with the tarball for that version (or checkout the trunk from Subversion). When you create the symbolic link, name it something other than ‘django’ (i.e. ‘django-1.1.1’ or ‘django-trunk’).

Plone Buildout on Snow Leopard… from the ground up

This is how I got a fresh Plone buildout up and running on my brand new iMac. I’m writing this mostly for my designer buddies here in Nashville, in the hopes that one day they will come to the light and start skinning Plone sites with me. We can dream can’t we?

Major thanks to Brian Gershon (without this blog post it would have taken me until the Ides of March to get through this), and especially Florian Schulze for his buildout that makes Python 2.4 on Snow Leopard a snap.

Step 1: Find Your Mac OS X Install DVD

Okay, if you’re like me, you don’t know where your install DVD is. Unless, of course, you’ve broken the seal on your new Mac less that 24 hours prior.

If you have your Install DVD:

  1. Insert the DVD, open it, and open “Optional Installs”
  2. Double click “Xcode.mpkg”
  3. Let Xcode install on your machine. It took me between 15 and 20 minutes.

If you DON’T have your Install DVD:

  1. Go to http://developer.apple.com/TOOLS/Xcode/
  2. Click “Download Latest Xcode”
  3. Create an ADC membership if you haven’t already (it’s free)
  4. Download the package (it’s a doozy, 2 GB+)
  5. Double click the package file after you’ve downloaded it
  6. Let Xcode install

Once you’ve gone through the install process, open up Terminal by going to Applications -> Utilities (go ahead and drag it to the dock, you’ll need it later). Type ‘gcc’ into Terminal and press Return. You should get something like the following:

i686-apple-darwin10-gcc-4.2.1: no input files

What’s that, you say? Why, that’s your brand new GNU C Compiler telling you it needs an input file before it can do anything! If you see something different, you probably had a problem installing Xcode.

Step 2: Installing Python 2.4 (and other goodies)

As I’m still working in Plone 3, I’ll have to install Python 2.4. SL ships with Pythons 2.5 and 2.6. Usually it’d be easy to install different versions of Python, but according to Brian’s post SL mangles up a Python 2.4 installation. Here come’s Florian’s buildout to the rescue.

NOTE: This installation method is specific to some problems that Snow Leopard had with Python 2.4. Details available here and on Brian’s blog.

To Install Python 2.4 and the rest of the gang:

  1. Open Terminal
  2. Create a new directory called ‘src’ in your home directory by typing in the following command
  3. mkdir src
  4. Move into that directory with this command
  5. cd src
  6. Checkout and run Florian’s buildout with the following commands
  7. svn co http://svn.plone.org/svn/collective/buildout/python/
    cd python
    python bootstrap.py
    bin/buildout

You should now be able to run Python 2.4 by typing the following code into Terminal:

python-2.4/bin/python2.4

That’s the Python2.4 deep inside your user directory. As it stands, you’d have to use the full path to that file to run Python 2.4. Let’s change that.

Symlinking Python 2.4 to the path:

The goal here is to be able to run Python 2.4 by simply typing “python2.4” into the Terminal. To accomplish this:

  1. Change to a directory in your path (I used /usr/bin)
  2. cd /usr/bin
  3. Type in the following command, substituting your username for “kevin”. You’ll have to type in your password, as we’re editing system files here (type carefully!)
  4. sudo ln -s /Users/kevin/src/python/python-2.4/bin/python2.4 python2.4
  5. Go back to your home folder, and try running Python 2.4 without the path
  6. cd ~
    python2.4

If you get a Python 2.4 interpreter (see below), you’re golden.

Python 2.4.6 (#1, Dec 29 2009, 23:33:05)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

While we’re at it, let’s symlink easy_install-2.4 as well. We’ll need this for ZopeSkel:

cd /usr/bin
sudo ln -s /Users/kevin/src/python/python-2.4/bin/easy_install-2.4 easy_install-2.4

If you ever happen to meet Florian Schulze, thank him for this buildout.

Step 3: Creating a Plone 3 Buildout (finally, right?)

To make a buildout, we’re gonna need Paster. To get Paster, we’re gonna need ZopeSkel. Let’s use that newly symlinked easy_install-2.4 to get ’em.

cd ~
easy_install-2.4 -U ZopeSkel

This installs what we need, but again deep in our user directory. A symlinking we will go:

cd /usr/bin
sudo ln -s /Users/kevin/src/python/python-2.4/bin/paster paster-2.4

Notice I named this particular Paster “paster-2.4”. That’s in case we ever install paster for a different version of Python, we’ll know which one is which.

Now let’s pick a home for our buildouts. I like to create a directory called “workspace” next to my “src” directory (sigh… good ol’ Eclipse). Make that directory, and move into it with these commands:

mkdir workspace
cd workspace

To start a new buildout, type the following command:

paster-2.4 create -t plone3_buildout myplone

Paster will ask you a lot of questions, like what version of Plone you want, and which Zope to use. Hit enter to accept all of the defaults. When Paster is done running, go into the directory you just created, bootstrap the buildout, and run buildout with the following commands:

cd myplone
python2.4 bootstrap.py
bin/buildout

If buildout ran without any errors, the last line of the Terminal output will look like this:

Generated interpreter '/Users/kevin/workspace/myplone/bin/zopepy'.

Step 4: Starting Plone

With our buildout created, now we simply start Zope with the following command:

bin/instance start

Point your browser to http://localhost:8080/manage_main, type in the username and password you supplied to Paster, and add a Plone site through the ZMI. Welcome to Plone on Snow Leopard!

HTML & CSS the Right Way: Part 1

With the glut of information and tutorials on writing HTML & CSS out there on the internet, it doesn’t seem to make much sense to write yet another how-to. However, considering the average quality of information out there is below par, confounded by the various (bad) coding styles in use, I’ve decided to write my own.

In the interest of accelerated learning, I’ll be skipping more basic code that isn’t best practice. For instance, you won’t see a style attribute in any of these following tutorials. All of our CSS from the very beginning will be housed in dedicated style sheets.

I’m not a designer, but I will talk some about layout and link to a couple great articles on turning Photoshop mockups into solid HTML & CSS. My focus instead will be on creating HTML documents as templates for dynamic websites, styled with CSS, using the least amount of code possible.

I’ll be making the following assumptions about you:

  1. You know how to open, edit, and save files on your computer
  2. You know how to open and use the basic text editor on your computer (NotePad for Windows, TextEdit for Mac, Text Editor for Ubuntu)
  3. You do not know anything about HTML. Some of my later posts will get slightly more advanced, but we’ll be starting from the ground up.

There are excellent, free resources on the internet that I’ll rely heavily upon. Generally speaking most of the links in these articles will point to Wikipedia or the W3 Schools. Wikipedia is the place to go if you want to wrap your head around a particular concept. For the nitty gritty on the implementation of a particular HTML tag or CSS rule, the W3 Schools website is your best bet (Googling a single tag almost always takes you directly to the W3 Schools).

So, first things first…

What is HTML?

HTML stands for Hypertext Markup Language. It the the basic programming language that web browsers (Internet Explorer, Firefox, etc.) are able to interpret. We use HTML to “mark up” a document or piece of text that we would like to display in a web browser.

For example, let’s say you wrote this piece of text:

Hello World!

…and you’d like to be able to display it on the web. Let’s try this now:

You’re First Web Page

  1. Create a new directory on your desktop, called “test”, and open it (directory is another word for folder)
  2. Open your text editor, and save a file called “index.html” in the directory you just created.
  3. To confirm that you created the right type of file, notice that the icon for “index.html” in the “test” directory has changed to the icon for your default web browser
  4. With “index.html” open in your text editor, enter the following code:
  5. <html>
        <head>
        </head>
        <body>
            <p>Hello World!</p>
        </body>
    </html>
  6. Save “index.html”, and double click it to open it in your your browser.

You’ve just created your first web page. Now let’s take a closer look at what we just did:

How HTML Works

  • An HTML document is made up of “elements” wrapped in “tags”. For example, the <p>Hello World!</p> bit would be an element wrapped in a paragraph tag. Tags usually have an opening tag (without a forward slash) and a closing tag (with a forward slash). In English, you are telling the web browser “When you see <p>, display everything after that as a paragraph until you come to</p>”
  • The entire HTML document is wrapped in an HTML tag. You’re telling the web browser “Hey, all this stuff you’re about to read is HTML”
  • HTML documents have “heads” and “bodies”. These two elements are present in almost every HTML document. The <body> tag denotes all of the information that will be displayed in the body of the web page. The <head> element will contain instructions for the web browser about displaying that information. More on <head> later.
  • HTML elements are nested. Did you notice that the <p> element is inside the <body> element? It has to be that way for the <p> element to work right. In HTML, elements can be wrapped in any number of tags. You would nest a tag within another tag if you wanted the effects of both tags to work on that element. For example, change “index.html” to this:
  • <html>
        <head>
        </head>
        <body>
            <p>Hello World! It's going to be a <strong>great</strong> day.</p>
        </body>
    </html>

See the difference? The <strong> makes text bold. It’s nested inside the <p>, making the word ‘great’ both bold and a part of the paragraph.

Now try adding a new paragraph:

<html>
    <head>
    </head>
    <body>
        <p>Hello World! It's going to be a <strong>great</strong> day.</p>
        <p>I can't believe I ate the whole thing. The quick brown fox
           jumped over the lazy dog. The rain in Spain falls mainly
           on the plain.</p>
    </body>
</html>

HTML Headings

Here, you create a new paragraph, and it shows up in the web page below the first. Now, let’s add a couple heading tags, <h1> and <h2>:

<html>
    <head>
    </head>
    <body>
        <h1>My first webpage</h1>
        <p>Hello World! It's going to be a <strong>great</strong> day.</p>
        <h2>Some famous quotes</h2>
        <p>I can't believe I ate the whole thing. The quick brown fox
           jumped over the lazy dog. The rain in Spain falls mainly
           on the plain.</p>
    </body>
</html>

HTML provides six different sizes of headings: <h1>, <h2>, <h3>, <h4>, <h5> and <h6>. Here’s how they are rendered on this page:

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

They probably look a little different on your “index.html”, don’t they? That’s because this page uses CSS to manipulate the appearance of those tags on this page. Will talk more about CSS in Part 2 of “HTML & CSS the Right Way”

Take Aways:

  • We use HTML to “markup” a document for display in a web browser. HTML is the markup, NOT THE CONTENT.
  • If you want to tell a web browser how to display something, you have to wrap it in HTML tags

Tags Learned:

  • <html>, <head>, and <body> (the basic structure of an HTML document)
  • <p> : paragraph
  • <strong> : bold
  • <h1> – <h6> : various levels of headings

Exercises:

  • Practice using these tags in index.html
  • Play around with the HTML examples at W3 Schools
  • Make “index.html” look exactly like this page. You can copy and paste the text, but don’t copy and paste the code!

Looking for Tiny RML2PDF?

One of the million and a half dependencies for Satchmo (the web store project for Django), Tiny RML2PDF seems to be the best kept secret on the web. Google it and you’ll get page after page of broken links to download the thing. So here’s one more working link to download it, the one that I finally found:

http://ftp.debian.org/debian/pool/main/p/python-trml2pdf/

Chris Moffitt also put one here: http://www.satchmoproject.com/snapshots/

A note on installation: it’s nothing fancy. Just unpack the tarball, cd into the first trml2pdf directory, and move the internal trml2pdf directory into your Python path.