Implementación de un sistema de cómputo Map-Reduce sobre AMQP

 

Para el cierre de la materia de de “Aprendizaje automático sobre grandes volúmenes de datos“, se me ocurrio que seria interesante la creación de una infraestructura “a la hadoop” en puro Python y sobre AMQP. Bueno hice eso y el resultado lo pueden ver acá: http://poopy.jbcabral.org

Además del código presente un informe de como encare el proyecto que esta disponible acá: https://bytebucket.org/leliel12/bigdata_famaf/raw/tip/poopy/build/latex/poopy.pdf

Creo que el informe es bastante ideal para el que quiera entender AMQP o los conceptos muy básicos de Hadoop desde AMQP

Leer Más

Caipyrinha 0.2

Y tan rapido como esto hice una version 0.2 (por necesidades laborales)

 

Diferencias fundamentales: ahora los exclude group se instancian con el parametro exclusive y no con group (ya implementare los grupos propiamente dichos)
Aca tienen como instalarlo: http://caipyrinha.readthedocs.org

si lo instalan con este código:

# ex.py

import caipyrinha

parser = caipyrinha.Caipyrinha(prog="Your Program")
parser.add_argument("--version", action='version', version="%(prog)s 0.1")

@parser.callback(exit=0, exclusive="group1")
def first(flags, returns):
    '''Execute this option and exit'''
    print "bye bye"

@parser.callback(action="store")
def second(flags, returns):
    '''set his own return value with his parameter'''
    return flags.second

@parser.callback("--third", exclusive="group1")
def no_used_name(flags, returns):
    '''you cant use this argument with first'''
    print returns.second

import sys
parser(sys.argv[1:])

Tienen este resultado

2013-01-23-030740_1056x346_scrot

Aca tienen un link donde lo estoy usando:  http://bitbucket.org/leliel12/yatel/src/tip/bin/yatel

Leer Más

Caipyrinha 0.1

Si hay algo desordenado que me queda siempre son los parsers de linea de comando. Así que se me ocurrió caipyrinha

Que hace caipyrinha? te da un decorador para hacer argumentos de linea de comando a mi criterio… mas facilmente

Aca tienen como instalarlo: http://caipyrinha.readthedocs.org

si lo instalan con este código:

# ex.py

import caipyrinha

parser = caipyrinha.Caipyrinha(prog="Your Program")
parser.add_argument("--version", action='version', version="%(prog)s 0.1")

@parser.callback(exit=0, group="group1")
def first(flags, returns):
    '''Execute this option and exit'''
    print "bye bye"

@parser.callback(action="store")
def second(flags, returns):
    '''set his own return value with his parameter'''
    return flags.second

@parser.callback("--third", group="group1")
def no_used_name(flags, returns):
    '''you cant use this argument with first'''
    print returns.second

import sys
parser(sys.argv[1:])

Tienen este resultado

2013-01-23-030740_1056x346_scrot

Aca tienen un link donde lo estoy usando:  http://bitbucket.org/leliel12/yatel/src/tip/bin/yatel

Leer Más

Snippet para usar un unittest bottle.py con un proceso separado

Necsitaba probar un api rest y se me ocurrio levantar bottle en un proceso separado dentro de un testcase; y necesite hacer todos este chicle.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# "THE WISKEY-WARE LICENSE":
# <jbc.develop@gmail.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a WISKEY in return Juan BC

import multiprocessing
import urllib2
import unittest

import bottle

class BottleTest(unittest.TestCase):

    def setUp(self):
        self.process = multiprocessing.Process(
            target=bottle.run,
            kwargs={"port": "8081"}
        )
        self.process.start()

        # wait until bottle process full started
        # si no ponen esto el testcase se va a ejecutar antes
        # que bottle este listo para recibir peticiones
        started = False
        while not started:
            try:
                urllib2.urlopen("http://127.0.0.1:8081/")
            except urllib2.HTTPError:
                started = True
            except urllib2.URLError as err:
                if err.reason.args[0] == 111:
                    pass
                else:
                    raise err
            else:
                started = True

    def tearDown(self):
        self.process.terminate()

    def test_something(self):
        pass

Leer Más

Pycante 0.2.1c

Actualicé Pycante el proyecto que ayuda a utilizar de manera cómoda los archivos “.ui” de QtDesigner  los cambios principales son:

  • El proyecto ahora es BEER-WARE… osea es mas libre que antes
  • No esta mas disponible la función “run”, ahora hay que crear la aplicación desde Qt.
  • Ahora hay una función “EDir” que recibe por parámetro un path de un directorio y retorna una función “E” que apunta al mismo (por ejemplo si tenemos todos nuestros archivos “.ui” en /home/tito).
  • La operatoria con files y widgets no cambia con los EDir.

Ejemplos:

import sys

import pycante

from PyQt4 import QtGui

# CONSTANTS
UI = pycante.EDir("path/to/all/my/ui/files/")

# using path "path/to/all/my/ui/files/file.ui"
class Window(UI("file.ui")):

    def on_buttonBox_accepted(self):
        # buttonBox exist inside file.ui
        ...

app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

Para instalar:

$ pip install pycante

o

$ easy_install pycante

o bajarlo de aca: https://bitbucket.org/leliel12/pycante/

Disclaimers:

  • Lo hice por una necesidad muy puntual
  • El codigo de “W3″ no lo probe aunque puede usarse asi pycante
  • Como notaran en ni un momento llame a SetupUi()… eso pycante lo hace solo.


				

Leer Más

Ninja-IDE Snippet Plugin (con screencast)

Acabo de terminar mi primer plugin  para Ninja-IDE 2.x, el cual consiste en un gestor de snippets.

Como funciona? 

  • Primero bajan el plugin y lanzan Ninja (estoy usando la 2.0b2)con una de estas intrucciones para que corra mi codigo.
  • En la ventana de settings “edit -> preferences -> plugin -> snippets” y van a ver algo asi

    • La lista de la izquierda enumera todos las exenciones disponibles para los snippets y la de la derecha los snippets, propiamente dicho, de
      dicha extensión. En la ventana de abajo se ve el texto de reemplazo de dicho snippet.
Los snippets deben crearse dentro de un lenguaje y una extensión (siendo un caso particular *General*) y poseen variables que se resuelven al momento de ser aplicados (la lista de todas las variables aparece si presionan el botón HELP)
  • Al momento de escribir un snippet en el editor de texto en el cual esta codificando y apretando la tecla <TAB> el plugin operara de la siguiente manera:
    1. Buscara la palabra justo anterior de apretar <TAB>  en la lista de plugins correspondiente a la extension del archivo que estamos editando.
    2. Si no encuentra un reemplazo en esa lista lo busca en *GENERAL*.
    3. Si no lo encuentra en general no hace nada
Screencast :D (los glitches son cosa de mi editor de video)
[youtube=http://www.youtube.com/watch?v=Mby7urOjuAA]
Descargenlo es Beerware

Leer Más

Django-hateconf 0.2.3

Odio configurar cosas, y mas odio olvidarme que mi settings.py de django esta versionado y subir algún password mio a un repo publico.

Así que probé varias soluciones de archivos de conf distribuidos pero todos metían conceptos nuevos que no me interesaba descular.

En fin… hice esto

django-hateconf

Las premisas eran:

  • el setttings.py original es suficiente información para utilizar de templates y de schema para los archivos externos.
  • Las conf pueden guardarse en varios formatos a gusto del usuario del proyecto.

Bueno a los bifes:

  • Paso 1:  Instalar

$ pip install django-hateconf

o

$ easy_install django-hateconf

o bajarlo de aca: https://bitbucket.org/leliel12/django-hateconf/

  • Paso 2: Crear proyecto django

$ django-admin start-project myproject
  • Paso 3: Editar el “settings.py” y agregar a la variable INSTALLED_APPS, django_hateconf.

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',

&quot;django_hateconf&quot;,
)
  • Paso 4: Editar al “settings.py” de myproject y agregar esta variable

SETTINGS_BIND = {
    &quot;file&quot;:
        &quot;archivo.yaml&quot;,
    &quot;bind&quot;:
        (&quot;DATABASES&quot;, &quot;DEBUG&quot;),
    &quot;header&quot;:
        &quot;Este es un archivo de configuracion del proyecto myproject&quot;
}

Esta diccionario tiene las siguientes llaves:

  • file: El cual es un path a un archivo que va a contener la configuración que va  a utilizar nuestro proyecto. El formato del archivo se deduce desde su extensión (NO es case sensitive); las cuales pueden ser:
  • “.yml” o “.yaml”  para  formato yaml YAML (
  •  “.json” para formato JSON (http://www.json.org/).
  •  “.xml” para formato XML (http://www.w3.org/XML/).
  •  “.cfg” o “.ini” pata formato que consiste en secciones que empiezan con la cabecera “[section]”y continua con combinaciones de “llave = valor” en el estilo
    de la RFC 822.
  • bind: Es una lista o tupla que contiene los nombres de las variables de settings.py que se deseamos que se configuren desde nuestro archivo. Con este campo, django-hateconf, busca por su nombre a las  variables en el settings.py y con su contenido genera un template en el formato especificado en el campo file. Las reglas para el contenido del campo bind son:
  • Las variables deben existir en el settings.py
  • No se puede “bindear” SETTINGS_BIND
  • Si en nuestro archivo declarado en file, por ejemplo, bindeamos la variable “TIME_ZONE” y esta no esta en el campo bind, django-hateconf  ignorará el bindeo y se utilizara el valor dentro del settings.py,
  • El valor que se asigne a las variables dentro de nuestro file, tiene que ser un valor “casteable” al que tenemos asignado a la misma variable dentro del settings.py. Para entender si decimos que la variable “A = 1″ en nuestro settings.py cualquier cosa que pueda convertirse automaticamente a un “int” puede existir dentro de nuestro archivo declarado en file. Un caso particular es el valor None el cual acepta cualquier objeto sin castearlo cuando se bindea.
  • Si el valor es una lista, tupla, diccionario o set; el casteo se hace recursivamente. Asi que los valores internos a estas colecciones también deben ser casteables.
  • header: Es el comentario que llevara en la cabecera el archivo declarado en file. Este campo es opcional.
  • Paso 5: Agregar al final de “settings.py” estas dos lineas:

import django_hateconf
django_hateconf.patch(locals())
  • Paso 6: Ejecutar…

$ python manage.py settings --sync

Con esto deberia haberse creado un nuevo archivo “archivo.yaml” en la misma carpeta del proyecto exactamente así:

# Este es un archivo de configuracion del proyecto myproject
– DATABASES:
default:
ENGINE: django.db.backends.dummy
HOST: ”
NAME: ”
OPTIONS: {}
PASSWORD: ”
PORT: ”
TEST_CHARSET: null
TEST_COLLATION: null
TEST_MIRROR: null
TEST_NAME: null
TIME_ZONE: America/Chicago
USER: ”
– DEBUG: true

Bueno para configurar su database solo tiene que editar su archivo.yaml.

Las otras opciones que da django hateconf son:

python manage.py settings --path                 Dice donde esta el archivo de configuración
 python manage.py settings --show                 Muestra el settings ya mergeado.
 python manage.py settings --sync                 Sincroniza los archivos
 python manage.py settings --vars     Muestra los valores de las variables ya bindeados
 python manage.py settings --formats              Lista los formatos validos para los archivos de configuración
 python manage.py settings --validate             Busca errores en nuestro archivo de bindeo
 python manage.py settings -h, --help             Muestra una ayuda

Links al proyecto

Leer Más

csvcool 0.1.2

Actualicé denuevo csvcool mi libreria para manejar archivos csv in a cool way!

Por un pedido le puse soporte para “key” en el metodo de ordenamiento:

Suponiendo que tenemos un csv como el siguiente:

nombre apellido mail
tito puente tito@puente.com
cosme fulanito cosme@fulanito.com

para ordenarlo por  la ultima letra del “nombre” deberiamos hacer

import csvcool
csvf = csvcool.read(open(&quot;/archivo.csv&quot;))
csvf.sort(lambda r: r[&quot;nombre&quot;][-1])
csvcool.write(csvf, open(&quot;/archivo.csv&quot;, &quot;w&quot;))

y el resultado seria:

nombre apellido mail
cosme fulanito cosme@fulanito.com
tito puente tito@puente.com

Ademas de eso tambien tiene los sigientes features viejos:

  • extraer una sola columna como una tupla.
  • recortar un csv dejando “algunas” columnas o “algunas filas”.
  • agregar filas y columnas.
  • remover filas y columnas.
  • guardar en un archivo.
  • y unas cosas mas.
Instalar:
PD: ahora si agregue los test al setup.py (para felicidad de nessita)

Leer Más