Saltar al contenido

PowerShell en los Notebooks de Jupyter

Normalmente suelo utilizar Windows Subsystem for Linux (WSL) a la hora de escribir libretas de Jupyter para cualquier tarea, pero en alguna ocasión también lo hago desde Windows.

En Linux suelo descargar archivos desde la libreta empleando el comando wget (anteponiendo el signo de exclamación «!» para indicar que ejecute el comando en el sistema operativo). Un ejemplo:

!wget https://filesamples.com/samples/document/txt/sample1.txt

Recientemente, escribiendo una libreta desde Windows, me he topado con la duda de ¿cómo puedo descargar un fichero directamente con el sistema operativo al igual que hago en Linux?

Se pueden descargar ficheros desde Windows tal y como lo hacemos desde Linux, pero el principal inconveniente es que en el cmd de Windows no existe ningún comando que nos permita descargar un fichero, tal como lo hacemos con wget en Linux. En cambio, en PowerShell (una shell mucho más moderna que también está disponible en Windows) si tenemos un comando que nos permite descargar un fichero de forma similar a wget: Invoke-WebRequest.

Este comando se ejecuta siguiendo la siguiente sintaxis:

Invoke-WebRequest url -outfile fichero_destino

Otro inconveniente es que en las libretas de Jupyter, en Windows, cuando queremos utilizar un comando del sistema operativo, estos se ejecutan sobre cmd. Pero para poder hacer uso de PowerShell en las libretas tenemos dos formas:

  1. Cambiar el valor de la variable «comspec» de Python para indicar que use PowerShell.
  2. Definir un comando mágico de IPython

1. Cambiar el valor de la variable «comspec» de Python

Esta opción es la más sencilla, solamente tenemos que cambiar el valor de la variable comspec por «powershell.exe», en el caso de Windows PowerShell (la versión que viene instalada con el sistema operativo), o por «pwsh.exe», en el caso de PowerShell Core (una versión más moderna, desarrollada en .NET Core). Si no tienes instalado PowerShell Core, puedes hacerlo desde la tienda de Windows (enlace).

Podemos cambiar el valor de comspec, en la libreta Jupyter, de la siguiente forma:

import os
os.environ['comspec']='pwsh.exe'

A partir de la ejecución del código anterior, todos los comandos que ejecutemos en el sistema operativo desde el notebook se harán empleando PowerShell.

Por ejemplo, si quisiéramos descargar un archivo bastaría con:

!Invoke-WebRequest https://filesamples.com/samples/document/txt/sample1.txt -outfile sample1.txt

En mi caso, dentro de mi perfil de Powershell, me he creado un alias llamado wget para el comando Invoke-WebRequest. La línea que debemos agregar en el fichero del perfil de Powershell es la siguiente:

Set-Alias wget Invoke-WebRequest

De esta forma nos es más fácil llamar al comando, puesto que el nombre del alias es el mismo que el nombre del comando que empleamos en Linux, wget.

!wget https://filesamples.com/samples/document/txt/sample1.txt -outfile sample1.txt

Si no sabes dónde se encuentra el fichero con el perfil de Powershell, ejecuta el siguiente comando en una terminal y obtendrás la ruta donde se encuentra:

$profile

2. Definir un «magic command» en nuestro perfil de IPython

En este caso existen dos métodos:

  • Definir el comando mágico en nuestro perfil de IPython
  • Crear una función que defina un comando mágico y que se ejecute al iniciar un kernel

Creación de un comando mágico en nuestro perfil de IPython

Sí únicamente nos interesara utilizar PowerShell en una celda determinada, podemos definir un magic command en nuestro perfil de IPython. Este perfil se encuentra en un fichero, normalmente con el nombre ipython_config.py, dentro de nuestra carpeta de usuario bajo la ruta \.ipython\profile_default

C:\Users\nombre_usuario\.ipython\profile_default\ipython_config.py

En caso de no tener un fichero con la configuración de IPython, podemos crearlo mediante el siguiente comando (desde el terminal, no desde el notebook):

ipython profile create

Una vez abierto el fichero, añadimos al final las siguientes líneas y guardamos:

c.ScriptMagics.script_magics = ['powershell']
c.ScriptMagics.script_paths = {
        'powershell':'pwsh.exe -noprofile -command -'}

Para ejecutar un comando PowerShell que hace uso del comando mágico que hemos creado, podemos hacerlo de la siguiente manera:

%%powershell
Invoke-WebRequest https://filesamples.com/samples/document/txt/sample1.txt -outfile sample1.txt

Función para crear un comando mágico al iniciar un kernel

De esta otra forma, en caso de que también quisiéramos almacenar los resultados de la ejecución de un comando PowerShell en una variable Python, podemos definir una función que se ejecute cada vez que se inicia el kernel de IPython, de tal forma que podamos hacer uso del comando mágico. Para esto, debemos crear un fichero Python en la ruta:

C:\Users\nombre_usuario\.ipython\profile_default\startup

A continuación, definimos la función que contendrá dicho fichero y lo guardamos:

from IPython.core.magic import register_line_cell_magic

from IPython import get_ipython
ipython = get_ipython()

@register_line_cell_magic
def ps(line, cell=None):
    "Magic that works both as %ps and as %%ps" 
    if cell is None:
        ipython.run_cell_magic('powershell', '--out posh_output' ,line)
        return posh_output.splitlines()
    else:
        return ipython.run_cell_magic('powershell', line, cell)

Debemos tener en cuenta que las funciones que contienen los ficheros dentro de la carpeta ~\.ipython\profile_default\startup se ejecutan en el orden alfabético, siguiendo el nombre del fichero. Por ejemplo, si tuviéramos estos ficheros dentro de la carpeta:

  • 01-func1.py
  • 02-func2.py
  • 03-func3.py

Primero se ejecutaría el fichero 01-func1.py, luego 02-func2.py y por último 03-func3.py

En mi caso he llamado 01-powershell_magic.py al fichero, puesto que es la única función/fichero que tengo creado en la carpeta ~\.ipython\profile_default\startup

Una vez creado el fichero y reiniciado el kernel de IPython, si está en funcionamiento, para emplear el comando mágico que hemos creado lo haremos de la misma forma que el comando mágico que vimos anteriormente, salvo que si ahora queremos almacenar el resultado de la ejecución de un comando PowerShell podemos hacer lo siguiente:

ps_version = %ps $PSVersionTable.PSVersion.ToString()
print(ps_version)

La celda anterior se encarga almacenar el resultado del comando PowerShell (en este caso obtenemos la versión en ejecución de PowerShell) en la variable ps_version


Fuentes:

Publicado enDesarrollo