Determinar si una imagen se cierra después de incluirla en un ReportLab

He escrito un script de Python que generará una serie de gráficos y luego generará un informe en PDF que contiene los gráficos. La intención es que esto se genere en un servidor. Estoy usando ReportLab para generar el PDF. El script se ejecuta en una máquina que ejecuta Windows 7.

Al comienzo del script, se establece una lista para almacenar los flujos de ReportLab y una lista para almacenar la ruta de cada figura.

Story = []
FigList = []

Cada gráfico se genera usando Matplotlib y se guarda como PNG. La imagen se adjunta a Story y la ruta del archivo se agrega a FigList.

fig = plt.figure(1)
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
fname = "figure.png"
fig.savefig(fname)
FigList.append(fname)
Story.append(Image(fname))

Esto se repite para varias imágenes (aproximadamente 10 - 15 en total). Al final del script se construye el documento.

doc = SimpleDocTemplate("report.pdf",
                        pagesize=A4,
                        rightMargin=cm,
                        leftMargin=cm,
                        topMargin=cm,
                        bottomMargin=cm)

doc.build(Story)

Después de esto, deseo eliminar todos los archivos PNG que se han creado usando

for f in FigList:
    if os.path.exists(f): os.remove(f)

Sin embargo, me aparece el siguiente error

WindowsError: [Error 32] El proceso no puede acceder al archivo porque está siendo utilizado por otro proceso: 'image.png'

Estoy asumiendo aquí que el proceso de creación de documentos se realiza en un hilo separado y, por lo tanto, cuando el script intenta eliminar los archivos de figuras, el administrador de archivos todavía los marca como abiertos.

Es importante que estos archivos de imagen se eliminen antes de que finalice el proceso, ya que este puede ejecutarse muchas veces, por lo que los archivos de imagen temporales pronto ocuparán demasiado espacio.

¿Hay alguna manera de hacer que el script espere a que se cierren todas las imágenes antes de proceder a eliminar los archivos?

preguntado el 12 de junio de 12 a las 13:06

¿Qué tiene de malo doc.close() antes de eliminar? -

Es posible que desee mirar este en lugar de ReportLab? -

@fp: no hay una instancia de .close() para SimpleDocTemplate. -

@jadkik94: Idealmente, produciría cada figura como una página A4 y luego las agruparía, pero en mi caso, algunas gráficas contienen una gran cantidad de líneas y puntos que resultan ser un problema tanto en la representación en pantalla como cuando se envían a una impresora. -

@medgoode: edité mi respuesta, creo que puede controlar los objetos del archivo. Echar un vistazo. -

2 Respuestas

Parece que el problema se puede resolver asignando Image(...) a una variable antes de agregarla a Story y luego borrarlo después. Si consideramos el ejemplo en la pregunta, esta modificación se convierte en

fig = plt.figure(1)
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
fname = "figure.png"
fig.savefig(fname)
FigList.append(fname)
img = Image(fname)
Story.append(img)
del img

Nota: Esto no está relacionado con el objeto de archivo creado por savefig().

Respondido el 18 de junio de 12 a las 16:06

¿Ha intentado envolver su archivo abierto en un with ¿declaración? Por lo general, python cierra el archivo por usted después de dejar el with cláusula.

Editar: parece que tu fig.savefig(fname) podría devolver el objeto de archivo de imagen. Si eso es correcto, puede intentar llamar a close en cada objeto de archivo que devuelve una vez que haya terminado.

Respondido el 16 de junio de 12 a las 18:06

No hace eso, no abre el archivo. ¡Reportlab hace (¿o debería hacer?) esto por él! - jadkik94

Si por 'archivo abierto' se refiere a la llamada a SimpleDocTemplate, acabo de intentar with SimpleDocTemplate(...) as doc: pero me sale el error AttributeError: SimpleDocTemplate instance has no attribute '__exit__'. Cada vez que una figura de la Lista de historias (que olvidé mencionar) se hace como Figure("figure.png") y entonces no puedo envolver un with alrededor de esto por desgracia. - medgoode

Estoy mirando hacia atrás en su pregunta ahora, y parece que usted crea los archivos; no SimpleDocTemplate. O al menos los archivos .png, ¿verdad? - no está mal.jpeg

@notbad.jpeg: Estoy creando los archivos PNG y luego pasando la ruta del archivo a SimpleDocTemplate. En cada caso uso plt.close(fig) para asegurarme de no crear demasiadas figuras de una sola vez y (con suerte) minimizar el uso de memoria. - medgoode

Muchas gracias por toda su ayuda con esta pregunta. Después de prueba y error, basado en algunas de sus sugerencias, ¡llegué a una solución! - medgoode

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.