Blog entries

  • iclassmethod decorator to define both a class and an instance method in one go

    2009/04/28 by Sylvain Thenault

    You'll find in the logilab.common.decorators module the iclassmethod decorator which may be pretty handy in some cases as it allows methods to be both called as class methods or as instance methods. In the first case the first argument will be the class and the second case it will be the instance.

    Example extracted (and adapted for simplicity) from CubicWeb:

    from logilab.common.decorators import iclassmethod
    class Form(object):
      _fields_ = []
      def __init__(self):
          self.fields = list(self._fields_)
      def field_by_name(cls_or_self, name):
          """return field with the given name and role"""
          if isinstance(cls_or_self, type):
              fields = cls_or_self._fields_
              fields = cls_or_self.fields
          for field in fields:
              if == name:
                  return field
          raise Exception('FieldNotFound: %s' % name)

    Example session:

    >>> from logilab.common import attrdict
    >>> f = Form()
    >>> f.fields.append(attrdict({'name': 'something', 'value': 1})
    >>> f.field_by_name('something')
    {'name': 'something', 'value': 1}
    >>> Form.field_by_name('something')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 15, in field_by_name
    Exception: FieldNotFound: something

    So we get a field_by_name method which will act differently (actually use different input data) when called as instance method or as class method.

    Also notice the attrdict trick that can also be achieved with the Python 2.6 named tuple.

  • Discovering logilab-common Part 1 - deprecation module

    2010/09/02 by Stéphanie Marcu

    logilab-common library contains a lot of utilities which are often unknown. I will write a series of blog entries to explore nice features of this library.

    We will begin with the logilab.common.deprecation module which contains utilities to warn users when:

    • a function or a method is deprecated
    • a class has been moved into another module
    • a class has been renamed
    • a callable has been moved to a new module


    When a function or a method is deprecated, you can use the deprecated decorator. It will print a message to warn the user that the function is deprecated.

    The decorator takes two optional arguments:

    • reason: the deprecation message. A good practice is to specify at the beginning of the message, between brackets, the version number from which the function is deprecated. The default message is 'The function "[function name]" is deprecated'.
    • stacklevel: This is the option of the warnings.warn function which is used by the decorator. The default value is 2.

    We have a class Person defined in a file The get_surname method is deprecated, we must use the get_lastname method instead. For that, we use the deprecated decorator on the get_surname method.

    from logilab.common.deprecation import deprecated
    class Person(object):
        def __init__(self, firstname, lastname):
            self._firstname = firstname
            self._lastname = lastname
        def get_firstname(self):
            return self._firstname
        def get_lastname(self):
            return self._lastname
        @deprecated('[1.2] use get_lastname instead')
        def get_surname(self):
            return self.get_lastname()
    def create_user(firstname, lastname):
        return Person(firstname, lastname)
    if __name__ == '__main__':
        person = create_user('Paul', 'Smith')
        surname = person.get_surname()

    When running we have the message below: DeprecationWarning: [1.2] use get_lastname instead
    surname = person.get_surname()


    Now we moved the class Person in a file. We notice in the file that the class has been moved:

    from logilab.common.deprecation import class_moved
    import new_person
    Person = class_moved(new_person.Person)
    if __name__ == '__main__':
        person = Person('Paul', 'Smith')

    When we run the file, we have the following message: DeprecationWarning: class Person is now available as new_person.Person
    person = Person('Paul', 'Smith')

    The class_moved function takes one mandatory argument and two optional:

    • new_class: this mandatory argument is the new class
    • old_name: this optional argument specify the old class name. By default it is the same name than the new class. This argument is used in the default printed message.
    • message: with this optional argument, you can specify a custom message


    The class_renamed function automatically creates a class which fires a DeprecationWarning when instantiated.

    The function takes two mandatory arguments and one optional:

    • old_name: a string which contains the old class name
    • new_class: the new class
    • message: an optional message. The default one is '[old class name] is deprecated, use [new class name]'

    We now rename the Person class into User class in the file. Here is the new file:

    from logilab.common.deprecation import class_renamed
    from new_person import User
    Person = class_renamed('Person', User)
    if __name__ == '__main__':
        person = Person('Paul', 'Smith')

    When running, we have the following message: DeprecationWarning: Person is deprecated, use User
    person = Person('Paul', 'Smith')


    The moved function is used to tell that a callable has been moved to a new module. It returns a callable wrapper, so that when the wrapper is called, a warning is printed telling where the object can be found. Then the import is done (and not before) and the actual object is called.


    The usage is somewhat limited on classes since it will fail if the wrapper is used in a class ancestors list: use the class_moved function instead (which has no lazy import feature though).

    The moved function takes two mandatory parameters:

    • modpath: a string representing the path to the new module
    • objname: the name of the new callable

    We will use in, the create_user function which is now defined in the file:

    from logilab.common.deprecation import moved
    create_user = moved('new_person', 'create_user')
    if __name__ == '__main__':
        person = create_user('Paul', 'Smith')

    When running, we have the following message: DeprecationWarning: object create_user has been moved to module new_person
    person = create_user('Paul', 'Smith')