Определение того, закрыто ли изображение после включения в ReportLab

Я написал скрипт Python, который будет генерировать серию графиков, а затем создавать отчет в формате PDF, содержащий графики. Намерение состоит в том, что это будет сгенерировано на сервере. Я использую ReportLab для создания PDF. Сценарий запускается на машине под управлением Windows 7.

В начале сценария задается список для хранения потоков ReportLab и список для хранения пути к каждой фигуре.

Story = []
FigList = []

Каждый график создается с помощью Matplotlib и сохраняется в формате PNG. Изображение добавляется в Story, а путь к файлу добавляется в 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))

Это повторяется для ряда изображений (всего примерно 10–15). В конце скрипта строится документ

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

doc.build(Story)

После этого я хочу удалить все файлы PNG, созданные с помощью

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

Тем не менее, я представлен со следующей ошибкой

WindowsError: [Ошибка 32] Процесс не может получить доступ к файлу, поскольку он используется другим процессом: «image.png»

Я предполагаю, что процесс создания документа выполняется в отдельном потоке, поэтому, когда скрипт пытается удалить файлы рисунков, они по-прежнему помечаются файловым менеджером как открытые.

Важно, чтобы эти файлы изображений были удалены до завершения процесса, так как этот процесс может выполняться много раз, поэтому временные файлы изображений вскоре займут слишком много места.

Есть ли способ заставить скрипт дождаться закрытия всех изображений, прежде чем приступить к удалению файлов?


person medgoode    schedule 12.06.2012    source источник
comment
Что не так с doc.close() перед удалением?   -  person f p    schedule 12.06.2012
comment
Вы можете посмотреть это вместо ReportLab ?   -  person jadkik94    schedule 12.06.2012
comment
@fp: для SimpleDocTemplate нет экземпляра .close().   -  person medgoode    schedule 12.06.2012
comment
@jadkik94: В идеале я бы создал каждую фигуру в виде страницы формата А4, а затем сгруппировал их вместе, но в моем случае некоторые графики содержат большое количество линий и точек, что доказывает проблему как при отображении на экране, так и при отправке на принтер!   -  person medgoode    schedule 12.06.2012
comment
@medgoode: я отредактировал свой ответ, думаю, вы можете разобраться с файловыми объектами. Посмотри.   -  person notbad.jpeg    schedule 16.06.2012


Ответы (2)


Казалось бы, проблему можно решить, присвоив переменной Image(...) перед добавлением ее к Story, а затем удалив ее после этого. Если мы рассмотрим пример в вопросе, эта модификация становится

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

Примечание. Это не относится к файловому объекту, созданному savefig().

person medgoode    schedule 18.06.2012

Вы пытались обернуть свой файл открытым в оператор with? Обычно python закрывает файл для вас после выхода из предложения with.

Изменить: похоже, что ваш fig.savefig(fname) может вернуть объект файла изображения. Если это правильно, вы можете попробовать вызвать close для каждого файлового объекта, который он возвращает после того, как вы закончите.

person notbad.jpeg    schedule 12.06.2012
comment
Он не то делает, не открывает файл. Reportlab делает (или должен делать?) это за него! - person jadkik94; 12.06.2012
comment
Если под «открытием файла» вы подразумеваете вызов SimpleDocTemplate, то я только что попробовал with SimpleDocTemplate(...) as doc:, но получаю сообщение об ошибке AttributeError: SimpleDocTemplate instance has no attribute '__exit__'. Каждый раз, когда фигура в списке историй (о которой я забыл упомянуть) делается как Figure("figure.png"), и поэтому я, к сожалению, не могу обернуть ее вокруг with. - person medgoode; 12.06.2012
comment
Сейчас я оглядываюсь на ваш вопрос, и похоже, что вы создаете файлы; не SimpleDocTemplate. Или хотя бы файлы .png, верно? - person notbad.jpeg; 16.06.2012
comment
@notbad.jpeg: я создаю файлы PNG, а затем передаю путь к файлу в SimpleDocTemplate. В каждом случае я использую plt.close(fig), чтобы не создавать слишком много фигур за один раз и (надеюсь) минимизировать использование памяти. - person medgoode; 18.06.2012
comment
Большое спасибо за вашу помощь в этом вопросе. После проб и ошибок, основываясь на некоторых ваших предложениях, я пришел к решению! - person medgoode; 18.06.2012