[Checkins] SVN: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/ added

Andreas Jung andreas at andreas-jung.com
Sat May 16 01:27:03 EDT 2009


Log message for revision 99998:
  added
  

Changed:
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/__init__.py
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.py
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.txt
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/index.pt
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/master.pt
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/showjobs.pt
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/configure.zcml
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/ftesting.zcml
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/README.txt
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/smartprintng.css
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/zopyx_logo.gif
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.html
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.jpg
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.zip
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/zip_client.py
  A   zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py

-=-
Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/__init__.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/__init__.py	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/__init__.py	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1 @@
+# this directory is a package

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.py	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.py	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,239 @@
+
+import re
+import os
+from datetime import datetime
+import grok
+import time
+import uuid
+import tempfile
+import base64
+import zipfile
+import glob
+import shutil
+from zope import interface, schema
+from zopyx.convert2.convert import Converter
+
+default_tempdir = unicode(tempfile.tempdir)
+
+class ManageServer(grok.Permission):
+    grok.name('zopyx.smartprintng.server.manage')
+
+class IServer(interface.Interface):
+    title = schema.TextLine(title=u'Title of this instance', 
+                            required=True)
+    spool_directory = schema.TextLine(title=u'Spool directory', 
+                                      default=default_tempdir,
+                                      required=True)
+
+
+class Zopyx_smartprintng_server(grok.Application, grok.Container):
+    """ This is the base of all evil """    
+
+    interface.implements(IServer)
+
+    title = u''
+    spool_directory = default_tempdir
+
+    def addJob(self, *args, **kw):
+        if not 'accounting' in self:
+            self['accounting'] = Accounting()
+        self['accounting'].addJob(*args, **kw)
+        self._p_changed = 1
+
+
+class EditForm(grok.EditForm):
+    """ Eggserver's edit form """
+
+    grok.name('edit')
+    grok.require('zopyx.smartprintng.server.manage')
+    grok.context(IServer)
+    form_fields = grok.AutoFields(IServer)
+
+    @grok.action('Apply changes')
+    def applyChanges(self, **data):
+        self.applyData(self.context, **data)
+        self.redirect(self.url(self.context))
+
+    @grok.action('Cancel')
+    def returnToIndex(self, **data):
+        self.redirect(self.url(self.context))
+
+
+class Accounting(grok.Container):
+    """ A folder for Job objects """
+
+    num_items = 0
+
+    def addJob(self, *args, **kw):
+        self.num_items += 1
+        self[str(self.num_items)] = Job(*args, **kw)
+        self._p_changed = 1
+
+
+class Job(grok.Model):
+    """ Holds informations about each conversion job """
+
+    def __init__(self, *args, **kw):
+        super(Job, self).__init__()
+        self.created = datetime.now()
+        for k,v in kw.items():
+            setattr(self, k, v)
+
+class Index(grok.View):
+    grok.context(Zopyx_smartprintng_server)
+
+class ShowJobs(grok.View):
+    grok.context(Zopyx_smartprintng_server)
+
+    def getJobs(self):
+        lst = list(self.context['accounting'].values())
+        lst.sort(lambda x,y: -cmp(x.created, y.created))
+        return lst
+
+class Master(grok.View):
+    grok.context(Zopyx_smartprintng_server)
+
+class Download(grok.View):
+    """ Provides download functionality for generated files over HTTP"""
+
+    grok.context(Zopyx_smartprintng_server)
+
+    def render(self, id, extension='pdf'):
+        """ Return generated PDF file """
+
+        filename = os.path.join(self.context.spool_directory, 
+                                '%s.%s' % (id, extension))
+        r = self.response
+        if not os.path.exists(filename):
+            r.setStatus(404)
+            return
+
+        r.setHeader('content-type', 'application/pdf')
+        r.setHeader('content-disposition', 'attachment; filename="%s"' % 
+                     toAscii(os.path.basename(filename)))
+        return file(filename)
+
+
+#######################################
+# The XML-RPC API
+#######################################
+
+class XMLRPC(grok.XMLRPC):
+
+    grok.context(Zopyx_smartprintng_server)
+
+    rxcountpages = re.compile(r"$\s*/Type\s*/Page[/\s]", re.MULTILINE|re.DOTALL)
+
+    def _countPages(self, filename):
+        data = file(filename,"rb").read()
+        return len(self.rxcountpages.findall(data))
+
+    def convertZIP(self, zip_archive, spool=0, converter_name='pdf-prince'):
+        """ Process html-file + images within a ZIP archive """
+
+        # store zip archive first
+        tempdir = tempfile.mkdtemp()
+        zip_temp = os.path.join(tempdir, 'input.zip')
+        file(zip_temp, 'wb').write(base64.decodestring(zip_archive))
+        ZF = zipfile.ZipFile(zip_temp, 'r')
+        for name in ZF.namelist():
+            destfile = os.path.join(tempdir, name)
+            if not os.path.exists(os.path.dirname(destfile)):
+                os.makedirs(os.path.dirname(destfile))
+            file(destfile, 'wb').write(ZF.read(name))
+        ZF.close()
+
+        # find HTML file
+        html_files = glob.glob(os.path.join(tempdir, '*.htm*'))
+        if not html_files:
+            raise IOError('No HTML files found in %s' % tempdir)
+        html_filename = html_files[0]
+
+        result = self.convert(html_filename, 
+                              spool=spool, 
+                              converter_name=converter_name)
+
+        # Generate result ZIP archive with base64-encoded result
+        zip_out = os.path.join(tempdir, 'output.zip')
+        ZF = zipfile.ZipFile(zip_out, 'w')
+        ZF.writestr('output.pdf', file(result, 'rb').read())
+        ZF.close()
+        encoded_result = base64.encodestring(file(zip_out, 'rb').read())
+        shutil.rmtree(tempdir)
+        return encoded_result
+
+    def convert(self, html_filename, spool=0, converter_name='pdf-prince'):
+        """ Process a single HTML file """
+
+        start_time = time.time()
+        c = Converter(html_filename)
+        output_filename = c(converter_name)
+        file_size = os.stat(output_filename)[6]
+        duration = time.time() - start_time
+        self.context.addJob(input_filename=html_filename, 
+                            output_filename=output_filename,
+                            output_size=file_size,
+                            duration=duration,
+                            pages=self._countPages(output_filename),
+                            converter_name=converter_name)
+        if spool:
+            id = uuid.uuid1()
+            if not os.path.exists(self.context.spool_directory):
+                os.makedirs(self.context.spool_directory)
+            new_filename = os.path.join(self.context.spool_directory, 
+                                        '%s.pdf' % id)
+            os.rename(output_filename, new_filename)
+            return grok.url(self.request, self.context) + \
+                            '/download?id=%s' % id
+        else:
+            return output_filename
+
+def _c(s):
+    if isinstance(s, unicode):
+        return s
+    try:
+        return unicode(s, 'utf-8')
+    except UnicodeError:
+        return unicode(s, 'iso-8859-15')
+
+def toAscii(s):
+    return _c(s).encode('ascii', 'ignore')
+
+
+class BaseForm(grok.AddForm):
+    grok.context(Zopyx_smartprintng_server)
+
+    def _deliver(self, filename):
+        """ Return generated PDF file """
+        r = self.response
+        r.setHeader('content-type', 'application/pdf')
+        r.setHeader('content-length', os.stat(filename)[6])
+        r.setHeader('content-disposition', 'attachment; filename="%s"' % 
+                     toAscii(os.path.basename(filename)))
+        return file(filename)
+
+
+#######################################
+# Businesscard demo
+#######################################
+
+class IBusinessCard(interface.Interface):
+    fullname = schema.TextLine(title=u"Fullname (firstname + lastname)")
+    position = schema.Choice(('CEO', 'Developer', 'Facility manager'), 
+                             title=u"Position")
+    phone = schema.TextLine(title=u"Phone", default=u'+49-7071-793257')
+    orientation= schema.Choice(('horizontal', 'vertical'), 
+                             title=u"Businesscard layout")
+
+
+class generateBusinessCard(BaseForm):
+    grok.name('generateBusinessCard')
+    grok.context(Zopyx_smartprintng_server)
+    form_fields = grok.AutoFields(IBusinessCard)
+
+    @grok.action('Generate businesscard')
+    def add(self, **data):
+        from zopyx.smartprintng.core.demo2 import demo_app as demo2
+        filename = demo2.demo_convert(**data)
+        return self._deliver(filename)
+

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.txt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.txt	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app.txt	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,32 @@
+Do a functional doctest test on the app.
+========================================
+
+:Test-Layer: functional
+
+Let's first create an instance of Zopyx_smartprintng_server at the top level:
+
+   >>> from zopyx_smartprintng_server.app import Zopyx_smartprintng_server
+   >>> root = getRootFolder()
+   >>> root['app'] = Zopyx_smartprintng_server()
+
+
+Run tests in the testbrowser
+----------------------------
+
+The zope.testbrowser.browser module exposes a Browser class that
+simulates a web browser similar to Mozilla Firefox or IE.  We use that
+to test how our application behaves in a browser.  For more
+information, see http://pypi.python.org/pypi/zope.testbrowser.
+
+Create a browser and visit the instance you just created:
+
+   >>> from zope.testbrowser.testing import Browser
+   >>> browser = Browser()
+   >>> browser.open('http://localhost/app')
+
+Check some basic information about the page you visit:
+
+   >>> browser.url
+   'http://localhost/app'
+   >>> browser.headers.get('Status').upper()
+   '200 OK'

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/index.pt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/index.pt	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/index.pt	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,9 @@
+<html metal:use-macro="context/@@master/macros/master">
+  <metal:slot fill-slot="main">
+  <ul>
+    <li>
+      <a href="generateBusinessCard">Businesscard generator demo</a>
+    </li>
+  </ul>
+  </metal:slot>
+</html>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/master.pt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/master.pt	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/master.pt	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,26 @@
+<metal:page define-macro="master">
+    <html>
+        <head>
+            <title tal:content="context/title" />
+            <link rel="stylesheet" type="text/css"
+                  tal:attributes="href static/smartprintng.css"
+            />
+            <metal:slot define-slot="css_slot" />
+            <metal:slot define-slot="js_slot" />
+        </head>
+        <body>
+            <a href="http://www.zopyx.com" border="0">
+                <img tal:attributes="src static/zopyx_logo.gif" />
+            </a>
+            <h1 i18n:translate="" tal:content="context/title" />
+
+            <metal:slot define-slot="main" />
+
+            <hr/>
+            <div class="footer">
+                The SmartPrintNG server is (C) 2008, ZOPYX Ltd. &amp; Co. KG, D-72070 T&uuml;bingen, 
+                Germany, www.zopyx.com. All rights reserved!
+            </div>
+        </body>
+    </html>    
+</metal:page>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/showjobs.pt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/showjobs.pt	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/app_templates/showjobs.pt	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,16 @@
+<html metal:use-macro="context/@@master/macros/master">
+    <metal:slot fill-slot="main">
+        <h1>Accounting</h1>
+        <table border="1">
+
+            <tal:loop repeat="job view/getJobs">
+                <tr>
+                    <td tal:content="python: job.created.strftime('%d.%m.%Y %H:%M:%S')" />
+                    <td tal:content="job/duration" />
+                    <td tal:content="job/pages" />
+                    <td tal:content="job/converter_name" />
+                <tr>
+            </tal:loop>
+        </table>
+    </metal:slot>
+</html>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/configure.zcml
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/configure.zcml	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/configure.zcml	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,6 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:grok="http://namespaces.zope.org/grok">
+  <include package="grok" />
+  <includeDependencies package="." />
+  <grok:grok package="." />
+</configure>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/ftesting.zcml
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/ftesting.zcml	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/ftesting.zcml	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,34 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   i18n_domain="zopyx_smartprintng_server"
+   package="zopyx_smartprintng_server"
+   >
+
+  <include package="zopyx_smartprintng_server" />
+
+  <!-- Typical functional testing security setup -->
+  <securityPolicy
+      component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy"
+      />
+
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User"
+      />
+  <grant
+      permission="zope.View"
+      principal="zope.anybody"
+      />
+
+  <principal
+      id="zope.mgr"
+      title="Manager"
+      login="mgr"
+      password="mgrpw"
+      />
+
+  <role id="zope.Manager" title="Site Manager" />
+  <grantAll role="zope.Manager" />
+  <grant role="zope.Manager" principal="zope.mgr" />
+
+</configure>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/README.txt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/README.txt	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/README.txt	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,2 @@
+Put static files here, like javascript and css.  They will be
+available as static/<filename> in views.

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/smartprintng.css
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/smartprintng.css	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/smartprintng.css	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,17 @@
+* {
+    font-family: Georgia,"Bitstream Vera Serif","New York",Palatino,serif;
+    font-weight:normal;    
+}
+
+.footer {
+    font-size: 11px;
+    font-style:italic;
+}
+
+img {
+    border: 0;
+}          
+
+a {
+    text-decoration: none;
+}

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/zopyx_logo.gif
===================================================================
(Binary files differ)


Property changes on: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/static/zopyx_logo.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.html
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.html	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.html	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,54 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <title></title>
+  <meta name="Generator" content="Cocoa HTML Writer">
+  <meta name="CocoaVersion" content="949.35">
+  <style type="text/css">
+    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
+    p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
+  </style>
+</head>
+<body>
+<img src="test.jpg" />
+<p class="p1"><span class="Apple-converted-space">  </span>Further technologies</p>
+<p class="p2"><br></p>
+<p class="p1">Programming languages:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Python, C, C++, Shell, Javascript,</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* SQL, PHP</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* SGML, XML, DOM, SAX, XSL, XSLT, XSL-FO, XPATH etc.</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Java, JDBC, Servlets</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* C, C++</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Middleware (ILU, CORBA)</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* HTML, CSS</p>
+<p class="p2"><br></p>
+<p class="p1">Databases:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Oracle, MySQL, Postgres, ZODB</p>
+<p class="p2"><br></p>
+<p class="p1">Tools:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Apache, Squid, Pound</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Zope, CMF, Plone</p>
+<p class="p2"><br></p>
+<p class="p1">Operating system:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Unix, Linux, Solaris</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Windows</p>
+<p class="p2"><br></p>
+<p class="p1">Applications server:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Zope 2, PHP</p>
+<p class="p2"><br></p>
+<p class="p1">Content-Management-Systems:</p>
+<p class="p2"><br></p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Typo 3</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Zope</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* Plone</p>
+<p class="p1"><span class="Apple-converted-space">    </span>* CPS</p>
+<p class="p2"><br></p>
+</body>
+</html>

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.jpg
===================================================================
(Binary files differ)


Property changes on: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.zip
===================================================================
(Binary files differ)


Property changes on: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/test.zip
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/zip_client.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/zip_client.py	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/test_data/zip_client.py	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,19 @@
+import base64
+import xmlrpclib
+import zipfile
+import tempfile
+
+# XMLRPC server instance
+server = xmlrpclib.Server('http://localhost:11080/demo')
+
+# send the ZIP archive base64 encoded
+zip_data = server.convertZIP(base64.encodestring(file('test.zip', 'rb').read()))
+
+# and receive the result PDF as base64 encoded ZIP archive
+zip_temp = tempfile.mktemp()
+file(zip_temp, 'wb').write(base64.decodestring(zip_data))
+ZF = zipfile.ZipFile(zip_temp, 'r')
+file('output.pdf', 'wb').write(ZF.read('output.pdf'))
+ZF.close()
+
+print 'output.pdf'

Added: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py	                        (rev 0)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py	2009-05-16 05:27:02 UTC (rev 99998)
@@ -0,0 +1,12 @@
+import os.path
+import z3c.testsetup
+import zopyx_smartprintng_server
+from zope.app.testing.functional import ZCMLLayer
+
+
+ftesting_zcml = os.path.join(
+    os.path.dirname(zopyx_smartprintng_server.__file__), 'ftesting.zcml')
+FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer',
+                            allow_teardown=True)
+
+test_suite = z3c.testsetup.register_all_tests('zopyx_smartprintng_server')



More information about the Checkins mailing list