Foros del Web » Programando para Internet » Python »

Python, y problema de ejecucion!

Estas en el tema de Python, y problema de ejecucion! en el foro de Python en Foros del Web. Hola, tengo un programa python que abre unas tablas DBF utilizando el modulo "dbf" que esta en python.org Todo va bien, pero en uno de ...
  #1 (permalink)  
Antiguo 11/01/2013, 10:30
Avatar de korg1988  
Fecha de Ingreso: junio-2006
Ubicación: Santa Fe, Argentina
Mensajes: 825
Antigüedad: 18 años, 4 meses
Puntos: 19
Python, y problema de ejecucion!

Hola, tengo un programa python que abre unas tablas DBF utilizando el modulo "dbf" que esta en python.org

Todo va bien, pero en uno de los bucles grandes el programa falla y se frena sin arrojar NINGUNA clase de error o excepcion... y siempre en el mismo ciclo... (Aunque hace una semana se paraba en otro totalmente distinto... Puntualmente lo hacia en la vuelta 162 del bucle, y hoy por hoy en la 712 (sin hacer cambios de parte mia en el codigo)
El programa no se cierra ni nada, solo se cierra el bucle, pero no de manera programatica... Les paso a contar porque digo esto

A modo de debuggeo puse un print "hola mundo" al final del bucle para imprimir algo en cada ciclo y ver si el bucle llega a su ultima linea de si mismo.

Aca es donde aparece lo mas raro. En la consola la frase se imprime a la mitad!
solo un "hol" se produce en la salida....

Mire en la consola de procesos de windows y todo esta normal con respecto al proceso de mi programa... el cual pasa a tener un consumo de cpu en 0 al suceder esto!

Otra cosa rara es que me sucede en todo los ordenadores de la red, excepto en mi ordenador, en donde hago las pruebas... Pero las pruebas las hago en 3 sistemas distintos..

OS X Nativo (Tengo una macbook pro) y Windows 7, y XP virtualizados ambos sobre parallels... En los 3 funciona perfecto, recorre todas las tablas y realiza el 100% de las operaciones correctamente... Pero al ponerlo en otras computadoras sucede esto, y como ya dije, no arroja ninguna clase de error ni excepcion de ningun timpo....
Lo raro es que .... no llegue a imprimir la cadena completa que le paso a la funcion "print", eso habla de un problema en otro nivel creo..

Saludos y gracias de antemano!
  #2 (permalink)  
Antiguo 11/01/2013, 10:41
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 8 meses
Puntos: 1360
Respuesta: Python, y problema de ejecucion!

Nos encantaría poder ayudarte, pero lamentablemente con los datos que nos das no podemos hacer nada.

Un trozo de código (con suficiente contexto) seria suficiente. O mensaje de error en los logs (si es que hay alguno), etc...
  #3 (permalink)  
Antiguo 11/01/2013, 11:23
Avatar de korg1988  
Fecha de Ingreso: junio-2006
Ubicación: Santa Fe, Argentina
Mensajes: 825
Antigüedad: 18 años, 4 meses
Puntos: 19
Respuesta: Python, y problema de ejecucion!

Aca paso el codigo de la clase "Rastrillador" que es la clase encargada de realizar el proceso..

Quiero aclarar algo antes... y que no se olvide... TODO EL RESTO DEL SISTEMA funciona OK.. Solo falla en este momento, y no arroja NINGUNA clase de error o excepcion...

El bucle en cuestion donde la aplicacion muere es el siguiente, y se encuentra en el metodo "run" (que sobreescribe al metodo run de la clase Thread) ya que ejecuto el proceso como un hilo aparte
Código:
for asociado, total_asociados in Asociado.factory():
Código Python:
Ver original
  1. class Rastrillador(threading.Thread, QtCore.QObject):
  2.     "Clase que se encarga de revisar asociado por asociado. Es un thread independiente"
  3.     confirmado = QtCore.Signal() # sucede cuando todo esta ok, y se inicia el bucle de rastrillaje
  4.     actual = QtCore.Signal((Asociado, tuple))
  5.     terminado = QtCore.Signal()
  6.     error = QtCore.Signal((unicode,))
  7.    
  8.     def __init__(self, fecha_periodo):
  9.         threading.Thread.__init__(self)
  10.         QtCore.QObject.__init__(self)
  11.        
  12.         self.fecha_periodo = fecha_periodo
  13.  
  14.     def periodo_fue_rastrillado(self, fecha_periodo):
  15.         tabla = abrir_tabla(Config.config.get("db_paths", "uif_periodos"))
  16.         for registro in tabla:
  17.             if str(registro.periodo).zfill(6) == fecha_periodo.strftime("%m%Y"):
  18.                 return True
  19.         return False
  20.    
  21.     def __registrar_rastrillaje(self, operador, asoc_r, asoc_e):
  22.         a = abrir_tabla(Config.config.get("db_paths", "uif_periodos"))
  23.         a.append((self.fecha_periodo.strftime("%m%Y"), datetime.date.today(), operador, asoc_r, asoc_e))
  24.    
  25.     def run_dbf_filter(self):
  26.         """Llama a una rutina externa encargada de filtrar las tablas de movimientos correspondiendo al periodo dado.
  27.         A partir de aqui toda operación sobre estas tablas asume que los datos son del período en cuestión"""
  28.         cmd = Config.config.get("engines", "uif_filter").format(periodo=self.fecha_periodo.strftime("%m%Y"))
  29.         return subprocess.call(cmd, shell=True)
  30.    
  31.     def run(self):
  32.         index = 0
  33.         total_excedidos = 0
  34.        
  35.         try:
  36.             if self.periodo_fue_rastrillado(self.fecha_periodo):
  37.                 raise Exception(u"El período ya fue rastrillado")
  38.            
  39.             if sys.platform == "win32":
  40.                 if self.run_dbf_filter() != 0:
  41.                     raise Exception(u"No se ha podido ejecutar la rutina de filtrado.\nVerifique la misma en el archivo uif.cfg > engines > uif_filter.")
  42.         except dbf.DbfError:
  43.             print "error en dbf iniciando rastrillaje"
  44.         except Exception, e:
  45.             self.error.emit(e.message)
  46.         else:
  47.             self.confirmado.emit()
  48.  
  49.             for asociado, total_asociados in Asociado.factory():
  50.                 index += 1
  51.                 self.actual.emit(asociado, (index, total_asociados)) # Asociado, tupla_porcentaje
  52.                
  53.                 asociado.calcular_totales()
  54.                 tope_asociado = asociado.obtener_tope_uif()
  55.                
  56.                 total_asociado = asociado.total_amt + asociado.total_cac + asociado.total_cae
  57.                
  58.                 valor_tope_general = Parametros().valoruif
  59.                 try:
  60.                     """ Si no existe tope personal, entonces la expresion arroja un error, y caigo en el except, utilizando el tope general.
  61.                     Si existe un tope personal, lo comparo al general, y utilizo el de mayor valor"""
  62.                     valor_tope, tipo_tope = ((valor_tope_general, "generico")
  63.                                              if valor_tope_general > tope_asociado.valor else
  64.                                              (tope_asociado.valor, "personal"))
  65.                 except:
  66.                     valor_tope, tipo_tope = valor_tope_general, "generico"
  67.  
  68.                 esta_excedido = total_asociado > valor_tope
  69.  
  70.                 if esta_excedido:
  71.                     total_excedidos += 1
  72.                     exceso = total_asociado - valor_tope
  73.                     asociado.informar_exceso(fecha_periodo=self.fecha_periodo, exceso=exceso, tipo_tope=tipo_tope,
  74.                                              valor_tope=valor_tope, generar_documento=True)
  75.            
  76.             self.__registrar_rastrillaje(operador=obtener_nombre_operador(),
  77.                                          asoc_r=total_asociados, asoc_e=total_excedidos)
  78.             self.terminado.emit()

Aca te pongo la clase "Asociado"

Código Python:
Ver original
  1. class Asociado(object):
  2.  
  3.     @staticmethod
  4.     def factory(nro_socio=None):
  5.         tabla = abrir_tabla(Config.config.get("db_paths", "asociados"))
  6.         if nro_socio is not None:
  7.             registros = tabla.query("select * where nro_socio == " + str(nro_socio))
  8.         else:
  9.             registros = tabla
  10.        
  11.         total_registros = len(registros)
  12.         for registro in registros:
  13.             yield Asociado(nro_socio=registro.nro_socio, apeynom=registro.apeynom, cuil=registro.cuil), total_registros
  14.            
  15.             """Este modo fue anulado porque el campo fecha de algunos registros tenia un caracter extraño que hacia
  16.             crashear la libreria al acceder al mismo e intentar transformarlo a datetime"""
  17.             #yield Asociado(**dict(zip(tabla.field_names, registro))), total_registros
  18.            
  19.     def __init__(self, nro_socio, apeynom, cuil, **kwargs):
  20.         self.nro_socio = nro_socio
  21.         self.apeynom = apeynom
  22.         self.cuil = cuil
  23.        
  24.         self.total_amt = None
  25.         self.total_cac = None
  26.         self.total_cae = None
  27.        
  28.     def __calcular_total_amt(self):
  29.         self.total_amt = 0.00
  30.         tabla = abrir_tabla(Config.config.get("db_paths", "amt"))
  31.        
  32.         for registro in tabla.query("select * where nrotit1 == " + str(self.nro_socio)):
  33.             cotiz = registro.cotiz if registro.cotiz else 1
  34.             self.total_amt += round(registro.capital * cotiz, 2)
  35.    
  36.     def __calcular_total_cac(self):
  37.         self.total_cac = 0.00
  38.         tabla = abrir_tabla(Config.config.get("db_paths", "cac"))
  39.        
  40.         for registro in tabla.query("select * where nrocta == " + str(self.nro_socio)):
  41.             self.total_cac += registro.importe
  42.    
  43.     def __calcular_total_cae(self):
  44.         self.total_cae = 0.00
  45.         tabla = abrir_tabla(Config.config.get("db_paths", "cae"))
  46.        
  47.         for registro in tabla.query("select * where nrocta == " + str(self.nro_socio)):
  48.             self.total_cae += registro.importe
  49.    
  50.     def calcular_totales(self):
  51.         self.__calcular_total_amt()
  52.         self.__calcular_total_cac()
  53.         self.__calcular_total_cae()
  54.    
  55.     def obtener_tope_uif(self):
  56.         tabla = abrir_tabla(Config.config.get("db_paths", "uif_asociados"))
  57.         query = tabla.query("select * where nro_socio == " + str(self.nro_socio))
  58.        
  59.         # obtengo el registro con fecha mas actual
  60.         registro_mas_actual = None
  61.         for registro in query:
  62.             if not registro_mas_actual:
  63.                 registro_mas_actual = registro
  64.                 continue
  65.            
  66.             if registro.fecha >= registro_mas_actual.fecha:
  67.                 registro_mas_actual = registro
  68.                
  69.         return registro_mas_actual if registro_mas_actual else None # devuelvo valor de tope personal
  70.    
  71.     def guardar_tope(self, valor, fecha, motivo):
  72.         fecha_dbfdate = dbf.Date(fecha.year,fecha.month,fecha.day)
  73.        
  74.         tabla = abrir_tabla(Config.config.get("db_paths", "uif_asociados"))
  75.         tabla.append((self.nro_socio, fecha_dbfdate, obtener_nombre_operador(), motivo, valor))
  76.    
  77.     def informar_exceso(self, fecha_periodo, exceso, valor_tope, tipo_tope, generar_documento=False):
  78.         hoy = datetime.datetime.today()
  79.         hoy_dbfdate = dbf.Date(hoy.year,hoy.month,hoy.day)
  80.         periodo = fecha_periodo.strftime("%m%Y")
  81.        
  82.         if self.total_cae is None and self.total_cac is None and self.total_amt is None:
  83.             self.calcular_totales()
  84.        
  85.         tabla = abrir_tabla(Config.config.get("db_paths", "uif_registro"))
  86.         tabla.append((self.nro_socio, self.apeynom, hoy_dbfdate, periodo, obtener_nombre_operador(), self.total_cae, self.total_cac, self.total_amt, exceso))
  87.        
  88.         if generar_documento:
  89.             filename = "%s_%s" % (re.sub("[^A-Za-z0-9]", "_", self.apeynom.strip()), self.nro_socio)
  90.             base_dir_path = Config.config.get("documentos", "dir_path").strip("/")
  91.             periodo_dir_path = base_dir_path + "/" + fecha_periodo.strftime("%Y-%m")
  92.             doc_filename = periodo_dir_path + "/" + filename + ".txt"
  93.            
  94.             create_folder(periodo_dir_path)
  95.            
  96.             total = self.total_amt + self.total_cac + self.total_cae
  97.            
  98.             "Patterns"
  99.             lalign = "{:<15}" # alinea a la izquierda
  100.             ralign = "{:>15}" # alinea a la derecha con 15 lugares
  101.             pcurrency = "${:,.2f}" # 2 decimales; la "," separa millares (3,000,000.00)
  102.            
  103.             if self.cuil:
  104.                 cuil_text = "%s-%s-%s" % (str(self.cuil)[:2], str(self.cuil)[2:-1], str(self.cuil)[-1:])
  105.             else:
  106.                 cuil_text = "Falta"
  107.                
  108.             with open(doc_filename, "w+") as f:
  109.                 doc_content = (u"ASOCIACIÓN DE PROTECCIÓN RECIPROCA ENTRE PRODUCTORES AGROPECUARIOS\n"
  110.                 u"MODULO DE CONTROL UIF {fecha}\n\n"
  111.                 u"{asociado}\n"
  112.                 u"{t_nro_socio}{nro_socio}\n"
  113.                 u"{t_cuil}{cuil}\n"
  114.                 u"{t_periodo}{periodo}\n\n"
  115.                 u"{t_amt}{total_amt}\n"
  116.                 u"{t_cac}{total_cac}\n"
  117.                 u"{t_cae}{total_cae}\n"
  118.                 u"{t_total}{total}\n\n"
  119.                 u"{t_tope}{valor_tope}\n"
  120.                 u"{t_exceso}{exceso}\n\n"
  121.                 u"Notas:\n\n\n\n"
  122.                 u"Firma ____________________________________"
  123.                 .format(t_cuil=lalign.format(u"CUIL:"), t_nro_socio=lalign.format(u"Nro. Socio:"),
  124.                     t_periodo=lalign.format(u"Período"), t_amt=lalign.format(u"Total AMT:"), t_cac=lalign.format(u"Total CAC:"),
  125.                     t_cae=lalign.format(u"Total CAE:"), t_total=lalign.format(u"Total:"), t_exceso=lalign.format(u"Exceso:"),
  126.                     t_tope=lalign.format(u"Tope %s:" % tipo_tope), cuil=ralign.format(cuil_text),
  127.                     fecha=hoy.strftime("%d/%m/%Y"), asociado=self.apeynom,
  128.                     nro_socio=ralign.format("%s/%s" % (str(self.nro_socio)[:-1], str(self.nro_socio)[-1:])),
  129.                     periodo=ralign.format(fecha_periodo.strftime("%m/%Y")),
  130.                     total_amt=ralign.format(pcurrency.format(self.total_amt)),
  131.                     total_cac=ralign.format(pcurrency.format(self.total_cac)),
  132.                     total_cae=ralign.format(pcurrency.format(self.total_cae)),
  133.                     total=ralign.format(pcurrency.format(total)), exceso=ralign.format(pcurrency.format(exceso)),
  134.                     valor_tope=ralign.format(pcurrency.format(valor_tope))))
  135.                 f.write(doc_content.upper())

La funcion "abrir_tabla" que veras por todos lados es simplemente un shortcut, y la pongo aca
Código Python:
Ver original
  1. def abrir_tabla(archivo):
  2.     tabla = dbf.Table(archivo, codepage="\x02", ignore_memos=True)
  3.     tabla.open()
  4.     return tabla
  #4 (permalink)  
Antiguo 11/01/2013, 12:15
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 8 meses
Puntos: 1360
Respuesta: Python, y problema de ejecucion!

Ya veo perfectamente que es lo que pasa.

1.- Estas usando threads
2.- Estas usando subprocess dentro de los threads.

Lo cual si lo haces con cuidado esta bien, por que subprocess es thread safe.

Pero print no, por eso solo imprime parte de tu "Hola mundo". Lo ideal seria usar loggin o imprimir directo al sys.stdout.write
  #5 (permalink)  
Antiguo 11/01/2013, 12:27
Avatar de korg1988  
Fecha de Ingreso: junio-2006
Ubicación: Santa Fe, Argentina
Mensajes: 825
Antigüedad: 18 años, 4 meses
Puntos: 19
Respuesta: Python, y problema de ejecucion!

Cita:
1.- Estas usando threads
No me queda otra alternativa para no frenar el hilo de la interfaz grafica y mostrar una barra de progreso.
Cita:
2.- Estas usando subprocess dentro de los threads.
Por la misma razon que lo anterior, el subprocess corre un programita externo (no hecho por mi) que filtra determinadas tablas previamente... Lo meti dentro del hilo por 2 razones. 1- debe ser ejecutado antes del bucle, 2- no puedo colgar el hilo principal hasta que termine...

Cita:
Lo cual si lo haces con cuidado esta bien, por que subprocess es thread safe.
Creo que lo estoy haciendo con cuidado, digamos no estoy haciendo nada raro, vos que opinas?

Cita:
Pero print no, por eso solo imprime parte de tu "Hola mundo". Lo ideal seria usar loggin o imprimir directo al sys.stdout.write
El tema de print esta bien, entiendo a lo que apuntas, pero seguimos sin poder saber por que razon se frena la ejecucion en un punto... porque no es la primer vuelta del bucle, sino la vuelva 700 y pico!
Los print "hola mundo" los imprime a todos, hasta que en esa vuelta el uso de CPU de la aplicacion pasa a 0% (segun windows) y queda en la consola impreso "hol".

Que opinas?

Etiquetas: programa
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:20.