>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> my_beer = ureg.pint
>>> print(my_beer.to('liter'))
0.473176473 liter
>>> print(my_beer.dimensionality)
[length] ** 3
>>> ureg.pint < ureg.imperial_pint
True
>>> ureg.pint < ureg.liter
True
>>> x1 = numpy.asarray([2., 3.]) * ureg.meterPint 0.2 extends the support to almost all ndarray methods and ufuncs. Each function/method has been tagged according to expected units and how to handle arguments and Pint attempts to convert them on the fly. For example, arctan2 expects two arguments with the same dimensionality and converts the second argument to the units of the first:
>>> # or simply by multipliying an iterable by the units.
>>> x1 = [2., 3.] * ureg.meter
>>> x2 = [2., 3.] * ureg.meterThe cosine function expects a quantity that can be converted to radians:
>>> x2 = [300., 200.] * ureg.centimeter
>>> numpy.arctan2(x1, x2)
<Quantity([ 0.5880026 0.98279372], 'radian')>
>>> numpy.cos(x1)
Traceback (most recent call last):
...
pint.unit.DimensionalityError: Cannot convert from 'meter' ([length]) to 'radian' (dimensionless)
>>> home = 25.4 * ureg.degC
>>> print(home.to('degF'))
77.7200004 degF
>>> difference = 5 * ureg.delta_degC
>>> print(difference.to('delta_degF'))
2.7777777777777777 delta_degF
>>> print(ureg.parse_units('degC/meter'))
delta_degC / meter
>>> result = ureg.pi_theorem({'V': 'meter/second', 'T': 'second', 'L': 'meter'})
>>> print(result)
[{'V': 1.0, 'T': 1.0, 'L': -1.0}] The returned value is a list containing the dimensionless parameters (in this case only one) each specified using a dictionary. The keys corresponds to the names of the physical variables and the values to the exponents. You can print it nicely using Pint's formatter function: >>> from pint import formatteror using the dimensions
>>> print(formatter(result[0].items()))
T * V / L
>>> result = ureg.pi_theorem({'V': '[speed]', 'T': '[time]', 'L': '[length]'})
>>> print(formatter(result[0].items()))
T * V / L >>> length = (2.3 * ureg.meter).plus_minus(.23)The measurement class also supports some basic uncertainty propagation:
>>> print(length)
(2.3 +/- 0.23) meter
>>> print('{:.02f!p}'.format(length))
(2.30 ± 0.23) meter
>>> print('The relative error is: {}'.format(length.rel))
The relative error is: 0.1
>>> width = (4.6 * ureg.meter).plus_minus(.23)
>>> print('{:.02f!p}'.format(width / length))
(2.00 ± 0.22)
This is the first SciPy Conference in Argentina (as far as I know, it is also the first one in Latin American).
It will be held from 16 to 18th of May in Puerto Madryn, at the Patagonia Argentina (more details at SciPyCon homepage).
I am very proud to have this kind of conference in my country, and I would like to thanks to the organizers (and the sponsors) for all their hard work to make it happens.
The conference will have exciting talks, tutorials and poster presentations. You can check the schedule here
I will be presenting a tutorial called, Python Científico: Episodio I (Scientific Python: Episode I). You can check the details here.
And I will be also presenting a talk called, IPython notebook: el "paper ejecutable" (IPython notebook: the "executable paper").
This conference will be a boost for our growing Scientific Pythonic Community and an exciting beginning!
Why I am writing in English about a Spanish Conference? Because I want to spread the word about this conference as much as I can and because there are international speakers scheduled (and I would love to see more in the next conference!)
I hope to see you there!
Damián.
Estos días hice dos releases rápidos.
El primero fue de LauncherPosta, porque resulta que en Ubuntu Raring crasheaba mal. O sea, no tiraba un traceback: crasheaba.
¿Lo peor? Es un problema de la librería PyGtk, de cómo está implementado para Gtk 3. ¿Lo peor más peor de todos los peores? Es por diseño, y les parece bien que crashee a la mierda en lugar de tirar un traceback decente (miren el bug que abrí y lo que me respondieron).
En fin, esto refuerza lo que les decía que Gtk3 me gustaba menos y menos y me estoy pasando a Qt.
BTW, de LauncherPosta liberé la versión 1.0, con el casi único cambio de soportar mejor el toqueteo de la configuración del systray bajo Unity (un pedazo de código que luego les compartiré más separadamente).
El segundo release fue de Enjuewemela.
Hace rato que no sacaba una versión del jueguito. Es que aunque le había hecho un montón de correcciones, había un gran feature que estaba esperando: el replayer.
¿Qué es el replayer? Es un modo de ejecución de Enjuewemela que le decís que te reproduzca un juego anterior (le tenés que pasar el log que generó la jugada), y podés ir viendo exactamente el juego que hiciste, avanzando y retrocediendo con las flechas. Esto más que nada lo hice porque era necesario para poder detectar algunos crashes raros, y porque era divertido de hacer, :)
Los cambios más interesantes para esta versión 0.5, aparte de la habilidad de "re-jugar un log", son:
- Alienta cuando hay múltiples coincidencias
- Cambia el tablero cuando cambia de nivel
- Múltiple fondos
- Correcto manejo de los highscores
- Otras pequeñas mejoras y un montón de correcciones.
La verdad es que estoy un poco harto de Enjuewemela. Hay que ponerle un montón de laburo para "hacerlo más lindo" al juego, y la verdad es que "hacerlo lindo" no es algo que me divierta.
Así que creo que sacaré un gran último feature, y luego creo que lo paso a mantenimiento, porque tengo otros proyectos bastante más interesantes para empujar.
Ya los comentaré por este mismo canal. Stay tuned.
Este no es un post sobre Encuentro precisamente, sino sobre la experiencia de migrar Encuentro a Qt.
O, mejor dicho, a PyQt. ¿Qué es PyQt? Sencillo: una capa de unión para poder usar Qt desde Python. ¿Y qué es Qt? Qt es una biblioteca multiplataforma para desarrollar aplicaciones con interfaz gráfica. En otras palabras, una biblioteca para hacer las ventanas, botones, y todo eso que arma la interfaz gráfica de un programa de escritorio.
Con esa descripciones no tendríamos diferencia entre PyQt/Qt y PyGtk/Gtk, que es lo que usaba Encuentro hasta ahora. Entonces, ¿por qué migrar?
Son varias las razones... pero principalmente porque empaquetar PyGtk en un .exe es un dolor de muelas, y eso llevó a que la última versión que corre en windows es la que no funciona porque cambió todo el backend web (cuando los videos pasaron de ser hosteados por Encuentro a estar en Conectate). En otras palabras: la última versión de Encuentro que corre en windows no sirve para nada, y básicamente es culpa de Gtk.
Otras razón de menor importancia es que no me gustó como Gtk evoluciona. El futuro del framework es Gtk3, y ya estuve tirando código para usarlo, y lo que usé me gustó menos que Gtk2, así que me pareció un buen momento de cambiar. Finalmente, es una buena excusa para aprender Qt, ;)
En fin. La migración ya está terminada, pude hacer en Qt todo lo que tenía que hacer en función de la interfaz de Encuentro. ¿Qué me pareció? Bueno, las sensaciones son varias.
Me gustó Qt, mucho más cuadradito, más pytónico especialmente en la versión 4 que es la que yo estoy usando. Aunque la mayoría del código es muy similar, hay varias cosas que son más sencillas que en Gtk, aunque no todas, y hay bordes que limar.
(En este punto quiero aclarar que en ningún punto usé Qt Creator, el constructor gráfico de interfaces, sino que hice todo todo a mano, lo cual me permitió meterme bien adentro del framework y aprender mucho de su estructura subyacente.)
Un ejemplo de borde sencillo: no se puede saber si una señal está conectada o no. Entonces, por ejemplo, yo tengo un botón que muta de función, y a veces tiene que tener una señal conectada, y a veces otra (para que al hacer click haga una cosa u otra; en particular en el contexto de Encuentro: que el botón dispare la descarga del episodio, o la reproducción). Cuando el contexto cambia y se hace la revisión del estado del botón, no puedo decirle que desconecte cualquier señal que tenga, o preguntar qué señal tiene y desconectarla, tengo que (a mano) guardar en algún lado la señal que había conectado antes para desconectarla y conectar la nueva que corresponda.
Un ejemplo de algo complicado de hacer en Qt (que en Gtk es trivial): QTreeWidget no soporta HTML en el texto. Esto es, la habilidad de insertar tags para cambiar el tipo de texto (en el caso de Encuentro, yo lo necesito para resaltar en amarillo el fondo de las letras que coinciden con lo que el usuario ingresó en el campo de filtrar). Finalmente lo pude hacer, adaptando un ejemplo que Roberto Alsina encontró en la web, pero lo hace más lento, le agrega pequeños glitches que aunque no me joden, no deberían estar, y me mete a mí código oscurísimo que no es ni cerca de fácil de debuguear.
Por último, la integración con Twisted no es trivial. Hay cosas que en Encuentro están hechas con Twisted que podrían hacerse con herramientas más propias de Qt, sí, pero en este caso de migración, ya estaban hechas en Twisted y mi idea era aprovecharlas. Pero tuve que meter en el proyecto todo un módulo de integración y levantar la aplicación y cerrarla de una manera no trivial (y que me costó tiempo y sudor hacer que funcione correctamente, especialmente la parte de cerrar la aplicación, porque tuve que apagar los hilos de Twisted a mano).
La conclusión es que Qt me gustó bastante, y aunque extraño algunas cositas de Gtk, seguramente mis nuevos proyectos estarán usando PyQt.
I am a very big proponent of static site generators. I would not have bothered writing Nikola otherwise. But there is always that feeling that maybe there is some little thing which is hard to implement, like a contact form.
And let's face it, the easiest way to solve some of those things is by sticking a few lines of PHP in your HTML.
So, if you really want to, you can do it. I think Nikola (github master) is the first static site generator that supports php code. Here's how:
Add php to your page_compilers (because I will never put it there by default):
post_compilers = {
"rest": ('.txt', '.rst'),
"markdown": ('.md', '.mdown', '.markdown'),
"textile": ('.textile',),
"txt2tags": ('.t2t',),
"bbcode": ('.bb',),
"wiki": ('.wiki',),
"ipynb": ('.ipynb',),
"html": ('.html', '.htm'),
"php": ('.php'),
}
Add php posts or pages to your post_pages:
post_pages = (
("posts/*.txt", "posts", "post.tmpl", True),
("posts/*.php", "posts", "post.tmpl", True),
("stories/*.txt", "stories", "story.tmpl", False),
("stories/*.php", "stories", "story.tmpl", False),
)
Create a php post:
nikola new_post posts/foo.php
Put php in there:
<!-- .. date: 2013/04/16 09:57:09 .. title: php test .. slug: foo --> <?php Print "Hello, World!"; ?>
Build the site as usual, and you should end up with a page with PHP extension, that has that PHP in the "content" area, so it will follow your site's theme. Of course you can't do things like add HTTP headers and such, but hey, read the title.
Yes, version 5.4.4 of Nikola, my static site/blog generator is just published at the usual place, including the following improvements:
No es porque lo haya escrito yo (bueno, sí) pero si necesitás un browser "limpio" sin cookies, etc, para testear algo, podrías encontrar maneras peores que usar Devicenzo así:
rm -f ~/.config/ralsina/devicenzo.conf curl https://devicenzo.googlecode.com/svn/trunk/devicenzo.py | python
La primera línea elimina toda la configuración, cookies, etc que puedas tener, y la segunda descarga la última versión (no te preocupes, tarda dos segundos) y la lanza.
Y voilá, un browser recién desembalado, basado en webkit, sin historia previa, ni cookies, ni configuración, y razonablemente feature-complete.
Note
Esto requiere que tengas python y PyQt instalado de antemano, por eso Devicenzo es tan chiquito.
pip es una herramienta esencial para el trabajo diario de un programador python: es el manejador de paquetes de nuestro entorno de trabajo (¡virtual por favor!), con el que instalamos, actualizamos o eliminamos las dependencias de nuestro proyecto (y, recursivamente, las dependencias que estas pudieran tener).
Conceptualmente es similar a los manejadores de paquetes de sistema como apt-get, diferenciándose en que, por defecto, consulta cada vez a una base de datos online si el paquete solicitado existe y de dónde puede bajar la última versión o la específica que se haya pedido.
Responder "qué, cuál y de dónde" es una tarea lenta porque dicha base de datos no es más que una página html por cada paquete con links que funcionan como un índice (como este que pip debe parsear comparar y elegir la mejor opción para bajar (a veces incluso debe parsear la homepage del proyecto en busca de links de descarga, puaj!).
Por eso (y porque muchas veces la infraestructura se satura) el uso estándar de pip es lento. Pero hay algunas maneras de que lo sea menos. Veámoslas.
El funcionamiento básico de pip es instalar un paquete con pip install <paquete>: busca, baja e instala el paquete. El flag --download_cache=<path> evita repetir el paso del medio, cosa tediosa cuando tenemos que instalar frecuentemente (por ejemplo en distintos virtualenvs) la misma dependencia o cuando el uso de ancho de banda es limitado.
Por ejemplo instalamos por primera vez lxml y vemos cuanto tarda.
(test)tin@traful:~/lab/test$ time pip install lxml --download-cache=~/.pip_download Downloading/unpacking lxml Downloading lxml-3.1.1.tar.gz (3.3MB): 3.3MB downloaded Storing download in cache at /home/tin/.pip_download_cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fl%2Flxml%2Flxml-3.1.1.tar.gz Running setup.py egg_info for package lxml Building lxml version 3.1.1. [... compilación] Successfully installed lxml Cleaning up... real 2m58.276s user 0m38.822s sys 0m0.676s (test)tin@traful:~/lab/test$
¡3 minutos! Y eso que estoy en una conexión bastante rápida.
Tip
Cualquier flag que pip acepta en su linea de comando se puede configurar como una variable de entorno. Entonces podemos setear flag por defecto en nuestro .bashrc, por ejemplo.. code-block: bash
export PIP_DOWNLOAD_CACHE=~/.pip_download_cache
Pero sigamos: una vez cacheado, las siguientes veces que queramos instalar la misma versión de lxml no bajará el archivo de nuevo
(test2)tin@traful:~/lab/test2$ time pip install lxml --download-cache=~/.pip_download Downloading/unpacking lxml Using download cache from /home/tin/.pip_download_cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fl%2Flxml%2Flxml-3.1.1.tar.gz Running setup.py egg_info for package lxml Building lxml version 3.1.1. [... compilación] Successfully installed lxml Cleaning up... real 2m30.624s user 0m38.966s sys 0m0.504s
Mejoró realmente poco. ¿que clase de caché es esta? Chusmeemos que hay en el directorio.
(test)tin@traful:~/lab/test$ ls ~/.pip_download_cache/ | grep lxml https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fl%2Flxml%2Flxml-3.1.1.tar.gz https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fl%2Flxml%2Flxml-3.1.1.tar.gz.content-type
¿Caché de urls? -download-cache no evita todo el laburo de averiguar de dónde bajar, sino simplemente no baja si la url resultante ya existe (como nombre de un archivo) en este directorio.
Lo explica simple Carl Meyer:
La función --download-cache no apunta a prevenir la búsqueda en la red del archivo correcto a bajar: todo lo que hace es guardarlo una vez que lo encontró. Si de verdad te interesa instalar tus depedencias desde tu compu (sin salir a la red) usá --download primero y luego --find-links (apuntando al path de descarga) con --no-index.
Sigamosle la corriente al bueno de @carljm:
(test3)tin@traful:~/lab/test3$ time pip install --download=~/.pip_packages lxml Downloading/unpacking lxml Using download cache from /home/mgaitan/.pip_download_cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fl%2Flxml%2Flxml-3.1.1.tar.gz Saved /home/mgaitan/.pip_packages/lxml-3.1.1.tar.gz [...] Successfully downloaded lxml Cleaning up... real 2m8.969s user 0m1.008s sys 0m0.136s
¡Uff, 2 minutos en copiar un archivo que ya tenía bajado! (evidentemente lo que demora mucho es averiguar la versión del archivo a bajar)
Tip
se puede inspeccionar el berenjenal de redirecciones y parseos que suceden hasta que pip da con el paquete lxml a bajar haciendo el comando más verborrágico con pip install lxml -vvv
En este caso, el caché es directamente el archivo:
(test)mgaitan@traful:~/lab/test$ ls ~/.pip_packages/ | grep lxml lxml-3.1.1.tar.gz
Por suerte, una vez cacheado el paquete de esta manera no tendremos que consultar el índice online las siguientes veces.
(test3)mgaitan@traful:~/lab/test3$ time pip install --no-index --find-links=~/.pip_packages lxml Ignoring indexes: https://pypi.python.org/simple/ Downloading/unpacking lxml Running setup.py egg_info for package lxml Building lxml version 3.1.1. [...] Successfully installed lxml Cleaning up... real 0m38.944s user 0m38.338s sys 0m0.564s
Ok, ya va mejor.
pip 1.4 (en desarrollo) trae soporte integrado para el nuevo formato de paquetes wheel (superador del viejo egg y basado en los estándares actuales) que es muchísimo más rápido que instalar desde fuentes (sobre todo en casos que se debe compilar, como lxml)
Para usar wheel el paquete a bajar tiene que existir en dicho formato y todavía no abundan en PyPi asi que podemos armarlos localmente con el propio pip
pip wheel --wheel-dir=./pip_packages lxml
Eso es similar a usar --download pero además compila y empaqueta como un archivo .whl
Para que pip acepte instalar estos archivos hay que usar --use-wheel y para que los busque localmente haremos:
pip install --use-wheel --no-index --find-links=~/.pip_packages lxml
¡Lo que tardó menos de 2 decimas de segundo! Un speedup del 90mil veces respecto al primer y canónico pip install lxml
(test)tin@morochita:~/lab/test$ time pip install --use-wheel --no-index --find-links=. lxml Ignoring indexes: https://pypi.python.org/simple/ Downloading/unpacking lxml Installing collected packages: lxml Successfully installed lxml Cleaning up... real 0m0.180s user 0m0.152s sys 0m0.024s
Asi que ya sabés: todos esos paquetes que instalás en cada entorno (quizas ipython, django, whatever) me los haces rodar para que pip vuele.
A while ago I got an email from Anja Skrba asking me for permission to translate PyQt by Example into Serbo-Croatian.
And here it is all nice and translated. Lots of thanks to Anja for the hard work!
I am thrilled to announce the release of version 5.4.3 of Nikola a static website/blog generator.
The changelog is pretty long, more information at the announcement
Have fun!