Facundo Batista: Asociación Civil Python Argentina


Hace un par de semanas finalmente salió el trámite de la Inspección General de Justicia sin nada para revisar o modificar... ¡está formada legalmente la Asociación Civil Python Argentina!

Estatuto todo sellado

Ahora estamos trabajando a full para sacar el CUIT en la AFIP, lo que nos va a permitir abrir una cuenta en el banco. De esta manera los chicos que están organizando la PyCon ya van a poder darle luz verde a los sponsors para que pongan plata.

Más allá de ayudar organizativamente en la PyCon y en otros eventos, son cuatro las cosas que queremos empujar el primer par de años:

  • Becas de viaje: porque creemos que hay mucho valor en que la gente se conozca, así que trataremos de ayudar a que la gente pueda viajar a eventos que se organicen en el país
  • Traducciones en eventos: si van a venir disertantes grosos que no hablen castellano, hacer lo posible para que la mayoría pueda entenderlos
  • Descuentos en cursos: estamos barajando un par de modalidades
  • Sitio web de PyAr y otra infraestructura: tenemos que dar un salto en seriedad a la hora de mantener los distintos servicios que da el grupo

Para eso (y para los costos operativos) básicamente vamos a necesitar dinero :) La Asociación se va a financiar de dos maneras, principalmente...

Una es por aporte de los socios. La idea es que los socios, que se beneficiarían directa e indirectamente por la Asociación Civil, pongan un manguito por mes para ayudar a hacer cosas.

El otro mecanismo es por aporte directo de empresas (de las cuales esperamos un manguito más grande, posiblemente anual).

Ya les contaremos bien cuales serán los mecanismos, montos, y eso. ¡Estén atentos!

Damián Avila: RISE 5.0.0 is out!

We're pleased to announce the release of RISE 5.0.0!

RISE let's you show yout Jupyter notebook rendered as an executable Reveal.js-based slideshow. It is your very same notebook but in a slidy way!

How you can get it?

Read more… (1 min remaining to read)

Facundo Batista: Primer Seminario de Introducción a Python


Al final salió una idea que venía dándome vuelta en la cabeza desde principios del año pasado, y que tardó sus meses en concretarse: voy a estar dando un Seminario de Introducción a Python junto a una empresa, con el objetivo de bajar el costo del curso a los asistentes (lo cubre en parte la empresa), y de esta manera poder hacer algo más largo y más masivo.

La empresa con la cual voy a hacer este Seminario es Onapsis, bastante cercana a la comunidad de Python Argentina, ya que hace mucho que es sponsor de eventos, pone los famosos "pybus" para ir a las PyCones, hosteó un meetup, etc, etc.

El Seminario es abierto al público en general, y será de 16 horas en total, cuatro sábados de Julio, durante la mañana, en CABA.

El costo es súper accesible, $600, ya que parte lo cubre Onapsis, y la idea es hacerlo barato para que pueda venir la mayor cantidad de gente posible.  Así y todo los cupos son limitados (la oficina tiene un límite), por lo que cuanto antes consigan reserva la posición, mejor.

Al final del Seminario entregaré un certificado de asistencia y la totalidad del curso en formato electrónico.

Para realizar la reserva deben enviarme un mail así les confirmo disponibilidad y les paso los datos necesarios para realizar el pago (que podrá ser por depósito, transferencia bancaria, tarjeta de crédito, débito, etc.).

Acá están todos los detalles del curso.

Facundo Batista: Salió fades 6


Salió la última versión de fades, el sistema que maneja automáticamente los virtualenvs en los casos que uno normalmente encuentra al escribir scripts y programas pequeños, e incluso ayuda a administrar proyectos grandes.

Esta es una de las versiones que más cambios metimos! Estos son solo algunos de los puntos de la lista de cambios:

- Instala no solamente desde PyPI sino también de repositorios remotos (GitHub, Bitbucket, Launchpad, etc) y directorios locales

    fades -d git+https://github.com/yandex/gixy.git@v0.1.3

    fades -d file://$PATH_TO_PROJECT

- Creamos un video para mostrar las características de fades más relevantes

- Selecciona el mejor virtualenv de los almacenados en casos de coincidencia múltiple

- Agregamos una opción --clean-unused-venvs para borrar todos los virtualenvs que no fueron usados en los últimos días

    fades --clean-unused-venvs=30

- Agregamos un --pip-options para pasarle los parámetros que sean necesarios a la ejecución subyacente de pip

    fades -d requests --pip-options="--no-cache-dir"

La lista completa de cambios está en el release formal, esta es la documentación entera, y acá tienen como instalarlo y disfrutarlo.

Roberto Alsina: How I Learned to Stop Worrying and Love JSON Schema

Intro

This post operates on a few shared assumptions. So, we need to explicitly state them, or otherwise you will read things that are more or less rational but they will appear to be garbage.

  • APIs are good
  • Many APIs are web APIs
  • Many web APIs consume and produce JSON
  • JSON is good
  • JSON is better if you know what will be in it

So, JSON Schema is a way to increase the number of times in your life that JSON is better in that way, therefore making you happier.

So, let's do a quick intro on JSON Schema. You can always read a much longer and surely better one from which I stole most examples at Understanding JSON Schema. later (or right now, it's your time, lady, I am not the boss of you).

Schemas

So, a JSON Schema describes your data. Here is the simplest schema, that matches anything:

{ }

Scary, uh? Here's a more restrictive one:

{
  "type": "string"
}

That means "a thing, which is a string." So this is valid: "foo" and this isn't 42 Usually, on APIs you exchange JSON objects (dictionaries for you pythonistas), so this is more like you will see in real life:

{
  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

That means "it's an object", that has inside it "street_address", "city" and "state", and they are all required.

Let's suppose that's all we need to know about schemas. Again, before you actually use them in anger you need to go and read Understanding JSON Schema. for now just assume there is a thing called a JSON Schema, and that it can be used to define what your data is supposed to look like, and that it's defined something like we saw here, in JSON. Cool?

Using schemas

Of course schemas are useless if you don't use them. You will use them as part of the "contract" your API promises to fulfill. So, now you need to validate things against it. For that, in python, we can use jsonschema

It's pretty simple! Here is a "full" example.

import jsonschema

schema = {
  "type": "object",
  "properties": {
    "street_address": {"type": "string"},
    "city": {"type": "string"},
    "state": {"type": "string"},
  },
  "required": ["street_address", "city", "state"]
}

jsonschema.validate({
    "street_address": "foo",
    "city": "bar",
    "state": "foobar"
}, schema)

If the data doesn't validate, jsonchema will raise an exception, like this:

>>> jsonschema.validate({
...     "street_address": "foo",
...     "city": "bar",
... }, schema)
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: 'state' is a required property

Failed validating 'required' in schema:
    {'properties': {'city': {'type': 'string'},
                    'state': {'type': 'string'},
                    'street_address': {'type': 'string'}},
     'required': ['street_address', 'city', 'state'],
     'type': 'object'}

On instance:
    {'city': 'bar', 'street_address': 'foo'}

Hey, that is a pretty nice description of what is wrong with that data. That is how you use a JSON schema. Now, where would you use it?

Getting value out of schemas

Schemas are useless if not used. They are worthless if you don't get value out of using them.

These are some ways they add value to your code:

  • You can use them in your web app endpoint, to validate things.
  • You can use them in your client code, to validate you are not sending garbage.
  • You can use a fuzzer to feed data that is technically valid to your endpoint, and make sure things don't explode in interesting ways.

But here is the most value you can extract of JSON schemas:

You can discuss the contract between components in unambiguous terms and enforce the contract once it's in place.

We are devs. We discuss via branches, and comments in code review. JSON Schema turns a vague argument about documentation into a fact-based discussion of data. And we are much, much better at doing the latter than we are at doing the former. Discuss the contracts.

Since the document describing (this part of) the contract is actually used as part of the API definitions in the code, that means the document can never be left behind. Every change in the code that changes the contract is obvious and requires an explicit renegotiation. You can't break API by accident, and you can't break API and hope nobody will notice. Enforce the contracts.

Finally, you can version the contract. Use that along with API versioning and voilá, you know how to manage change! Version your contracts.

  • Discuss your contracts
  • Enforce your contracts
  • Version your contracts

So now you can stop worrying and love JSON Schema as well.

Roberto Alsina: Creating Languages For Dummies

Intro

I don't have the usual programmer's education. I studied maths, and then dropped out of that, and am mostly self-taught. So, there are some parts of programming I always saw wearily, thinking to myself that I really should go to school to learn them. One remarkable such area is parsing and implementing languages.

Well... sure, school is always a good idea, but this is not that hard. In this article I will explain how to go from nothing to a functioning, extensible language, using Python and PyParsing. If you are as scared of grammars, parsers and all that jazz as I used to be, come along, it's pretty simple,

Leer más… (quedan 15 minutos de lectura)

Facundo Batista: PyCamp 2017, en Baradero


¡Otra vez un PyCamp relativamente cerca de casa! Eso me permitió ir en auto. Bah, fuimos en auto, Diego, Nico, Edu y yo. Salimos tempranito y a eso de las nueve ya estábamos ahí.

Las primeras dos horas las pasamos armando toda la infraestructura: fue colgar la bandera, poner las Antenas Sable Láser, configurar la red con el router nuevo, preparar los badges y otros pequeños souvenirs, hacer mate, etc, etc.

A las once y media arrancamos la gran charla introductoria, que era muy necesaria porque este Pycamp era el primero para un montón de los asistentes. Y a continuación de la misma presentamos todos los proyectos que llevamos y votamos más o menos en cuales nos gustaría participar.

Luego el primer almuerzo, y ya arrancamos el PyCamp a todo motor.

Algunos trabajando, otros en un curso superbásico inicial

Trabajando a la sombrita

Yo participé en varios proyectos, pero el fuerte del tiempo lo puse en estos tres:

  • Linkode: aprovechando que estábamos cara a cara, estuvimos pensando con Mati Barriento mucho en un cambio muy grande que estamos haciendo, lo que nos llevó a un refactor de la base de datos, con migración de información que la hicimos el último día en producción. Mucho laburo puesto en esto, que nos dejó un modelo más simple y el código listo para la próxima gran mejora, que es la renovación de como manejamos el lado del cliente.
  • Fades: Gilgamezh y yo laburamos bastante también acá. Él estuvo principalmente con el video instructivo que armamos el año pasado y necesitaba mucha edición, y con mucha ayuda de Marian lograron un resultado bárbaro, que pueden ver acá. En el proyecto en sí yo metí dos fixes pequeñitos, y estuve ayudando y haciendo reviews a dos branches de Juan y Facundo (otro, no yo).
  • Recordium: acá no hicimos mucho, pero conté de qué iba el proyecto y ahí surgieron varias pequeñas mejoras para hacer, incluso para la GUI final a la que apuntar. Y también tocamos un tema de seguridad, donde Matías nos contó qué detalle habría que mejorar para que no nos puedan "inyectar" mensajes.

Laburanding

Charlando diseño y aprendiendo malabares

Pero aparte de los proyectos en sí, también tuvimos un campeonato de ping pong (pasé la primera ronda, pero luego perdí un partido de la segunda ronda y quedé afuera), pileta (me metí y todo), hicimos la foto grupal de siempre, un partidito de futbol (sobre pasto, ¡en patas!), un asado, la típica reunión de PyAr integrada al Pycamp, y mucha, mucha charla con diferentes grupos, viendo qué hacían, tratando de tirar alguna idea o aplicar alguna experiencia.

La grupal

Como actividades fuera del predio, tuvimos un paseo guiado una mañana (con guia y todo, que nos contó muchísimo del pasado y presente de Baradero y alrededores), y un festival de jazz una noche (muy lindo, y la gente de donde nos hospedábamos se copó y nos armó una vianda así los que íbamos al festival cenábamos allá).

El último día también hicimos (como queremos que se haga costumbre) un video donde todos los que empujamos algún proyecto pasamos y contamos qué se hizo. Está muy bueno a nivel resumen para los que estuvimos ahí y como registro para los que no pudieron ir (y que quede a futuro). Mil gracias a José Luis que siempre se copa con la edición del video final.

Caminando por Baradero

Festival de Jazz

Un punto aparte para lo que fue el "lugar" del PyCamp. Mucho verde a metros nomás de donde estábamos trabajando, que era un salón grandote donde entrábamos relativamente cómodos (aunque en el día a día siempre había grupos laburando en lo que era el comedor y/o al aire libre). Las habitaciones estaban bien (considerando que eran grupales) y los baños limpios. La comida bárbara, incluyendo el asado, y un lujo todas las preparaciones especiales para gente vegetariana, con dietas raras, alergias, etc (les estuve preguntando a varios y todos comentaron que estuvo perfecto). Hasta la internet, anduvo...

En fin, pasó otro PyCamp. Yo siempre digo que es el mejor evento del año, y este no fue la excepción. Es más, esta edición, la 10°, fue uno de los mejores PyCamps!

Clases de espadas

El parque y la pileta

PD: charlando sobre que era la décima edición, nos anotamos cuales habían sido hasta ahora, lo dejo acá como registro...

    2008  Los Cocos, Córdoba
    2009  Los Cocos, Córdoba
    2010  Verónica, Buenos Aires
    2011  La Falda, Córdoba
    2012  Verónica, Buenos Aires
    2013  Villa Giardino, Córdoba
    2014  Villa Giardino, Córdoba
    2015  La Serranita, Córdoba
    2016  La Serranita, Córdoba
    2017  Baradero, Buenos Aires

PD2: fotos! las mías y las que sacó Yami (casi fotógrafa oficial del evento).

Marcos Dione: implementing-selenium-with-python-and-qt

I'm writing a python module that allows me to 'drive' a site using Qt. This means that I can navigate the site, fill forms, submit them and read the resulting pages and scrape them, Selenium style. The reasons I'm using Qt are that it has enough support for the site I'm driving (it's the web frontend of the SIP telephony solution we're using, which has an incomplete API and I have to automatize several aspects not covered by it); there are python bindings; and because I can do it headless: instead of using browser instances, I simply instanciate one QWebPage[1] per thread and that's it.

The first thing I learned today is that JS objects representing the DOM elements have two sets of value holders: attributes and properties. The properties is what in Python we call attributes: the object's elements which are accesible with the '.' operator and hold instance values. The attributes are in fact the HTML element's attributes that gave the properties' initial values. That is, given the following HTML element:

<input type="text" name="foo° id="bar" value="quux">

the initial JS object's attributes and properties will have those values. If you change the value with your browser, the value property of that element will be changed, but not the attribute. When you submit the form, the value properties of all the form elements are used, so if you "only' change the value attribute, that won't be used. So forget attributes. Also, the DOM is the representation of the actual state of the page, but this state is never reflected in the HTML source that you can ask your browser to show, but you see those changes reflected in the browser's debugger. It's like they really wanted[3] to keep initial values apart from current state[2].

On the Qt side, QWebElement is only the DOM element representation, not the JS object[4], so you can't access the properties via its API, but by executing JS[5]:

e = DOMRoot.findFisrt('[name="foo"]')
e.evaluateJavaScript("this.value = 'abracadabra'")

Tonight I finished fixing the most annoying bug I had with this site. To add a user I have to fill a form that is split in 7 'tabs' (which means 7 <div>s with fields where only one is shown at a time). One of the fields on the second tab has a complex JS interaction and I was cracking my skull trying to make it work. Because the JS is reacting to key presses, setting the value property was not triggering it. Next I tried firing a KeyboardEvent in JS, but I didn't succeed. Maybe it was me, maybe the fact that the engine behind QWebPage is the original Webkit and for some reason its JS support is lacking there, who knows.

But the good guys from #qtwebkit gave me a third option: just send plain QKeyEvents to the input element. Luckily we can do that, the web engine is completely built in Qt and supports its event system and more. I only had to give focus to the widget.

Again, I tried with JS and failed[7], so I went back cheating with Qt behind curtains. QWebElemnt.geometry() returns the QRect of the QWidget that implements the input element; I just took the .center() of it, and generated a pair of mouse button press/release events in that point. One further detail is that the .geometry() won't be right unless I force the second tab to be shown, forcing the field to be drawn. Still, for some reason getting a reference to the input field on page load (when I'm trying to figure out which fields are available, which in the long run does not make sense, as fields could easily be created or destroyed on demand with JS) does not return an object that will be updated after the widget is repositioned, so asking its geometry returns ((0, -1), (-1, 0)), which amounts to an invalid geometry. The solution is to just get the reference to the input field after forcing the div/tab to be shown.

Finally, I create a pair of key press/release events for each character of the string I wanted as value, and seasoned everything with a lot of QMainLoop.processEvents(). Another advantage of using the Qt stuff is that while I was testing I could plug a QWebView, sprinkle some time.sleep() of various lengths, and see how it behaved. Now I can simply remove that to be back to headlessness.

I'm not sure I'll publish the code; as you can see, it's quite hacky and it will require a lot of cleanup to be able to publish it without a brown paper bag in my head.


[1] Yes, I'm using qt5.5 because that's what I will have available in the production server.

[2] Although as I said, you can change the attributes and so you lose the original values.

[3] I guess the answer is in in the spec.

[4] I think i got it: QWebElement is the C++ class that is used in WebKit to represent the HTML tree, the real DOM, while somewhere deeper in there are the classes representing the JS objects which you just can't reach[6].

[5] This clearly shows that there is a connection between the DOM object and the JS one, you just can't access it via the API.

[6] This is the original footnote: Or something like that. Look, I'm an engineer and I usually want to know how things work, but since my first exposure to HTML, CSS and JS, back in the time when support was flaky and fragmented on purpose, I always wanted to stay as far away from them as possible. Things got much better, but as you can see the details are still somewhat obscure. I guess, I hope the answer is in the spec.

[7] With this I mean that I executed something and it didn't trigger the events it should, and there's no practical way to figure out why.


python pyqt