Buenas tardes a todos.
Hoy en día, Python es uno de los lenguajes más utilizados en la creación de no solo productos de software, sino también en la gestión de su infraestructura. Debido a esto, muchos devops, ya sea por decisión propia o no, han tenido que aprender un nuevo lenguaje como complemento a los viejos e queridos scripts en Bash. Sin embargo, Bash y Python siguen diferentes enfoques en la escritura de código y presentan características específicas, por lo que portar scripts de Bash al 'lenguaje de la serpiente' a veces resulta ser una tarea extensa y no trivial.
Para simplificar la vida de los devops, se han creado y continúan desarrollándose muchas bibliotecas y utilidades útiles en Python. Este artículo describe dos nuevas bibliotecas creadas por el autor de este post — y — que están diseñadas para liberar al devops de la necesidad de prestar demasiada atención a los detalles del trabajo con Python, dejando espacio para tareas más interesantes. El ámbito de actividad de las bibliotecas son las variables de entorno y la ejecución de utilidades externas.
A aquellos interesados, por favor, sigan leyendo.
¿Nuevas 'bicicletas'?
Aparentemente, ¿por qué crear nuevos paquetes para operaciones tan comunes? ¿Qué impide el uso directo de os.environ y subprocess.?
Daré pruebas a favor de cada una de las bibliotecas por separado.
La biblioteca smart-env
Antes de escribir tu propia creación, es útil explorar Internet y buscar soluciones ya disponibles. Por supuesto, existe el riesgo de no encontrar lo que se necesita, pero eso es más bien un 'caso de seguro'. Por lo general, este enfoque resulta efectivo y ahorra un montón de tiempo y esfuerzo.
Según los resultados de se encontró lo siguiente:
- hay paquetes que realmente envuelven las llamadas a os.environ, pero requieren un montón de acciones distractoras (crear una instancia de clase, parámetros especiales en las llamadas, etc.);
- hay buenos paquetes que, sin embargo, están estrictamente vinculados a un ecosistema particular (principalmente a frameworks web como Django) y por tanto no son completamente universales sin modificaciones;
- hay raras intentonas de hacer algo nuevo. Por ejemplo, y analizar explícitamente los valores de las variables llamando a métodos como
get_(nombre_variable)O esta , que sin embargo, no soporta el actualmente obsoleto Python 2 (en el que, a pesar de , aún quedan montañas de código escrito y ecosistemas enteros);
- hay proyectos escolares y estudiantiles que, de alguna manera, han terminado en el PyPI upstream y solo generan problemas con la nomenclatura de nuevos paquetes (en particular, el nombre "smart-env" es una medida obligada).
Y esta lista podría continuar por mucho tiempo. Sin embargo, los puntos mencionados son suficientes para encender la idea de crear algo conveniente y universal.
Los requisitos establecidos para la creación de smart-env:
- Esquema de uso lo más sencillo posible
- Soporte para la tipificación de datos fácilmente configurable
- Compatibilidad con Python 2.7
- Buena cobertura de pruebas de código
Al final, todo esto se logró. Aquí hay un ejemplo de uso:
from smart_env import ENV
print(ENV.HOME) # Igual que print(os.environ['HOME'])
# asumiendo que estableciste la variable de entorno MYVAR a "True"
ENV.enable_automatic_type_cast()
my_var = ENV.MY_VAR # Igual a boolean True
ENV.NEW_VAR = 100 # Establece una nueva variable de entorno
Como se puede ver en el ejemplo, para trabajar con la nueva clase, basta con importarla (no es necesario crear una instancia, eliminando un paso innecesario). El acceso a cualquier variable de entorno se logra refiriéndose a ella como si fuera una variable de clase ENV, lo que, de hecho, convierte esta clase en un envoltorio intuitivo del entorno del sistema nativo, al tiempo que la transforma en una posible opción de objeto de configuración para prácticamente cualquier sistema (un enfoque similar, por ejemplo, se logra en Django, donde el objeto de configuración es directamente el módulo/paquete settings).
La activación/desactivación del modo de soporte de tipificación automática se logra mediante el uso de dos métodos: enable_automatic_type_cast() y disable_automatic_type_cast(). Esto puede ser conveniente si en la variable de entorno hay un objeto parecido a JSON serializado o incluso solo una constante booleana (la declaración explícita de la variable DEBUG en Django mediante la comparación de la variable de entorno con cadenas 'permitidas' es uno de los casos más comunes). Pero ahora no es necesario convertir explícitamente las cadenas: la mayoría de las acciones necesarias ya están integradas en las profundidades de la biblioteca y solo esperan una señal de acción. 🙂 En general, la tipificación funciona de manera transparente y admite casi todos los tipos de datos incorporados existentes (no se han probado frozenset, complex y bytes).
El requisito de soporte para Python 2 se ha implementado prácticamente sin sacrificios (se descartaron typing y algunos "caramelos" de las últimas versiones de Python 3), gracias en particular a la omnipresente six (para resolver problemas relacionados con el uso de metaclases).
Pero también hay algunas limitaciones:
- El soporte para Python 3 implica la versión 3.5 o superior (su presencia en su proyecto es resultado de la pereza o la falta de necesidad de mejoras, ya que es difícil encontrar una razón objetiva para seguir usando 3.4);
- En Python 2.7, la biblioteca no admite la deserialización de literales de conjuntos. Descripción . Pero, si alguien quiere implementarlo, será bienvenido;)
La biblioteca también incluye un mecanismo de excepciones en caso de errores de análisis. Si la cadena no puede ser reconocida por ninguno de los analizadores disponibles, el valor se mantiene como una cadena (más por conveniencia y compatibilidad con la lógica habitual de las variables en Bash).
La biblioteca python-shell
Ahora hablaré sobre la segunda biblioteca (saltaré la descripción de las desventajas de los análogos existentes, ya que es similar a lo descrito para smart-env. Análogos — y ).
En general, la idea de implementación y sus requisitos son similares a los descritos para smart-env, como se puede ver en el siguiente ejemplo:
from python_shell import Shell
Shell.ls('-l', '$HOME') # Equivale a "ls -l $HOME"
command = Shell.whoami() # Equivale a "whoami"
print(command.output) # imprime su nombre de usuario actual
print(command.command) # imprime "whoami"
print(command.return_code) # imprime "0"
print(command.arguments) # imprime ""
Shell.mkdir('-p', '\/tmp\/new_folder') # crea una nueva carpeta
La idea es la siguiente:
- Una sola clase que personifica Bash en el mundo de Python;
- Cada comando de Bash se invoca como una función de la clase Shell;
- Los parámetros de cada función se transmiten luego a la invocación correspondiente del comando Bash;
- Cada comando se ejecuta "aquí y ahora" en el momento de su invocación, es decir, utiliza un enfoque sincrónico;
- hay la posibilidad de acceder a la salida del comando en stdout, así como a su código de retorno;
- Si el comando no está presente en el sistema, se arroja una excepción.
Al igual que en el caso de smart-env, se garantiza el soporte para Python 2 (aunque se requirió un poco más de sacrificios) y no hay soporte para Python 3.0-3.4.
Planes para el desarrollo de bibliotecas
Las bibliotecas ya se pueden usar: ambas están disponibles en el PyPI oficial. Los códigos fuente están disponibles en Github (ver más abajo).
Ambas bibliotecas se desarrollarán teniendo en cuenta la retroalimentación recopilada de los interesados. Y, aunque puede ser complicado pensar en una variedad de nuevas características para smart-env, definitivamente hay más que añadir en python-shell:
- soporte para llamadas no bloqueantes;
- capacidad de comunicación interactiva con el equipo (trabajo con stdin);
- agregar nuevas propiedades (por ejemplo, propiedad para obtener la salida de stderr);
- implementación de un catálogo de comandos disponibles (para usar con la función dir());
- etc.
Enlaces
- Biblioteca smart-env: y
- Biblioteca python-shell: y
- actualizaciones de bibliotecas
UPD 23.02.2020:
* Los repositorios se han trasladado, los enlaces pertinentes han sido actualizados
* La versión python-shell==1.0.1 está programada para salir el 29.02.2020. Entre los cambios se incluyen el soporte para autocompletado de comandos y el comando dir(Shell), ejecución de comandos con identificadores no válidos en Python, corrección de errores.
Fuente: habr.com
