Posts de ‘Igor Sobreira’

[Igor Sobreira] Book review: Being Geek

Thursday, December 29th, 2011

Published on: 28/12/2011 23:50h

I’ve finished reading this book, Being Geek, by Michael Lopp, an experienced engineering manager from Silicon Valley. And recommend it…

It’s a book about geeks professionalism, career. I liked the way the author exposes his ideas, he’s clear and pragmatic. Right in the second chapter there are these three questions I think it’s worth pointing out:

  1. Are you actively defining the technical direction for your product?
  2. Do you understand what you need to do in order to grow?
  3. Are you hitting your dates? Are you meeting your commitments? Are you doing what you say you’re going to do?

That’s it! That’s what you need to ask yourself every day. Those answers will make you realize if this job is being useful for you to archive your professional goal in your life.

Later in the book he talks about task management, to-do lists and so on. And a very interesting one he calls “The Trickle List”. This is not a simple to-do list for that day. It’s a list of tasks you do every day with a bigger goal in mind, in the future. If you want to be a better engineer, every day you may want to learn something, improve on something, read something. I suddenly realized I was missing this list…

Well, I liked the book. I was not very excited reading the first chapters. But as I continued reading it just got better and better. The author writes comfortably about our career, being an engineer or a manager. The book is full of good advices based on experience. Hiring process, remote working, giving presentations, etc.

By Igor Sobreira

[Igor Sobreira] Command line interface to FMS Admin

Monday, December 26th, 2011

Published on: 25/12/2011 13:29h

I’ve been working with Flash Media Server for the last 8 months now, and
one tool that really annoys me is the Administration Console. I miss a
command line interface to accomplish tasks like see all live streams, reload
an app, etc.

That’s why I’ve started the fms-admin-api. It’s a command line
client to Flash Media Server Administration API.
Since it’s written in ruby, it’s possible to use the ruby client class directly.
Use rubygems to install:


$ gem install fms-admin-api

The way it works is really simple. Here is an example: there is a reloadApp() method available
that accepts the arguments host, auser,
apswd and appInst. The command line interface just replaces
from camelCase syntax to underscore:


$ fmsapi reload_app –host=fms.example.com –auser=fms –apswd=secret –app_inst=live

There are improvements to be made
and help is welcome.

By Igor Sobreira

[Igor Sobreira] Change object after saving all inlines in Django Admin

Wednesday, October 19th, 2011

Published on: 12/02/2011 11:45h

UPDATE Aug, 2011: This patch added a new hook to ModelAdmin called save_related(). Now you don’t the hack described bellow anymore.


Admin is an awesome Django builtin app to create nice CRUDs for your models, and offers a lot of customizations hooks. You can personalize the templates, perform custom filters, modify newly created objects and if that’s not enough, you can always create your own view to do something it doesn’t by default.

The admin docs are great, I’m not going to explain how it works. The intention here is to show a way to modify an object, after it’s saved, and other objects related to it using inlines are saved too.

Once you’ve configured your admin interface with inlines, you end up with something similar to:

from django.contrib import admin
from fooapp.models import Foo, Related

class RelatedInline(admin.TabularInline):
    model = Related

class FooAdmin(admin.ModelAdmin):
    inlines = [RelatedInline]

admin.site.register(Foo, FooAdmin)

this mean whens you’re adding a Foo, since Related has a foreign key to it, django will display a few forms to add Relateds in the same page.

Imagine you need to do something with the new foo instance that needs to now how many related objects it has. Admin already has methods you can override to do something after Foo is saved, like ModelAdmin.save_model(). See how it works:

class FooAdmin(admin.ModelAdmin):
    inlines = [RelatedInline]

    def save_model(self, request, obj, form, change):
        obj.save()
        # do something with obj.related_set.all()
        # OPS! it's empty!

admin.site.register(Foo, FooAdmin)

the problem here is that save_model() is called before the inlines are saved.

Let’s find out how it works. Open django source code, specifically in django.contrib.admin.options.py go to add_view(), it’s the view called when you are creating an object. As you can see, when the request method is “POST” it goes through all validation, for the main form and all related formsets (your inlines). And if all of then are valid it calls save_model(), then save_formset() for each formset. The interesting piece is shown below:

class ModelAdmin(BaseModelAdmin):

    # ...

    def add_view(self, request, form_url='', extra_context=None):

        # ... all validation here ...

        if all_valid(formsets) and form_validated:
            self.save_model(request, new_object, form, change=False)
            form.save_m2m()
            for formset in formsets:
                self.save_formset(request, form, formset, change=False)

            self.log_addition(request, new_object)
            return self.response_add(request, new_object)

Notice here that the last method it calls is response_add(), and it passes the created object, that’s all we need! If you see the change_view() method (witch it the view called when you’re editing an object) it calls a similar method: response_change().

Now we can solve our problem doing something like this:

class FooAdmin(admin.ModelAdmin):
    inlines = [RelatedInline]

    def response_add(self, request, new_object):
        obj = self.after_saving_model_and_related_inlines(new_object)
        return super(FooAdmin, self).response_add(request, obj)

    def response_change(self, request, obj):
        obj = self.after_saving_model_and_related_inlines(obj)
        return super(FooAdmin, self).response_change(request, obj)

    def after_saving_model_and_related_inlines(self, obj):
        print obj.related_set.all()
        # now we have what we need here... :)         return obj

There are two things to keep in mind when using these methods:

  • They are not documented. So probably it’s not part of the API admin expects you to override. Thankfully django publishes excellent release notes including backwards incompatible changes. And I hope you have good test coverage to know if it will break when you update django :)
  • Their intention is to handle the response of the view, as it docstring says: “Determines the HttpResponse for the add_view stage”. So if you do something there not related to it, it works, wont make much sense if you look at the overall architecture.

Maybe django will add a more specific hook to solve this issue later, but I hope it helps you for now.

By Igor Sobreira

[Igor Sobreira] Adding methods dynamically in Python

Wednesday, October 19th, 2011

Published on: 06/02/2011 20:50h

Given the dynamic nature of Python you can do many things in runtime, like add methods dynamically to an object or class. This is particularly useful when writing unit tests.

Here is the simplest way, adding a method to and object:

class Person(object):
    pass

def play():
    print "i'm playing!"

p = Person()
p.play = play
p.play()

note that play is just a function, it doesn’t receive self. There is no way to p knows that it’s a method. If you need self, you must create a method and then bind to the object:

from types import MethodType

class Person(object):
    def __init__(self, name):
        self.name = name

def play(self):
    print "%s is playing!" % self.name

p = Person("igor")
p.play = MethodType(play, p)
p.play()

In these examples, only the p instance will have play method, other instances of Person won’t. To accomplish this we need to add the method to the class:

class Person(object):
    def __init__(self, name):
        self.name = name

def play(self):
    print "%s is playing!" % self.name

Person.play = play

p1 = Person("igor")
p1.play()

p2 = Person("joh")
p2.play()

note that we don’t need to create a method with types.MethodType here, because all functions in the body of a class will become methods and receive self, unless you explicit say it’s a classmethod or staticmethod.

Adding methods to builtin types

Python doesn’t allow to add methods to builtin types, actually to any type defined in C. The unique way around this is to subclass the type, here is an example:

class UpperList(list):
    pass

def to_upper(self):
    for index, item in enumerate(self):
        self[index] = item.upper()

UpperList.to_upper = to_upper

l = UpperList(['i','g','o','r'])
l.to_upper()
print l

Here is a nice comparison on dynamically adding methods in Python and Ruby.

By Igor Sobreira

[Igor Sobreira] Mocks, Stubs, Fakes and Spies

Wednesday, October 19th, 2011

Published on: 15/12/2010 01:05h

Reading the Continous Delivery book I found a good definition of mocks, fakes, stubs and spies:

  • “Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production. A good example of this is the in-memory database.
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.
  • Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.
  • Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don’t expect and are checked during verification to ensure they got all the calls they were expecting.”

This terminology was taken from xUnit Test Patterns book.

I’ve already seen cases where people write lot’s of unit tests, abusing from mock objects, but without good integration and acceptance tests you can’t really guarantee that each scenario is really working as expected.

“It’s very easy to misuse mocks to write tests that are both pointless and fragile, using them simply to assert the specific details of the workings of some code, rather than an assertion of interactions with collaborators.”

A couple links if you want to read more about it:

[Igor Sobreira] Extending the User model in Django

Wednesday, October 19th, 2011

Published on: 11/12/2010 00:20h

Django brings a built-in user authentication system, it includes an User model which has the most common attributes. But in most applications you may need to store additional attributes to users. Django has a way to do this too.

Extending using foreign key

Basically you create your UserProfile model with a OneToOneField to User:

class UserProfile(models.Model):

    user = models.OneToOneField('auth.User')

    bio = models.TextField()

    # ...

and define in on settings.py

AUTH_PROFILE_MODULE = 'accounts.UserProfile'     # app name (dot) model name

From now on your User objects will have a get_profile() method.

I personally can’t see a reason to use this setting (and I hate “getters” methods), you just need to do this:

class UserProfile(models.Model):

    user = models.OneToOneField('auth.User', related_name='profile')

    bio = models.TextField()

    # ...

See the related_name='profile' parameter, now you don’t need the get_profile() method anymore, just use user_instance.profile.

But there is a small problem here, if the user instance don’t have a profile related to it you will receive an ObjectDoesNotExist exception. This happens with get_profile() too. And it’s not good to handle the exception every time you access the profile. The simplest way to solve this is connect to django.db.models.signals.post_save on the User model and create your UserProfile instance related to it

from django.db.models import signals

from accounts.models import UserProfile

def create_user_profile(sender, instance, created, **kwargs):

    if created:

        UserProfile.objects.create(user=instance)

signals.post_save.connect(create_user_profile, sender=User)

Why subclassing User is a bad idea

There are a few reasons I prefer to create user profiles as another model instead of just subclassing the default User. If you think for a while, an user has a lot to do in your site, and there are at a few default steps:

  • first she needs to register, confirm by email, and so on
  • login and logout, change and reset password
  • admins may need to manage groups and permissions, to restrict user actions, offer features to specific groups
  • manage profile, with personal information

Django doesn’t handle the first topic, there is a great app to handle registration.

The second and third topics can be done with django.contrib.auth app, this is exactly it’s purpose.

And then you have the forth topic, which is profiles. As you can see, it can be done as a separate app. A user has a profile. So makes sense to have a profile attribute in the User object.

If you split features in apps like this it’s easier to reuse too, that’s the idea of django apps after all! The django-registration is an example. And as you can imagine, there are apps to manage profiles too.

Editing User profile in admin

If you’re using admin you may want to edit the UserProfile fields in the same page as the User fields, and it’s possible using admin inlines. Here is how you admin configuration will look like:

from django.contrib import admin

from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin

from django.contrib.auth.models import User

from accounts.models import UserProfile

class UserProfileInline(admin.TabularInline):

    model = UserProfile

class UserAdmin(DjangoUserAdmin):

    inlines = (UserProfileInline,)

admin.site.unregister(User)

admin.site.register(User, UserAdmin)

Conclusion

As you can see, it quite easy to manage user profiles in django. Although there is a way to hook you profile model in settings.py, you can do it with a simple foreign key. And as usual, there are a few reusable apps around to handle the generic stuff.

By Igor Sobreira

[Igor Sobreira] Campos numéricos localizados no Django

Wednesday, October 19th, 2011

Published on: 25/09/2010 14:42h

A criação de campos numéricos ficou muito mais fácil no Django na versão 1.2. Imagine o seguinte model:

class Debito(models.Model):

    descricao = models.CharField(max_length=256)

    valor = models.DecimalField(max_digits=10, decimal_places=2)

    def __unicode__(self):

        return self.descricao

E seu registro no admin

admin.site.register(Debito)

Ao tentar cadastrar um valor numérico, por exemplo: 1.450,60, receberíamos um erro já que esse formato não era entendido como numérico. Agora, basta informar que esse campo precisa ser localizado. Como isso é feito no formulário, e não no model, vamos sobrescrever o formulário padrão do admin

class DebitoForm(forms.ModelForm)

    valor = forms.DecimalField(max_digits=10, decimal_places=2, localize=True)

    class Meta:

        model = Debito

class DebitoAdmin(admin.ModelAdmin):

    form = DebitoForm

admin.site.register(Debito, DebitoAdmin)

Note o parâmetro localize no campo DecimalField do formulário.

Estamos quase lá, só precisamos nos certificar de que as seguintes configurações estão no settings.py

USE_L10N = True         # essa é padrão

USE_THOUSAND_SEPARATOR = True

Mas ainda tem um detalhe, se você tentar acessar debito.valor vai receber uma instância da classe decimal.Decimal do python, e ainda terá que formatar manualmente. Felizmente o django já possui uma função pra fazer isso. Para facilitar, você pode adicionar um método no seu model:

from django.utils.formats import number_format

class Debito(models.Model):

    descricao = models.CharField(max_length=256)

    valor = models.DecimalField(max_digits=10, decimal_places=2)

    def __unicode__(self):

        return self.descricao

    @property

    def valor_formatado(self):

        return u"R$ %s" % number_format(self.valor, 2) 

Agora sim, basta acessar debito.valor_formatado.

Confira a documentação para mais detalhes.

Até a próxima!

By Igor Sobreira

[Igor Sobreira] Slides: Desenvolvimento web com Python e Django

Wednesday, October 19th, 2011

Published on: 08/11/2010 21:23h

Segue os slides da minha palestra Desenvolvimento web com Python e Django.

Apresentei essa palestra no Jatic, na faculdade Facisa em Campina Grande, PB. E também no CITOS, na faculdade Univem, em Marília, SP.

A maior parte da apresentação fala sobre Django, mas também mostra como funciona o WSGI, as maneiras mais comuns de fazer deployment de aplicações em python hoje em dia, configuração de ambiente usando virtualenv, testes…

Desenvolvimento web com python e django

Veja outras aprensentações minhas no Slideshare.

By Igor Sobreira

[Igor Sobreira] Difference between _, __ and __xx__ in Python

Wednesday, October 19th, 2011

Published on: 16/09/2010 02:27h

When learning Python many people don’t really understand why so much underlines in the beginning of the methods, sometimes even in the end like __this__! I’ve already had to explain it so many times, it’s time to document it.

One underline in the beginning

Python doesn’t have real private methods, so one underline in the beginning of a method or attribute means you shouldn’t access this method, because it’s not part of the API. It’s very common when using properties:

class BaseForm(StrAndUnicode):

    ...

    def _get_errors(self):

        "Returns an ErrorDict for the data provided for the form"

        if self._errors is None:

            self.full_clean()

        return self._errors

    errors = property(_get_errors)

This snippet was taken from django source code (django/forms/forms.py). This means errors is a property, and it’s part of the API, but the method this property calls, _get_errors, is “private”, so you shouldn’t access it.

Two underlines in the beginning

This one causes a lot of confusion. It should not be used to mark a method as private, the goal here is to avoid your method to be overriden by a subclass. Let’s see an example:

class A(object):

    def __method(self):

        print "I'm a method in A"

    def method(self):

        self.__method()

a = A()

a.method()

The output here is


$ python example.py 

I'm a method in A

Fine, as we expected. Now let’s subclass A and customize __method

class B(A):

    def __method(self):

        print "I'm a method in B"

b = B()

b.method()

and now the output is…


$ python example.py

I'm a method in A

as you can see, A.method() didn’t call B.__method() as we could expecte. Actually this is the correct behavior for __. So when you create a method starting with __ you’re saying that you don’t want anybody to override it, it will be accessible just from inside the own class.

How python does it? Simple, it just renames the method. Take a look:


a = A()

a._A__method()  # never use this!! please!

$ python example.py

I'm a method in A

If you try to access a.__method() it won’t work either, as I said, __method is just accessible inside the class itself.

Two underlines in the beginning and in the end

When you see a method like __this__, the rule is simple: don’t call it. Why? Because it means it’s a method python calls, not you. Take a look:

>>> name = "igor"

>>> name.__len__()

4

>>> len(name)

4



>>> number = 10

>>> number.__add__(20)

30

>>> number + 20

30

There is always an operator or native function that calls these magic methods. The idea here is to give you the ability to override operators in your own classes. Sometimes it’s just a hook python calls in specific situations. __init__(), for example, is called when the object is created so you can initialize it. __new__() is called to build the instance, and so on…

Here’s an example:

class CrazyNumber(object):

    def __init__(self, n):

        self.n = n

    def __add__(self, other):

        return self.n - other

    def __sub__(self, other):

        return self.n + other

    def __str__(self):

        return str(self.n)

num = CrazyNumber(10)

print num           # 10

print num + 5       # 5

print num - 20      # 30

Another example:

class Room(object):

    def __init__(self):

        self.people = []

    def add(self, person):

        self.people.append(person)

    def __len__(self):

        return len(self.people)

room = Room()

room.add("Igor")

print len(room)     # 1

The documentation covers all these special methods.

Conclusion

Use _one_underline to mark you methods as not part of the API. Use __two_underlines__ when you’re creating objects to look like native python objects or you wan’t to customize behavior in specific situations. And don’t use __just_to_underlines, unless you really know what you’re doing!

By Igor Sobreira

[Igor Sobreira] Customize settings.py locally in Django

Wednesday, October 19th, 2011

Published on: 12/09/2010 19:22h

The django configuration file is pure python code, this gives us a lot of flexibility to setup settings when the application starts. Actually you could even modify settings in runtime, but promise me you won’t do this, ever!

Imagine you have an open-source django project, you have your code in github or something like that, but you probably don’t want to publish your DATABASES configuration. Or maybe you can add all your server configuration under version control, it’s private, great, but your local configuration is probably different too, you will need to set DEBUG = True at least.

There are a few ways to extend the settings.py file…

Use the –settings option

The manage.py command has a –settings option that you can use to specify a different settings file, so you could have a local_settings.py file similar to:

from settings import *

DEBUG = True

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.sqlite3',

        'NAME': 'db.sqlite',

        'USER': '',

        'PASSWORD': '',

        'HOST': '',

        'PORT': '',

    }

}

And locally you use:

$ python manage.py runserver –settings=local_settings

This is the simplest way to extend the settings.py file and is probably enough for most situations, but let’s take a look in other options.

Importing from settings.py

This method is the opposite from above. In the end of your settings.py you add:

try:

    from local_settings import *

expect ImportError:

    pass

Now you local_settings.py file won’t need to import anything from settings.py, just set your configuration variables. And you don’t need to pass –settings anymore.

Adding code dynamically to settings.py

This is similar to the method above but gives you more flexibility. Imagine you need a local_settings.py file similiar to this:

DEBUG = True

INTERNAL_IPS = ('127.0.0.1',)

MIDDLWARE_CLASSES = MIDDLWARE_CLASSES + ('debug_toolbar.middleware.DebugToolbarMiddleware',)

INSTALLED_APPS = INSTALLED_APPS + ('debug_toolbar',)

How could you use MIDDLWARE_CLASSES or INSTALLED_APPS from settings.py if you didn’t import those? Here is the answer:

import os

PROJECT_ROOT = os.path.dirname(__file__)

try:

    execfile(os.path.join(PROJECT_ROOT, 'local_settings.py'), globals(), locals())

except IOError:

    pass

The trick here is the execfile function, it reads the content of the file and appends it to the file you calling from. In the end, it’s like the contents of you local_settings.py file are inside settings.py.

Host specific settings

Now you already have a way to customize your settings locally, just create a local_settings.py file, don’t add it under version control, and add one of these code snippets in the end of your settings.py.

But what if you need specific settings per host? You have this project that runs on multiple servers, and you want specific settings for each one. You could create a settings_SERVER_HOSTNAME.py file, and import dynamically:

import socket

import os

PROJECT_ROOT = os.path.dirname(__file__)

settings = 'settings_%s.py' % socket.gethostname()

try:

    execfile( os.path.join(PROJECT_ROOT, settings), globals(), locals())

except IOError:

    pass

To view your hostname just execute:

$ hostname

globo-mac

so, in my case I have a file called settings_globo-mac.py

Conclusion

That’s it! How I said in the beginning, settings.py is just python, this gives us a lot of power to customize our settings dynamically. If you have another idea let us know.

See you!

By Igor Sobreira