Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Duda buenas prácticas
#1
Buenas a todos me llamo Adán y soy nuevo en el foro. Tengo pendiente escribir en inicio un presentación un poco más elaborada  peor de momento os pongo esta duda. Si está en sitio incorrecto solo tenéis que decírmelo Tongue Bueno, al lío.

Tengo este código que buscar ficheros en un FTP por un patrón de nombre y después, dentro de estos  X cadena de texto. Este código se llama a través de otro script(creo, porque es en Amazon Lambda) que invoca la función lambda_handler() de manera que es obligatorio que se llama siempre esta de primero. Aunque se que hay un SDK para trabajar con esto, el AWS SAM, pongo el código de forma que no haga falta usarlo ya que es una prueba muy básica:

Código:
import re
import json

import pysftp


cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
SFTP = pysftp.Connection(
        os.getenv('FTP_HOST'),
        username=os.getenv('FTP_USER'),
        password=os.getenv('FTP_PASSWORD'),
        cnopts=cnopts
    )


def search_error_logs(log_file):
    if re.match('^.*error [0-9]+\\.txt', log_file.filename):
        if log_file.st_size < 500:
            return find_string(log_file.filename)
        return True


def find_string(error_file):
    with SFTP.open(f"upload/{error_file}", 'r') as f:
        content = f.read().decode("utf-8")
        if "Empty source" not in content:
            return True


def lambda_handler(event, context):
    event_id = json.loads(event)['ID']
    print(f"Try event: {event_id}")
    result = SFTP.listdir_attr('/upload')
    error_logs = [x.filename for x in list(filter(search_error_logs, result))]
    SFTP.close()
    if error_logs:
        return f"Files with errors in the FTP.\nLogs name: {error_logs}"
    return f"Finally event {event_id}"


Mi duda es la siguiente. Tal como está el código que pongo ahí da problemas si se llama más de una vez la función lambda_handler en tiempo de ejecución porque en la segunda llamada no reabre la conexión con el FTP. Ej:

Código:
import json

from app import lambda_handler

event1 = json.dumps({'ID': 'djl1jl2j12l1j2'})
event2 = json.dumps({'ID': '3232323sddsdwd'})

print(lambda_handler(event1, ''))
print(lambda_handler(event2, ''))

  • Puedo mover donde se instancia el objeto SFTP a la función lambda_handler y  indicar que es GLOBAL y ya funciona pero no me convence nada.
  • También pensé en crear la conexión con el FTP directamente en la función lambda_handler y después ir pasando esta a la funciones que le hagan falta pero me parece que queda lioso si quiero utilizar la función filter y tener que pasarle a esta la conexión.
Si me podéis dar un buen consejo de que sería lo más pytonico y si lo que planteo está bien, mal, otras soluciones ... os lo agradezco.

Gracias de antemano y un saludo a todos !
Responder
#2
Hola, bienvenido!

No veo mal que pases la conexión como un argumento, eso es mejor que tener una variable global. Por lo que veo estás usando filter() con la función search_error_logs(), que no requiere tener acceso a la conexión. De cualquier manera, si esto fuese necesario, podés usar functools.partial() y no cambiaría mucho el código, sería algo así (suponiendo que el argumento se llama sftp):

Código:
filter(partial(search_error_logs, sftp=...), result))

Ahora bien, si te encontrás con que muchas de tus funciones van a tener que recibir el argumento sftp y vas a estar pasando ese objeto de un lado a otro, ahí lo mejor sería crear una clase que herede de pysftp.Connection.

Saludos!
¡No te pierdas nuestro curso oficial en Udemy para aprender Python, bases de datos SQL, orientación a objetos, tkinter y mucho más!

También ofrecemos consultoría profesional de desarrollo en Python para personas y empresas.
Responder
#3
(28-09-2020, 12:01 AM)Francisco escribió: Hola, bienvenido!

No veo mal que pases la conexión como un argumento, eso es mejor que tener una variable global. Por lo que veo estás usando filter() con la función search_error_logs(), que no requiere tener acceso a la conexión. De cualquier manera, si esto fuese necesario, podés usar functools.partial() y no cambiaría mucho el código, sería algo así (suponiendo que el argumento se llama sftp):

Código:
filter(partial(search_error_logs, sftp=...), result))

Ahora bien, si te encontrás con que muchas de tus funciones van a tener que recibir el argumento sftp y vas a estar pasando ese objeto de un lado a otro, ahí lo mejor sería crear una clase que herede de pysftp.Connection.

Saludos!

Muchas gracias. Creo que la opción de la clase es la que más me convence pero se agradecen igual ambas explicaciones. Poco use functools y parece un módulo muy interesante

Un saludo
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)