New test system based on doctest and unittest and many more.
This commit is contained in:
		
							parent
							
								
									53a945e78c
								
							
						
					
					
						commit
						546caa485d
					
				
					 21 changed files with 312 additions and 144 deletions
				
			
		| 
						 | 
				
			
			@ -127,7 +127,7 @@ class Integer(Type):
 | 
			
		|||
                 specificWritePermission=False, width=None, height=None,
 | 
			
		||||
                 master=None, masterValue=None, focus=False):
 | 
			
		||||
        Type.__init__(self, validator, multiplicity, index, default, optional,
 | 
			
		||||
                      editDefault, show, page, group, move, indexed, False,
 | 
			
		||||
                      editDefault, show, page, group, move, indexed, searchable,
 | 
			
		||||
                      specificReadPermission, specificWritePermission, width,
 | 
			
		||||
                      height, master, masterValue, focus)
 | 
			
		||||
        self.pythonType = long
 | 
			
		||||
| 
						 | 
				
			
			@ -549,4 +549,9 @@ class Config:
 | 
			
		|||
        # If you don't need the portlet that appy.gen has generated for your
 | 
			
		||||
        # application, set the following parameter to False.
 | 
			
		||||
        self.showPortlet = True
 | 
			
		||||
        # Default number of flavours. It will be used for generating i18n labels
 | 
			
		||||
        # for classes in every flavour. Indeed, every flavour can name its
 | 
			
		||||
        # concepts differently. For example, class Thing in flavour 2 may have
 | 
			
		||||
        # i18n label "MyProject_Thing_2".
 | 
			
		||||
        self.numberOfFlavours = 2
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -150,6 +150,7 @@ class Generator:
 | 
			
		|||
        self.workflows = []
 | 
			
		||||
        self.initialize()
 | 
			
		||||
        self.config = Config.getDefault()
 | 
			
		||||
        self.modulesWithTests = set()
 | 
			
		||||
 | 
			
		||||
    def determineAppyType(self, klass):
 | 
			
		||||
        '''Is p_klass an Appy class ? An Appy workflow? None of this ?
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +172,12 @@ class Generator:
 | 
			
		|||
                    break
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    def containsTests(self, moduleOrClass):
 | 
			
		||||
        '''Does p_moduleOrClass contain doctests?'''
 | 
			
		||||
        if moduleOrClass.__doc__ and (moduleOrClass.__doc__.find('>>>') != -1):
 | 
			
		||||
            return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    IMPORT_ERROR = 'Warning: error while importing module %s (%s)'
 | 
			
		||||
    SYNTAX_ERROR = 'Warning: error while parsing module %s (%s)'
 | 
			
		||||
    def walkModule(self, moduleName):
 | 
			
		||||
| 
						 | 
				
			
			@ -190,6 +197,8 @@ class Generator:
 | 
			
		|||
        except SyntaxError, se:
 | 
			
		||||
            print self.SYNTAX_ERROR % (moduleName, str(se))
 | 
			
		||||
            return
 | 
			
		||||
        if self.containsTests(moduleObj):
 | 
			
		||||
            self.modulesWithTests.add(moduleObj.__name__)
 | 
			
		||||
        classType = type(Generator)
 | 
			
		||||
        # Find all classes in this module
 | 
			
		||||
        for moduleElemName in moduleObj.__dict__.keys():
 | 
			
		||||
| 
						 | 
				
			
			@ -215,10 +224,14 @@ class Generator:
 | 
			
		|||
                            descrClass = self.classDescriptor
 | 
			
		||||
                            self.classes.append(
 | 
			
		||||
                                descrClass(moduleElem, attrs, self))
 | 
			
		||||
                        if self.containsTests(moduleElem):
 | 
			
		||||
                            self.modulesWithTests.add(moduleObj.__name__)
 | 
			
		||||
                    elif appyType == 'workflow':
 | 
			
		||||
                        descrClass = self.workflowDescriptor
 | 
			
		||||
                        self.workflows.append(
 | 
			
		||||
                            descrClass(moduleElem, attrs, self))
 | 
			
		||||
                        if self.containsTests(moduleElem):
 | 
			
		||||
                            self.modulesWithTests.add(moduleObj.__name__)
 | 
			
		||||
            elif isinstance(moduleElem, Config):
 | 
			
		||||
                self.config = moduleElem
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,6 +132,7 @@ class Generator(AbstractGenerator):
 | 
			
		|||
        self.generateInstall()
 | 
			
		||||
        self.generateWorkflows()
 | 
			
		||||
        self.generateWrappers()
 | 
			
		||||
        self.generateTests()
 | 
			
		||||
        if self.config.frontPage == True:
 | 
			
		||||
            self.labels.append(msg('front_page_text', '', msg.FRONT_PAGE_TEXT))
 | 
			
		||||
            self.copyFile('frontPage.pt', self.repls,
 | 
			
		||||
| 
						 | 
				
			
			@ -155,8 +156,8 @@ class Generator(AbstractGenerator):
 | 
			
		|||
        f = open(os.path.join(self.outputFolder, 'version.txt'), 'w')
 | 
			
		||||
        f.write(self.version)
 | 
			
		||||
        f.close()
 | 
			
		||||
        # Make Extensions a Python package
 | 
			
		||||
        for moduleFolder in ('Extensions',):
 | 
			
		||||
        # Make Extensions and tests Python packages
 | 
			
		||||
        for moduleFolder in ('Extensions', 'tests'):
 | 
			
		||||
            initFile = '%s/%s/__init__.py' % (self.outputFolder, moduleFolder)
 | 
			
		||||
            if not os.path.isfile(initFile):
 | 
			
		||||
                f = open(initFile, 'w')
 | 
			
		||||
| 
						 | 
				
			
			@ -539,6 +540,14 @@ class Generator(AbstractGenerator):
 | 
			
		|||
        repls['podTemplateBody'] = PodTemplate._appy_getBody()
 | 
			
		||||
        self.copyFile('appyWrappers.py', repls, destFolder='Extensions')
 | 
			
		||||
 | 
			
		||||
    def generateTests(self):
 | 
			
		||||
        '''Generates the file needed for executing tests.'''
 | 
			
		||||
        repls = self.repls.copy()
 | 
			
		||||
        modules = self.modulesWithTests
 | 
			
		||||
        repls['imports'] = '\n'.join(['import %s' % m for m in modules])
 | 
			
		||||
        repls['modulesWithTests'] = ','.join(modules)
 | 
			
		||||
        self.copyFile('testAll.py', repls, destFolder='tests')
 | 
			
		||||
 | 
			
		||||
    def generateTool(self):
 | 
			
		||||
        '''Generates the Plone tool that corresponds to this application.'''
 | 
			
		||||
        # Generate the tool class in itself and related i18n messages
 | 
			
		||||
| 
						 | 
				
			
			@ -672,7 +681,7 @@ class Generator(AbstractGenerator):
 | 
			
		|||
        poMsgPl.produceNiceDefault()
 | 
			
		||||
        self.labels.append(poMsgPl)
 | 
			
		||||
        # Create i18n labels for flavoured variants
 | 
			
		||||
        for i in range(2,10):
 | 
			
		||||
        for i in range(2, self.config.numberOfFlavours+1):
 | 
			
		||||
            poMsg = PoMessage('%s_%d' % (classDescr.name, i), '',
 | 
			
		||||
                              classDescr.klass.__name__)
 | 
			
		||||
            poMsg.produceNiceDefault()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,6 +104,7 @@ class PloneInstaller:
 | 
			
		|||
        if not hasattr(site.portal_types, self.appyFolderType):
 | 
			
		||||
            self.registerAppyFolderType()
 | 
			
		||||
        # Create the folder
 | 
			
		||||
        
 | 
			
		||||
        if not hasattr(site.aq_base, self.productName):
 | 
			
		||||
            # Temporarily allow me to create Appy large plone folders
 | 
			
		||||
            getattr(site.portal_types, self.appyFolderType).global_allow = 1
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +115,7 @@ class PloneInstaller:
 | 
			
		|||
                               title=self.productName)
 | 
			
		||||
            getattr(site.portal_types, self.appyFolderType).global_allow = 0
 | 
			
		||||
        appFolder = getattr(site, self.productName)
 | 
			
		||||
        
 | 
			
		||||
        # All roles defined as creators should be able to create the
 | 
			
		||||
        # corresponding root content types in this folder.
 | 
			
		||||
        i = -1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								gen/plone25/mixins/TestMixin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								gen/plone25/mixins/TestMixin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
# ------------------------------------------------------------------------------
 | 
			
		||||
class TestMixin:
 | 
			
		||||
    '''This class is mixed in with any PloneTestCase.'''
 | 
			
		||||
    def createUser(self, userId, roles):
 | 
			
		||||
        '''Creates a user p_name p_with some p_roles.'''
 | 
			
		||||
        pms = self.portal.portal_membership
 | 
			
		||||
        pms.addMember(userId, 'password', [], [])
 | 
			
		||||
        self.setRoles(roles, name=userId)
 | 
			
		||||
 | 
			
		||||
    def changeUser(self, userId):
 | 
			
		||||
        '''Logs out currently logged user and logs in p_loginName.'''
 | 
			
		||||
        self.logout()
 | 
			
		||||
        self.login(userId)
 | 
			
		||||
 | 
			
		||||
# Functions executed before and after every test -------------------------------
 | 
			
		||||
def beforeTest(test):
 | 
			
		||||
    g = test.globs
 | 
			
		||||
    g['tool'] = test.app.plone.get('portal_%s' % g['appName'].lower()).appy()
 | 
			
		||||
    g['appFolder'] = g['tool'].o.getProductConfig().diskFolder
 | 
			
		||||
    moduleOrClassName = g['test'].name # Not used yet.
 | 
			
		||||
    # Initialize the test
 | 
			
		||||
    test.createUser('admin', ('Member','Manager'))
 | 
			
		||||
    test.login('admin')
 | 
			
		||||
    g['t'] = g['test']
 | 
			
		||||
 | 
			
		||||
def afterTest(test): pass
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,7 +1024,8 @@ class AbstractMixin:
 | 
			
		|||
        self._appy_manageRefsFromRequest()
 | 
			
		||||
        # If the creation was initiated by another object, update the
 | 
			
		||||
        # reference.
 | 
			
		||||
        if created:
 | 
			
		||||
        if created and hasattr(self.REQUEST, 'SESSION'):
 | 
			
		||||
            # When used by the test system, no SESSION object is created.
 | 
			
		||||
            session = self.REQUEST.SESSION
 | 
			
		||||
            initiatorUid = session.get('initiator', None)
 | 
			
		||||
            initiator = None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -200,7 +200,7 @@
 | 
			
		|||
<metal:group define-macro="showGroup">
 | 
			
		||||
  <fieldset class="appyGroup">
 | 
			
		||||
    <legend><i tal:define="groupDescription python:contextObj.translate('%s_group_%s' % (contextObj.meta_type, widgetDescr['name']))"
 | 
			
		||||
               tal:content="groupDescription"></i></legend>
 | 
			
		||||
               tal:content="structure groupDescription"></i></legend>
 | 
			
		||||
    <table tal:define="global fieldNb python:-1" width="100%">
 | 
			
		||||
      <tr valign="top" tal:repeat="rowNb python:range(widgetDescr['rows'])">
 | 
			
		||||
        <td tal:repeat="colNb python:range(widgetDescr['cols'])"
 | 
			
		||||
| 
						 | 
				
			
			@ -754,8 +754,8 @@
 | 
			
		|||
    var state = readCookie(groupId);
 | 
			
		||||
    if ((state != 'collapsed') && (state != 'expanded')) {
 | 
			
		||||
      // No cookie yet, create it.
 | 
			
		||||
      createCookie(groupId, 'expanded');
 | 
			
		||||
      state = 'expanded';
 | 
			
		||||
      createCookie(groupId, 'collapsed');
 | 
			
		||||
      state = 'collapsed';
 | 
			
		||||
    }
 | 
			
		||||
    var group = document.getElementById(groupId);
 | 
			
		||||
    var displayValue = 'none';
 | 
			
		||||
| 
						 | 
				
			
			@ -829,7 +829,7 @@
 | 
			
		|||
    <tal:searchOrGroup repeat="searchOrGroup python: tool.getSearches(rootClass)">
 | 
			
		||||
      <tal:group condition="searchOrGroup/isGroup">
 | 
			
		||||
      <tal:expanded define="group searchOrGroup;
 | 
			
		||||
                            expanded python: tool.getCookieValue(group['labelId']) == 'expanded'">
 | 
			
		||||
                            expanded python: tool.getCookieValue(group['labelId'], default='collapsed') == 'expanded'">
 | 
			
		||||
        <tal:comment replace="nothing">Group name</tal:comment>
 | 
			
		||||
        <dt class="portletAppyItem portletGroup">
 | 
			
		||||
          <img align="left" style="cursor:pointer"
 | 
			
		||||
| 
						 | 
				
			
			@ -839,15 +839,15 @@
 | 
			
		|||
          <span tal:replace="group/label"/>
 | 
			
		||||
        </dt>
 | 
			
		||||
        <tal:comment replace="nothing">Group searches</tal:comment>
 | 
			
		||||
        <div tal:attributes="id group/labelId;
 | 
			
		||||
        <span tal:attributes="id group/labelId;
 | 
			
		||||
                             style python:test(expanded, 'display:block', 'display:none')">
 | 
			
		||||
          <dt class="portletAppyItem portletSearch" tal:repeat="search group/searches">
 | 
			
		||||
          <dt class="portletAppyItem portletSearch portletGroupItem" tal:repeat="search group/searches">
 | 
			
		||||
            <a tal:attributes="href python: '%s?type_name=%s&flavourNumber=%s&search=%s' % (queryUrl, rootClass, flavourNumber, search['name']);
 | 
			
		||||
                         title search/descr;
 | 
			
		||||
                         class python: test(search['name'] == currentSearch, 'portletCurrent', '');"
 | 
			
		||||
               tal:content="structure search/label"></a>
 | 
			
		||||
          </dt>
 | 
			
		||||
        </div>
 | 
			
		||||
        </span>
 | 
			
		||||
      </tal:expanded>
 | 
			
		||||
      </tal:group>
 | 
			
		||||
      <dt tal:define="search searchOrGroup" tal:condition="not: searchOrGroup/isGroup"
 | 
			
		||||
| 
						 | 
				
			
			@ -855,8 +855,7 @@
 | 
			
		|||
 | 
			
		||||
        <a tal:attributes="href python: '%s?type_name=%s&flavourNumber=%s&search=%s' % (queryUrl, rootClass, flavourNumber, search['name']);
 | 
			
		||||
                     title search/descr;
 | 
			
		||||
                     class python: test(search['name'] == currentSearch, 'portletCurrent', '');
 | 
			
		||||
                     id search/group"
 | 
			
		||||
                     class python: test(search['name'] == currentSearch, 'portletCurrent', '');"
 | 
			
		||||
           tal:content="structure search/label"></a>
 | 
			
		||||
      </dt>
 | 
			
		||||
    </tal:searchOrGroup>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
from AccessControl import ClassSecurityInfo
 | 
			
		||||
from DateTime import DateTime
 | 
			
		||||
from Products.Archetypes.atapi import *
 | 
			
		||||
import Products.<!applicationName!>.config
 | 
			
		||||
from Extensions.appyWrappers import <!genClassName!>_Wrapper
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
from AccessControl import ClassSecurityInfo
 | 
			
		||||
from DateTime import DateTime
 | 
			
		||||
from Products.Archetypes.atapi import *
 | 
			
		||||
import Products.<!applicationName!>.config
 | 
			
		||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,12 @@
 | 
			
		|||
/* Appy-specific IE-fixes */
 | 
			
		||||
.portletSearch {
 | 
			
		||||
  font-size: 85%;
 | 
			
		||||
  border-left: 1px solid #8cacbb;
 | 
			
		||||
  border-right: 1px solid #8cacbb;
 | 
			
		||||
}
 | 
			
		||||
.portletGroup {
 | 
			
		||||
  font-size: 85%;
 | 
			
		||||
  padding-left: 0.7em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Stylesheet with Internet Explorer-specific workarounds. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
from AccessControl import ClassSecurityInfo
 | 
			
		||||
from DateTime import DateTime
 | 
			
		||||
from Products.Archetypes.atapi import *
 | 
			
		||||
import Products.<!applicationName!>.config
 | 
			
		||||
from appy.gen.plone25.mixins.PodTemplateMixin import PodTemplateMixin
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,7 +229,7 @@ fieldset {
 | 
			
		|||
}
 | 
			
		||||
.portletSearch {
 | 
			
		||||
  padding: 0 0 0 0.6em;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
  font-size: 95%;
 | 
			
		||||
}
 | 
			
		||||
.portletGroup {
 | 
			
		||||
| 
						 | 
				
			
			@ -237,6 +237,10 @@ fieldset {
 | 
			
		|||
  font-weight: bold;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
}
 | 
			
		||||
.portletGroupItem {
 | 
			
		||||
  padding-left: 0.8em;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
.portletCurrent {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
from AccessControl import ClassSecurityInfo
 | 
			
		||||
from DateTime import DateTime
 | 
			
		||||
from Products.Archetypes.atapi import *
 | 
			
		||||
from Products.CMFCore.utils import UniqueObject
 | 
			
		||||
import Products.<!applicationName!>.config
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
import sys
 | 
			
		||||
import os, os.path, sys
 | 
			
		||||
try: # New CMF
 | 
			
		||||
    from Products.CMFCore.permissions import setDefaultRoles
 | 
			
		||||
except ImportError: # Old CMF
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ except ImportError: # Old CMF
 | 
			
		|||
 | 
			
		||||
import Extensions.appyWrappers
 | 
			
		||||
<!imports!>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
# The following imports are here for allowing mixin classes to access those
 | 
			
		||||
# elements without being statically dependent on Plone/Zope packages. Indeed,
 | 
			
		||||
# every Archetype instance has a method "getProductConfig" that returns this
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ logger = logging.getLogger('<!applicationName!>')
 | 
			
		|||
 | 
			
		||||
# Some global variables --------------------------------------------------------
 | 
			
		||||
PROJECTNAME = '<!applicationName!>'
 | 
			
		||||
diskFolder = os.path.dirname(<!applicationName!>.__file__)
 | 
			
		||||
defaultAddRoles = [<!defaultAddRoles!>]
 | 
			
		||||
DEFAULT_ADD_CONTENT_PERMISSION = "Add portal content"
 | 
			
		||||
ADD_CONTENT_PERMISSIONS = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								gen/plone25/templates/testAll.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								gen/plone25/templates/testAll.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
<!codeHeader!>
 | 
			
		||||
 | 
			
		||||
from unittest import TestSuite
 | 
			
		||||
from Testing import ZopeTestCase
 | 
			
		||||
from Testing.ZopeTestCase import ZopeDocTestSuite
 | 
			
		||||
from Products.PloneTestCase import PloneTestCase
 | 
			
		||||
from appy.gen.plone25.mixins.TestMixin import TestMixin, beforeTest, afterTest
 | 
			
		||||
<!imports!>
 | 
			
		||||
 | 
			
		||||
# Initialize Zope & Plone test systems -----------------------------------------
 | 
			
		||||
ZopeTestCase.installProduct('<!applicationName!>')
 | 
			
		||||
PloneTestCase.setupPloneSite(products=['<!applicationName!>'])
 | 
			
		||||
 | 
			
		||||
class Test(PloneTestCase.PloneTestCase, TestMixin):
 | 
			
		||||
    '''Base test class for <!applicationName!> test cases.'''
 | 
			
		||||
 | 
			
		||||
# Data needed for defining the tests -------------------------------------------
 | 
			
		||||
data = {'test_class': Test, 'setUp': beforeTest, 'tearDown': afterTest,
 | 
			
		||||
        'globs': {'appName': '<!applicationName!>'}}
 | 
			
		||||
modulesWithTests = [<!modulesWithTests!>]
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
def test_suite():
 | 
			
		||||
    return TestSuite([ZopeDocTestSuite(m, **data) for m in modulesWithTests])
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +7,8 @@ def stringify(value):
 | 
			
		|||
        for v in value:
 | 
			
		||||
            res += '%s,' % stringify(v)
 | 
			
		||||
        res += ')'
 | 
			
		||||
    elif value.__class__.__name__ == 'DateTime':
 | 
			
		||||
        res = 'DateTime("%s")' % value.strftime('%Y/%m/%d %H:%M')
 | 
			
		||||
    else:
 | 
			
		||||
        res = str(value)
 | 
			
		||||
        if isinstance(value, basestring):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import time, os.path, mimetypes, unicodedata
 | 
			
		|||
from appy.gen import Search
 | 
			
		||||
from appy.gen.utils import sequenceTypes
 | 
			
		||||
from appy.shared.utils import getOsTempFolder
 | 
			
		||||
from appy.shared.xml_parser import XmlMarshaller
 | 
			
		||||
 | 
			
		||||
# Some error messages ----------------------------------------------------------
 | 
			
		||||
WRONG_FILE_TUPLE = 'This is not the way to set a file. You can specify a ' \
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +69,8 @@ class AbstractWrapper:
 | 
			
		|||
            self._set_file_attribute(name, v)
 | 
			
		||||
        else:
 | 
			
		||||
            exec "self.o.set%s%s(v)" % (name[0].upper(), name[1:])
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '<%s wrapper at %s>' % (self.klass.__name__, id(self))
 | 
			
		||||
    def __cmp__(self, other):
 | 
			
		||||
        if other: return cmp(self.o, other.o)
 | 
			
		||||
        else:     return 1
 | 
			
		||||
| 
						 | 
				
			
			@ -258,6 +261,26 @@ class AbstractWrapper:
 | 
			
		|||
           method in those cases.'''
 | 
			
		||||
        self.o.reindexObject()
 | 
			
		||||
 | 
			
		||||
    def export(self, at='string'):
 | 
			
		||||
        '''Creates an "exportable", XML version of this object. If p_at is
 | 
			
		||||
           "string", this method returns the XML version. Else, (a) if not p_at,
 | 
			
		||||
           the XML will be exported on disk, in the OS temp folder, with an
 | 
			
		||||
           ugly name; (b) else, it will be exported at path p_at.'''
 | 
			
		||||
        # Determine where to put the result
 | 
			
		||||
        toDisk = (at != 'string')
 | 
			
		||||
        if toDisk and not at:
 | 
			
		||||
            at = getOsTempFolder() + '/' + self.o.UID() + '.xml'
 | 
			
		||||
        # Create the XML version of the object
 | 
			
		||||
        xml = XmlMarshaller().marshall(self.o, objectType='archetype')
 | 
			
		||||
        # Produce the desired result
 | 
			
		||||
        if toDisk:
 | 
			
		||||
            f = file(at, 'w')
 | 
			
		||||
            f.write(xml)
 | 
			
		||||
            f.close()
 | 
			
		||||
            return at
 | 
			
		||||
        else:
 | 
			
		||||
            return xml
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
class FileWrapper:
 | 
			
		||||
    '''When you get, from an appy object, the value of a File attribute, you
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue