создать экземпляр класса python из класса, доступного как строка, только в памяти!

Я использую Reportlab для создания PDF-файлов. Я создаю два PDF-файла, которые хочу объединить после их создания. Reportlab предоставляет способ сохранения pycanvas (source) (который в основном является моим pdf-файлом в памяти) в виде файла python и вызовом метода doIt(filename) для этого python-файла воссоздает pdf-файл. Это здорово, так как вы можете объединить два PDF-файла на основе исходного кода и создать один объединенный PDF-файл.

Это делается так:

from reportlab.pdfgen import canvas, pycanvas
#create your canvas
p = pycanvas.Canvas(buffer,pagesize=PAGESIZE)
#...instantiate your pdf...

# after that, close the PDF object cleanly.
p.showPage()
p.save()

#now create the string equivalent of your canvas
source_code_equiv = str(p)
source_code_equiv2 = str(p)

#merge the two files on str. basis
#not shown how it is exactly done, to make it more easy to read the source
#actually one just have to take the middle part of source_code_equiv2 and add it into source_code_equiv
final_pdf = source_code_equiv_part1 + source_code_equiv2_center_part + source_code_equiv_part2

#write the source-code equivalent of the pdf
open("n2.py","w").write(final_pdf)
from myproject import n2
p = n2.doIt(buffer)

# Get the value of the StringIO buffer and write it to the response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response  

Это прекрасно работает, но я хочу пропустить шаг сохранения n2.py на диск. Таким образом, я ищу способ создать из строки final_pdf соответствующий класс python и использовать его непосредственно в источнике. Это возможно?

Это должно работать как-то так..

n2 = instantiate_python_class_from_source(final_pdf)
p = n2.doIt(buffer)

Причина этого в основном в том, что на самом деле нет необходимости сохранять исходный код на диск, а во-вторых, что это абсолютно не сохранение потока. Я мог бы назвать созданный файл во время выполнения, но тогда я не знаю, что импортировать!? Если нет способа предотвратить сохранение файла, есть ли способ определить импорт на основе имени файла, которое определяется во время выполнения!?

Можно спросить, почему я заранее не создаю один pdf, но это невозможно, так как они идут из разных приложений.


person Thomas Kremmel    schedule 28.08.2010    source источник
comment
Действительно ли код, который вы предоставили, является минимумом, необходимым для объяснения вопроса? Это довольно долго.   -  person allyourcode    schedule 28.08.2010


Ответы (2)


Это кажется очень долгим путем к тому, что вы хотите. Разве в Reportlab нет класса Canvas, из которого можно извлечь PDF-документ? Я не понимаю, почему здесь должен быть задействован сгенерированный исходный код Python.

Но если по какой-то причине это необходимо, то можно использовать StringIO, чтобы "записать" исходник в строку, а затем выполнить его exec:

from cStringIO import StringIO

source_code = StringIO()
source_code.write(final_pdf)
exec(source_code)
p = doIt(buffer)
person Ned Batchelder    schedule 28.08.2010
comment
хм... Простой вызов doIt(buffer) не сработает, так как doIt() - это метод сериализованного pycanvas. - person Thomas Kremmel; 28.08.2010
comment
Я думаю, нам нужно увидеть образец этого сгенерированного источника, чтобы знать правильный синтаксис. Если вы можете записать это в n2.py, затем импортировать n2, а затем вызвать n2.doIt(), тогда мой код также должен работать. - person Ned Batchelder; 28.08.2010
comment
Я бы трижды проверил, что вам вообще нужно генерировать код Python. Определенно кажется, что есть более простой способ сделать это. - person Ned Batchelder; 28.08.2010
comment
Ты прав. Я отказался от этой идеи слияния и реструктурировал всю систему, чтобы иметь возможность создавать этот объединенный PDF-файл на лету. - person Thomas Kremmel; 15.09.2010

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

import code
import string
coded_data = """
def doIt():
    print "XXXXX"
"""
script = coded_data + "\ndoIt()\n" 
co = code.compile_command(script, "<stdin>", "exec")
if co:
    exec co

Дайте мне знать, если это помогло.

person pyfunc    schedule 28.08.2010
comment
Спасибо, но я еще не уверен, поможет ли это ;-) Мне нужно, чтобы возвращаемое значение вызова метода doIt(buffer) было присвоено p, как я делаю с этим оператором: p = n2.doIt(buffer) .. Это возможно? - person Thomas Kremmel; 28.08.2010