Generic Python Decorators
1 de Agosto de 2011, 0:00 - sem comentários ainda<p>The past days I came across a need to check specific attributes in a class instance before calling a specific method of it. I decided to use decorators, but my problem was that I needed to check different attributes and I would like to do it without duplicating code and also in an elegant way. So I started to check how I could create decorators in a generic way, to be reusable, something that would end up as the following:</p> <pre class="brush:py">class Obj(object): @need_foo def foo(self): return self._foo @need_bar def bar(self): return self._bar o=Obj() o.foo() AttributeError: Attr _foo not specified.</pre> <p>Then it turned out that I could have two possibilities. The two implementations basically do exactly the same thing, the only difference is that one is simply a function and the other one is a class based decorator that have the flexibility of all resources of a class over a function. It doesn’t mean you will always use it, but it gives you the power.</p> <pre class="brush:py">class CheckAttr(object): """ Class decorator to help checking whether an attribute of an object is set before calling the wanted (decorated) method. This class decorator must be instantiated with a 'attr' and 'message', which are respectively the attr name to be checked and the exception message in case it was not set yet. """ def __init__(self, attr, message): self.attr = attr self.message = message def __call__(self, func): def _wrapper(*args, **kwargs): if not getattr(args[0], self.attr, None): raise AttributeError(self.message) return func(*args, **kwargs) return _wrapper def check_attr(attr, message): """ Decorator to help checking whether an attribute of an object is set before calling the wanted (decorated) method of an object. This decorator must be called with a 'attr' and 'message', which are respectively the attribute name to be checked and the exception message in case it was not set yet. """ def _check_func(func): def _wrapper(*args, **kwargs): if not getattr(args[0], attr, None): raise AttributeError(message) return func(*args, **kwargs) return _wrapper return _check_func # # DECORATOR WRAPPERS # # def need_bar(func): return CheckAttr('_bar', 'Attr _bar not specified.')(func) def need_qux(func): return check_attr('_qux', 'Attr _qux not specified.')(func) </pre> <p>The code above allow us to use those two kinds of decorators in the following ways. Examples on how to invoke the code are in the docstrings as doctest:</p> <pre class="brush:py">class Obj(object): """ >>> o = Obj() >>> o.foo() Traceback (most recent call last): ... AttributeError: Attr _foo not specified. Use `bind_foo`. >>> o.bar() Traceback (most recent call last): ... AttributeError: Attr _bar not specified. >>> o.baz() Traceback (most recent call last): ... AttributeError: Attr _baz not specified. Use `bind_baz`. >>> o.qux() Traceback (most recent call last): ... AttributeError: Attr _qux not specified. """ # Calling the class based decorator directly @CheckAttr('_foo', 'Attr _foo not specified. Use `bind_foo`.') def foo(self): return self._foo def bind_foo(self, foo): self._foo = foo # Calling the class based decorator using a wrapper @need_bar def bar(self): return self._bar # Calling the function based decorator directly @check_attr('_baz', 'Attr _baz not specified. Use `bind_baz`.') def baz(self): return self._baz def bind_baz(self, baz): self._baz = baz # Calling the function based decorator using a wrapper @need_qux def qux(self): return self._qux </pre> <p>In the end I used the function based decorator with the wrappers (@need_attribute), because it was enough for what I wanted. But it’s quite obvious now to me that decorators can be used in much more powerful ways.</p>
FISL 12
18 de Julho de 2011, 0:00 - sem comentários aindaHow nice was to be one more time at FISL. It was my 5th edition and it could have been the 6th, if I haven’t had missed the 2010 one. I remember well when back there, 5 years ago, I and a friend of mine took a bus and went to Porto Alegre for our first contact with the Free Software community. At that time I wasn’t involved to any FOSS effort, but that was definitely a starter point to me.
FISL is all about meeting people, opportunities and making friends. You can find practically any kind of geek over there and for the major part of those, you will just be able to meet them in person again in the next FISL.
This year I have met a bunch of ‘old’ FISL guys, people that I have been in touch since FISL 6 and some other new guys. Great people. From those, I couldn’t not mention the Fedora guys. This year we had the current Fedora Project leader, Jared Smith, among us and it was really cool to meet him in person.
I’m really glad that I was able to make it this year. We had a presentation about Transifex in the main schedule and also got mentioned in the speakers list of the event. Hopefully the video of the presentation (in pt_BR) will be available in the following weeks, but you can find the slides here for now.
Dear (Slovenian) Translator
17 de Fevereiro de 2011, 0:00 - sem comentários aindaLast week we came across an issue involving a request from Django. A person from the Slovenian team filed a ticket on the Django system asking to change the plural equation for the translation files. Once Django is now officially using Transifex for managing its translations, this ended up here to us.
Long short history…
Transifex plural rules are based on this document. The possible plural rules currently supported are 6, *always* in the respect order:
zero, one, two, few, many, other
The ‘other’ rule is the general exception for anything that doesn’t fit into the other rules. For Japanese, for example, that doesn’t have plural forms, it only uses the ‘other’ rule and nothing else.
According to the document above, Slovenian has 4 plural rules, which are:
one → n mod 100 is 1;
two → n mod 100 is 2;
few → n mod 100 in 3..4;
other → everything else
For the PO file format, the plural equation for the above would be:
(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)
Which means that for a sl.po with a plural entry, we would have the following mapping:
msgstr[0] → one
msgstr[1] → two
msgstr[2] → few
msgstr[3] → other
Back to the initial issue, for some reason good part of the Slovenian teams across the FOSS world started to prefer to use the following plural equation:
(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0)
This results in the following swapping of position:
msgstr[0] → other
msgstr[1] → one
msgstr[2] → two
msgstr[3] → few
This, as far as I know, because the ‘zero’ rule, which actually doesn’t exist for the language, just fits as the ‘other’ rule and in this way the ‘one’ and ‘two’ rules would have a synchronized msgstr index (e.g. msgstr[1] → one).
So, dear Slovenian translator, is there any other reason for doing it that I’m not aware of?
Changing that because of the above seems just wrong to me. And I would like to ask a greater audience of people that might be interested on it, before taking any decision on the Transifex side.
Django Database Router using settings
10 de Fevereiro de 2011, 0:00 - sem comentários aindaIt’s been a while without passing here… but let’s not talk about it!
So, this week I just came across an issue related to how to setup multiple databases on Django. Reading the documentation I found it quite trivial to setup. After having the databases configured, you can use a Database Router, if you want to automatically route your app models, or use .using(‘db1′) manually on your queries, specifying the wanted database.
As I didn’t want to specify the databases on the queries in my code, so I decided to use the Database Router, which is, by the way, a very nice solution for such a problem. Looking at the example on the Django docs, I realized that the example was only covering the routing of an unique app. Looking further, I also noticed that it was a bit tied with placeholders related to the app and the database names inside the class. Then I asked myself:
Couldn’t it be more generic and reusable for more than one app?
Searching a bit on the Web I couldn’t find anything. Having that in mind, I came with the following code that can be used to specify several apps using different databases. Everything just using a single settings variable and in a very simple way:
from django.conf import settings class DatabaseAppsRouter(object): """ A router to control all database operations on models for different databases. In case an app is not set in settings.DATABASE_APPS_MAPPING, the router will fallback to the `default` database. Settings example: DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'} """ def db_for_read(self, model, **hints): """"Point all read operations to the specific database.""" if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label): return settings.DATABASE_APPS_MAPPING[model._meta.app_label] return None def db_for_write(self, model, **hints): """Point all write operations to the specific database.""" if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label): return settings.DATABASE_APPS_MAPPING[model._meta.app_label] return None def allow_relation(self, obj1, obj2, **hints): """Allow any relation between apps that use the same database.""" db_obj1 = settings.DATABASE_APPS_MAPPING.get(obj1._meta.app_label) db_obj2 = settings.DATABASE_APPS_MAPPING.get(obj2._meta.app_label) if db_obj1 and db_obj2: if db_obj1 == db_obj2: return True else: return False return None def allow_syncdb(self, db, model): """Make sure that apps only appear in the related database.""" if db in settings.DATABASE_APPS_MAPPING.values(): return settings.DATABASE_APPS_MAPPING.get(model._meta.app_label) == db elif settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label): return False return None
I hope the code can self explain what each one of those methods do. And, of course, it’s a generic solution that might be customized as needed.
Django reverse with JavaScript
16 de Julho de 2010, 0:00 - Um comentárioTaking the cobwebs out of here…
Here I go to cite a way that can ‘solve’ the URL reversing problem when you are using a Django app that uses some JavaScript and Ajax requests.
Django has a very nice way to resolve URLs based on its name and optionally some args. It uses the regex pattern defined in the related urls.py file of the given app. Example:
from django.core.urlresolvers import reverse
reverse(‘project_detail’, args=['foo'])
‘/projects/p/foo/’reverse(‘project_detail’, args=['bar'])
‘/projects/p/bar/’
The problem turns when you want to make a Ajax request based on some dynamic data from a form or something. As some URL sometimes need arguments to be resolved, we can’t always pre-reverse and attach them to the Context, on the Django response.
For the record, I found an alternative here. With it you can take the args from the browser and request through Ajax to Django the resolved URL. It’s pretty cool, but I think it was a bit expensive to multiply by 2 the number of requests to the server.
It made me think on another approach, where I would pre-fill in the Context response of Django, the URL already resolved, but with named args like, %(project)s, for the required arguments. I ended up with this:
from django.core.urlresolvers import get_resolver
def get_url_pattern(urlname):
“”"
Return URL pattern for a URL based on its name.>>> get_url_pattern(‘project_deails’)
u’/projects/p/%(project_slug)s/’“”"
return ‘/%s’ % get_resolver(None).reverse_dict.get(urlname)[0][0][0]
As you can notice. Passing a URL name to that function will give you the resolved URL with named args. I’m not really sure about corner cases, so feel free to give any comment on it.
Once you have the URL as a string with named args, you can use this JQuery plugin, to resolved the named args using only JavaScript.
… and That’s it!