Ir al contenido principal

This is my blog, more about me at marianoguerra.github.io

🦋 @marianoguerra.org 🐘 @marianoguerra@hachyderm.io 🐦 @warianoguerra

Decoradores, introspeccion y señales

Jugando un poco con decoradores y el modulo inspect por primera vez, se me ocurrió intentar reemplazar alguna funcionalidad de gobject.

La funcionalidad que implemente primero, que es bastante útil, es la de notificar a un objeto cuando un atributo de otro objeto cambia, por ejemplo, es útil para la lista de usuarios saber cuando el atributo "status" de un contacto cambia.
Lo que quería, era que las clases "notificadoras" y las clases "notificables" no tuvieran tanto código feo de manejo de eventos, para eso, decidí ver si los decoradores eran la solución, parece ser que si.

ejemplo, una clase "TestObject" tiene un atributo llamado "attribute" con las properties de get/set.
Eel código seria así:


class TestObject(object):
'''a class that have a property called attribute'''

def __init__(self, attribute):
'''class contructor'''
self._attribute = attribute

def set_attribute(self, attribute):
'''set the value of self._attribute'''
self._attribute = attribute

def get_attribute(self):
'''return the value of attribute'''
return self._attribute

attribute = property(fget=get_attribute, fset=set_attribute)


si, ya se que el property en ese caso es al pedo, pero va a ser requerido mas adelante, así que lo pongo :D.

ahora, una clase que desea ser notificada cuando el atributo "attribute" de la clase "TestObject" cambia.
El código seria mas o menos así:


class TestNotificable(object):
'''a class that is notified when an attribute on other object changes'''

def __init__(self):
'''class constructor'''
pass

def on_property_changed(self, obj, attr_name, method_name,
old_value, new_value):
'''method called when an attribute is changed
on an object that we are attached to
'''
print("%s: %s changed in %s(%s).%s from %s to %s" % \
(str(id(self)), attr_name, obj.__class__.__name__,
str(id(obj)), method_name, repr(old_value),
repr(new_value)))



no hay mucha magia, solo lo que necesitamos, un atributo y un método el cual es llamado cuando este atributo cambia

imaginen que haciendo:


obj = TestObject(5)
notificable = TestNotificable()
obj.attach(notificable)
obj.attribute = 10


la salida fuera:


3084746540: attribute changed in TestObject(3084722988).set_attribute from 5 to 10


estaría bueno, pero cuantas lineas habría que agregar a cada clase para eso?
si mis cálculos no fallan, 2 lineas a TestObject y ninguna a TestNotificable.

el código de las clases seria:


import signals

class TestNotificable(signals.Notificable):
'''a class that implements the notificable interface'''

def __init__(self):
'''class constructor'''
pass

def on_property_changed(self, obj, attr_name, method_name,
old_value, new_value):
'''method called when a method with the
@notify_change decorator from a signal.Object is called
'''
print "%s: %s changed in %s(%s).%s from %s to %s" % \
(str(id(self)), attr_name, obj.__class__.__name__,
str(id(obj)), method_name, repr(old_value),
repr(new_value))

class TestObject(signals.Object):
'''a class that have a property that notify when it's changed'''

def __init__(self, attribute):
'''class contructor'''
signals.Object.__init__(self)
self._attribute = attribute

@signals.notify_change
def set_attribute(self, attribute):
'''set the value of self._attribute'''
self._attribute = attribute

def get_attribute(self):
'''return the value of attribute'''
return self._attribute

attribute = property(fget=get_attribute, fset=set_attribute)


una función para probar el ejemplo:


def test():
'''test the implementation of signals'''
obj = TestObject(5)

notificable = TestNotificable()
obj.attach(notificable)

obj.attribute = 10

notificable1 = TestNotificable()
obj.attach(notificable1)

print("")
obj.attribute = None
print("")

notificable2 = TestNotificable()
obj.attach(notificable2)

try:
obj.attach("")
print("[EE] doesn't catch not notificables being attached")
except TypeError:
print("catch not notificables being attached")

notificable = None

if len(obj.notificables) == 2:
print("clean the list if a reference is removed")
else:
print("[EE] doesn't clean the list if a reference is removed")

print("")
obj.attribute = True

obj.deattach(notificable2)
print("\nshould show 1 notification\n")
obj.attribute = []

notificable1 = None

if len(obj.notificables) == 0:
print("clean the list if a reference is removed")
else:
print("[EE] doesn't clean the list if a reference is removed")

obj.attribute = "shouldn't be shown"

if __name__ == '__main__':
test()


que produce la salida:


3083871212: attribute changed in TestObject(3083871244).set_attribute from 5 to 10

3083871212: attribute changed in TestObject(3083871244).set_attribute from 10 to None
3083221740: attribute changed in TestObject(3083871244).set_attribute from 10 to None

catch not notificables being attached
clean the list if a reference is removed

3083221740: attribute changed in TestObject(3083871244).set_attribute from None to True
3083222572: attribute changed in TestObject(3083871244).set_attribute from None to True

should show 1 notification

3083221740: attribute changed in TestObject(3083871244).set_attribute from True to []
clean the list if a reference is removed


el código de signals.py es el siguiente:


import weakref
import inspect

'''a module that implement classes and methods to do signals on a pythonic
way
'''

class Object(object):
'''a class that represent an object that can call other objects
to notify about a changed property, must be used with the
@notify_change decorator, the classes that want to register
to receive notifications over property changes must inherit from
the Notificable interface
'''

def __init__(self):
'''class constructor'''
# a list of weakrefs
self.notificables = []

def notify_property_change(self, attr_name, method_name,
old_value, new_value):
'''call the on_property_changed of all the objects on the list
'''
# uncomment the code below to have a nice debug of the changes
# made to the properties on the objects that inherit from this
# class
#print("%s: %s changed in %s(%s).%s from %s to %s" % \
# (str(id(self)), attr_name, obj.__class__.__name__,
# str(id(obj)), method_name, repr(old_value),
# repr(new_value)))

for notificable in self.notificables:
notificable.on_property_changed(self, attr_name, method_name,
old_value, new_value)

def attach(self, notificable):
'''attach an object that implement the Notificable interface,
add a weakref so it's deleted when the other reference to the
object are 0
'''

if Notificable not in notificable.__class__.mro():
raise TypeError("the object must implement Notificable")

self.notificables.append(weakref.proxy(notificable,
self.__clean_refs))

def deattach(self, notificable):
'''remove the notificable obect from the list, if it exists'''
proxy = weakref.proxy(notificable)

if proxy in self.notificables:
self.notificables.remove(proxy)

def __clean_refs(self, reference):
'''remove the reference from the list, since it's going to be
cleaned by the garbage collector
'''

self.notificables.remove(reference)

class Notificable(object):
'''Interface that define the methods to be implemented to be able
to register to an signals.Object to receive notifications when
a method with the @notify_change decorator is called
'''

def on_property_changed(self, obj, attr_name, method_name,
old_value, new_value):
'''method called when a method with the
@notify_change decorator from a signal.Object is called
'''
pass

def notify_change(method):
'''decorator that add the ability to a setter/fset property to
notify other objects when an attribute of the object is modified
'''

def new_method(*args):
'''the function that decorates the class method, basically it
run the setter and then try to notify the objects about the
change, the setter is runned first since it may raise an
exception, and we dont want to notify over a change that
wasn't made
'''

arguments = inspect.getargspec(method)[0]

if Object not in args[0].__class__.mro():
raise TypeError("object doesn't inherit from signals.Object")

if len(arguments) != 2:
raise ValueError("method should receive two arguments")

self_object = args[0]
name = arguments[1]
method_name = method.__name__
old_value = getattr(self_object, name)
new_value = args[1]

return_value = method(*args)
self_object.notify_property_change(name, method_name,
old_value, new_value)

return return_value

return new_method

Buzzword marketing

por alguna razón derivada de la compra de BEA por parte de Oracle termine leyendo la descripción de dos productos de esta empresa para saber a que se dedican aparte de su J2EE Aplication server, entre a ver dos descripciones:

BEA Tuxedo
BEA aqualogic

se hace casi imposible deducir que es lo que hacen, es una descripción totalmente genérica, retorcida y llena de buzzwords, algunos extractos sublimes, pero los invito a leer la descripción y sin consultar fuentes externas, deducir que hacen estos dos productos.

"Usted necesita una plataforma de infraestructura de aplicaciones probada, fiable y escalable: una plataforma que pueda conectar y autorizar a todo tipo de usuarios, a la vez que integra todas sus aplicaciones y datos corporativos en una solución de e-commerce poderosa, flexible y de punto a punto."

"BEA Tuxedo elimina el tiempo, la complejidad y el riesgo de desarrollar y desplegar esta solución."

"La agilidad de la empresa depende del flujo libre de información, servicios y procesos empresariales por toda la organización"

"La Arquitectura Orientada a Servicios (SOA) ha emergido como la estrategia principal de la TI para perfeccionar la presentación de servicios. SOA toma las funciones empresariales discretas contenidas en aplicaciones empresariales y las organiza en servicios interoperativos y basados en estándares que pueden combinarse y reutilizarse rápidamente en procesos y aplicaciones compuestas."

"La Infraestructura de Servicios, se adhiere a los principios de SOA de servicios de grano grueso, débilmente acoplados y basados en servicios para presentar un contenedor neutral para la lógica empresarial que aísla las complejidades de las tecnologías suyacentes."

me envuelve una docena para llevar?

The daily WTF

leyendo clarin, veo esta noticia: http://www.clarin.com/diario/2008/01/10/um/m-01582119.htm

A titulo "Saquean una casa de Caballito mientras sus dueños estaban de viaje".

Esta noticia me hizo pensar dos cosas:

  • Titular sensacionalista, ya que aunque el uso de saquear esta bien utilizado, en argentina suele tener otra acepción, mas relacionadas con 1989 y 2001.
  • Noticia totalmente "de barrio", porque es tapa de un diario de tirada nacional el hecho de que le roben a una familia la casa?, encima como se ve en la foto, también fue noticia en el canal de televisión TN.
En serio, acaso es la unica casa asaltada en toda la argentina durante esta epoca?, a una persona en Tucuman le importa que asalten una casa en Caballito?.
Con la duda de que por ahí, había algo importante, distinto a otros asaltos en este, me fui a leer el cuerpo de la noticia.
Básicamente tres párrafos cortos, que se podrían referir a cualquier asalto a una casa en verano.

Solo imagino al periodista redactando la noticia..

Quote


"Bigger is just something you have to live with in Java. Growth is a fact of life. Java is like a variant of the game of Tetris in which none of the pieces can fill gaps created by the other pieces, so all you can do is pile them up endlessly."

"if you begin with the assumption that you need to shrink your code base, you will eventually be forced to conclude that you cannot continue to use Java. Conversely, if you begin with the assumption that you must use Java, then you will eventually be forced to conclude that you will have millions of lines of code."

"But you should take anything a "Java programmer" tells you with a hefty grain of salt, because an "X programmer", for any value of X, is a weak player. You have to cross-train to be a decent athlete these days. Programmers need to be fluent in multiple languages with fundamentally different "character" before they can make truly informed design decisions.

Recently I've been finding that Java is an especially bad value for X. If you absolutely must hire an X programmer, make sure it's Y."

"The second difficulty with the IDE perspective is that Java-style IDEs intrinsically create a circular problem. The circularity stems from the nature of programming languages: the "game piece" shapes are determined by the language's static type system. Java's game pieces don't permit code elimination because Java's static type system doesn't have any compression facilities – no macros, no lambdas, no declarative data structures, no templates, nothing that would permit the removal of the copy-and-paste duplication patterns that Java programmers think of as "inevitable boilerplate", but which are in fact easily factored out in dynamic languages."


http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html

Codigo viejo

este codigo es una partecita de una libreria para manejar VESA en DOS que escribi hace 5 años, esta parte me encanta, porque esa lib esta toda escrita para hacer todo independiente de la resolucion, los bits por pixel y los bancos del modo (una cosa que es una porqueria:

esta parte:


void Video::putPixel( word x , word y , byte red , byte green , byte blue )

{

word color = ( ( word )( red & ( ( 1
color |= ( ( word )( green & ( ( 1
color |= ( ( word )( blue & ( ( 1
long addr = (long)y * vbeModeInfoBlock.BytesPerScanLine + x * (vbeModeInfoBlock.BitsPerPixel >> 3);

setBank((int)(addr >> 16));

*(videoMemory + (addr & 0xFFFF)) = (char)color;

*(videoMemory + (addr & 0xFFFF) + 1 ) = (char)(color >> 8);

}


pone un pixel en la posicion definida con el color definido en la pantalla para cualquier modo de vesa.

C++, 17 años, DOS, Turbo C++ 1.01, que epocas aquellas :P

the marianoguerra experimento

mi notebook se esta convirtiendo lentamente en un centro de desarrollo, ya tiene:
* pastebin
* viewvc
* Apache/2.2.4 (Ubuntu) mod_python/3.3.1 Python/2.5.1 PHP/5.2.3-1ubuntu6.2
* mysql
* postgres

iba a instalar mediawiki, pero pensé que hay una solución interesante que también pensaba instalar que ya tiene wiki, así que pensé en instalar trac, se me ocurrió ver si servía administrar la vida con trac.

* tickets como un TODO personal y laboral
* wiki para ir escribiendo cosas que luego se convertirán en trabajos, posts, documentaciones variadas
* integración con svn para ver en que andan mis desarrollos locales
* no se me ocurre nada mas por ahora... (ideas?)


sudo trac-admin /var/mariano-trac initenv
Project Name [My Project]> Vida de Mariano
Database connection string [sqlite:db/trac.db]>
Repository type [svn]>
Path to repository [/path/to/repos]> /svnroot
Templates directory [/usr/share/trac/templates]>
sudo vim /var/mariano-trac/conf/trac.ini
chwon www-data.www-data /var/mariano-trac
sudo vim /var/mariano-trac/conf/trac.ini
sudo htpasswd -c -m /etc/apache2/trac.htpasswd mariano
New password:
Re-type new password:
Adding password for user mariano
sudo vim /etc/apache2/sites-available/trac
cat /etc/apache2/sites-available/trac

<virtualhost>
ServerName trac.localhost
SetHandler mod_python
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv /var/mariano-trac
</virtualhost>

<location>
AuthType Basic
AuthName "vida de marianoguerra"
AuthUserFile /etc/apache2/trac.htpasswd
Require valid-user
</location>

sudo a2ensite trac
sudo /etc/init.d/apache2 force-reload

esto es mas un ayuda memoria que otra cosa..

PS: creo que no me falto ningún paso