Feed on
Posts
Comments

Ok. I’m usually not posting such stupid stuff. But I couldn’t hold myself this time.

I came into my bed room where I had this bed-linen with pictures of lizards, turtles, chameleons and other creatures. Then I saw something quickly moving from the sheet to the blanket. Looks like it came to life from the pictures. Amazing isn’t it?

(click on the picture for a larger version)

If you are like me, spending a lot of time in the command line, you might be looking for ways to edit the command lines more efficiently. Many interactive UNIX programs implement line editing by using GNU’s readline library. This means that all these programs, which include the different shells, Python and many others, offer the same set of keyboard shortcuts. Mastering these shortcuts is worthwhile, since you’ll be able to use them over and over again in many places.

Moving around quickly

The most basic part is to move to the place you want to edit quickly. Here are the most useful shortcuts:

  • Ctrl-a - Move to the start of the line.
  • Ctrl-e - Move to the end of the line.
  • Alt-f - Move forward a word.
  • Ctrl-f - Move forward a char.
  • Alt-b - Move backward a word.
  • Ctrl-b - Move backward a char.

Another very common shortcut is Ctrl-L which clears the screen and reprints the current line at the top. This is useful if you are organizing your movies library and somebody enters the room.

Cut, Paste and Undo

Here is the list of most useful shortcuts for deleting text:

  • Ctrl-w - Deletes from cursor position to the previous whitespace.
  • Ctrl-k - Deletes from cursor position to the end of the line.
  • Ctrl-d - Deletes from current character.
  • Ctrl-u - Deletes from whole line.
  • Alt-d - Deletes from cursor position to the end of the current word.
  • Alt-DEL - Deletes from cursor position to the start of the current word.

The deleted text can be pasted (yanked) using Ctrl-y. You can use Ctrl-_ or Ctrl-X-U to undo the last editing command.

Summary

This covers the essentials. On the next parts of this series we’ll explore the more powerful abilities of readline. Feel free to leave here questions, suggestions, or perhaps your own tips and tricks.

Filters 0.1 Released

Filters is a Python package that provides shell-like data processing operators for generation of web content. Filters is designed to work together with a template-engine like Kid and Genshi.

What is a filter?

We’ll start with an example.

${ identity.is_anonymous() | tg.yesno() }


The output of this will be the value returned by is_anonymous() after being processed by the yesno filter, which translates a boolean to either “yes” or “no”.

Some filters can do really cool stuff. For instance, consider this:

  • {{ file_size | tg.filesizeformat() }}: this would print the size in a human-readable format (i.e. 17 KB, 102.4MB and so on).
  • {{ story.text | tg.escape() | tg.linebreaks() }}: this will escape all ampersands from the text and then convert all newlines to <p> and <br/>. This also demonstrates that filters can be chained.
  • You have {{egg_count}} egg{{egg_count | tg.pluralize()}} left: will pluralize the egg noun with the suffix ’s’ if egg_count is not one.

The main goal of Filters is to provide a rich set of easy-to-use operations that are commonly needed in real-world applications.

After implementing this in a form of patches for Kid and Genshi, Christopher Lenz from Genshi suggested a way to implement this externally to the parsers. The idea is based on this recipe from the Python Cookbook. This solution enjoys the benefits of using pure Python syntax. This means that we are now using single bar (|) again.

Here’s how to use it.

Download and install

Get this: Filters-0.1.tar.gz. Extract the archive and run python setup.py install.

Hook into TurboGears

Go to controllers.py, add add the following lines:

from filters.core import tg_add_variables
tg_add_variables()

If you’d like to have the filters under their own namespace, replace the last line by:

tg_add_variables(pollute=False)


And the filters will be available under tg.filters instead of under tg.

Using filters

Here are some examples demonstrating how to use filters:

${ identity.is_anonymous() | tg.yesno() }

You have ${count} cherr${count | tg.pluralize('y,ies') }.

Note that filters accept their argument in parenthesis. The paranthesis are required even if there are no arguments.

Writing your own filters

Basically, a filter is just a function that takes input and possibly some arguments, and returns an output, that will
be passed to the next filter, or to the output. The Filters package provide two decorators to help you with filters. The first is make_filter that transforms your function to a filter class, and the second is register_filter which registers your filter and makes it available inside templates. Here’s how to use it:

from filters.core import register_filter, make_filter

@register_filter()
@make_filter()
def shorturl(input, max_length=50):
    return input.split('?')[0][:max_length]

Then, inside your template:

${ my_url | tg.shorturl() }

or

${ my_url | tg.shorturl(25) }

Good luck, and feel free to leave here questions or comments.

This post is deprecated and superseded by this post.


I’ve had a look recently at Django’s templates. I know most of my readers are fans of TurboGears, so if you are one of them, hold yourself from throwing tomatoes at me - I was only playing with it. It was nothing serious.

Then, I came back to Kid, and started to miss Django’s filters. These filters are a lot like UNIX pipes. You can do things like: {{ identity.is_anonymous() | yes_no }}. The output of this will be the value returned by is_anonymous() after being processed by the yes_no filter, which translates a boolean to either “yes” or “no”.

Some filters can do really cool stuff. For instance, consider this:

  • {{ file_size | filesizeformat }}: this would print the size in a human-readable format (i.e. 17 KB, 102.4MB and so on).
  • {{ story.text | escape | linebreaks }}: this will escape all ampersands from the text and then convert all newlines to <p> and <br/>. This also demonstrates that filters can be chained.
  • You have {{egg_count}} egg{{egg_count | pluralize}} left: will pluralize the egg noun with the suffix ’s’ if egg_count is not one.

“But you can achieve the same by using the existing functional notation!”, I see you thinking. “You can do {{ linebreaks(escape(story.text)) }}. And it has the benefits of using a pure Python expression”. That’s right. But having pipe-notation:

  • is 217% more fun, since it is more intuitive and readable
  • makes it easy to build a standard library of filters which can be commonly used, to the benefit of the frameworks’ users.
  • makes it easy to add project-specific filters, without having to pass them as a template variable (they aren’t).
  • adds a new dimension to Kid or Genshi. Currently they work great on the XML level, which is their primary design goal. But a bit lacking on text interpolation capabilties. The stuff surrounded by those XML tags also matters :)

Then, I thought that there should be no reason that this will not be easy to implement with Kid (or Genshi). Fast forward 30 minutes, and it is now possible to do all the above in Kid. To comply to Kid and Python syntax, it is done with double pipes:

${ story.text || escape || linebreaks }

or

${ story.link || urlize }

The last one converts URLs in the text to a clickable link.

To get a rich set of filters to start with, I just borrowed Django’s default filters module. It was fairly easy to disconnect the dependency of most on them on Django. I threw away the rest for the time being. Adding your own filter is also extremely easy. You can just add to controllers.py the following:

def handle_shorturl(s):
    """Returns the URL without the query string"""
    return s.split('?')[0]

from kid.filterslib import register_filter
register_filter(’shorturl’, handle_shorturl)

If you’d like to start playing with it as well, I’ve prepared two patches, against Kid 0.9.3 and Kid 0.9.4:

To apply the patch, just cd into the kid directory and type: patch -p1 < djangokid-0.9.4.patch.

For a superset of what is currently implemented, see: Django built-in filter reference.

UPDATE: I’ve added also a patch for Genshi.

I’m looking forward for your feedback.

This post is deprecated and superseded by this post.

In this tutorial I’ll show you how to create a simple, yet powerful, tagging system using SQLAlchemy with TurboGears. As the concept of tags, and social tagging in particular, have become very popular, clients now demand “tagging-enabled” applications. So, here’s a simple way to get you started.

Our application will associate sites with tags (many to many relationship), like delicious does, but in a much simplified manner. For instance, delicious keeps tracks of which user gave which tag to which URL. We will only associate sites with tags. But it will be very easy to add this functionality later.

We’ll quickstart a new project (the -s argument tells tg-admin that the project will use SQLAlchemy and not SQLObject)

$ tg-admin quickstart -s tags
Enter package name [tags]:
Do you need Identity (usernames/passwords) in this project? [no] yes

Defining The Model

We are going to have a table for the sites, a table for the tags and a table that associates sites with tags (many-to-many). Here’s the code which defines the tables (which goes in model.py):

sites_table = Table(’sites’, metadata,
        Column(’site_id’, Integer, primary_key=True),
        Column(‘title’, Unicode(256)),
        Column(‘url’, Unicode(1024)),
        )

tags_table = Table(‘tags’, metadata,
        Column(‘tag_id’, Integer, primary_key=True),
        Column(‘name’, Unicode(32), index=‘tag_idx’))

sites_tags_table = Table(’sites_tags’, metadata,
        Column(’site_id’, Integer,
              ForeignKey(’sites.site_id’),
              primary_key=True),
        Column("tag_id", Integer,
              ForeignKey(‘tags.tag_id’),
              primary_key=True))

We will now create the Python classes that correspond to these tables:

class Tag(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name
    def link(self):
        return "/tags/"+self.name

class Site(object):
    def __init__(self, url, title):
        self.url, self.title = url, title

Note the link() method in the Tag class. You might wonder what it does there. It just a little habbit that I wanted to share with you. I’ve found myself many times hard-coding URLs inside my templates. Then, if you want to make a tag linkable in many different places in your app, you have to hard-code the link every time. In this way, you can just pass the tag object to your template and do something like:

<a href="${tag.link()}">${tag.name}</a>

Ok, now we continue with mapping the classes to the tables:

mapper(Tag, tags_table)
mapper(Site, sites_table, properties = {
    ‘tags’: relation(Tag, secondary=sites_tags_table, lazy=False),
    })

Great. Now we can construct the database and start populating it:

$ tg-admin sql create
$ tg-admin shell

>>> g = Site(‘http://www.google.com’, ‘Search engine’)
>>> g.tags
[]
>>> g.tags = [Tag(’search’), Tag(‘google’)]
>>> session.save(g)
>>> session.flush()
(here SQLAlchemy echos the SQL statements it executes)

Handling tags

So we got the model right. The next step is to allow the users to provide tags for the site. The easiest way (for you and your users) is to ask them to enter the tags in a space-separated list. Suppose you are given this kind of space-seperated string of tags from a user, then you have to:

  • convert all tags to lower case, in order to avoid case senstivity issues
  • check if the string contains the same tag twice
  • find which tags are already in the database and which are new
  • recover from some nonsense that users might throw at you

and then get a list of Tag objects that you can assign to a site. So here’s a function that does just that:

def get_tag_list(tags):
    """Get a string of space sperated tag,
    and returns a list of tag objects"
""
    result = []
    tags = tags.replace(‘;’,‘ ‘).replace(‘,’,‘ ‘)

    tags = [tag.lower() for tag in tags.split()]
    tags = set(tags)        # no duplicates!
    if in tags:
        tags.remove()

    for tag in tags:
        tag = tag.lower()
        tagobj = session.query(Tag).selectfirst_by(name=tag)
        if tagobj is None:
            tagobj = Tag(name=tag)
        result.append(tagobj)
    return result

So you can now easily do something like:

>>> f = Site(‘http://www.flickr.com’, ‘Flickr!’)
>>> f.tags = get_tag_list(‘photo sharing photograpy’)
>>> f.tags
[photo, sharing, photograpy]
>>> f.tags[0].link()
‘/tags/photo’

Tag Search

It is straightforward to just list a site together with its tags:

<h3 class="site-title"><a href="${site.url}" target="_blank">${site.title}</a></h3>
        <p class="site-tags">Tags:
        <a py:for="tag in site.tags[:5]" href="${tag.link()}" class="tag">${tag.name}</a>
        </p>

Search is a bit more tricky. It took me few attempts until I got the search queries right. Here’s how to fetch all sites that are tagged by ‘google’:

    q = session.query(Site)
    sites = q.select((Tag.c.name==‘google’) &amp; q.join_to(‘tags’))

the magic is mostly inside the join_to method - it stands for the SQL statements that makes sure that the Tag clause is associated to the sites. Without it, the query runs over the entire cartesian product of Sites x Tags.

You can make the query simpler (for MySQL; not you), if you fetch the tag_id of ‘google’ first. Then, the query uses only 2 of the 3 tables:

    tagobj = session.query(Tag).get_by(name=‘google’)
    if not tagobj:
        raise cherrypy.InternalRedirect(‘/notfound’)
    sites = session.query(Site).select((sites_tags_table.c.tag_id == tagobj.tag_id) &amp;
                 (sites_tags_table.c.site_id == Site.c.site_id))

To search for google|photo:

q = session.query(Site)
sites = q.select(
    Tag.c.name.in_(‘google’, ‘photo’) &amp;
        q.join_to(‘tags’))

To search for sharing+photos:

q = session.query(Site)
sites = q.select(
    Tag.c.name.in_(’sharing’,‘photos’) &amp;
        q.join_to(‘tags’),
    group_by=[Site.c.site_id],
    having=(func.count(Site.c.site_id)==2))

The idea is that sites that are tagged both with ’sharing’ and ‘photos’ will appear twice in the select, then after grouping by site_id and getting all which appear twice, we get the desired result.

There are many more things that can be done from this point, like: associating with the tag-site relationship which user added the tag, rendering a tag cloud and so on. Feel free to leave comments!

Webilder 0.5 Released

Webilder is a great way to have beautiful wallpapers on your GNOME or KDE desktop. You tell Webilder what flickr tags to follow and relevant photos are downloaded to your computer. Very simple. So how Webilder is related to TurboGears?

It occured to me that it would be nice to have a place where people can share the tags they are watching. It can become a good place to find ideas for wallpapers, or just to find good tag combinations. That’s how Webilder Channels was born.

Webilder Channels is a very simple TurboGears application. It lets you search for tags, and see the popular ones. Next to the popular channels (these are tag combinations), there are a few photos from that channel. A cronjob running on the server is responsible to query Flickr from time to time and to make sure the database contains URLs of most interesting photos for that channel.

The same TurboGears application also manages the user votes and suggestions - it has an API controller which is called from the desktop application.

Download Webilder, and have high quality wallpapers on your desktop today!

Internet Explorer is known to cache the responses of GET calls. The problem occurs if your javascript functions request the same url over and over again. Internet Explorer will cache the response of the first call, and subsequent calls will automatically return the same response, without actually contacting the server. There are two approaches to solve this problem.
Continue Reading »

I remember that day about a month ago, when it occured to me it is high time that I write some unit tests for my project. In the beginning, it felt like travelling where no man has gone before - a lot of technical issues to settle. I introduced my BrowserSession class to aid stateful unit testing few days ago. From responses that I got, it seems that a lot of people are still fighting with the technicalities of setting up the testing environment. So I took the time to give some hints and tips on the matter. Attached to this post is a project which demonstrates simple identity tests (that work).
Continue Reading »

Lately I’ve started to write many unit tests for my secret turbogears project. My secret project, like many other web 2.0 applications, can have a lot of users logged in at the same time and the actions of one user can affect other users.

The current testing tools provided by TurboGears do not give “one obvious way” to test multi-user scenarios. I came up last week with a simple class that will emulate a browser session of a single user against a cherrypy server. Its only task is actually to keep track of the visit cookie. Continue Reading »

Sign up to BlueHost

I have been a customer of BlueHost (a very friendly web hosting provider) since I’ve created the Python Challenge, about a year ago. A short time later, I’ve added to my account the domain thesamet.com which I use as my personal homepage and blog. Recently, I’ve started working with TurboGears and wondered whether BlueHost could host my application. Fortunately, it was quite easy to do so.

UPDATE: BlueHost does not officially support TurboGears. Furthermore, FastCGI is much slower and difficult to work with than mod_rewrite. Therefore, I prefer to spend a few more extra bucks a month and get an hosting plan in WebFaction, where deployment of a TurboGears application is a matter of point and click.

Continue Reading »

« Newer Posts