En iCarto habíamos planificado hace un tiempo migrar nuestra infraestructura de desarrollo (repositorios de código principalmente) a GitLab. Estos días hemos terminado la migración y he aprovechado para escribir un artículo de como se pueden mantener mirrors de los repos de gitlab en github a través de la propia plataforma o con un servidor intermedio.
Etiqueta: desarrollo sofware
Libro: Dive Into Python
Hay una versión del libro para python 2, cuya última edición es de 2004, y una versión centrada en python 3 con algo de contenido reescrito. El autor original Mark Pilgrim hace tiempo que desapareció de internet, pero los libros continúan siendo mantenidos aunque poco actualizados en github.
Ambas versiones de los libros tienen buenas puntuaciones en Amazon y Goodreads [v2] [v3]
Se venden como un hands-on en python, es decir poca teoría y presentar ejemplos prácticos.
La estructura de ambas versiones es la misma para todos los capítulos comienza con un ejemplo de código, y a continuación lo explica paso a paso. Durante el proceso va introduciendo nuevas funcionalidades del lenguaje. Tal y como está estructurado no es adecuado para alguien sin conocimientos de programación previos. Tampoco me parece adecuado para gente que sepa de otro lenguaje y quiera aprender python.
Algunos de los capítulos de la segunda versión se quedan antiguos y/o muy específicos como trabajar con http, xml o html. La parte de testing, tdd y refactoring es bastante limitada y no me acaba de convencer, aunque hay que reconocer que pocos libros no específicos tratan estos temas, por lo que es de agradecer que al menos los mencionen. Los primeros tres capítulos y el de expresiones regulares son casi un relleno, me parecen avanzados para alguien que no sepa python, poco útiles para quien ya controle del lenguaje. Los capítulos de Introspección, POO, Programación Funcional y Funciones dinámicas pueden aportar algún conocimiento de interés y funcionalidades del lenguaje algo menos habituales de usar.
En la versión 3 pasa más o menos lo mismo, aunque los capítulos sobre Closures & Generatos, Classes & Iteratos, Advanced Iteratos, y Special Method Names son interesantes. Esta versión tiene un poco menos de carga en la parte de Programación orientada a objetos, así que esos capítulos se pueden revisar en la versión para python 2. Los capítulos sobre migración de python 2 a python 3 sólo son de interés para quien tenga que abordar un proyecto de ese tipo.
Si estás buscando un libro para aprender python sepas o no programar previamente esta no es una buena opción. Pero si merece la pena cuando ya tengas idea del lenguaje y estés buscando aprender un poco más y conocer algunos idioms, sobre todo en modo lectura rápida. Abre cada capítulo y trata de entender el ejemplo propuesto, si no tienes dudas puedes pasar al siguiente capítulo. Si el ejemplo tiene algo que te resulta de interés lee un poco más de ese capítulo.
Libro: Think Python: How to Think Like a Computer Scientist
How to Think Like a Computer Scientist es un libro clásico entre los recomendados para comenzar a programar en python. La primera edición es de 2002, escrito por Jeffrey Elkner, Allen B. Downey y Chris Meyers bajo licencia GNU FDL. El ser tan «antiguo» y el estar publicado bajo licencia libre ha hecho que a lo largo del tiempo hayan aparecido diversas versiones del libro.
Tenemos dos versiones del libro para python 2
- How to Think Like a Computer Scientist: Learning with Python 2nd edition, sería la última edición para python 2 del libro original, y está fechada en 2012. Las soluciones a algunos ejercicios se pueden encontrar en wikibooks (y seguramente valgan para otras versiones).
- La primera edición (2002) de ese mismo libro la podemos encontrar en Green Tea Press la página personal (y «editorial») de Allen B. Downey uno de los autores originales
- Y también en Green Tea Press podemos encontrar una reedición distinta del mismo libro para python, renombrada simplemente a Think Python. Revisando el github donde se mantiene el libro los últimos cambios serios parecen ser de 2015
También tenemos varias versiones del libro enfocadas a python 3.
- La que podríamos considerar primera, de 2012, es How to Think Like a Computer Scientist: Learning with Python 3, reeditada fundamentalmente por Peter Wentworth como libro de texto para un primer curso de programación.
- Otra versión sería una adaptación de la de Peter Wentworth, hecha por varios profesores de la Universidad de Groningen, para emplearla también como libro de texto para sus clases. En el prólogo declaran que su idea era cambiar la filosofía del libro, de «how to think like a computer scientist» to «how to think as a scientist with a computer», pero revisándolo en mi opinión, los cambios no son tan significativos como para conseguirlo. Está en readthedocs por lo que también se puede descargar
- En Green Tea Press también encontramos una versión (los últimos cambios serios en el github son de 2016). Esta sería algo así como la segunda edición de Think Python
- Por último, un experimento interesante. Un libro interactivo, que parece basado fundamentalmente la versión de Wentworth. Consiste en una aplicación web que permite ejecutar código en el propio navegador, depurar paso a paso a modo educativo y responder a cuestionarios
En la página de Green Tea Press hay un dos artículos explicando porqué publicar «free books», y su filosofía a la hora de escribir libros de texto. Además en el prólogo del libro se puede leer algo sobre su historia para entender los autores y los cambios a lo largo del tiempo.
Todas las versiones (inluída la interactiva) están en repositorios de código en github o launchpad, por lo que es posible colaborar en su mejora. Y están escritos en reStructuredText o Markdown y convertidos a libros con sphinx u otras herramientas.
No resulta sencillo decir «cual es mejor», cada una de las veriones tiene sus puntos fuertes y débiles:
- Los que hemos hemos numerado como dos y como tres son los que tienen para mi un orden de capítulos más lógico. Por ejemplo trata listas, tuplas y diccionarios en capítulos contiguos mientras que en las otras versiones los diccionarios están separados del resto de tipos de datos. Pero en dos han juntado varios capítulos en uno sólo por lo que su lectura se hace algo más difícil. Además los capítulos sobre numpy, matplotlib y data handling no encajan muy bien como están escritos en un libro para principiantes. Por tanto a pesar de ser el más actualizado yo en principio descartaría esta versión.
- El número tres (Think Python) tiene para mi otros alicientes como que algunos de los problemas y soluciones están resueltos en el github del autor. Es de los que siguen un orden más lógico, capítulos cortos, y una sección «debugging» al final de cada capítulo que explica «técnicas mentales» a la hora de depurar y construír un programa que resultan útiles. Además se puede comprar a través de Amazon, descargar gratuitamente en PDF, leer en html… Así que seguramente esta es la versión más recomendable.
- La versión interactiva también me ha sorprendido gratamente. El texto no es tan bueno como el de Think Python, pero el poder jugar con el código mientras leemos el texto, da muchas opciones a alguien que se introduce en el lenguaje y le permite aprender sin tener que liarse con el entorno. Además la opción de debug (codelens en su terminología es especialmente útil para ver lo que pasa en el programa). Esta tambień es un opción recomendable.
El uno tiene algún material adicional respecto a los otros como capítulos sobre estructuras de datos más avanzadas (pilas, colas y árboles). Si bien creo que estos capítulos son de interés, tampoco pasa nada por prescindir de ellos en un primer contacto, porque hay otros libros más avanzados o más específicos que tratan mejor este tipo de temas.
Entre la opción interactiva y Think Python es difícil decidirse, si quieres avanzar rápido y tener una panorámica general, el libro seguramente es mejor, y la irrupción de cajas y botones en medio del texto menos molesta. Depende del estilo de aprendizaje de cada uno. Leer un par de capítulos de cada uno y decide tu mismo.
Si está revisión te ha ahorrado tiempo y quieres agradacerme el esfuerzo planteate donar usando el botón de la derecha, o simplemente dejar un comentario en esta entrada.
Hacen falta más programadores contando sus miserias
Desde que Andrés planteara hace ya dos años el reto de escribir sobre la selección tecnológica en pymes llevo queriendo escribir algo sobre ello.
Todavía no va a ir de esta, pero valga este mini-post para referenciar dos enlaces que han entrado en mi radar esta misma semana. En el primero Matt Mullenweg quota a Jony Ive de Apple para afirmar que tan importante como el producto (o el servicio) que proporcionas a tus clientes es el proceso, o el aprendizaje, con el que has llevado hasta él. Algo en lo que creo firmemente y que también leí en Kent Beck (aunque ahora no encuentro el enlace). En el segundo nos hablan de como no todas las arquitecturas valen para todos los casos.
Basicamente mi opinión va en la línea de que los creadores de opinión en torno al software, son lógicamente, increiblemente expertos en sus campos. Los frameworks con más éxito, son hechos por empresas como Google o Facebook. Las conferencias están llenas de gente que hace cosas muy chulas con las últimas tecnologías. Pero cuando tengas que decidir, si estás leyendo este post, seguramente no trabajes en Google, ni serás un mega-experto. Puede que tus clientes para hacer el deploy te hagan conectarte a un teamviewer ejecutándose en un Windows en una red interna donde te permiten abrir un putty al servidor y «monitorizan» todo lo que tecleas que debe hacerse a mano para validarlo. Trata de hablar con ellos de docker (o incluso de scripts para automatizar).
Hace falta más conferencia, más libros y más posts de gente contando sus miserias, y de como su trabajo es tan necesario como el de quien tiene la suerte de poder desplegar en AWS, porqué también están resolviendo problemas reales.
Libro: A Byte of Python de Swaroop C H
El libro «A Byte of Python» es uno de los que se suelen recomendar en las QA de como iniciarse en el desarrollo con Python. Es un libro corto, unas 120 hojas en la versión impresa que se puede ojear en apenas un par de horas. Está distribuído bajo licencia CC-by-sa 4.0 y el desarrollo se realiza en github. Al ser libre hay distintas versiones en la red, la canónica está en la página del autor y es la que se debería leer.
El libro hace un repaso básico a la sintaxis del lenguaje, sin entrar en demasiada profundidad en ningún tema y con ejemplos tipo «¡Hola mundo!». Tampoco se para demasiado en conceptos de teoría de la programación, como explicar que es una variable o un lenguaje interpretado pero si lo menciona. Eso sí, la terminología que emplea para hacer referencia a los conceptos es correcta.
Creo que es una buena guía si ya sabes algo de programación en otro lenguaje y quieres de una forma rápido poder empezar a hacer cosas con python, pero no es adecuado como primer contacto con el mundo del desarrollo.
Porqué creo que es útil discutir de Tabuladores y Espacios
Discutir de tabuladores y espacios es importante útil.
Por mucho scrum y mucha retro, generar el clima de confianza adecuado para cagarse en el facilitador o que los nóveles opinen si se debe usar una arquitectura hexagonal es difícil. Discutir sobre el color del cobertizo para bicicletas, en algunos contextos será una perdida de tiempo y energía. En otros será una buena actividad, un ejercicio práctico antes de elevar el nivel de abstracción de las discusiones.
Y en todo caso, es algo que hay que decidir, así que mejor que sea por consenso.
Charlas «The better Parts» por Douglas Crockford
Seguramente las charlas más conocidas de Crockford son las basadas en su libro The good parts y o algunas más modernas a las que llama de «The better parts» donde revisa alguna de sus anteriores prácticas y comenta features de ES6.
Dentro de esta serie de The Better Parts se pueden encontrar varias dadas en distintas momentos, entre ellas.
- The Better Parts | .concat() 2015. El problema de esta charla es que no se ven las transparencias (y a pesar de ser similares) a las slides que usa en otras se hace un poco complicado seguir el hilo. Creo que una de las novedades de esta charla respecto a otra es cuando habla de los Template Literals.
- The Better Parts. Infoq. Agosto/2014. Las transparencias de esta charla, que también valen de guía para el resto están aquí. La de la JSConfUY me pareció un poco más fluída que esta. Pero hay al menos dos secciones que en esta están mejor explicadas o ampliadas la que llama en las transaprecias New Good Parts in ES6 que empieza en el minuto 12 y acaba en el 25. Y cuando explica su constructor pattern (slide 46) a partir del minuto 34. El constructor también lo explica en la JSConfUY pero aquí se entienda mejor.
- The Better Parts – JSConfUY Septiembre/2014. En apareciencia esta tiene un poco más de carga filosófica que la de Infoq.
Yo ví la charla de JSConfUY, ojee la de concat, y fuí a algunas partes concretas de la de InfoQ. Mi recomendación es que veas la de InfoQ. O si no que veas de la JSConfUY y las partes concretas que mencionó de la de InfoQ.
A nivel contenidos las charlas son similares.
Arranca con una cita de Saint-Exupéry, «It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to subtract.» y de como los programadores deben buscar la perfección. Por ello hace incapié en uno de sus habituales, que un lenguaje nos dé un montón de características no significa que tengamos que usarlas todas si no sólo las «buenas».
Luego habla de jslint y de su libro de «The good parts». Combate algunas de las criticas que se hacen de jslint y defiende porqué el estilo de desarrollo no es simplemente un «acuerdo», si no que hay estilos mejores que otros, y que escribir de una determinada forma elimina bugs y por tanto te acerca a la perfección.
Continúa con una mini revisión de esas buenas partes de JavaScript en general mezclándolo con como debería ser el lenguaje del futuro (tiene otra charla sobre esto llamada The Post JavaScript Apocalypse), centrándose en su propuesta para un nuevo tipo de datos numérico llamado DEC64.
Y termina hablando un poco de JSON.
The better parts
Entre las prácticas que menciona como mejores están.
* No usar for. Sólo array.forEach y derivados
* No dice nada de for..of, supongo que en el momento todavía no habría una propuesta al respecto, pero si habla de evitar for..in y emplear unicamente Object.keys(object).forEach
* Y dice que tampoco usa ya while si no que usa una construcción de este tipo
function repeat(func) {
if (func() !== undefined) {
return repeat(func);
}
}
Como vemos, y como el mismo dice, estás Better Parts van en la línea de usar JavaScript como un lenguaje funcional.
Especial atención merece su nuevo patrón para la construcción de objetos. Hace tiempo que aboga por no usar new pero también ha dejado de usar Object.create, de hecho ha dejado de usar this para evitar problemas de seguridad. También defiende que la herencia basada en prototipos es una mejor idea que las jerarquías clásicas. Porqué, las jerarquías son en general erróneas, y además suelen establecerse al principio del proyecto, cuando menos información se tiene de como debe ser.
Su patrón para la construcción de objetos tendría este aspecto
function constructor(spec) {
let {member} = spec,
{other} = other_constructor(spec),
method = function () {
// member, other, method
};
return Object.freeze({
method,
other
});
}
Donde
- spec será generalmente un object literal, que permite inicializar el objeto
- member será un miembro privado de la clase, no accesible desde el exterior
- Esta construcción permite que se pueden llamar tantas veces como se quiera a otros constructores (other_constructor), de ese modo se obtiene herencia múltiple, y se pueden copiar, las funciones de interés de esos otros objetos en nuestro objetos
- También puedo crear nuevos métodos (method), que tendrán acceso a los miembros privados, a otros métodos, a lo que proporcione other. En este caso method es público porque se devuelve al llamante pero con el mismo diseño podría ser un método privado
- Se devuelve un nuevo objeto (el literal dentro de freeze, con todos los métodos de interés)
- Lo congela para hacerlo inmutable, con todas las implicaciones que eso trae. Seguridad, comparaciones más sencillas, …
- Comenta que este sistema tiene un costo en memoria. Al contrario que otras estrategias que reaprovechan los métodos, en esta method sería creado cada vez. Pero a cambio es muy rápido, porque no hay que recorrer el prototype chain para encontrar las claves si no que están directamente en el propio objeto
En otro momento, me gustaría hacer un artículo con los distintos patrones de creación de objetos de Javascript, pero debo decir que este me convence mucho, porque debe ser de las pocas veces que veo algo de este tema en JS que parece tener sentido a la primera. Lo que no comprendo es porque llama «constructor» a su función de ejemplo cuando en realidad es una «factory».
Modelado de datos booleanos en la base de datos
Cuando definimos la información que un usuario puede visualizar o modificar a través de un formulario nos encontraremos datos aparentemente booleanos. Por ejemplo: ¿Hay un pozo en esta aldea?.
La primera aproximación para implementar esta información es poner un checkbox en el formulario y definir el campo como booleano en la base de datos.
CREATE TABLE aldea (id serial, pozo boolean);
Haciéndolo de este modo existen varios posibles problemas:
- A nivel usabilidad. Que pasa si el usuario no sabe si hay un pozo. Lógicamente dejará el checkbox sin marcar, pero cuando se revise esa información no se podrá saber si a conciencia se dejo en blanco indicando que no había pozo, o si se desconocía el dato.
- A nivel implementación. Por defecto, a no ser que la lógica implementada en cliente lo gestione de otra forma, en la base de datos almacenaremos un valor NULL y no un valor FALSE. Al tener valores nulos las queries que hagamos se pueden complicar, por ejemplo un SELECT * FROM aldea WHERE pozo IS FALSE; no nos devolverá los valores nulos. Si empleamos la tabla para hacer un informe o exportarla a una hoja de cálculo tendremos que lidiar con los nulos, …
Por tanto cuando modelemos una información que parezca binaria, preguntémonos (y preguntemos al cliente) si es necesario distinguir entre falso, y desconocer el dato. Si estamos en la segunda situación debemos huír de usar checkboxes y emplear otro tipo de widget, como un combobox donde el usuario pueda escoger «Existe», «No existe» o dejar en blanco si no conoce el dato. A nivel implementación la información del combobox la guardaremos en general como un texto o un tipo enumerado. Y si eres un producto owner que usa algún tipo de documento para definir el modelo de datos a los desarrolladores asegurate siempre de especificar esta información.
Habrá situaciones en las que aún presentando al usuario la información mediante un combo, nos interese modelar el campo como un booleano. En este caso la lógica por encima de la base de datos sería la responsable de traducir el campo en blanco por un nulo, el ‘Existe’ por un true y el ‘No existe’ por un false.
Cuando modelemos un campo en la base de datos que sea verdaderamente binario para evitar confusiones deberíamos implementarlo de esta forma.
CREATE TABLE aldea (
id serial,
pozo boolean NOT NULL DEFAULT false
)
Addendum
Cuando trabajamos con campos booleanos que admiten el valor nulo nos podemos encontrar un problema adicional al hacer migraciones de la base de datos. Imaginemos que tenemos un campo contador de tipo boolean, y que en la base de datos tenemos valores a true, false y null. Si a posteriori decidimos cambiar contador por un sistema de medida, con opciones como Contador, Manual, Volumétrico, … hacer la migración hacia adelante será sencillo.
UPDATE myschema.mytable SET sistema_medicion = 'Contador' WHERE contador IS true;
Pero el revert no sería tan sencillo, porque habremos perdido la información de nulos y false.
Usando GeoProcesos en gvSIG desde Java
La semana pasada había un correo en la lista de desarrollo de gvSIG preguntando como poder lanzar geoprocesos desde tu propio plugin mediante Java. Tras una pequeña investigación he escrito un código de ejemplo que espero que sea útil a quien tenga esta necesidad.
Descargar el código
A mi particularme me gusta descargar el código fuente de las partes de gvSIG con las que voy a trabajar. Esto simplifica el usar las herramientas del IDE para saber como usarlo, encontrar errores, y revisar los tests, en caso de haberlos, para tener pistas de como escribir mi propio código.
Para ello primero se mira la versión del plugin que se corresponda con la versión de gvSIG que estás usando. Creo que lo más fácil es descargar una versión portable de gvSIG. Entrar a la carpeta que contiene el plugin, en este caso org.gvsig.geoprocess.app.mainplugin y abrir el fichero package.info. En la property version está el tag del repo correspondiente a esa versión. Por ejemplo para la 2.3RC2 sería el 2.266. Por tanto para descargar el repo haremos:
svn checkout http://devel.gvsig.org/svn/gvsig-geoprocess/org.gvsig.geoprocess/tags/org.gvsig.geoprocess-2.2.66/
A continuación,e n caso de usar Eclipse, iremos a import -> Existing maven projects, e importaremos la raíz del nuevo plugin descargado.
Añadir las dependencias
Al desarrollar en gvSIG debemos tener en cuenta que las dependencias de nuestro plugin, por decirlo de algún modo, serán de dos tipos. En «Tiempo de desarrollo», y en «Tiempo de ejecución». Las dependencias en desarrollo se definen en el pom del proyecto permitiéndonos definir el classpath de desarrollo para trabajar con las clases que nos hagan falta.
En ejecución, cuando estamos probando o ejecutando gvSIG, el classpath se define de manera dinámica por decirlo de algún modo en el fichero de config.xml. gvSIG buscará entre las dependencias que hayamos definido en el config las clases que se pueden usar en nuestro plugin.
Para que quede claro, a nuestro pom se añadirán otros proyectos maven. A nuestro config se añadirán plugins de gvSIG.
Por ejemplo para el caso de usar los geoprocesos, añadiremos al pom:
y al config
Obtener el algoritmo que queremos
Esta una de las partes en las que tengo más dudas que esté correcta.
En general accederemos a las funcionalidades de gvSIG a través de un Locator que nos dará un Manager que nos dará la funcionalidad. En el caso de los geoprocesos sería:
String ALG_NAME = "gvSIG-intersection";
SextanteGeoProcessManager manager = (SextanteGeoProcessManager) GeoProcessLocator.getGeoProcessManager();
HashMap
GeoAlgorithm alg = algs.get(ALG_NAME);
Debemos castear a la implementación por defecto del manager SextanteGeoProcessManager porque la interfaz en sí no proporciona el método getAlgorithms. Esto diría que es un bug.
La forma de obtener ALG_NAME, no estoy seguro de cual es. En principio lo más fácil sería poner un breakpoint y mirar los valores de algs. Aunque en mi caso sólo salen los propios de gvSIG y no los de Sextante.
Seteando valores al algoritmo
Todos los algoritmos definen un método defineCharacteristics que nos indican los valores que recibe, tanto de entrada como de salida. Esta definición de valores se obtiene a través del método getParameters
En nuestro código debemos obtener cada uno de los parámetros necesarios y setear su valor real para nuestro caso. Por ejemplo:
private void setParams(GeoAlgorithm alg) throws WrongParameterIDException {
ParametersSet params = alg.getParameters();
FLyrVect interLyr = getLayer("inter");
FlyrVectIVectorLayer inter = new FlyrVectIVectorLayer();
inter.create(interLyr);
FLyrVect layerLyr = getLayer("layer");
FlyrVectIVectorLayer layer = new FlyrVectIVectorLayer();
layer.create(layerLyr);
params.getParameter(IntersectionAlgorithm.INTER).setParameterValue(
inter);
params.getParameter(IntersectionAlgorithm.LAYER).setParameterValue(
layer);
params.getParameter(IntersectionAlgorithm.SELECTGEOM_INPUT)
.setParameterValue(false);
params.getParameter(IntersectionAlgorithm.SELECTGEOM_OVERLAY)
.setParameterValue(false);
}
En este caso para no escribir a mano los idenfificadores de los parámetros uso las variables estáticas definidas en el propio algoritmo. Eso hace que haya que añadir al pom el algortimo:
Para las capas de entrada al algoritmo hay que generar una FlyrVectIVectorLayer. Como se muestra en el código de ejemplo lo más sencillo es obtener un FLyrVect y construirla con el create.
Ejecutando el algoritmo
Los algoritmos se lanzan mediante el método execute que como indica la documentación admite hasta tres parámetros.
- ITaskMonitor task. Que puede ser nulo y permite monitorizar el estado para por ejemplo poner una barra de progreso al usuario
- HashMap
outputMap. Que permite modificar los nombres que sextante asigna a los parámetros de salida (en general capas) - OutputFactory outputFactory. Define como se crearán los objetos de salida. Puede ser nuestra propia implementación o usar la factoría por defecto
Por tanto ejecutarlo sería simplemente:
alg.execute(null, new DefaultOutputFactory(), null);
Obteniendo los resultados
Con la factoría por defecto las capas se crean en un directorio temporal que en linux es /tmp/tmp-andami y les asigna nombres aleatorios (creo que basados en el timestamp). Supongo que habrá alguna utilidad que nos permite ejecutar una especie de FinalActions para añdirlos automáticamente a la vista. O implementando nuestra propia OutputFactory podríamos definir otras rutas. También diría que podemos prescindir del OutputFactory y lanzar el algoritmo mediante processAlgorithm si igual que hicimos con los parámetros de entrada seteamos adecuadamente los valores de salida, especialmente el OutputChannel de las capas.
En todo caso el método getOutputObjects nos devuelve los objetos de salida, así por ejemplo podríamos llegar el FlyrVectIVectorLayer de la capa de polígonos de salida con:
OutputObjectsSet outputSet = alg.getOutputObjects();
OutPut output = outputSet.getOutPut(IntersectionAlgorithm.RESULT_POL)
FlyrVectIVectorLayer result_pol = (FlyrVectIVectorLayer) output.getOutputObject();
Atom: Autocompletado de código en python
Al margen del «Code Completion» de PyCharm, y algún otro, el resto de editores/IDEs proveen autocompletado a través de librerías o «servicios externos». Para el caso de python hay fundamentalmente dos, rope y jedi. Rope está más enfocada a Refactoring y Jedi a Autocompletado, por tanto las dos son complementarias. En la actualidad varios editores que usaban rope están migrando a jedi, su autor ha hecho una comparación defendiendo su librería.
Además de estas librerías cada editor suele proporcionar un plugin base para autocompletado (autocomplete-plus en atom, auto-complete en emacs) y plugins adicionales para cada lenguaje concreto que actúan como wrapper de las librerías base (rope, jedi,…). Por ejemplo en atom tenemos autocomplete-python que es un wrapper para jedi.
Instalación
Primero hay que instalar jedi sea a nivel global como en el ejemplo, o dentro de un virtualenv.
sudo pip install jedi
Luego se instala el plugin de autocomplete-pyhon (que es el más actualizado de los varios que hay). Si usas virtualenv también debería funcionar sin problemas pero si usas algo como virtualenvwrapper donde tu módulo está en un directorio distinto al «entorno virtual de python» puedes haber más problemas.
Lanzado atom desde un virtualenv activado siempre funciona correctamente. Si lo lanzas de otra forma hay que configurar la opción de configuración Python executable path del plugin con algo como:
PATH_TO_VIRTUALENV_WRAPPERS_FOLDER/$PROJECT_NAME/bin/python
o
PATH_TO_VIRTUALENV_WRAPPERS_FOLDER/$PROJECT/bin/python
Donde PATH_TO_VIRTUALENV_WRAPPERS_FOLDER es la ruta absoluta al directorio donde se guardan todos los entornos virtuales de virtualenwrapper y $PROJECT_NAME y $PROJECT son cadenas que debes escribir tal cual. Son variables que entiende el plugin. De la documentación parece deducirse que lo que hay que usar es $PROJECT pero a mi me ha funcionado sólo con $PROJECT_NAME. Además el directorio padre que se añade a atom a través del «Add project folder» debería llamarse igual que el virtualenv para que $PROJECT_NAME tome el valor correcto y puedas usar la misma configuración para distintos proyectos.
Uso
Por la naturaleza dinámica de python muchas veces jedi no es capaz de detectar el tipo de datos de un objeto. Pero podemos ayudarlo documentado el método. Por ejemplo en un caso como el del ejemplo siguiente con una vista de pyramid, jedi no será capaz de determinar el tipo de datos del parámetro request.
@view_config(route_name='my_route')
def my_route(request):
pass
Pero si hacemos lo siguiente si que autocompletará correctamente los métodos de request:
def cultivos_get(request):
"""
:type request: pyramid.request.Request
"""
pass
No lo he probado con python 3 para ver si soporta el type hinting pero este issue me hace suponer que si.
Teclas principales
- Sugerencias de autocompletado.
Ctrl+space
Cursores y tab/intro para escoger y aceptar sugerencia - Go to definition:
Ctrl+Alt+G
- Show usages:
Ctrl+Shift+P show usages
- Renombrado en varios ficheros a la vez: Con el cursor encima del símbolo.
Ctrl+Shift+P rename
Conclusiones
Las funcionalidades que proporciona son de todas formas muy justas porqué a no ser que documentes los métodos, la mayoría de veces no es capaz de inferir el tipo de datos de una variable. Además las funciones de autocompletado normal de atom incluyen habitualmente opciones que no tienen porque corresponder con métodos o propiedades reales del objeto. Y si se desactiva el autocompletado normal para los ficheros python, tendremos muy pocas sugerencias.