[Checkins] SVN: z3c.rml/trunk/src/z3c/rml/ Implemented a workaround
for rendering PDF with
Roger Ineichen
roger at projekt01.ch
Sat Aug 11 21:50:07 EDT 2007
Log message for revision 78750:
Implemented a workaround for rendering PDF with
the "not thread safe" ReportLab library.
Implemented a method which renders PDF in a subprocess
using the sys.path from the parent process. Oh this eggs!
Note:
In the test_subprocess, we get rid of the thread
un-safe error: ValueError: object named but not registered
Changed:
U z3c.rml/trunk/src/z3c/rml/directive.py
A z3c.rml/trunk/src/z3c/rml/rml2pdfscript.py
U z3c.rml/trunk/src/z3c/rml/tests/test_rml.py
A z3c.rml/trunk/src/z3c/rml/tests/test_subprocess.py
-=-
Modified: z3c.rml/trunk/src/z3c/rml/directive.py
===================================================================
--- z3c.rml/trunk/src/z3c/rml/directive.py 2007-08-11 19:17:42 UTC (rev 78749)
+++ z3c.rml/trunk/src/z3c/rml/directive.py 2007-08-12 01:50:06 UTC (rev 78750)
@@ -23,6 +23,7 @@
from lxml import etree
from z3c.rml import interfaces
+logging.raiseExceptions = False
logger = logging.getLogger("z3c.rml")
Added: z3c.rml/trunk/src/z3c/rml/rml2pdfscript.py
===================================================================
--- z3c.rml/trunk/src/z3c/rml/rml2pdfscript.py (rev 0)
+++ z3c.rml/trunk/src/z3c/rml/rml2pdfscript.py 2007-08-12 01:50:06 UTC (rev 78750)
@@ -0,0 +1,117 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""RML to PDF Converter
+
+$Id: rml2pdf.py 74160 2007-04-15 22:04:24Z srichter $
+"""
+__docformat__ = "reStructuredText"
+
+import subprocess
+import sys
+import os
+
+_fileOpen = None
+
+
+def excecuteSubProcess(xmlInputName, outputFileName, testing=None):
+ # set the sys path given from the parent process
+ sysPath = os.environ['Z3CRMLSYSPATH']
+ for p in sysPath.split(';'):
+ sys.path.insert(0, p)
+
+ # now it come the ugly thing, but we need to hook our test changes into
+ # our subprocess.
+ if testing is not None:
+
+ # set some globals
+ import z3c.rml.attr
+ import z3c.rml.directive
+ global _fileOpen
+ _fileOpen = z3c.rml.attr.File.open
+ def testOpen(img, filename):
+ # cleanup win paths like:
+ # ....\\input\\file:///D:\\trunk\\...
+ if sys.platform[:3].lower() == "win":
+ filename.replace('/', '\\')
+ if filename.startswith('file:///'):
+ filename = filename[len('file:///'):]
+ path = os.path.join(os.path.dirname(xmlInputName), filename)
+ return open(path, 'rb')
+ # override some testing stuff for our tests
+ z3c.rml.attr.File.open = testOpen
+ import z3c.rml.tests.module
+ sys.modules['module'] = z3c.rml.tests.module
+ sys.modules['mymodule'] = z3c.rml.tests.module
+
+ # import rml and process the pdf
+ from z3c.rml import rml2pdf
+ rml2pdf.go(xmlInputName, outputFileName)
+
+ if testing is not None:
+ # reset some globals
+ z3c.rml.attr.File.open = _fileOpen
+ del sys.modules['module']
+ del sys.modules['mymodule']
+
+
+def goSubProcess(xmlInputName, outputFileName, testing=False):
+ """Processes PDF rendering in a sub process.
+
+ This method is much slower then the ``go`` method defined in rml2pdf.py
+ because each PDF generation is done in a sub process. But this will make
+ sure, that we do not run into problems. Note, the ReportLab lib is not
+ threadsafe.
+
+ Use this method from python and it will dispatch the pdf generation
+ to a subprocess.
+
+ Note: this method does not take care on how much process will started.
+ Probably it's a good idea to use a queue or a global utility which only
+ start a predefined amount of sub processes.
+ """
+ # get the sys path used for this python process
+ env = os.environ
+ sysPath = ';'.join(sys.path)
+ # set the sys path as env var for the new sub process
+ env['Z3CRMLSYSPATH'] = sysPath
+ py = sys.executable
+
+ # setup the cmd
+ program = [py, __file__, 'excecuteSubProcess', xmlInputName, outputFileName]
+ if testing is True:
+ program.append('testing=1')
+ program = " ".join(program)
+
+ # start processing in a sub process, raise exception or return None
+ try:
+ p = subprocess.Popen(program, env=env, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except Exception, e:
+ raise Exception("Subprocess error: %s" % e)
+
+ # Do we need improve the implementation and to kill subprocess which will
+ # fail? ri
+ stdout, stderr = p.communicate()
+ error = stderr
+ if error:
+ raise Exception("Subprocess error: %s" % error)
+
+
+if __name__ == '__main__':
+ if len(sys.argv) == 5:
+ #testing support
+ canvas = excecuteSubProcess(sys.argv[2], sys.argv[3], sys.argv[4])
+ else:
+ canvas = excecuteSubProcess(sys.argv[2], sys.argv[3])
+
Property changes on: z3c.rml/trunk/src/z3c/rml/rml2pdfscript.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: z3c.rml/trunk/src/z3c/rml/tests/test_rml.py
===================================================================
--- z3c.rml/trunk/src/z3c/rml/tests/test_rml.py 2007-08-11 19:17:42 UTC (rev 78749)
+++ z3c.rml/trunk/src/z3c/rml/tests/test_rml.py 2007-08-12 01:50:06 UTC (rev 78750)
@@ -17,7 +17,7 @@
"""
import os
import PIL
-import popen2
+import subprocess
import unittest
import sys
import z3c.rml.tests
@@ -26,6 +26,7 @@
GS_COMMAND = ('gs -q -sNOPAUSE -sDEVICE=png256 -sOutputFile=%s[Page-%%d].png '
'%s -c quit')
+
class RMLRenderingTestCase(unittest.TestCase):
def __init__(self, inPath, outPath):
@@ -37,6 +38,12 @@
# Switch file opener for Image attibute
self._fileOpen = attr.File.open
def testOpen(img, filename):
+ # cleanup win paths like:
+ # ....\\input\\file:///D:\\trunk\\...
+ if sys.platform[:3].lower() == "win":
+ filename.replace('/', '\\')
+ if filename.startswith('file:///'):
+ filename = filename[len('file:///'):]
path = os.path.join(os.path.dirname(self._inPath), filename)
return open(path, 'rb')
attr.File.open = testOpen
@@ -71,13 +78,13 @@
def runTest(self):
# Convert the base PDF to image(s)
- status = popen2.Popen3(
- GS_COMMAND %(self._basePath[:-4], self._basePath), True).wait()
+ status = subprocess.Popen(
+ GS_COMMAND %(self._basePath[:-4], self._basePath)).wait()
if status:
return
# Convert the test PDF to image(s)
- status = popen2.Popen3(
- GS_COMMAND %(self._testPath[:-4], self._testPath), True).wait()
+ status = subprocess.Popen(
+ GS_COMMAND %(self._testPath[:-4], self._testPath)).wait()
if status:
return
# Go through all pages and ensure their equality
Added: z3c.rml/trunk/src/z3c/rml/tests/test_subprocess.py
===================================================================
--- z3c.rml/trunk/src/z3c/rml/tests/test_subprocess.py (rev 0)
+++ z3c.rml/trunk/src/z3c/rml/tests/test_subprocess.py 2007-08-12 01:50:06 UTC (rev 78750)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTLAR PURPOSE.
+#
+##############################################################################
+"""Testing all XML Locale functionality.
+
+$Id: test_rml.py 74170 2007-04-16 08:42:13Z srichter $
+"""
+import os
+import PIL
+import popen2
+import unittest
+import sys
+import z3c.rml.tests
+from z3c.rml import rml2pdfscript
+from z3c.rml import attr
+from z3c.rml.tests.test_rml import ComparePDFTestCase
+from z3c.rml.tests.test_rml import RMLRenderingTestCase
+
+
+class RMLRenderingTestCase(RMLRenderingTestCase):
+
+ def runTest(self):
+ rml2pdfscript.goSubProcess(self._inPath, self._outPath, True)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ inputDir = os.path.join(os.path.dirname(z3c.rml.tests.__file__), 'input')
+ outputDir = os.path.join(os.path.dirname(z3c.rml.tests.__file__), 'output')
+ expectDir = os.path.join(os.path.dirname(z3c.rml.tests.__file__), 'expected')
+ for filename in os.listdir(inputDir):
+ if not filename.endswith(".rml"):
+ continue
+ inPath = os.path.join(inputDir, filename)
+ outPath = os.path.join(outputDir, filename[:-4] + '.pdf')
+ expectPath = os.path.join(expectDir, filename[:-4] + '.pdf')
+
+ # ** Test RML to PDF rendering **
+ # Create new type, so that we can get test matching
+ TestCase = type(filename[:-4], (RMLRenderingTestCase,), {})
+ case = TestCase(inPath, outPath)
+ suite.addTest(case)
+
+ # ** Test PDF rendering correctness **
+ TestCase = type('compare-'+filename[:-4], (ComparePDFTestCase,), {})
+ case = TestCase(expectPath, outPath)
+ suite.addTest(case)
+
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: z3c.rml/trunk/src/z3c/rml/tests/test_subprocess.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Checkins
mailing list