miércoles, 8 de abril de 2026

Python ASYNC (III). Ejecutando otros procesos

 1. Llamada a comandos de la shell SINCRONA

Veamos como se llama a un proceso síncronamente ya sea por el ecomando entero o pasándole parámetros:

def run_text(cmd):
    '''
    Executes a command and captures its output as text.
    Parameters:
        cmd: A list of command arguments to execute (e.g., ["certutil", "-L", "-d", "sql:/home/user/.pki/nssdb"]).
    Returns:
    The standard output of the command as a string if successful, or None if an error occurs.
    Example usage:
        # List certificates in the NSS database
        output = run_text(["certutil", "-L", "-d", "sql:/home/user/.pki/nssdb"])
    '''
    try:
        res = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            check=True
        )
        return res.stdout
    except subprocess.CalledProcessError as e:
        print(f"Error ejecutando: {' '.join(cmd)}", file=sys.stderr)
        return None


def run_bytes(cmd, input_data=None):
    '''
    Executes a command and captures its output as bytes.
    Parameters:
        cmd: A list of command arguments to execute (e.g., ["openssl", "x509", "-in", "cert.pem", "-outform", "DER"]).
        input_data: Optional bytes to be sent to the command's standard input.
    Returns:
    The standard output of the command as bytes if successful, or None if an error occurs.
    Example usage:
        # Get the PEM-encoded certificate for a given nickname from the NSS database
        pem_bytes = run_bytes(["certutil", "-L", "-d", "sql:/home/user/.pki/nssdb", "-n", "My Certificate", "-a"])
    '''
    try:
        res = subprocess.run(
            cmd,
            input=input_data,
            capture_output=True,
            check=True
        )
        return res.stdout
    except subprocess.CalledProcessError:
        return None

 2. Llamada a comandos de la shell ASINCRONA

Veamos como se llama a un proceso asíncronamente ya sea por el ecomando entero o pasándole parámetros:

async def run_text_async(cmd: list[str]) -> str | None:
    '''
    Executes a command asynchronously and captures its output as text.
    Parameters:
        cmd: A list of command arguments to execute (e.g., ["ls", "-l"]).
    Returns:
        The standard output of the command as a string if successful, or None if an error occurs.
    Example usage:
        # List files in the current directory asynchronously
        output = await run_text_async(["ls", "-l"])    
    '''
    try:
        proc = await asyncio.create_subprocess_exec(
            *cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await proc.communicate()
        if proc.returncode != 0:
            print(f"Error ejecutando: {' '.join(cmd)}", file=sys.stderr)
            if stderr:
                print(stderr.decode(errors="ignore").strip(), file=sys.stderr)
            return None
        return stdout.decode(errors="ignore")
    except Exception as e:
        print(f"Excepción ejecutando {' '.join(cmd)}: {e}", file=sys.stderr)
        return None


async def run_bytes_async(cmd: list[str], input_data: bytes | None = None) -> bytes | None:
    '''
    Executes a command asynchronously and captures its output as bytes.
    Parameters:
        cmd: A list of command arguments to execute (e.g., ["openssl", "x509", "-in", "cert.pem", "-outform", "DER"]).
        input_data: Optional bytes to be sent to the command's standard input.
    Returns:
        The standard output of the command as bytes if successful, or None if an error occurs.
    Example usage:
        # Get the PEM-encoded certificate for a given nickname from the NSS database asynchronously
        pem_bytes = await run_bytes_async(["certutil", "-L", "-d", "    
    '''
    try:
        proc = await asyncio.create_subprocess_exec(
            *cmd,
            stdin=asyncio.subprocess.PIPE if input_data is not None else None,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await proc.communicate(input=input_data)
        if proc.returncode != 0:
            print(f"Error ejecutando: {' '.join(cmd)}", file=sys.stderr)
            if stderr:
                print(stderr.decode(errors="ignore").strip(), file=sys.stderr)
            return None
        return stdout
    except Exception as e:
        print(f"Excepción ejecutando {' '.join(cmd)}: {e}", file=sys.stderr)
        return None




martes, 7 de abril de 2026

Python ASYNC (II). El event loop

1. Introducción

El event loop es el organizador de las tareas que se ejecutan dentro de é.

 El event loop normalmente se crea desde un una función síncrona con asyncio.run() 

def funcion_sync():
    resultado = asyncio.run(mi_funcion_async())
    print(resultado)


2. Entornos FastAPI (como FastHTML)

En este caso ya se ha creado un event loop. Para ello lo mas normal es utilizar funciones asíncronas.

Los puntos de partida para llamadas a las funciones suelen ser los "endpoints"(o urls) y conviene definirlas como asíncronas:

@app.post("/softprop/validate_login")
async def post_login(req, login: xmclasses.Login):
''' 1. Verifica usuario y contraseña ''' ldap_authenticated= await xmldap.autheticate_by_login(login.usuari, login.paraula_de_pass) if not ldap_authenticated: print ("returning to first login page") return fh.Div("Error en l'usuari o la paraula de pas", cls="alert alert-danger")


Pero puede haber casos que  "recojamos el event loop con asyncio.get_event_loop()  y ejcutemos funciones dendro de él con asyncio.run_coroutine_threadsafe() y recogiendo el resultado con .result() .

import asyncio

loop = asyncio.get_event_loop()
future = asyncio.run_coroutine_threadsafe(mi_funcion_async(), loop)
resultado = future.result()





Python ASYNC (I). Introducción

 1. Introducción

Async ejecuta una tarea mientras otra tarea está esperando. No es paraleleismo real pues no utiliza varios núcleos.


Veamos un ejemplo de programa sj́ncrono y su homólogo asíncrono.

La versión síncrona ejecuta el proceso tarea() dos veces que espera 2 segundos cada vez por tanto tarda 4 segundos

import time

def tarea():
    time.sleep(2)
    print("Hecho")

tarea()
tarea()


La versión asíncrona solo tarda 2 segundos pues cuando lanza la primera tarea(), no se espera a que termine para lanzar la segunda tarea() 


import asyncio

async def tarea():
    await asyncio.sleep(2)
    print("Hecho")

async def main():
    await asyncio.gather(
        tarea(),
        tarea()
    )

asyncio.run(main())


2. Cuando usar async?

  • Redes (HTTP, APIs)
  • Escaneo de red
  • I/O (archivos, sockets)
  • Bots, servidores

No sirve para:

  • CPU intensivo (usar multiprocessing mejor)
Librerías async importantes:
  • asyncio (core)
  • aiohttp (HTTP)
  • asyncssh (SSH)
  • aiomysql, asyncpg (DB)
  • aiofiles (archivos)

3. Conceptos clave

1. Las funciones asíncronas se definen con async def

async def mi_funcion():
    pass

2. El comando async ejecuta funciones asíncronas dentro de otras funciones asíncronas

async def mi_funcion():
    await my_async_func()

3. Para el main utilizar asyncio.run(my_async_fun()) (es el event loop)

if __name__ == "__main__":
    asyncio.run(run_from_yaml())

4. courutines, problematica de su ejecución. Si una función asíncrono no se la llama con async, entonces es una courutina y no se ejecuta aún

import asyncio

async def tarea():
    await asyncio.sleep(2)
    return 'hola'

async def main():
    #MALA llamada, a1 es una corrutina y no se ejecuta aún
    #  a1 es una referencia a la función tarea()
    a1= tarea()
 
    #BUENA llamada
    a2=await tarea()
    
asyncio.run(main())

5. ejecución de varias fuinciones (a la vez)con asyncio.gather

import asyncio

async def main():
    await asyncio.gather(tarea1(), tarea2(), tarea3()) 
    
asyncio.run(main())

6. await asyncio.sleep(1) para parar la ejecución dentro de una función asíncrona pero sin parar otras funciones que se ejecutan en paralelo

import asyncio

async def my_async_func():
    #Para 1 sefundo esta tarea solo y no el resto de funciones asíncronas
    await asyncio.sleep(1)









viernes, 20 de marzo de 2026

WEBPROPv2 (XIX). Ejecución de procesos en modo sudo

 A veces hay librerías como python-nmap que algunas opciones se tienen que ejecutar como sudo para ello se plantea ejecutar esta sentencia:

#Poder utiliza algunas capacidades de nmpa sin sudo
sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip $(which nmap)
#Revertir al estado anterior sudo setcap -r $(which nmap)


⚙️ Desglose por partes

1. setcap

Herramienta de Linux para asignar capabilities a ejecutables.Las capabilities son permisos finos (más seguros que sudo).

2. $(which nmap)

Devuelve la ruta de nmap, normalmente:

/usr/bin/nmap

3. Las capabilities

🔹 cap_net_raw

Permite usar sockets RAW. Necesario para:

  • Ping SYN
  • OS fingerprinting (-O)
  • Escaneos stealth

🔹 cap_net_admin

Permite operaciones de red avanzadas. Necesario para:

  • manipular paquetes
  • técnicas avanzadas de escaneo

🔹 cap_net_bind_service

Permite usar puertos < 1024. No es crítico para nmap, pero útil en algunos casos

4. +eip

Significa que las capabilities se aplican en:

  • e → effective
  • i → inheritable
  • p → permitted

En resumen: el binario puede usar esos permisos al ejecutarse

🎯 Concretando

No hace falta ejecutar sudo en

sudo nmap -O 192.168.1.1

pero  cualquier usuario que ejecute nmap tiene esos privilegios


miércoles, 11 de febrero de 2026

QGis (I). Instalar. Importar de Catastro

 1. Instalar en Linux Mint (o Ubuntu)

Veamos segun chapgpt lo que hay que hacer


#1. Instalar las herramientas necesarias
sudo apt update
sudo apt install gnupg software-properties-common

# Añadir la clave oficial
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://qgis.org/downloads/qgis-archive-keyring.gpg | sudo tee /etc/apt/keyrings/qgis-archive-keyring.gpg > /dev/null

# Ver el repositorio oficial
lsb_release -a

#Si sale Linx Mint 21.X entonces:
#echo "deb [signed-by=/etc/apt/keyrings/qgis-archive-keyring.gpg] https://qgis.org/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/qgis.list

# Si sale Linux Mint 22.x:
#echo "deb [signed-by=/etc/apt/keyrings/qgis-archive-keyring.gpg] https://qgis.org/ubuntu noble main" | sudo tee /etc/apt/sources.list.d/qgis.list

# Instalar QGIS
sudo apt update
sudo apt install qgis qgis-plugin-grass


Ahora debería de estar en el menú de aplicaciones



domingo, 8 de febrero de 2026

FreeCAD (X). Creación de un molde para plomada de atarraya. (V) Mas agujeros de tornillos y simetrías

 1. Introducción

Después de resuelto el problema de los pasantes ahora toca hacer agujeros en otras 2 cara y crear simetría

2. Crear un cuerpo sobre el cut008 y los sketchs de agujeros

Vamos a Part Design y seleccionamos el último cut el "cut008" y creamos un cuerpo

Marcamos la cara donde va el agujero lateral y creamos un sketch y dibujamos un círculo donde irá el agujero. Recordar que lo importante es el centro del círculo


Con la herramienta Hole creamos el agujero

Hay que repetir la operación con la cara opuesta. Este es el sketch


3. Crear una pieza simétrica a esta. 

Seleccionamos el desplegable Part, y le damos al botón de simetría

Y le damos estos parámetros que se observan en la figura:


Y obtenemos la pieza simétrica



4. Unir las 2 piezas (original y simétrica)

Seleccionamos las 2 piezas y le damos al botón de unir piezas:


Y obtenemos la fusión de ambas piezas




5. Crea agujero

Seleccionamos del desplegable "Part Design" , seleccionamos la pieza Fusion002 y Menu Part Design - Crear Cuerpo vamos a crear un cuerpo cuerpo sobre Fusion002


Ahora seleccionamos la cara y creamos un sketch y dibujamos donde va el agujero


Le damos a Hole y con M6 dibujamos donde se asirá el mango



Análogamente con la cara opuesta se crea el sketch y el círculo para el agujero


Y el sketch



Y le damos al Hole y con los mismos valores anteriores M6 roscado ...


Ya tenemos nuestra pieza acabada.

Como la otra pieza es la misma y al mismo tiempo es simétrica se puede crear una pieza por simetria y girarla un poco para ver como queda

6. Crear pieza simétrica compañera

Seleccionamos la pieza y  le damos al icono de simetría y elegimos el plano e simetria la cara vertical que contiene los agujeros de lo plomos:
Vamos a Part y buscamos el icono de simetría 



Y se obtiene


Ya tenemos nuestro maravilloso molde para confeccionar plomos de atarraya.

Justo ahora que se ha plantado prohibir el plomo para la pesca.

En fin, como decía mi madre, "el saber no ocupa lugar" y "nunca viena mal". Estoy contento de haber aprendido un poco de FreeCAD y poder haber hecho este experimento.


Y el archivo se envia a una empresa de mecanizado CNC y te hace un presupuesto y si te cuadra, te lo hacen



FreeCAD (IX). Creación de un molde para plomada de atarraya. (IV) Agujeros de tornillos

1. Introducción

Queremos dejar preparado el cuerpo para meter un mango y unas bisagras.

Lo agujeros se duplicaran ya que se pretende crear una pieza simétrica

2. Agujeros de las bisagras

La bisagra mide 30 mm x 40 mm pero nos interesa mas la distancia entre los agujeros de los tornillos que són 19 mm y 12 mm


3. Crear un sketch sobre la cara a taladrar

El problema es que un "cut" no es un cuerpo. Por tanto hay que ir a "Part Design", marcar el "cut" en cuestión que es la pieza del cuerpo a taladrar y seleccionar "Crear cuerpo". Con ello se crea un cuerpo referenciado al "cut003"


Creara un cuerpo con un BaseFeature que es el referencia al elemento y sobre este ya podemos crear un sketch sobre la cara correcta y dibujar los agujeros de taladro


Y una vez creado el sketch se le da a la herramienta hole y se le indican los parámetros



Y obtenemos



Ahora nos hacen falta los agujeros del mango:

Seleccionamos la vara otra vez y creamos el sketch


y el "hole"

Y se puede observar como ha ido



4. Solucionar un problema. La colada no entra

Hay que crear 4 cilindros y una cuña para que se comunique la boca de la colada con el hueco del plomo

Veamos sus cariables.

  1. Radio= 1,5 mm
  2. Altura =10 mm (podría ser menor)
  3. Posición x=-55 (para los otros tres cilindros serían x= 55, x=-10 y x=10)
y  para la cuña:
  1.  x max/min -10 y 10
  2.  y max/min -1,5 y 1,5
  3.  z min/max 0 y 10
  4. x2 min/max igual a x min/max
  5. z2 min/max igual a z min/max

queda:


 Ahora hay que sustraer estas piezas

Para ello se selecciona primeramente operación binaria de diferencia y se va combinando  el cuerpo001 que es el que está referenciado con el primer cilindor, y el resultado de cada cut se le resta cada uno de los cilindros restantes y la cuña