Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados

Shell Python administrativo sobre SSH para tu servidor Twisted en 10 líneas

entre tu reactor.listeTCP(puerto, factory) y reactor.run():

from twisted.conch import manhole, manhole_ssh

from twisted.cred import portal, checkers

def getManholeFactory(namespace, **passwords):

realm = manhole_ssh.TerminalRealm()

def getManhole(_): return manhole.Manhole(namespace)

realm.chainedProtocolFactory.protocolFactory = getManhole

p = portal.Portal(realm)

p.registerChecker(

checkers.InMemoryUsernamePasswordDatabaseDontUse(**passwords))

f = manhole_ssh.ConchFactory(p)

return f

reactor.listenTCP(2222, getManholeFactory(globals(), admin='aaa'))

Los aplausos para este tutorial.


Servidor SSH con Twisted

Actualicé este ejemplo, tamibién incluido en el libro de Twisted para que no tire Deprecation Warnings:

from twisted.cred import portal, checkers, credentials

from twisted.conch import error, avatar, recvline, interfaces as conchinterfaces

from twisted.conch.ssh import factory, userauth, connection, keys, session, common

from twisted.conch.insults import insults

from twisted.application import service, internet

from zope.interface import implements

import os

class SSHDemoProtocol(recvline.HistoricRecvLine):

def __init__(self, user):

    self.user = user



def connectionMade(self) :

    recvline.HistoricRecvLine.connectionMade(self)

    self.terminal.write("Welcome to my test SSH server.")

    self.terminal.nextLine()

    self.do_help()

    self.showPrompt()



def showPrompt(self):

    self.terminal.write("$ ")



def getCommandFunc(self, cmd):

    return getattr(self, 'do_' + cmd, None)



def lineReceived(self, line):

    line = line.strip()

    if line:

        cmdAndArgs = line.split()

        cmd = cmdAndArgs[0]

        args = cmdAndArgs[1:]

        func = self.getCommandFunc(cmd)

        if func:

           try:

               func(*args)

           except Exception, e:

               self.terminal.write("Error: %s" % e)

               self.terminal.nextLine()

        else:

           self.terminal.write("No such command.")

           self.terminal.nextLine()

    self.showPrompt()



def do_help(self, cmd=''):

    "Get help on a command. Usage: help command"

    if cmd:

        func = self.getCommandFunc(cmd)

        if func:

            self.terminal.write(func.__doc__)

            self.terminal.nextLine()

            return



    publicMethods = filter(

        lambda funcname: funcname.startswith('do_'), dir(self))

    commands = [cmd.replace('do_', '', 1) for cmd in publicMethods]

    self.terminal.write("Commands: " + " ".join(commands))

    self.terminal.nextLine()



def do_echo(self, *args):

    "Echo a string. Usage: echo my line of text"

    self.terminal.write(" ".join(args))

    self.terminal.nextLine()



def do_whoami(self):

    "Prints your user name. Usage: whoami"

    self.terminal.write(self.user.username)

    self.terminal.nextLine()



def do_quit(self):

    "Ends your session. Usage: quit"

    self.terminal.write("Thanks for playing!")

    self.terminal.nextLine()

    self.terminal.loseConnection()



def do_clear(self):

    "Clears the screen. Usage: clear"

    self.terminal.reset()

class SSHDemoAvatar(avatar.ConchUser):

implements(conchinterfaces.ISession)



def __init__(self, username):

    avatar.ConchUser.__init__(self)

    self.username = username

    self.channelLookup.update({'session':session.SSHSession})



def openShell(self, protocol):

    serverProtocol = insults.ServerProtocol(SSHDemoProtocol, self)

    serverProtocol.makeConnection(protocol)

    protocol.makeConnection(session.wrapProtocol(serverProtocol))



def getPty(self, terminal, windowSize, attrs):

    return None



def execCommand(self, protocol, cmd):

    raise NotImplementedError



def closed(self):

    pass

class SSHDemoRealm:

implements(portal.IRealm)



def requestAvatar(self, avatarId, mind, *interfaces):

    if conchinterfaces.IConchUser in interfaces:

        return interfaces[0], SSHDemoAvatar(avatarId), lambda: None

    else:

        raise Exception, "No supported interfaces found."

def getRSAKeys():

if not (os.path.exists('public.key') and os.path.exists('private.key')):

    # generate a RSA keypair

    print "Generating RSA keypair..."

    from Crypto.PublicKey import RSA

    KEY_LENGTH = 1024

    rsaKey = RSA.generate(KEY_LENGTH, common.entropy.get_bytes)

    publicKeyString = keys.Key(rsaKey).toString()

    privateKeyString = keys.makePrivateKeyString(rsaKey)

    # save keys for next time

    file('public.key', 'w+b').write(publicKeyString)

    file('private.key', 'w+b').write(privateKeyString)

    print "done."

else:

    publicKeyString = file('public.key').read()

    privateKeyString = file('private.key').read()

return publicKeyString, privateKeyString

if name == "main":

sshFactory = factory.SSHFactory()

sshFactory.portal = portal.Portal(SSHDemoRealm())

users = {'admin': 'aaa', 'guest': 'bbb'}

sshFactory.portal.registerChecker(

checkers.InMemoryUsernamePasswordDatabaseDontUse(**users))

pubKeyString, privKeyString = getRSAKeys()

sshFactory.publicKeys = {

    'ssh-rsa': keys.Key.fromString(pubKeyString)}

sshFactory.privateKeys = {

    'ssh-rsa': keys.Key.fromString(privKeyString)}



from twisted.internet import reactor

reactor.listenTCP(2222, sshFactory)

reactor.run()</pre></body></html>

La historia de Python: El uso de tipado dinámico

El siguiente texto es una traducción del artículo Python's Use of Dynamic Typing de Guido van Rossum publicado en http://python-history.blogspot.com/.

El uso de tipado dinámico en Python

Una diferencia importante entre ABC y Python es el estilo general del sistema de tipos. ABC es estáticamente tipado, lo cual significa que el compilador de ABC analiza el uso de tipos en un programa y decide si están siendo usados consistentemente. Si no, el programa es rechazado y su ejecución no puede comenzar. A diferencia de la mayoría de los lenguajes con tipado estático de esos días, ABC usaba inferencia de tipos (no distinto que Haskell) en lugar de declaraciones explícitas de tipos como en C. En contraste, Python es dinámicamente tipado. El compilador de Python ignora felizmente los tipos usados en un programa y todo el control de tipos es hecho en tiempo de ejecución.

Aunque esto pueda parecer muy distinto de ABC, no es tan diferente como uno imaginaría. A diferencia de otros lenguajes de tipado estático, ABC no depende (¿dependía? es prácticamente histórico hoy : - ) exclusivamente de controles de tipado estático para evitar que el programa termine abruptamente, también tiene una librería en tiempo de ejecución que controla los tipos de los argumentos en todas las operaciones nuevamente cada vez que son ejecutadas. Esta verificación no estaba de más para los algoritmos de control de tipos del compilador, que no estaban totalmente implementados en el primer prototipo del lenguaje. La librería en tiempo de ejecución también servía como una ayuda para la depuración, ya que el control de tipos explícito en tiempo de ejecución puede producir lindos mensajes de error (algo requerido por los implementadores), en lugar de los vuelcos de memoria que sucederían si el intérprete siguiera ciegamente con una operación sin controlar si los argumentos tienen sentido.

Sin embargo, la razón más importante por la que ABC tenía control de tipos en tiempo de ejecución, además de control de tipado estático, es su naturaleza interactiva. En una sesión interactiva, el usuario tipea sentencias de ABC y definiciones que son ejecutadas tan pronto como son completadas. En una sesión interactiva, es posible crear una variable y asignarle un número, borrarla y luego volver a crearla (en otras palabras, crear otra variable con el mismo nombre) y asignarle un string. Dentro de un solo procedimiento, sería un error de tipado estático usar el mismo nombre de variable primero como un número y luego como un string, pero no sería razonable forzar ese control entre diferentes sentencias entradas en una sesión interactiva, mientras que la creación accidental de una variable llamada x a la que se le asigna un número, !prohiba para siempre la creación de una variable x con otro tipo!. El compromiso de ABC es usar control de tipos dinámico para las variables globales, pero estático para las locales. Para simplificar la implementación, las variables locales obtienen control de tipo dinámico también.

Así, hay solo un pequeño paso desde el enfoque usado en la implementación de ABC para el control de tipos al de Python; Python simplemente deja todo el control de tipos en tiempo de compilación. Esto se alinea completamente con la filosofía de Python de "tomar atajos", ya que simplifica la implementación y no afecta la eventual seguridad, ya que todos los errores de tipo son atrapados en tiempo de ejecución antes de que causen un mal funcionamiento del intérprete de Python.

Sin embargo, una vez que te decides por el tipado dinámico no hay vuelta atrás. Las operaciones de ABC fueron cuidadosamente diseñadas para que el tipo de los argumentos pueda ser deducido de la forma de los operadores. Por ejemplo, de la expresión "x^y" el compilador deduciría que las variables x e y son strings, así como el resultado. En Python, esa deducción no se puede generalizar. Por ejemplo, la expresión "x+y" puede ser una concatenación de strings, una suma entre números, o una operación sobrecargada sobre tipos definidos por el usuarios.

Traducido por Juan José Conti.

Revisado por César Portela.

Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


FPDF en Django

Si intentás usar FPDF en Django hay algunas cosas que necesitás saber:

    <li>(ya sabés qué) <a href="http://www.fpdf.org/">FPDF</a> está originalmente escrita en PHP y permite generar documentos PDF sin usar PDFLib (C).</li>
    
    <li>(ya sabés qué) hay más de un port de esta librería a Python. Todos son incompletos.</li>
    
    <li>Usá este <a href="http://www.nsis.com.ar/svn/pyfpdf/" target="_blank">http://www.nsis.com.ar/svn/pyfpdf/</a> (parcheado en Argentina para utilizar unicode).</li>
    
    <li>FPDF <a href="http://www.fpdf.org/en/FAQ.php#q7">trabaja con la codificación ISO-8859-1</a>.</li>
    
    <li>Mi código fuente Django usa la cotificación UTF-8 y en los documentos resultantes aparecían caracteres raros en lugar de vocales con tilde o eñes.</li>
    
    <li>Lo soluciné haciendo una modificacicón en el método Output:</li>
    

    self.buffer = buffer.encode('iso-8859-1')


    El segundo color predominante: PIL

    Hace unas semanas necesité hacer un script en Python que genere algunas decenas de imágenes. Básicamente, se tiene como entrada imágenes como estas:

    (un borde con alguna forma y un color en un fondo blanco)

    Las imágenes generadas tienen que tener ciertos números en el centro, pintados en cada caso del mismo color que el borde:

    La primer parte del script tiene que determinar el segundo color predominante de la imagen (el primero es el blanco), esta es la forma en que lo hice usando PIL:

    def get_color(image):
    
    colors = image.getcolors()  # colors is a list of (count, color)
    
    colors.sort(lambda y,x: cmp(x[0], y[0])) # bigger count first
    
    c = colors.pop(0)
    
    while white(c): # find the non-white color most used in the image
    
        c = colors.pop(0)
    
    return c[1]
    

    def white(color):

    color = color[1]
    
    return color[0] == 255 and color[1] == 255 and color[2] == 255</pre></body></html>
    

    La historia de Python: El principio del diseño y desarrollo del lenguaje

    El siguiente texto es una traducción del artículo Early Language Design and Development Guido van Rossum publicado en http://python-history.blogspot.com/.

    El principio del diseño y desarrollo del lenguaje

    De ABC a Python

    La primera y principal influencia de Python fue ABC, un lenguaje diseñado a principios de los 80 por Lamber Meertens, Leo Geurts y otros en CWI. El objetivo de ABC era ser un lenguaje de enseñanza, un reemplazo para BASIC, y un lenguaje y entorno para computación personal. Fue diseñado en un principio haciendo un análisis de la tarea de programar y luego haciendo varias iteraciones que incluían pruebas de usuario a conciencia. Mi rol en el grupo de ABC era principalmente implementar el lenguaje y su entorno integrado de edición.

    El uso que Python hace de la identación viene directamente de ABC, pero esta idea no se originó con ABC (ya había sido promovida por Donald Knuth y era un concepto bien conocido de estilo de programación). (El lenguaje de programación occam también lo usaba). Si embargo, los autores de ABC sí inventaron el uso de los dos puntos que separa la cláusula inicial del bloque identado. Luego de las primeras pruebas con usuarios sin los dos puntos, se descubrió que el significado de la identación no le quedaba claro a los principiantes que tomaban sus primeras lecciones de programación. Agregar los dos puntos clarificó su significado: los dos puntos de alguna formar guiaban la atención a lo que seguía y unía lo anterior con lo siguiente de forma correcta.

    Los principales tipos de datos de Python también vienen de ABC, aunque con algunas modificaciones. Las listas en ABC eran en realidad bags o multisets, que siempre se mantenían ordenadas utilizando una implementación modificada de árboles B. Sus tablas eran arrays asociativos que se mantenían ordenados en forma similar mediante claves. Encontré que ningún tipo de dato era preciso para representar, por ejemplo, la secuencia de líneas leídas de un archivo, el cual anticipé que sería un caso de uso común (en ABC tenías que usar una tabla con el número de línea como clave, pero eso complicaba las inserciones y los borrados). Entonces convertí el tipo lista en un array flexible con operaciones de inserción y borrado, dándole a los usuarios control total sobre el orden de los elementos en una lista. Un método sort soportaba la necesidad ocasional de resultados ordenados.

    También reemplacé las tablas ordenadas implementando una tabla hash. Elegí una tabla hash porque creía que sería más rápida y fácil de implementar que el árbol B de ABC. Estaba teóricamente probado que los árboles B eran asintóticamente óptimos en tiempo y espacio para una gran variedad de operaciones, pero en la práctica se volvieron difíciles de implementar correctamente debido a la complejidad de sus algoritmos. Por la misma razón, la performance tampoco era óptima para tablas pequeñas.

    Mantuve el tipo de dato inmutable de ABC llamado tupla (las operaciones de empaquetado y desempaquetado en Python vienen directamente de ABC). Ya que las tuplas son implementadas mediante arrays, decidí agregarles indexación y rebanado.

    Una consecuencia de añadirle una interfaz de tipo array a las tuplas fue que tuve que pensar en una forma de resolver los casos límites de tuplas de longitud 0 ó 1. Una de las reglas que tomé de ABC fue que cada tipo de datos, al ser impreso o convertido a string, debía ser representado por una expresión que sea una entrada válida para el parser del lenguaje. De esto siguió que necesitaba notaciones para las tuplas de longitud 0 y 1. Al mismo tiempo no quería perder la distinción entre una tupla y una expresión entre paréntesis, entonces utilicé un enfoque feo pero pragmático en el cual una coma final convertiría una expresión en una tupla de un elemento y "()" representaría a una tupla de cero elementos. Vale la pena mencionar que los paréntesis por lo general no son necesarios en la sintaxis de Python, excepto aquí (representar la tupla vacía con "nada" podría fácilmente enmascarar errores genuinos).

    Los strings de Python empezaron con una semántica (inmutable) muy parecida a los strings de ABC, pero con una notación diferente e indexación basada en 0. Ya que ahora tenía tres tipos indexables -listas, tuplas y strings- decidí generalizar todo en un concepto común, la secuencia. Esta generalización hizo que ciertas operaciones básicas como obtener la longitud (len(s)), indexar (s[i]), rebanar (s[i:j]) e iterar (for i in s) funcionen de la misma forma en cualquier tipo que sea una secuencia.

    Los números son uno de los puntos en los que más en desacuerdo estuve con ABC. ABC tenía dos tipos de números en tiempo de ejecución; los números exactos que eran representados como números racionales de precisión arbitraria y los números aproximados que eran representados mediante punto flotante binario con un rango de exponente extendido. Los números racionales no encajaban en mi visión del tema (anécdota: una vez intenté computar mis impuestos usando ABC. El programa, que parecía bastante directo, estaba demorando mucho en computar unos pocos números. Luego de investigar descubrí que estaba haciendo aritmética con números con miles de dígitos de precisión, que tenían que ser redondeados a florines -pie 100 centavos holandeses - y centavos para ser impresos). Es por esto que para Python elegí un modelo más tradicional con enteros de máquina y punto flotante binario de máquina. En la implementación de Python, estos números son representados simplemente con los tipos de datos de C long y double respectivamente.

    Creyendo que también había un caso de uso importante para números exactos sin límite, agregué un tipo de dato bignum, que llamé long. Ya tenía una implementación de bignum que había sido el resultado de un intento inconcluso por mejorar la implementación de ABC unos años antes (la implementación original de ABC, una de mis primeras contribuciones, usaba una representación decimal internamente). Sonaba lógico usar este código en Python.

    A pesar de haber agregado bignums a Python, es importante enfatizar que no quería usar bignums para todas las operaciones entre enteros. De extrapolar lo que veía en programas escritos por mí y por colegas en CWI, sabía que las operaciones entre enteros representaban una porción significativa del total del tiempo que la mayoría de los programas corrían. El uso más común de los enteros es indexar secuencias que entran en memoria. Así, decidí usar enteros de máquina para los casos de uso más comunes y el rango extra de bignums solo para hacer "matemática seria" o calcular la deuda externa de Estados Unidos en peniques.

    El problema con los números

    La implementación de números, especialmente enteros, es un área en la que cometí varios errores de diseño serios, pero también aprendí lecciones importantes sobre el diseño de Python.

    Ya que Python tiene dos tipos diferentes de enteros, necesitaba una forma de distinguir entre los dos tipos en un programa. Mi solución era pedirle a los usuarios que explícitamente digan cuando querían usarlos agregando una L al final de los números (por ejemplo 1234L). Esta es un área en la que Python violaba la filosofía inspirada en ABC de no necesitar que los usuarios se encargar de detalles de implementación que no les importaban.

    Lamentablemente, este era solo el menor detalle de un problema mayor. Un error más ilustre fue que mi implementación de enteros y longs ¡tenía una ligera diferencia semántica en algunos casos! Ya que el tipo int era representado como un entero de máquina, las operaciones que desbordaban silenciosamente recortaban el resultado a 32 bits o a la precisión que el tipo long de C tuviera. Además, el tipo int, que normalmente se considera tiene signo, era tratado como sin signo por las operaciones bitwise y shift y en la conversión desde/hacia octales o hexadecimales representados como int o long. Los longs, por otro lado, siempre se consideraban con signo. Por lo tanto, algunas operaciones producían un resultado diferente, dependiendo de si un argumento era representado como int o como long. Por ejemplo, en una aritmética de 32 bits, 1<<31 (1 shift a izquierda 31 bits) produciría el entero negativo más grande de 32 bits y 1<<32 produciría cero, mientras que 1L<<31 (1 representado como long shift a izquierda 31 bits) produciría un entero enorme igual a 231 y 1L<<32 produciría 232.

    Para resolver algunos de estos asuntos hice un arreglo simple. En lugar de tener operaciones entre enteros que recorten silenciosamente el resultado, cambié la mayoría de las operaciones aritméticas para que lancen una excepción OverflowError cuando el resultado no encaje. (La única excepción a este control eran las operaciones de "bit-wise" mencionadas anteriormente, ya que asumí que los usuarios esperarían que estas operaciones se comporten como en C). Si no hubiese añadido este control, los usuarios de Python indudablemente hubiesen empezado a escribir código dependiente de la semántica de la aritmética binaria con signo de módulo 2**32 (como hacen los usuarios de C), y arreglar el error hubiese sido una transición mucho más dolorosa para la comunidad.

    A pesar de que la inclusión del control de desborde pueda parecer un detalle de implementación menor, una dolorosa experiencia de debugging me hizo dar cuenta que era una característica útil. Como uno de mis primeros experimentos en Python, intenté implementar un algoritmo matemático simple, el computo de los "Números de Meertens", un poco de matemática recreativa inventada por Richard Bird al celebrar los 25 añosen WCI del principal autor de ABC. Los primeros números de Meertens son pequeños, pero al traducir el algoritmo en código no me había dado cuenta de que los resultados intermedios del computo eran mucho más grandes que 32 bits. Me llevó una larga y dolorosa sesión de debugging descubrir esto, y decidí entonces manejar el asunto controlando todas las operaciones entre enteros y lanzando una excepción siempre que el resultado no pueda ser representado como un long de C. El costo extra del control de desborde no se notaría junto a la sobrecarga que ya tenía con la decisión de implementación de crear un nuevo objeto para el resultado.

    Lamentablemente, siento decir que lanzar una excepción por desborde ¡tampoco era la solución correcta! En ese entonces, estaba trabado por la regla de C "las operaciones con tipos numéricos T retornan un resultado de tipo T". Esta regla también era la razón de mi otro gran error en la semántica de los enteros: truncar el resultado de la división entre enteros, que discutiré en una de las próximas entradas. En retrospectiva, debí hacer que las operaciones entre enteros que desbordaban cambien el tipo de su resultado a long. Esta es la forma en que Python funciona hoy, pero completar esta transición llevó mucho tiempo.

    A pesar del problema con los números, una cosa muy positiva salió de esta experiencia. Decidí que no debía haber valores de retorno no definidos en Python, en lugar de esto, siempre se lanzarían excepciones cuando un valor de retorno no correcto podía ser computado. Así, los programas escritos en Python nunca fallarían debido a que valores no definidos se estén pasando silenciosamente por detrás. Este es aún un principio importante del lenguaje, tanto en el lenguaje propiamente dicho como en las librerías.

    Traducido por Juan José Conti.

    Revisado por César Portela.

    Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

    Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


    La historia de Python: Microsoft distribuye código Python... en 1996

    El siguiente texto es una traducción del artículo Microsoft Ships Python Code... in 1996 de Greg Stein publicado en http://python-history.blogspot.com/.

    Microsoft distribuye código Python... en 1996

    ¡Muchas gracias a Guido por permitirme compartir mi propia historia de Python!

    Me guardo mi iniciación en Python para otro post, pero el resultado final fue su introducción en un emprendimiento que co-fundé en 1991 con otras personas. Estábamos trabajando en un gran sistema cliente/servidor de comercio electrónico entre empresas y consumidores. Protocolos TCP propios operando sobre la vieja red X.25 y todo eso. Vieja escuela.

    En 1995 nos dimos cuenta, contrariamente a nuestra primera impresión, que la mayoría de los consumidores no estaban en Internet, y que necesitábamos un sistema para nuestros clientes (los vendedores) para que lleguen a sus clientes basados en Internet. Tuve la tarea de definir nuestro enfoque y elegí Python como mi herramienta de prototipado.

    Nuestro primer problema fue cambiar a una solución basada totalmente en el navegador. Nuestro cliente a medida ya no era viable, necesitamos una experiencia de compra nueva para los clientes e infraestructura de servidores para soportarla. En ese entonces, hablarle a un navegador significaba escribir scripts de CGI para los servidoes Apache o Netscape HTTP. Usando CGI, me conectaba a nuestro servidor existente para procesar las ordenes, mantener el carrito de compras y obtener información de los productos. Estos scripts producían HTML plano (¡no había AJAX en 1995!).

    Este enfoque era menos que ideal ya que cada petición tomaba tiempo y creaba un nuevo proceso CGI. La velocidad de respuesta era muy pobre. Luego, en diciembre de 1995, mientras asistía al Python Workshop en Washington DC, me introdujeron a algunos módulos para Apache y Netscape (de Digital Creations, mejor conocidos como Zope) que corrían en forma persistente en el proceso del servidor. Estos módulos usaban un sistema RPC llamado ILU para comunicarse contra otros procesos por detrás. Con este sistema funcionando, la sobrecarga del CGI desapareció y la experiencia de compra ¡se podía disfrutar bastante! Empezamos a convertir el prototipo en código real. Mientras más lejos íbamos, mejor lucía y más personas se unían al proyecto. El desarrollo se movió muy rápido durante los siguientes meses (¡gracias Python!).

    En enero de 1996 Microsoft llamó a nuestra puerta. Su esfuerzo interno por crear un sistema de comercio electrónico no tenía éxito y necesitaban personas que conocieran la industria (nosotros habíamos estado haciendo comercio electrónico ya por varios años en ese momento) y que fueran ágiles. Continuamos desarrollando el software durante la primavera mientras las negociaciones se llevaban a cabo y luego la adquisición finalizó en junio de 1996.

    Una vez que llegamos a Microsoft con nuestra pequeña pila de código Pyhon, tuvimos que resolver como distribuir el producto en Windows NT. El equipo al que nos unimos tenía mucha experiencia y creó un plug-in para IIS que permitía comunicarse mediante tuberías nombradas al servidor que estaba por detrás, un servicio de NT con el código de nuestro servidor Python embebido. Con una primavera loca empezando en julio, distribuimos Microsoft Merchant Server 1.0 en octubre de 1996.

    Y si... si mirabas bajo la alfombra, en algún lugar escondido, había un intérprete de Python, algunas DLLs y un montón de archivos .pyc. Ciertamente Microsoft no se dio cuenta de este hecho, pero estaba ahí si sabías dónde mirar.

    Traducido por Juan José Conti.

    Revisado por César Portela.

    Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

    Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


    La historia de Python: Historia Personal - parte 2, CNRI y más

    El siguiente texto es una traducción del artículo Personal History - part 2, CNRI and beyond de Guido van Rossum publicado en http://python-history.blogspot.com/.

    Historia Personal - parte 2, CNRI y más

    Luego del workshop de Python (ver artículo anterior) obtuve una oferta de trabajo para venir a trabajar en agentes móviles en el CNRI (Corporation for National Research Initiatives). CNRI es un laboratorio de investigación sin fines de lucro en Reston, Virginia. Me uní en abril de 1995. El director del CNRI, Bob Kahn, fue el primero en señalarme cuánto tenía Python en común con Lisp, a pesar de ser completamente diferentes en un nivel superficial (sintaxis). El trabajo en Python en el CNRI fue financiado indirectamente por un subsidio de DARPA para investigación en agentes móviles. A pesar de que había apoyo de DARPA para proyectos que usaban Python, no había mucho apoyo directo para el desarrollo del lenguaje en si.

    En el CRNI, lideré y ayudé a contratar a un pequeño grupo de desarrolladores para construir un agente móvil enteramente en Python. Los miembros iniciales del equipo fueron Roger Masse y Barry Warsaw, quienes habían sido mordidos por el bichito de Python en el Python workshop del NIST.  Además, contratamos a los miembros de la comunidad de Python Ken Manheimer y Fred Drake. Jeremy Hylton, un graduado del MIT contratado originalmente para trabajar en recuperación de texto, también se unió al equipo. Este fue dirigido originalmente por Ted Strollo y luego por Al Vezza.

    El equipo me ayudó a crear y mantener elementos adicionales de la infraestructura de la comunidad de Python como el sitio web python.org, el servidor CVS y las listas de correo para varios grupos de intereses especiales en Python. Las versiones de la 1.3 a 1.6 fueron publicados desde el CNRI. Por muchos años, Python 1.5.2 fue la versión más popular y estable.

    GNU mailman también nació aquí: originalmente usábamos una herramienta escrita en Perl llamada Majordomo, pero Ken Manheimer encontró que era inmantenible y buscó una solución en Python. Encontró algo escrito en Python por John Viega y tomo su mantenimiento. Cuando Ken dejó el CNRI para ir a Digital Creations, Barry Warsaw lo tomó y convenció a la Free Software Foundation de adoptarlo como su herramienta oficial para listas de correo. Barry entonces la licenció bajo la GPL (GNU Public License).

    El Python workshops continuó, al principio dos veces al año, pero debido al crecimiento y los esfuerzos en logística cada vez mayores pronto se convirtió en un evento anual. Estos era llevados a cabo al principio por cualquiera que quería alojarlos, como el NIST (el primero), USGS (el segundo y el tercero) y LLNL (el cuarto y el comienzo de la serie anual). Eventualmente, CNRI tomó la organización, y luego (junto a las conferencias de la WWW y de IETF) se separó como una iniciativa comercial, Fortec. La audiencia pronto llegó a varios miles. Cuando Fortec se desvaneció un poco después de que dejé el CNRI, la Python Conference empezó a desarrollarse dentro de OSCON (O'Reilly's Open Source Conference), pero al mismo tiempo la Python Software Foundation (ver abajo) empezó una nueva serie de conferencias populares llamada PyCon.

    También creamos la primer (hoy inexistente) organización alrededor de Python en el CNRI. En respuesta a los esfuerzos de Mike McLay y Paul Everitt de crear una "Python Foundation", que terminó en las arenas movedizas de borradores de estatutos, Bob Kahn se ofreció a crear la "Python Software Activity", que no sería una entidad legal independiente, sino simplemente un grupo de personas trabajando bajo el paraguas legal (sin fines de lucro) del CNRI. La PSA tuvo éxito en congregar la energía de un grupo grande de usuarios de Python comprometidos, pero su falta de independencia limitó su efectividad.

    CNRI también usaba dinero de DARPA para financiar el desarrollo de JPython (luego acortado a Jython), una implementación de Python en y para Java. Jim Hugunin creó originalmente JPython mientras hacía su trabajo para graduarse en el MIT. Luego convenció al CNRI de que lo contrate para completar el trabajo (o tal vez el CNRI lo convenció a Jim para que se una --  sucedió mientras estaba de vacaciones). Cuando Jim dejó el CNRI menos de dos años después para unirse al proyecto AspectJ en Xerox PARC, Barry Warsaw continuó el desarrollo de JPython. (Mucho después,  Jim también crearía IronPython, la versión de Python para la plataforma .NET de Microsoft. Jim también escribió la primera versión de Numeric Python).

    Otros proyectos en el CNRI también empezaron a usar Python. Muchos de los nuevos desarrolladores principales de Python salieron de allí, en particular Andrew Kuchling, Neil Schemenauer, y Greg Ward, que trabajaron para el proyecto MEMS Exchange. (Andrew contribuyó con Python incluso antes de unirse al CNRI; su primer proyecto grande fue el Python Cryptography Toolkit, una librería de terceros que ponía a disposición de los usuarios de Python muchos de los algoritmos criptográficos fundamentales).

    Cuando Python estaba empezando a tener éxito, CNRI intentó encontrar un modelo para financiar su desarrollo más directamente que a través del subsidio de investigación de DARPA. Creamos el Python Consortium, modelado luego del X Consortium, con un costo de inscripción mínimo de u$s 20.000. Sin embargo, excepto por un grupo en Hewlett-Packard, no conseguimos muchos adherentes y eventualmente el consorcio murió de anemia. Otro intento de encontrar fondos fue Computer Programming for Everybody (CP4E), que recibió algún financiamiento de DARPA. Si embargo, el mismo no era suficiente para todo el equipo y resultó que había toda una red de viejos miembros queriendo obtener más dinero del que habíamos obtenido del dinero durante esos años. Eso no fue algo que me agradace, y empecé a buscar otras opciones.

    Eventualmente, al principio del 2000, el boom de las las .com, que no había colapsado aún, me convenció a mi y a otros tres miembros del equipo de Python en el CNRI (Barry Warsaw, Jeremy Hylton y Fred Drake) de unirnos a BeOpen.com, una startup en California que estaba reclutando desarrolladores de código abierto. Tim Peters, un miembro clave de la comunidad de Python, también se nos unió.

    Anticipándonos a la transición a BeOpen.com, una cuestión difícil fue la propiedad futura de Python. CNRI insistió en cambiar la licencia y pidió que distribuyéramos Python 1.6 con una nueva versión de la misma. La vieja licencia, usada mientras aún estaba en CWI, era una versión de la licencia MIT. Las versiones previas hechas en CNRI usaban una versión ligeramente modificada de esa licencia, básicamente con una sentencia agregada en la que el CNRI se liberaba de la mayoría de las responsabilidades. Sin embargo, la licencia de la versión 1.6 era un montón de palabras en lenguaje técnico escrita por los abogados del CNRI.

    Tuvimos varios largos forcejeos con Richard Stallman y Eben Moglen de la Free Software Foundation sobre algunas partes de esta nueva licencia. Se temían que sería incompatible con la GPL, y por lo tanto amenazaba la viabilidad de GNU mailman que se había convertido en una herramienta esencial para la FSF. Con la ayuda de Eric Raymond, se hicieron cambios en la licencia para Python del CNRI que satisficieron tanto a la FSF como al CNRI, pero el lenguaje resultante no es fácil de entender. La única cosa buena que puedo decir sobre esto es que (otra vez gracias a la ayuda de Eric Raymond) tenía el sello de aprobación de la Open Source Initiative como una licencia open source genuina. Solo pequeños cambios se hicieron en el texto de la licencia para reflejar los dos siguientes cambios de propiedad, primero para BeOpen.com y luego para la Python Software Foundation, pero en esencia, el trabajo de los abogados del CNRI todavía perdura.

    Como tantas startups de ese entonces, el plan de negocio de BeOpen.com falló espectacularmente. Dejó atrás una gran deuda, algunas serias dudas sobre el rol jugado por algunos administradores de la compañía y algunos muy desilusionados desarrolladores además de mi propio equipo.

    Afortunadamente mi equipo, conocido como Python Labs, era bastante reciente y fuimos contratados como una unidad de Digital Creations, una de las primeras compañías en usar Python (Ken Manheimer nos había precedido varios años antes). Digital Creations pronto cambió su nombre a Zope Corporation por su principal producto open source, el sistema web de manejo de contenidos Zope. Los fundadores de Zope, Paul Everitt y Rob Page, asistieron al primer Python workshop en NIST en 1994, como lo hizo su CTO, Jim Fulton.

    La historia podría haber sido diferente: además de Digital Creations, también consideramos ofertas de VA Linux and ActiveState. VA Linux era la nueva estrella naciente del mercado de acciones,  pero eventualmente el precio de las mismas (que había hecho multi-millonario a Eric Raymond en los papeles) colapsó más que dramáticamente. Mirando hacia atrás, pienso que ActiveState no hubiera sido una mala elección, a pesar de la controversial personalidad de su fundador Dick Hardt, si no hubiera estado ubicada en Canadá.

    En el 2001 creamos la Python Software Foundation, una organización sin fines de lucro, que tuvo como miembros iniciales a los principales desarroladores de Python de ese entonces. Eric Raymond fue uno de los miembros fundadores. Tengo que escribir más sobre este período en otro momento.

    Traducido por Juan José Conti.

    Revisado por César Portela.

    Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

    Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


    La historia de Python: Historia Personal - parte 1, CWI

    El siguiente texto es una traducción del artículo Personal History - part 1, CWI de Guido van Rossum publicado en http://python-history.blogspot.com/.

    Historia personal - parte 1, CWI

    El desarrollo de Python empezó en un instituto de investigación en Amsterdam llamado CWI, el cual es un acrónimo en holandés que en español significa Centro de Matemáticas y Ciencias de la computación. CWI es un lugar interesante; fundado por el Departamento de Educación del gobierno y otros fondos para investigación, guía investigaciones de nivel académico en ciencias de la computación y matemáticas. En todo momento está lleno de estudiantes de doctorado paseando y los más viejos profesionales deben aún recordar su nombre original, el Centro Matemático. Bajo este nombre, es tal vez más famoso por la invención de Algol 68.

    Empecé a trabajar en CWI al final de 1982, recién salido de la universidad, como programador en el grupo de desarrollo de ABC liderado por Lambert Meertens y Steven Pemberton. Luego de 4 o 5 años, el proyecto ABC fue interrumpido debido a la obvia falta de éxito y me trasladé al grupo Amoeba liderado por Sape Mullender. Amoeba era un sistema operativo distribuido basado en micro-kernel desarrollado en forma conjunta por CWI y la Vrije Universiteit of Amsterdam, bajo la dirección de Andrew Tanenbaum. En 1991, Sape dejó CWI para dar clases en la University of Twente y terminé en otro grupo recientemente formado en CWI sobre multimedia liderado por Dick Bulterman.

    Python es un producto directo de mi experiencia en CWI. Como explico más adelante, ABC me dio la inspiración clave para Python, Amoeba la motivación inmediata, y el grupo multimedia fomentó su crecimiento. Sin embargo, hasta donde sé, ningún fondo de CWI fue alguna vez destinado oficialmente para su desarrollo. En cambio, sólo evolucionó como una herramienta importante para usar en los grupos Amoeba y de multimedia.

    Mi motivación original pare crear Python fue la necesidad que percibí por un lenguaje de alto nivel en el proyecto Amoeba. Me dí cuenta de que el desarrollo de utilidades para administración de sistemas en C llevaría mucho tiempo. Más aún, hacer esto en el shell Bourne funcionaría por una variedad de razones. La más importante fue que al ser Amoeba un sistema micro-kernel distribuido con un diseño radicalmente nuevo, sus operaciones primitivas eran diferentes (y de granularidad fina) de las primitivas tradicionales disponibles en el shell Bourne. Existía la necesidad de un nuevo lenguaje que "una la brecha entre C y el shell". Por mucho tiempo, este fue el principal slogan de Python.

    En este punto tal vez se pregunte "¿por qué no portar un lenguaje existente?". En mi forma de verlo, no había muchos lenguajes apropiados en esos días. Estaba familiarizado con Perl 3, pero estaba más atado a Unix que el shell Bourne. Tampoco me gustaba la sintaxis de Perl --mi gusto en la sintaxis de los lenguajes de programación fue fuertemente influenciado por lenguajes como Algol 60, Pascal, Algol 68 (a todos los había aprendido mucho antes) y, por último pero no el peor, ABC, en el cual gasté cuatro años de mi vida. Así que decidí diseñar un lenguaje por mi cuenta que tomaría prestado todo lo que me gustaba de ABC a la vez que arreglaba todos sus problemas (como los percibía).

    ¡El primer problema que decidí arreglar era el nombre! Sucedió que el equipo de desarrollo de ABC tenía algunos problemas en elegir un nombre para su lenguaje. El nombre original del lenguaje, B, tuvo que ser abandonado porque se confundía con otro lenguaje llamado B, que era más viejo y más conocido. De cualquier modo, B era solo un título de trabajo (el chiste era que B era el nombre de la variable que contenía el nombre del lenguaje, de ahí la itálica). El equipo tuvo un concurso público para obtener un nuevo nombre, pero ninguna de las propuestas fue apropiada, y al final el backup interno prevaleció. Con el nombre se quería expresar la idea de que el lenguaje hacía que la programación sea "tan simple como el ABC", pero a mi nunca me convenció mucho.

    Así que, en lugar de sobre analizar el problema del nombre, decidí hacer lo contrario. Elegí el primer nombre que me vino a la mente, que resultó ser Monty Python’s Flying Circus, uno de mis grupos cómicos preferidos. La referencia parece bastante irrelevante para lo que era esencialmente un proyecto innovador pero solitario. La palabra "Python" era pegadiza, te ponía un poco los pelos de punta, y al mismo tiempo encajaba en la tradición de ponerle a los lenguajes nombres de personas famosas, como Pascal, Ada y Eiffel. Puede que el equipo de The Monty Python no sea famoso por sus avances en ciencia o tecnología, pero son ciertamente un favorito de los geeks. También encajaba en la tradición del grupo Amoeba de CWI de ponerle a los programas el nombre de shows televisivos.

    Por muchos años resistí la tentación de asociar el lenguaje con serpientes. Finalmente me rendí cuando O'Reilly quizo poner una serpiente en la tapa del primer libro de Python "Programming Python". Era una tradición de O'Reilly usar fotos de animales, y si tenía que ser un animal, que sea una serpiente.

    Con el asunto del nombre resuelto, empecé a trabajar en Python a finales de diciembre de 1989, y tuve una versión funcionando en los primeros meses de 1990. No tomé notas, pero recuerdo vivamente que la primer pieza de código que escribí de la implementación de Python era un LL(1) parser generator simple que llamé "pgen". Este parser generator es aún parte de los fuentes de Python y probablemente lo menos cambiado de todo el código. Esta versión temprana de Python fue usada por algunas personas en CWI, mayormente, pero no en forma exclusiva en el grupo Amoeba durante 1990. Los desarrolladores clave, demás de mi, eran mis compañeros de oficina, los programadores Sjoerd Mullender (el hermano menor de Sape) y Jack Jansen (quien fue uno de los desarrolladores líderes de la versión para Macintosh por muchos años, luego de dejar CWI).

    El 20 de febrero de 1991 publiqué por primera vez Python para el mundo en el grupo de noticias alt.sources (como 21 partes codificadas que tenían que ser juntadas y decodificadas para formar el archivo tar comprimido). Esta versión fue etiquetada 0.9.0 y publicada bajo una licencia que era prácticamente una copia textual de la licencia MIT usada por el proyecto X11 en ese entonces, poniendo “Stichting Mathematisch Centrum”, la organización padre de CWI, como la entidad responsable legal. Así que, como casi todo lo que he escrito, Python era open source antes de que el término sea inventado por Eric Raymond y Bruce Perens a finales de 1997.

    Enseguida hubo mucha retroalimentación y con este apoyo mantuve un firme flujo de publicaciones durante algunos años. Empecé a usar CVS para seguir los cambios y para facilitar compartir la responsabilidad de codificar con Sjoerd y Jack (coincidentemente, CVS fue desarrollado originalmente como un set de shell scripts por Dick Grune, quien era uno de los miembros originales del equipo de desarrollo de ABC). Escribí una FAQ, que era regularmente publicada en algunos grupos de noticias, como era costumbre para las FAQs en aquellos días anteriores a la web. Empecé una lista de correos, en marzo de 1993 se creó el grupo de noticias comp.lang.python con mi apoyo pero sin estar directamente involucrado. El grupo de noticias y la lista de correos fueron unidos mediante un gateway bidireccional que aún existe, aunque hoy está implementado con mailman (el gestor de listas de correos líder, escrito en Python).

    En el veranode 1994, en el grupo de noticias apareció un hilo titulado "¿si a Guido lo atropella un colectivo?" sobre la dependencia de la creciente comunidad de Python en mis contribuciones personales. Culminó con una invitación que me hizo Michael McLay para pasar dos meses como investigador invitado en el NIST, el Instituto Nacional de Estándares y Tecnologías de los Estados Unidos, antes el Bureau Nacional de Estándares, en Gaithersburg, Maryland. Michael tenía varios "clientes" del NIST interesados en usar Python para una variedad de proyectos relacionados con estándares y el presupuesto para mi estancia allí nació de la necesidad de ayudarlos a mejorar sus habilidades con Python, así como posiblemente adaptar Python a sus necesidades.

    El primer workshop de Python se llevó a cabo mientras estuve allí en noviembre de 1994, con el programador del NIST, Ken Manheimer, dándome un importante apoyo. De los aproximadamente 20 asistentes, alrededor de la mitad son aún participantes activos de la comunidad de Python y algunos se volvieron líderes principales de proyectos open sources (Jim Fulton de Zope y Barry Warsaw de GNU mailman). Con el apoyo del NIST también di una charla para 400 personas en la conferencia Usenix Little Languages en Santa Fe, organizada por Tom Christiansen, un defensor de Perl de mente abierta quien me presentó al creador de Perl, Larry Wall, y al author de Tcl/Tk, John Ousterhout.

    En la próxima entrega: cómo conseguí un trabajo en los Estados Unidos...

    Traducido por Juan José Conti.

    Revisado por César Portela.

    Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

    Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


    Asociación de métodos en tiempo de ejecución en Python

    En el primer artículo de La Historia de Python (en) se menciona, entre las cualidades que hacen a Python un lenguaje que permite la programación orientada a objetos, la posibilidad de "asociación de métodos en tiempo de ejecución" ("run-time binding of methods"). Hoy en otro artículo del autor, vuelvo a leer sobre el tema:

    Now instances of C have a method with one argument named 'meth' that works exactly as before. It even works for instances of C that were created before the method was poked into the class.

    Vamos a ver un ejemplo de esto:

    >>> class C:
    
    ...     pass
    
    ...
    
    >>> c1 = C()
    
    >>> c1.hello()
    
    Traceback (most recent call last):
    
      File "", line 1, in 
    
    AttributeError: C instance has no attribute 'hello'
    
    >>> def hello(myself, name):
    
    ...     myself.lasthello = name
    
    ...     print "Hello %s" % name
    
    ...
    
    >>> C.hello = hello
    
    >>> c2 = C()
    
    >>> c2.hello("mary")
    
    Hello mary
    
    >>> c1.hello("juanjo")
    
    Hello juanjo