Introducción a Templates de Pycharm

PyCharm es un IDE desarrollado por JetBrains para Python. Al ser un IDE, su objetivo es proveer al programador de un conjunto de funcionalidades que hacen que el desarrollo de código en este lenguaje sea más eficiente. Por ejemplo, escribe automáticamente líneas de import en un script, señala disparidad entre los argumentos esperados y los proporcionados en los métodos y subraya violaciones del estándar de programación en Python (PEP 8).   

Una funcionalidad que es fácil de utilizar y ayuda a reducir el tiempo de trabajo en una tarea son las plantillas (templates). PyCharm nos provee con dos tipos: file templates y live templates. En este post, trataremos con los live templates, su funcionamiento y cómo construir nuestros propios templates.

Live Templates en PyCharm

Los live templates son trozos de código que PyCharm escribe automáticamente por nosotros. Dentro del propio PyCharm, ya hay creado un conjunto de éstos y, para utilizarlos, basta con escribir en un script parte del nombre del template que queramos utilizar (o presionar ctrl + j para que nos muestre una lista de todos los templates disponibles para el contexto en el que nos encontramos) y presionar enter en el template deseado. 

Por ejemplo, supongamos que tenemos definida una lista de enteros en nuestro script y queremos hacer una list comprehension con los elementos de esa lista para seleccionar los que son menores que 5. PyCharm tiene un template llamado “compli” que nos da todos los elementos necesarios para crear tal list comprehension:

PyCharm denota los templates con un icono que representa un sello. Al seleccionar el template “compli” y presionar enter, PyCharm nos escribirá una list comprehension usando como iterable la lista que se encuentra más arriba:

Si vamos presionando enter o tab en cada una de las palabras subrayadas, podremos ir introduciendo y modificando la list comprehension que nos propone PyCharm y llegar a una que nos parezca apropiada rápidamente:

Si hubiese otro iterable, PyCharm nos lo colocaría entre las opciones del iterable sobre el que queremos hacer las list comprehension:

“compli” es un ejemplo de template parametrizado. Los parámetros son las palabras que nos subraya el sistema y que nos permite ir modificando. En la documentación, se nos detallan además otros dos tipos: template simple, que al invocarlo nos reemplaza la palabra por el texto que tenemos en el template; y template envolvente, que coloca el bloque de código seleccionado entre el texto especificado en el template.

El menú de los templates se encuentra en File > Settings > Editor > Live Templates. En este menú, podremos ver la descripción de cada template así como modificar y crear otros nuevos. Además, podemos crear grupos de templates de forma que podamos desactivar o activar un conjunto de ellos con facilidad.

Para crear un template, basta con presionar el símbolo “+” en la parte superior. Abbreviation es el nombre que le daremos a nuestro template mientras que en Description podemos colocar una pequeña referencia de lo que hace.

Lo último necesario para poder usar nuestro template es definir en qué contextos PyCharm permitirá el uso del mismo. Para Python disponemos de tres: class, top-level y other. Si seleccionamos class, nos dejará utilizar el template solo cuando estemos trabajando dentro de una clase, mientras que top-level nos permite utilizar el template dentro de cualquier script de Python siempre que no estemos trabajando dentro de una función. Por último, other nos habilita el uso del template dentro de cualquier función que no sea el método de una clase.

Las siguientes imágenes muestran cómo definimos un template simple que escribe un comentario y cómo está disponible en el script que estábamos creando:

Templates parametrizados

Un template parametrizado, como indicamos más arriba, contiene ciertas palabras que nos permite modificar para adaptar el template al uso que le vayamos a dar. En la definición del template, estas palabras se denominan variables y deben declararse en el texto del template entre dos símbolos “$”.

Para ejemplificar la creación de un template parametrizado, imaginemos que queremos crear una interfaz genérica que tenga un método abstracto. Para ello, podemos colocar en el texto del template el siguiente código:

import abc

class $className$(abc.ABC):

    @abc.abstractmethod
    def $methodName$(self) -> $returnType$:
        pass

Dado que estamos creando una clase, queremos que este template no esté disponible dentro de otra clase. Desmarcamos esta opción y presionamos “ok”. Ahora, nuestro template ya está disponible para su uso y lo podemos comprobar escribiendo su nombre en un script:

Modificar los valores de las variables de un template

En el ejemplo anterior, vemos que las variables que declaramos en el template se convierten en espacios marcados para rellenar por el usuario cuando el template es invocado. Sin embargo, también sirven para automatizar tareas si les asignamos un valor que dependa del contexto donde el template es invocado.

Para ejemplificar este uso, pensemos en el problema que tenemos cuando tests. Al realizar tests en Python, lo habitual es crear una clase que herede de unittest.Testcase, luego hacer un método setup donde se llame al constructor de la clase que queremos testear y, en último lugar, un conjunto de métodos donde probamos diferentes funcionamientos de ese objeto creado:

Mucho de este código se puede automatizar con un template, si tenemos como regla siempre colocar el nombre del archivo que contiene los tests como test_clase_testeada.py. Para hacerlos, accedemos al menú de live templates como lo hicimos anteriormente y colocamos el siguiente texto en la definición del template:

import unittest


class $class_name$(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.$tested_object$ = $tested_class$Impl()

    def test_1(self):

        expected =

        result = self.$tested_object$.$method_tested$

        $assertion_type$(result, expected)

Ahora tenemos que modificar el valor de esas variables para que se coloque automáticamente. Para ello, haremos uso del menú Edit Variables que se encuentra justo a la derecha de donde colocamos el texto del template. 

En este cuadro, encontraremos todas las variables que definimos en el texto del template. Podemos modificar el campo Expression para colocar funciones que modifiquen el valor de la variable, utilizar el campo Default value para colocar un valor que tendrá por defecto la variable (si el usuario no quiere modificarlo) y marcar Skip if defined si queremos que cuando la variable ya tenga un valor al llamar al template no aparezca como un texto subrayado por rellenar, sino como texto normal.

Volviendo a nuestro ejemplo, queremos que las variables $class_name$, $tested_object$ y $tested_class$ tengan un valor y que el usuario no necesite modificarlo, por lo que marcamos Skip if defined en todas ellas. Ahora, vamos a la columna de Expression. En ella, podemos hacer uso de las funciones predefinidas por PyCharm para generar el comportamiento deseado en la variable. 

Para nuestra variable $class_name$, vemos que debe ser igual al nombre del archivo pero con un cambio de formato y sin la extensión, por lo que hacemos uso de fileNameWithoutExtension para obtenerlo. Luego, usamos camelCase para colocarlo de esa forma y, finalmente, colocamos la primera letra del string en mayúscula con capitalize

La variable $tested_class$ podemos obtenerla del nombre del archivo, pero PyCharm también nos permite referenciar otras variables dentro del campo Expression, por lo que usando la función regularExpression sobre $class_name$ podemos eliminar fácilmente la palabra “Test” del string. Un detalle importante es que cuando hacemos referencia a otras variables del template en la columna Expression, usamos el nombre de la misma y no debemos colocarlo entre dos signos «$».

Por su lado, $tested_object$ es el nombre que daremos en el script al objeto cuyo tipo es la clase que queremos testear. De esta forma, si estamos testeando la clase ForecastCreator, querremos un objeto llamado forecast_creator. Este string lo podemos obtener aplicando snakeCase sobre $tested_class$, la cual cambiará de camel case al formato al deseado.

$method_tested$ queremos que sea una variable que el usuario deba modificar, por lo que dejaremos desmarcado Skip if defined y no colocaremos nada más.

Finalmente, la variable $assertion_type$ queremos que sea colocada por el usuario pero, como en la mayoría de los casos creemos que se probara la igualdad de dos números, podemos colocarle un valor por defecto self.assertEqual (usando la columna Default value). 

Con todo esto, al llamar a nuestro template en un script vemos que tiene el comportamiento deseado y que en muy poco tiempo podemos completar los detalles faltantes como el método o la importación de la clase testeada:

Aunque en nuestro ejemplo no era necesario, la columna Default value también permite el uso de las funciones que podemos utilizar en la columna Expression,  por lo que es posible crear valores por defecto que dependan del contexto del template. Una lista de todas las funciones disponibles para los templates la podemos encontrar en la documentación sobre edición de variables templates de Jetbrains.

Una función a destacar es groovyScript, que permite implementar cualquier lógica que deseemos ya que ejecuta un script del lenguaje Groovy. Apache Groovy es un lenguaje implementado sobre Java y se conecta sin problemas con las librerías desarrolladas para este lenguaje.  

Conclusión

En este post, hemos visto las diferentes características de los live templates en PyCharm. A partir de los ejemplos propuestos, demostramos cómo pueden ser herramientas útiles para aumentar la productividad al ahorrarnos escribir código que sigue un patrón.   

Hasta aquí nuestro post de hoy. Si te ha parecido interesante, te animamos a visitar la categoría Software para ver otros artículos relacionados y a compartirlo en redes con tus contactos. ¡Hasta pronto!
Carlos Rodriguez
Carlos Rodriguez
Artículos: 10