1. Introducción
Pasos:
- Desde el programa python creamos un array que contenga la ruta del script (bash de linux) como primer componente. Cada componente restante estará formada por la cadena "clave=valor", donde las comillas dobles forman parte del parámetro. Ojo los espacios en blanco pueden dar problemas, para ello se pueden sustituir por algúna cadena , en mi caso he utilizado "¬spc¬"(sin colillas dobles)
- Desde el script de linux verificamos que recibimos obligatoriamente los parámetros "folder", "module","funcion" y "venv". Siendo "folder" la carpeta donde tenemos que situarnos, "venv" la carpeta dentro de folder donde está el entrono virtual, "module" el módulo a llamar y "function" la función del módulo a ejecutar. En el script cambiamos a la carpeta definida en la variable "folder" y activamos el entorno virtual de la variable "venv" y ejecutamos pyton xmexec.py "module=miModulo" "function=miFuncion" .....
- El módulo xmexec.py que se encuentra en la carpeta "folder" se encarga de recibir los parámetros, arreglar los mismos sustituyendo "¬spc¬" por espacios en blanco, cargando el módulo indicado en el parámetro "module" y ejecutando la función indicada "function".
2. Llamada al script desde python
Para ello supongamos que tenemos un diccionario con el nombre del script, del módulo, función a ejecutar, entorno virtual y otros parámetros.
Sustituimos los espacios en blanco por "¬spc¬" y construimos el array para llamar a "subproces.run".
Observar que el modulo se puede definir como:
- "carpeta.modulo" ó
- "carpeta/modulo.py"
siendo "carpeta" la carpeta que contien a "modulo.py" que vamos a llamar
El script a llamar está en la carpeta "static/scripts" y se llama "execShell.sh"
import subprocess # Diccionario que contiene los parámetros PARA EL SHELL SCRIPT execDict={ 'shell':'static/scripts/execShell.sh', 'folder':'../02.llibreries', 'venv':'/static/scripts/llibreries.sh', 'module':'eni/xmexpeni.py', #'module':'eni.xmexpeni', 'function':'expedientENI', 'param1':'1814787N', 'param2':12, 'param3':'TD02', 'param4':'INDEX_ACTES_PLE', 'param5':'ENIExpTemplate.xml', } if __name__ == '__main__': # Recogemos la ruta del shell y lo quitamos del diccionario myShell=execDict['shell'] del execDict['shell'] execProgs=[myShell] #Creamos la cadena con los parámetros paraejecuar for key,value in execDict.items(): value1=value.replace(" ","¬spc¬") st=f'"{key}={value1}"' execProgs.append(st) #Exec progs. print(str(subprocess.run(execProgs, capture_output=True)))
3. Llamada al programa xmexec.
Desde el script vamos a llamar al programa pyhon xmexec, paa ello:
- Verificamos que recibimos los parámetros "folder", "venv", module" y "function"
- Nos situamos a la carpeta del parámetro "folder"
- Activamos el entorno virtual de la carpeta indicada en el parámetro "venv"
- Ejecutamos "python" al que pasamos el propgrama xmexec.py y el resto de parámetros (excepto "venv" y "folder")
#!/bin/bash #-------------------------- # 0. Exemple de crida # ./static/scripts/llibreries.sh \ # "folder=../02.llibreries" "venv=venv02" \ # "module=eni.xmexpeni" "function=expedientENI" \ # "docsFolderPath=docs/actes2022/" \ # "templatesPath=templates/ENI/" \ # "filter=*ord*aprov*sio*_signed.pdf" \ # "anyPle=2022" \ # "expCodi=1814787N" \ # "organo=L01462384" \ # "tDocu=TD02" \ # "prefPle=INDEX_ACTES_PLE" \ # "plantillaXML=ENIExpTemplate.xml" \ # "docxIndex=indexTemplate.docx" # # # O també podriem executar en background # Run the Python script in the background # nohup python myscript.py > /dev/null 2>&1 & # #--------------------------- remove_quotes() { local arg="$1" # Remove leading double quote if present arg="${arg#\"}" # Remove leading double quote if present arg="${arg%\"}" echo "$arg" } #------------------------------------ # 1. Recogemos los parametros #------------------------------------ # Inicialize variables folder_value="" venv_value="" module_value="" other_params="" # Función para mostrar uso del script usage() { echo "Uso: $0 'folder=RUTA' 'venv=carpeta entorno virtual' 'module=carpeta.modulo.py' ... otros_parametros=VALOR ..." echo "Ejemplo:" echo " $0 folder=/mi/carpeta env=producción venv=venv02 module=eni.xmexpeni config=ejemplo version=1.0" exit 1 } # Verificar si se proporcionaron argumentos if [ $# -lt 3 ]; then usage fi # Procesar cada argumento for argIni in "$@"; do # Remover comillas arg=$(remove_quotes "$argIni") # Verificar si el argumento contiene un '=' if [[ "$arg" == *=* ]]; then # Dividir el argumento en clave y valor key="${arg%%=*}" value="${arg#*=}" #echo "$key AAAA $value AAAAA $arg" case "$key" in folder) folder_value="$value" ;; venv) venv_value="$value" ;; module) module_value="$arg" ;; *) # Concatenar otros parámetros other_params+=" \"$arg\"" ;; esac #echo "$key BBBBB $value" else echo "Argumento inválido: $arg" usage fi done #echo "FOLDER= $folder_value" #echo "VENV= $venv_value" #echo "MODULE= $module_value" # Verificar que 'folder' y 'env' hayan sido proporcionados if [[ -z "$folder_value" || -z "$venv_value" || -z "$module_value" ]]; then echo "Error: Se requieren al menos un argumento 'folder' 'venv'y 'module'." usage fi #-------------------------------------- # 2. Nos cambiamos a la carpeta del modulo #------------------------------------- pwd cd "$folder_value" pwd #-------------------------------------- # 3. Activamos el entorno virtual #------------------------------------- source "$venv_value"/bin/activate # Crear la cadena concatenada final_string1="python xmexec.py \"${module_value}\" ${other_params}" echo "--------------------------------------" echo "FINAL STRING=$final_string1" echo "--------------------------------------" python xmexec.py \"${module_value}\" ${other_params}
4. Verificar que la carpeta del entrono virtual "venv" está creado dentro de la carpteta "folder"
5. Crear el programa python "xmexec.py" en la crpeta folder.
Este programa:
- Recoge los argumentos y cambia "¬spc¬ por espacio " "
- Carga el módulo "module" y
- Ejecuta la función con el diccionario que recoge todos los parámetrso menos "module" y "function"
''' Execute a function from a module paramenters: "module= module name" "function= function name" "param1 = value1" "param2 = value2" "param_n = value_n" ''' import importlib import sys requiredProps=['module','function'] def arreglaArg(arg:str)->str: if arg.startswith('"') or arg.startswith("'"): arg=arg[1:] if arg.endswith('"') or arg.endswith("'"): arg=arg[:-1] arg=arg.replace('¬spc¬',' ') return arg if __name__ == '__main__': argDict={} for i, arg1 in enumerate (sys.argv): arg=arreglaArg(arg1) #print(i, "--", arg1, '===', arg) if i>0: aArg=arg.split('=') #print(aArg) argDict[aArg[0]]=aArg[1] keys=argDict.keys() for prop in requiredProps: if prop not in keys: raise Exception (prop + ' not in arguments') moduleName=argDict['module'].replace('.py','').replace("/",".") #print (moduleName) #module = __import__(argDict['module']) # No acaba d'anar be module = importlib.import_module(moduleName) #print (module) aFunc=argDict['function'] func = getattr(module, aFunc) # Remove module and function props for prop in requiredProps: del argDict[prop] # Execute the function with arguments #print ("executing the function "+ aFunc) #print (argDict) #print ("=======================================================") func (**argDict)
6. Verificaciones
Verificar que :
- Exista el módulo dentro de la carpeta correcta
- Que el módulo tenga la funcion que vamos a llamar
- Que los parámetros de la fucnión tengan los mismos nombres y sean del mismo tipo que los parámetros que le pasamos.
7. Parámetros regex pattern
Si los parámetros "regex pattern" pueden estar definidos en un fichero u¡yaml o dentro del programa python
Por ejemplo en este fichero yaml hay 2 elementos tipo pattern.
pattern1: '^Ple \d{2} ord \d{2}-\d{2}-\d{4} .* \d{2} \d{2} \d{4}(?:_|\.)signed(?:_|\.)signed\.pdf$' params: [1, '^Acta d{2} .* \d{2} \d{2} \d{4}.pdf$', 'otro valor']
Para el caso de der definidos en un progama python vale la pena utilizar un string "rau" que se hace anteponiendo r al string
pattern = r'^Acta d{2} .* \d{2} \d{2} \d{4}.pdf$'
Los posibles problemas que pueden aparecer son:
- Las interrogaciones "?"
- Los espacios en blanco
Las interrogaciones pueden dar problemas al convertirlas en una cadena dela URL, mientras que los espacios en blanco pueden dar problemas al pasarlos a un script como parámetro, pues los trocea.
Para el caso de las interrogaciones, se puede pasar el parámetro codificado en base64 y a veces aún así puede fallar. A un caso se pueden cambiar por "¬qm¬" y luego deshacer el cambio. Para el caso de los espacios hemos optado por sustituirlos por "¬spc¬".
No hay comentarios :
Publicar un comentario