More input and output formats for OO conversion in converter.py and bugfix in skyn edit.

This commit is contained in:
Gaetan Delannay 2009-12-17 21:14:52 +01:00
parent fff2b6a329
commit e89eda4838
7 changed files with 190 additions and 113 deletions

View file

@ -355,7 +355,7 @@ class Ref(Type):
class Computed(Type): class Computed(Type):
def __init__(self, validator=None, multiplicity=(0,1), index=None, def __init__(self, validator=None, multiplicity=(0,1), index=None,
default=None, optional=False, editDefault=False, show=True, default=None, optional=False, editDefault=False, show='view',
page='main', group=None, move=0, indexed=False, page='main', group=None, move=0, indexed=False,
searchable=False, specificReadPermission=False, searchable=False, specificReadPermission=False,
specificWritePermission=False, width=None, height=None, specificWritePermission=False, width=None, height=None,

View file

@ -33,9 +33,13 @@ class AbstractMixin:
# creates the final object from the temp object. # creates the final object from the temp object.
previousData = None previousData = None
if not created: previousData = self.rememberPreviousData() if not created: previousData = self.rememberPreviousData()
# We do not process form data (=real update on the object) if the tool # Perform the change on the object, unless self is a tool being created.
# itself is being created. if (obj._appy_meta_type == 'tool') and created:
if obj._appy_meta_type != 'tool': obj.processForm() # We do not process form data (=real update on the object) if the
# tool itself is being created.
pass
else:
obj.processForm()
if previousData: if previousData:
# Keep in history potential changes on historized fields # Keep in history potential changes on historized fields
self.historizeData(previousData) self.historizeData(previousData)
@ -389,7 +393,7 @@ class AbstractMixin:
fieldDescr = fieldDescr.__dict__ fieldDescr = fieldDescr.__dict__
appyType = fieldDescr['appyType'] appyType = fieldDescr['appyType']
if isEdit and (appyType['type']=='Ref') and appyType['add']:return False if isEdit and (appyType['type']=='Ref') and appyType['add']:return False
if isEdit and (appyType['type'] in ('Action', 'Computed')): return False if isEdit and (appyType['type'] == 'Action'): return False
if (fieldDescr['widgetType'] == 'backField') and \ if (fieldDescr['widgetType'] == 'backField') and \
not self.getBRefs(fieldDescr['fieldRel']): return False not self.getBRefs(fieldDescr['fieldRel']): return False
# Do not show field if it is optional and not selected in flavour # Do not show field if it is optional and not selected in flavour

View file

@ -3,23 +3,19 @@
errors request/errors | python:{}; errors request/errors | python:{};
Iterator python:modules['Products.Archetypes'].IndexIterator; Iterator python:modules['Products.Archetypes'].IndexIterator;
schematas contextObj/Schemata; schematas contextObj/Schemata;
fieldsets python:[key for key in schematas.keys() if (key != 'metadata') and (schematas[key].editableFields(here, visible_only=True))]; fieldsets python:[key for key in schematas.keys() if (key != 'metadata') and (schematas[key].editableFields(contextObj, visible_only=True))];
default_fieldset python:(not schematas or schematas.has_key('default')) and 'default' or fieldsets[0]; default_fieldset python:(not schematas or schematas.has_key('default')) and 'default' or fieldsets[0];
fieldset request/fieldset|options/fieldset|default_fieldset; fieldset request/fieldset|options/fieldset|default_fieldset;
fields python:schematas[fieldset].editableFields(here); fields python:schematas[fieldset].editableFields(contextObj);
dummy python:here.at_isEditable(fields); lockable python:hasattr(contextObj, 'wl_isLocked');
portal_type python:here.getPortalTypeName().lower().replace(' ', '_'); isLocked python:lockable and contextObj.wl_isLocked();
type_name here/getPortalTypeName|here/archetype_name;
lockable python:hasattr(here, 'wl_isLocked');
isLocked python:lockable and here.wl_isLocked();
tabindex tabindex|python:Iterator(pos=7000);
isEdit python:True; isEdit python:True;
tool contextObj/getTool; tool contextObj/getTool;
flavour python: tool.getFlavour(contextObj); flavour python: tool.getFlavour(contextObj);
appFolder tool/getAppFolder; appFolder tool/getAppFolder;
appName appFolder/id; appName appFolder/id;
css python:here.getUniqueWidgetAttr(fields, 'helper_css'); css python:contextObj.getUniqueWidgetAttr(fields, 'helper_css');
js python:here.getUniqueWidgetAttr(fields, 'helper_js'); js python:contextObj.getUniqueWidgetAttr(fields, 'helper_js');
phaseInfo python: contextObj.getAppyPhases(fieldset=fieldset, forPlone=True); phaseInfo python: contextObj.getAppyPhases(fieldset=fieldset, forPlone=True);
phase request/phase|phaseInfo/name; phase request/phase|phaseInfo/name;
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);"> pageName python: contextObj.getAppyPage(isEdit, phaseInfo);">
@ -91,24 +87,20 @@
<tal:previousButton condition="python: pageIndex &gt; 0"> <tal:previousButton condition="python: pageIndex &gt; 0">
<input class="context" type="submit" name="buttonPrevious" <input class="context" type="submit" name="buttonPrevious"
i18n:attributes="value label_previous;" i18n:domain="plone" i18n:attributes="value label_previous;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next; tal:attributes="disabled python:test(isLocked, 'disabled', None);"/>
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="previousPage" tal:attributes="value python: pages[pageIndex-1]"/> <input type="hidden" name="previousPage" tal:attributes="value python: pages[pageIndex-1]"/>
</tal:previousButton> </tal:previousButton>
<tal:nextButton condition="python: pageIndex &lt; numberOfPages - 1"> <tal:nextButton condition="python: pageIndex &lt; numberOfPages - 1">
<input class="context" type="submit" name="buttonNext" value="Next" <input class="context" type="submit" name="buttonNext" value="Next"
i18n:attributes="value label_next;" i18n:domain="plone" i18n:attributes="value label_next;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next; tal:attributes="disabled python:test(isLocked, 'disabled', None);"/>
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="nextPage" tal:attributes="value python: pages[pageIndex+1]"/> <input type="hidden" name="nextPage" tal:attributes="value python: pages[pageIndex+1]"/>
</tal:nextButton> </tal:nextButton>
<input class="context" type="submit" name="buttonOk" <input class="context" type="submit" name="buttonOk"
i18n:attributes="value label_save;" i18n:domain="plone" i18n:attributes="value label_save;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next; tal:attributes="disabled python:test(isLocked, 'disabled', None);"/>
disabled python:test(isLocked, 'disabled', None);"/>
<input class="standalone" type="submit" name="buttonCancel" <input class="standalone" type="submit" name="buttonCancel"
i18n:attributes="value label_cancel;" i18n:domain="plone" i18n:attributes="value label_cancel;" i18n:domain="plone"/>
tal:attributes="tabindex tabindex/next"/>
</metal:block> </metal:block>
</form> </form>
<div metal:use-macro="here/skyn/macros/macros/showPageFooter"/> <div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>

View file

@ -202,7 +202,7 @@
<metal:editRef use-macro="here/skyn/ref/macros/editReference" /> <metal:editRef use-macro="here/skyn/ref/macros/editReference" />
</tal:ref> </tal:ref>
</tal:editRef> </tal:editRef>
<tal:computedField condition="python: (not isEdit) and (appyType['type'] == 'Computed')"> <tal:computedField condition="python: appyType['type'] == 'Computed'">
<metal:cf use-macro="here/skyn/macros/macros/showComputedField" /> <metal:cf use-macro="here/skyn/macros/macros/showComputedField" />
</tal:computedField> </tal:computedField>
<tal:actionField condition="python: appyType['type'] == 'Action'"> <tal:actionField condition="python: appyType['type'] == 'Action'">

View file

@ -2,7 +2,8 @@
developer the real classes used by the underlying web framework.''' developer the real classes used by the underlying web framework.'''
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import time, os.path, mimetypes, unicodedata, random import os, os.path, time, mimetypes, unicodedata, random
import appy.pod
from appy.gen import Search from appy.gen import Search
from appy.gen.utils import sequenceTypes from appy.gen.utils import sequenceTypes
from appy.shared.utils import getOsTempFolder from appy.shared.utils import getOsTempFolder
@ -236,15 +237,23 @@ class AbstractWrapper:
wfTool.doActionFor(self.o, transitionName, comment=comment) wfTool.doActionFor(self.o, transitionName, comment=comment)
del self.o._v_appy_do del self.o._v_appy_do
def log(self, message, logLevel='info'): def log(self, message, type='info'):
'''Logs a message in the log file. p_logLevel may be "info", "warning" '''Logs a message in the log file. p_logLevel may be "info", "warning"
or "error".''' or "error".'''
logger = self.o.getProductConfig().logger logger = self.o.getProductConfig().logger
if logLevel == 'warning': logMethod = logger.warn if type == 'warning': logMethod = logger.warn
elif logLevel == 'error': logMethod = logger.error elif type == 'error': logMethod = logger.error
else: logMethod = logger.info else: logMethod = logger.info
logMethod(message) logMethod(message)
def say(self, message, type='info'):
'''Prints a message in the user interface. p_logLevel may be "info",
"warning" or "error".'''
mType = type
if mType == 'warning': mType = 'warn'
elif mType == 'error': mType = 'stop'
self.o.plone_utils.addPortalMessage(message, type=mType)
def normalize(self, s): def normalize(self, s):
'''Returns a version of string p_s whose special chars have been '''Returns a version of string p_s whose special chars have been
replaced with normal chars.''' replaced with normal chars.'''
@ -338,11 +347,16 @@ class FileWrapper:
raise 'Impossible to set attribute %s. "Settable" attributes ' \ raise 'Impossible to set attribute %s. "Settable" attributes ' \
'are "name", "content" and "mimeType".' % name 'are "name", "content" and "mimeType".' % name
def dump(self, filePath=None): def dump(self, filePath=None, format=None, tool=None):
'''Writes the file on disk. If p_filePath is specified, it is the '''Writes the file on disk. If p_filePath is specified, it is the
path name where the file will be dumped; folders mentioned in it path name where the file will be dumped; folders mentioned in it
must exist. If not, the file will be dumped in the OS temp folder. must exist. If not, the file will be dumped in the OS temp folder.
The absolute path name of the dumped file is returned.''' The absolute path name of the dumped file is returned.
If an error occurs, the method returns None. If p_format is
specified, OpenOffice will be called for converting the dumped file
to the desired format. In this case, p_tool, a Appy tool, must be
provided. Indeed, any Appy tool contains parameters for contacting
OpenOffice in server mode.'''
if not filePath: if not filePath:
filePath = '%s/file%f.%s' % (getOsTempFolder(), time.time(), filePath = '%s/file%f.%s' % (getOsTempFolder(), time.time(),
self.name) self.name)
@ -358,5 +372,20 @@ class FileWrapper:
# Only one chunk # Only one chunk
f.write(self.content) f.write(self.content)
f.close() f.close()
if format:
if not tool: return
# Convert the dumped file using OpenOffice
convScript = '%s/converter.py' % os.path.dirname(appy.pod.__file__)
cmd = '%s %s "%s" %s -p%d' % (tool.unoEnabledPython, convScript,
filePath, format, tool.openOfficePort)
res = os.system(cmd)
os.remove(filePath)
if res != 0: return
# Return the name of the converted file.
baseName, ext = os.path.splitext(filePath)
if (ext == '.%s' % format):
filePath = '%s.res.%s' % (baseName, format)
else:
filePath = '%s.%s' % (baseName, format)
return filePath return filePath
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -20,15 +20,26 @@
import sys, os, os.path, time, signal import sys, os, os.path, time, signal
from optparse import OptionParser from optparse import OptionParser
ODT_FILE_TYPES = {'doc': 'MS Word 97', # Could be 'MS Word 2003 XML' htmlFilters = {'odt': 'HTML (StarWriter)',
'pdf': 'writer_pdf_Export', 'ods': 'HTML (StarCalc)',
'rtf': 'Rich Text Format', 'odp': 'impress_html_Export'}
'txt': 'Text',
'html': 'HTML (StarWriter)', FILE_TYPES = {'odt': 'writer8',
'htm': 'HTML (StarWriter)', 'ods': 'calc8',
'odt': 'ODT'} 'odp': 'impress8',
# Conversion to ODT does not make any conversion; it simply updates indexes and 'htm': htmlFilters, 'html': htmlFilters,
# linked documents. 'rtf': 'Rich Text Format',
'txt': 'Text',
'csv': 'Text - txt - csv (StarCalc)',
'pdf': {'odt': 'writer_pdf_Export', 'ods': 'calc_pdf_Export',
'odp': 'impress_pdf_Export', 'odg': 'draw_pdf_Export'},
'swf': 'impress_flash_Export',
'doc': 'MS Word 97',
'xls': 'MS Excel 97',
'ppt': 'MS PowerPoint 97',
}
# Conversion from odt to odt does not make any conversion, but updates indexes
# and linked documents.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class ConverterError(Exception): pass class ConverterError(Exception): pass
@ -46,7 +57,7 @@ DEFAULT_PORT = 2002
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Converter: class Converter:
'''Converts an ODT document into pdf, doc, txt or rtf.''' '''Converts an document readable by OpenOffice into pdf, doc, txt or rtf.'''
exeVariants = ('soffice.exe', 'soffice') exeVariants = ('soffice.exe', 'soffice')
pathReplacements = {'program files': 'progra~1', pathReplacements = {'program files': 'progra~1',
'openoffice.org 1': 'openof~1', 'openoffice.org 1': 'openof~1',
@ -54,41 +65,64 @@ class Converter:
} }
def __init__(self, docPath, resultType, port=DEFAULT_PORT): def __init__(self, docPath, resultType, port=DEFAULT_PORT):
self.port = port self.port = port
self.docUrl, self.docPath = self.getDocUrls(docPath) self.docUrl, self.docPath = self.getInputUrls(docPath)
self.resultFilter = self.getResultFilter(resultType) self.inputType = os.path.splitext(docPath)[1][1:].lower()
self.resultUrl = self.getResultUrl(resultType) self.resultType = resultType
self.resultFilter = self.getResultFilter()
self.resultUrl = self.getResultUrl()
self.ooContext = None self.ooContext = None
self.oo = None # OpenOffice application object self.oo = None # The OpenOffice application object
self.doc = None # OpenOffice loaded document self.doc = None # The OpenOffice loaded document
def getDocUrls(self, docPath):
def getInputUrls(self, docPath):
'''Returns the absolute path of the input file. In fact, it returns a
tuple with some URL version of the path for OO as the first element
and the absolute path as the second element.'''
import uno import uno
if not os.path.exists(docPath) and not os.path.isfile(docPath): if not os.path.exists(docPath) and not os.path.isfile(docPath):
raise ConverterError(DOC_NOT_FOUND % docPath) raise ConverterError(DOC_NOT_FOUND % docPath)
docAbsPath = os.path.abspath(docPath) docAbsPath = os.path.abspath(docPath)
# Return one path for OO, one path for me. # Return one path for OO, one path for me.
return uno.systemPathToFileUrl(docAbsPath), docAbsPath return uno.systemPathToFileUrl(docAbsPath), docAbsPath
def getResultFilter(self, resultType):
if ODT_FILE_TYPES.has_key(resultType): def getResultFilter(self):
res = ODT_FILE_TYPES[resultType] '''Based on the result type, identifies which OO filter to use for the
document conversion.'''
if FILE_TYPES.has_key(self.resultType):
res = FILE_TYPES[self.resultType]
if isinstance(res, dict):
res = res[self.inputType]
else: else:
raise ConverterError(BAD_RESULT_TYPE % (resultType, raise ConverterError(BAD_RESULT_TYPE % (self.resultType,
ODT_FILE_TYPES.keys())) FILE_TYPES.keys()))
return res return res
def getResultUrl(self, resultType):
def getResultUrl(self):
'''Returns the path of the result file in the format needed by OO. If
the result type and the input type are the same (ie the user wants to
refresh indexes or some other action and not perform a real
conversion), the result file is named
<inputFileName>.res.<resultType>.
Else, the result file is named like the input file but with a
different extension:
<inputFileName>.<resultType>
'''
import uno import uno
baseName = os.path.splitext(self.docPath)[0] baseName = os.path.splitext(self.docPath)[0]
if resultType != 'odt': if self.resultType != self.inputType:
res = '%s.%s' % (baseName, resultType) res = '%s.%s' % (baseName, self.resultType)
else: else:
res = '%s.res.%s' % (baseName, resultType) res = '%s.res.%s' % (baseName, self.resultType)
try: try:
f = open(res, 'w') f = open(res, 'w')
f.write('Hello') f.write('Hello')
f.close() f.close()
os.remove(res) os.remove(res)
return uno.systemPathToFileUrl(res) return uno.systemPathToFileUrl(res)
except OSError, oe: except (OSError, IOError), ioe:
raise ConverterError(CANNOT_WRITE_RESULT % (res, oe)) raise ConverterError(CANNOT_WRITE_RESULT % (res, ioe))
def connect(self): def connect(self):
'''Connects to OpenOffice''' '''Connects to OpenOffice'''
if os.name == 'nt': if os.name == 'nt':
@ -115,73 +149,90 @@ class Converter:
'com.sun.star.frame.Desktop', self.ooContext) 'com.sun.star.frame.Desktop', self.ooContext)
except NoConnectException, nce: except NoConnectException, nce:
raise ConverterError(CONNECT_ERROR % (self.port, nce)) raise ConverterError(CONNECT_ERROR % (self.port, nce))
def disconnect(self):
self.doc.close(True) def updateOdtDocument(self):
# Do a nasty thing before exiting the python process. In case the '''If the input file is an ODT document, we will perform 2 tasks:
# last call is a oneway call (e.g. see idl-spec of insertString), 1) Update all annexes;
# it must be forced out of the remote-bridge caches before python 2) Update sections (if sections refer to external content, we try to
# exits the process. Otherwise, the oneway call may or may not reach include the content within the result file)
# the target object. '''
# I do this here by calling a cheap synchronous call (getPropertyValue). from com.sun.star.lang import IndexOutOfBoundsException
self.ooContext.ServiceManager
def loadDocument(self):
from com.sun.star.lang import IllegalArgumentException, \
IndexOutOfBoundsException
# I need to use IndexOutOfBoundsException because sometimes, when # I need to use IndexOutOfBoundsException because sometimes, when
# using sections.getCount, UNO returns a number that is bigger than # using sections.getCount, UNO returns a number that is bigger than
# the real number of sections (this is because it also counts the # the real number of sections (this is because it also counts the
# sections that are present within the sub-documents to integrate) # sections that are present within the sub-documents to integrate)
# Update all indexes
indexes = self.doc.getDocumentIndexes()
indexesCount = indexes.getCount()
if indexesCount != 0:
for i in range(indexesCount):
try:
indexes.getByIndex(i).update()
except IndexOutOfBoundsException:
pass
# Update sections
self.doc.updateLinks()
sections = self.doc.getTextSections()
sectionsCount = sections.getCount()
if sectionsCount != 0:
for i in range(sectionsCount-1, -1, -1):
# I must walk into the section from last one to the first
# one. Else, when "disposing" sections, I remove sections
# and the remaining sections other indexes.
try:
section = sections.getByIndex(i)
if section.FileLink and section.FileLink.FileURL:
section.dispose() # This method removes the
# <section></section> tags without removing the content
# of the section. Else, it won't appear.
except IndexOutOfBoundsException:
pass
def loadDocument(self):
from com.sun.star.lang import IllegalArgumentException, \
IndexOutOfBoundsException
from com.sun.star.beans import PropertyValue from com.sun.star.beans import PropertyValue
try: try:
# Load the document to convert in a new hidden frame # Loads the document to convert in a new hidden frame
prop = PropertyValue() prop = PropertyValue()
prop.Name = 'Hidden' prop.Name = 'Hidden'
prop.Value = True prop.Value = True
self.doc = self.oo.loadComponentFromURL(self.docUrl, "_blank", 0, self.doc = self.oo.loadComponentFromURL(self.docUrl, "_blank", 0,
(prop,)) (prop,))
# Update all indexes if self.inputType == 'odt':
indexes = self.doc.getDocumentIndexes() # Perform additional tasks for odt documents
indexesCount = indexes.getCount() self.updateOdtDocument()
if indexesCount != 0: try:
for i in range(indexesCount): self.doc.refresh()
try: except AttributeError:
indexes.getByIndex(i).update() pass
except IndexOutOfBoundsException:
pass
# Update sections
self.doc.updateLinks()
sections = self.doc.getTextSections()
sectionsCount = sections.getCount()
if sectionsCount != 0:
for i in range(sectionsCount-1, -1, -1):
# I must walk into the section from last one to the first
# one. Else, when "disposing" sections, I remove sections
# and the remaining sections other indexes.
try:
section = sections.getByIndex(i)
if section.FileLink and section.FileLink.FileURL:
section.dispose() # This method removes the
# <section></section> tags without removing the content
# of the section. Else, it won't appear.
except IndexOutOfBoundsException:
pass
except IllegalArgumentException, iae: except IllegalArgumentException, iae:
raise ConverterError(URL_NOT_FOUND % (self.docPath, iae)) raise ConverterError(URL_NOT_FOUND % (self.docPath, iae))
def convertDocument(self): def convertDocument(self):
if self.resultFilter != 'ODT': '''Calls OO to perform a document conversion. Note that the conversion
# I must really perform a conversion is not really done if the source and target documents have the same
from com.sun.star.beans import PropertyValue type.'''
prop = PropertyValue() properties = []
prop.Name = 'FilterName' from com.sun.star.beans import PropertyValue
prop.Value = self.resultFilter prop = PropertyValue()
self.doc.storeToURL(self.resultUrl, (prop,)) prop.Name = 'FilterName'
else: prop.Value = self.resultFilter
self.doc.storeToURL(self.resultUrl, ()) properties.append(prop)
if self.resultType == 'csv':
# For CSV export, add options (separator, etc)
optionsProp = PropertyValue()
optionsProp.Name = 'FilterOptions'
optionsProp.Value = '59,34,76,1'
properties.append(optionsProp)
self.doc.storeToURL(self.resultUrl, tuple(properties))
def run(self): def run(self):
'''Connects to OO, does the job and disconnects.'''
self.connect() self.connect()
self.loadDocument() self.loadDocument()
self.convertDocument() self.convertDocument()
self.disconnect() self.doc.close(True)
# ConverterScript-related messages --------------------------------------------- # ConverterScript-related messages ---------------------------------------------
WRONG_NB_OF_ARGS = 'Wrong number of arguments.' WRONG_NB_OF_ARGS = 'Wrong number of arguments.'
@ -191,12 +242,13 @@ ERROR_CODE = 1
class ConverterScript: class ConverterScript:
usage = 'usage: python converter.py fileToConvert outputType [options]\n' \ usage = 'usage: python converter.py fileToConvert outputType [options]\n' \
' where fileToConvert is the absolute or relative pathname of\n' \ ' where fileToConvert is the absolute or relative pathname of\n' \
' the ODT file you want to convert;\n'\ ' the file you want to convert (or whose content like\n' \
' indexes need to be refreshed);\n'\
' and outputType is the output format, that must be one of\n' \ ' and outputType is the output format, that must be one of\n' \
' %s.\n' \ ' %s.\n' \
' "python" should be a UNO-enabled Python interpreter (ie the one\n' \ ' "python" should be a UNO-enabled Python interpreter (ie the ' \
' which is included in the OpenOffice.org distribution).' % \ ' one which is included in the OpenOffice.org distribution).' % \
str(ODT_FILE_TYPES.keys()) str(FILE_TYPES.keys())
def run(self): def run(self):
optParser = OptionParser(usage=ConverterScript.usage) optParser = OptionParser(usage=ConverterScript.usage)
optParser.add_option("-p", "--port", dest="port", optParser.add_option("-p", "--port", dest="port",

View file

@ -25,7 +25,7 @@ import appy.pod
from appy.pod import PodError from appy.pod import PodError
from appy.shared.xml_parser import XmlElement from appy.shared.xml_parser import XmlElement
from appy.pod.pod_parser import PodParser, PodEnvironment, OdInsert from appy.pod.pod_parser import PodParser, PodEnvironment, OdInsert
from appy.pod.converter import ODT_FILE_TYPES from appy.pod.converter import FILE_TYPES
from appy.pod.buffers import FileBuffer from appy.pod.buffers import FileBuffer
from appy.pod.xhtml2odt import Xhtml2OdtConverter from appy.pod.xhtml2odt import Xhtml2OdtConverter
from appy.pod.doc_importers import OdtImporter, ImageImporter, PdfImporter from appy.pod.doc_importers import OdtImporter, ImageImporter, PdfImporter
@ -423,9 +423,9 @@ class Renderer:
os.rename(resultOdtName, self.result) os.rename(resultOdtName, self.result)
else: else:
if resultType.startswith('.'): resultType = resultType[1:] if resultType.startswith('.'): resultType = resultType[1:]
if not resultType in ODT_FILE_TYPES.keys(): if not resultType in FILE_TYPES.keys():
raise PodError(BAD_RESULT_TYPE % ( raise PodError(BAD_RESULT_TYPE % (
self.result, ODT_FILE_TYPES.keys())) self.result, FILE_TYPES.keys()))
# Call OpenOffice to perform the conversion or document update # Call OpenOffice to perform the conversion or document update
self.callOpenOffice(resultOdtName, resultType) self.callOpenOffice(resultOdtName, resultType)
# I have the result. Move it to the correct name # I have the result. Move it to the correct name