• Notes
  • Tags
  • Python
  • python -m compatibility

    As we all know, python -m name can run module named name that is present in PYTHONPATH. Also it can run package, if there is __main__ module inside of that package (actually, it will run that module).

    Running module with python -m in Python ≥ 2.4 is okay. But beware of running packages this way in Python 2.4, 2.5 and 2.6.

    • Python
    · Wednesday, July 13th
  • Django 1.3 and as_html decorator

    Why we use as_html decorator (known as render_to)? Because we need to provide context_instance argument to render_to_response function:

    from django.template import RequestContext
    from django.shortcuts import render_to_response
    
    
    def show_entry(request, slug):
        entry = get_object_or_404(Entry, status=Entry.statuses.published, slug=slug)
        return render_to_response(
            'blog/entry.html',
            {'entry': entry},
            context_instance=RequestContext(request)
        )
    

    We write less code with decorator:

    from common.decorators import as_html
    
    
    @as_html('blog/entry.html')
    def show_entry(request, slug):
        entry = get_object_or_404(Entry, status=Entry.statuses.published, slug=slug)
        return {'entry': entry}

    This is just example, normally we should use generic view. Now let’s see how our view will change, if we’ll use new render shortcut:

    from django.shortcuts import render
    
    
    def show_entry(request, slug):
        entry = get_object_or_404(Entry, status=Entry.statuses.published, slug=slug)
        return render(request, 'blog/entry.html', {'entry': entry})

    Just few changes, but the latter is better. Ivan Sagalaev wrote nice comment about render_to decorator, but another reason not to use it is that template name is at the start of function while dictionary of values is at the end. It’s good to keep all template-related code in one place, at the end of your function.

    • Python
    • and Django
    · Friday, April 29th
  • Template rendering in webapp

    For some people writing code like this in every handler’s method isn’t very good:

    path = os.path.join(os.path.dirname(__file__), 'index.html')
    self.response.out.write(template.render(path, template_values))

    I totally agree with them, so I wrote very simple subclass of webapp.RequestHandler:

    from os.path import join, dirname
    
    from google.appengine.ext import webapp
    from google.appengine.ext.webapp import template
    
    
    class RequestHandler(webapp.RequestHandler):
    
        def render(self, tmpl, ctx={}):
            if hasattr(self, 'get_additional_ctx'):
                ctx.update(self.get_additional_ctx())
            path = join(dirname(__file__), 'templates/', tmpl)
            self.response.out.write(template.render(path, ctx))

    Example usage:

    from google.appengine.api import users
    
    from util import RequestHandler
    
    
    class AdminRequestHandler(RequestHandler):
    
        def get_additional_ctx(self):
            return {
                'logout_url': users.create_logout_url(self.request.uri),
            }
    
    
    class IndexHandler(AdminRequestHandler):
    
        def get(self):
            self.render('admin/index.html', {'greeting': 'Hello, World!'})

    This is not the only way to do this, but the simplest.

    • Python
    • and webapp
    · Tuesday, November 9th
  • Abbreviations in Python code

    When you need to code fast, efforts to type “transaction” look somewhat funny. Why don’t just use abbreviations that will save you from a lot of typing? However, they need to be consistent, so some system of abbreviations is necessary.

    kw
    kwargs
    inst
    instance
    txn
    transaction
    ctx
    context
    pth (sometimes is useful)
    path
    cls
    class
    fmt
    format
    mw
    middleware
    th
    thread
    dfd
    deferred
    cb
    callback
    tmpl
    template
    fn
    filename
    dir
    directory
    ext
    extension
    app
    application

    Beta testing:

    pr
    processor (thing that is called middleware in Django)
    fs
    formset
    cmd
    command

    For futher reading: PEP 8, Sergey Schetinin’s style guide and Pocoo’s one.

    • Python
    · Monday, November 8th
  • Django project organization

    I was asked to write about “correct” django project’s structure at least twice. To be honest, I’m not very enthusiastic about this because there is no silver bullet in this case. Structure of the project must evolve with project and must be determined by its needs. But I can suggest some techniques that may help (I also must note that most of them may be used somewhere already).

    Django is Python code. Structure your code as you need. When models.py is too long, split it (but don’t forget about app_label). Some people tend to split out Manager subclasses into managers.py (or managers package) even if it's very likely that it will be the only Manager in file, but I'd not recommend you to do that unless you have few large Managers.

    Though render_to decorator is rather popular now, I suggest to name it as_html. So now you can have decorator family: as_xml, as_json, etc. Use feed and confirm decorators (wisely; maybe I’ll publish them someday :) Let’s assume you have a view:

    @feed
    @as_html('questions/list.html')
    def questions_list(request):
        questions = Question.active.last(50)
        return {'objects': questions}

    Now /questions/ URL will show rendered template and /questions/rss/ will show RSS 2.01 feed. You can use confirm decorator like this:

    @confirm(messages={
        'confirmation': 'Do you really want to delete this question?',
        'success': 'Question deleted',
        'error': 'You can\'t delete this question'},
        #action=lambda obj: obj.delete(),  # this is assumed by default
        #cancel=lambda obj: obj.get_url_path(),  # this is assumed by default
        #authorize=lambda obj, user: obj.can_be_deleted_by(user),  # this is assumed by default
        redirect_to=lambda obj: reverse('questions_list'))
    def delete_question(request, id):
        question = get_object_or_404(Question, id=id)
        return {'obj': question}

    It works like lorien’s confirmation processor, but it’s, you know, decorator :) Also few pagination decorators exist.

    For futher reading I’d recommend you Django Project Conventions, revisited by Zachary Voase, Django Best Practices by Lincoln Loop and then search for “django project structure” in your favourite search engine.

    • Python
    • and Django
    · Sunday, November 7th
  • Writing Werkzeug routing converter

    Recently I finished project, where I needed to support legacy URLs with paths like this:

    /path/to/something/741,2345,2858739,991,3241,2556,3453.aspx

    Project uses Werkzeug’s routing, so the only thing I needed to do is to write converter and then somehow handle values in views.

    import re
    
    from werkzeug.routing import BaseConverter, ValidationError
    
    
    class IntListConverter(BaseConverter):
        def __init__(self, url_map, separator):
            super(IntListConverter, self).__init__(url_map)
            self.regex = r'(\d%s?)+' % re.escape(separator)
            self.separator = separator
    
        def to_python(self, value):
            values = value.strip(self.separator).split(self.separator)
            return map(int, values)
    
        def to_url(self, values):
            return self.separator.join(map(str, values))

    Then I added rule and converter to URL map:

    url_map = Map(
        [
            # ...
            Rule('/path/to/something/<intlist(separator=","):values>.aspx',
                 endpoint='someapp/someview'),
        ],
        strict_slashes=True,
        converters={'intlist': IntListConverter},
    )
    
    

    You can go on and create ListConverter that takes additional type_ argument to convert each value of list to some Python type.

    • Python
    • and Werkzeug
    · Tuesday, October 5th
  • How to use elementflow-based iterator’s results in other elementflow-based iterator

    Elementflow is a Python library for generating XML as a stream. Some existing XML producing libraries (like ElementTree, lxml) build a whole XML tree in memory and then serialize it. It might be inefficient for moderately large XML payloads (think of a content-oriented Web service producing lots of XML data output). Python's built-in xml.sax.saxutils.XMLGenerator is very low-level and requires closing elements by hand. Also, most XML libraries, to be honest, suck when dealing with namespaces.

    Let’s assume we have a fridge with products on its shelves that is represented by this code:

    FRIDGE = (
        {
            'sausage': 1,
            'cake': 3,
        },
        {
            'juice': 1,
            'apple': 7,
        },
        {
            'water': 17,
        },
    )

    Our goal is to produce XML like this:

    <?xml version="1.0" encoding="utf-8"?>
    <fridge>
      <shelf>
        <product name="cake" quantity="3"/>
        <product name="sausage" quantity="1"/>
      </shelf>
      <shelf>
        <product name="juice" quantity="1"/>
        <product name="apple" quantity="7"/>
      </shelf>
      <shelf>
        <product name="water" quantity="17"/>
      </shelf>
    </fridge>
    

    There is nothing special about XML generation for fridge, except that we want to reuse shelf generator (that can be used without fridge :) By default elementflow’s XML generators output XML declaration, but in the middle of the document that wouldn’t be nice. So we need to write generator that can accept declaration argument (which can be True or False).

    import elementflow
    
    
    BUFSIZE = 1024
    
    
    class IndentingGenerator(elementflow.IndentingGenerator):
    
        def __init__(self, file, root,
                     attrs={}, namespaces={}, declaration=True, **kwargs):
            super(IndentingGenerator, self).__init__(file, root,
                                                     attrs, namespaces, **kwargs)
    
            if not declaration:
                self.file.pop()
                self.container(root, attrs, **kwargs)

    It’s not elegant solution, but it works. Now let’s write XML generation:

    def shelf_to_xml(shelf, declaration=True):
        xml = IndentingGenerator(elementflow.Queue(), 'shelf',
                                 declaration=declaration)
        with xml:
            for name, quantity in shelf.items():
                xml.element('product', {'name': unicode(name),
                                        'quantity': unicode(quantity)})
    
                if len(xml.file) > BUFSIZE:
                    yield xml.file.pop()
    
        yield xml.file.pop()
    
    
    def fridge_to_xml(fridge):
        with IndentingGenerator(elementflow.Queue(), 'fridge') as xml:
            for shelf in fridge:
                for chunk in shelf_to_xml(shelf, declaration=False):
                    xml.file.write(chunk.decode('utf-8'))
    
                    if len(xml.file) > BUFSIZE:
                        yield xml.file.pop()
    
        yield xml.file.pop()

    And now let’s test:

    print(''.join(fridge_to_xml(FRIDGE)))

    It works.

    • Python
    • and XML
    · Monday, September 20th
  • Sort dict’s keys by values

    Can we actually sort a Python’s dict? No, but we can sort a list that contains its keys and values.

    A simplest way to do this is to use a sort method:

    >>> d = {'c': 100, 'a': 0, 'b': 10}
    >>> items = d.items()
    >>> items.sort(lambda x, y: cmp(x[1], y[1]))
    >>> items
    [('a', 0), ('b', 10), ('c', 100)]

    We can use a key argument to make function call a bit shorter:

    >>> items = d.items()
    >>> items.sort(key=lambda i: i[1])
    >>> items
    [('a', 0), ('b', 10), ('c', 100)]

    Also we can use a sorted built-in:

    >>> sorted(d.iteritems(), key=lambda i: i[1])
    [('a', 0), ('b', 10), ('c', 100)]

    But what if we care about speed? According to Gregg Lind, the fastest solution uses operator.itemgetter (that is suggested in PEP 265 named “Sorting Dictionaries by Value”) instead of lambda function:

    >>> from operator import itemgetter
    >>> sorted(d.iteritems(), key=itemgetter(1))
    [('a', 0), ('b', 10), ('c', 100)]

    This version is 10x faster than first three.

    • Python
    · Sunday, August 29th
  • pymongo and binary data

    Let’s imagine we need to save zlib-compressed string.

    >>> import zlib
    >>> s = '...'
    >>> compressed = zlib.compress(s) # type(compressed) == str

    Here’s a problem: an exception will be raised if we’ll try to save it into DB as-is. pymongo uses unicode, while compressed is an instance of str. And we can’t just .decode('utf-8') it.

    >>> collection.insert({'c': compressed})
    ---------------------------------------------------------------------------
    InvalidStringData                         Traceback (most recent call last)
    .../env/lib/python2.6/site-packages/pymongo/collection.pyc in insert(self, doc_or_docs, manipulate, safe, check_keys) 211 212 self.__database.connection._send_message( --> 213 message.insert(self.__full_name, docs, check_keys, safe), safe) 214 215 ids = [doc.get("_id", None) for doc in docs]
    InvalidStringData: strings in documents must be valid UTF-8

    But we can use Binary from pymongo.binary:

    >>> from pymongo.binary import Binary
    >>> collection.insert({'c': Binary(compressed)})

    Now it works.

    • Python,
    • NoSQL
    • and MongoDB
    · Monday, March 1st

© 2006–2012 Pavlo Kapyshin (@)