def addExpression(self, expression): try: self.dumpContent(Expression(expression).evaluate(self.env.context)) except Exception, e: PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False)
def evaluate(self, subElements=True, removeMainElems=False): result = self.getFileBuffer() if not subElements: # Dump the root tag in this buffer, but not its content. res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1), g(2), g(3), g(1), g(2))) else: iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = iter.next() result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: result.dumpContent(evalEntry.evaluate( self.env.context)) except Exception, e: PodError.dump(result, EVAL_EXPR_ERROR % (evalEntry.expr, e), dumpTb=False) else: # It is a subBuffer if evalEntry.action: evalEntry.action.execute() else: result.write(evalEntry.content) stopIndex = self.getStopIndex(removeMainElems) if currentIndex < (stopIndex - 1): result.write(self.content[currentIndex:stopIndex])
def manageError(self, result, context, errorMessage, originalError=None): '''Manage the encountered error: dump it into the buffer or raise an exception.''' if self.buffer.env.raiseOnError: if not self.buffer.pod: # Add in the error message the line nb where the errors occurs # within the PX. locator = self.buffer.env.parser.locator # The column number may not be given col = locator.getColumnNumber() if col == None: col = '' else: col = ', column %d' % col errorMessage += ' (line %s%s)' % (locator.getLineNumber(), col) # Integrate the traceback (at least, its last lines) errorMessage += '\n' + Traceback.get(6).decode('utf-8') if originalError: raise EvaluationError(originalError, errorMessage) raise Exception(errorMessage) # Create a temporary buffer to dump the error. If I reuse this buffer to # dump the error (what I did before), and we are, at some depth, in a # for loop, this buffer will contain the error message and not the # content to repeat anymore. It means that this error will also show up # for every subsequent iteration. tempBuffer = self.buffer.clone() PodError.dump(tempBuffer, errorMessage, withinElement=self.elem) tempBuffer.evaluate(result, context)
def evaluate(self, result, context, subElements=True, removeMainElems=False): '''Evaluates this buffer given the current p_context and add the result into p_result. With pod, p_result is the root file buffer; with px it is a memory buffer.''' if not subElements: # Dump the root tag in this buffer, but not its content. res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1),g(2),g(3),g(1),g(2))) else: iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = iter.next() result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: res, escape = evalEntry.evaluate(context) if escape: result.dumpContent(res) else: result.write(res) except Exception, e: if not self.env.raiseOnError: PodError.dump(result, EVAL_EXPR_ERROR % ( evalEntry.expr, e), dumpTb=False) else: raise Exception(EVAL_EXPR_ERROR %(evalEntry.expr,e)) elif isinstance(evalEntry, Attributes) or \ isinstance(evalEntry, Attribute): result.write(evalEntry.evaluate(context)) else: # It is a subBuffer
def manageError(self, result, context, errorMessage, dumpTb=True): '''Manage the encountered error: dump it into the buffer or raise an exception.''' if self.buffer.env.raiseOnError: if not self.buffer.pod: # Add in the error message the line nb where the errors occurs # within the PX. locator = self.buffer.env.parser.locator # The column number may not be given. col = locator.getColumnNumber() if col == None: col = '' else: col = ', column %d' % col errorMessage += ' (line %s%s)' % (locator.getLineNumber(), col) raise Exception(errorMessage) # Create a temporary buffer to dump the error. If I reuse this buffer to # dump the error (what I did before), and we are, at some depth, in a # for loop, this buffer will contain the error message and not the # content to repeat anymore. It means that this error will also show up # for every subsequent iteration. tempBuffer = self.buffer.clone() PodError.dump(tempBuffer, errorMessage, withinElement=self.elem, dumpTb=dumpTb) tempBuffer.evaluate(result, context)
def evaluate(self, subElements=True, removeMainElems=False): result = self.getFileBuffer() if not subElements: # Dump the root tag in this buffer, but not its content. res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1),g(2),g(3),g(1),g(2))) else: iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = iter.next() result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: result.dumpContent(evalEntry.evaluate(self.env.context)) except Exception, e: PodError.dump(result, EVAL_EXPR_ERROR % ( evalEntry.expr, e), dumpTb=False) else: # It is a subBuffer if evalEntry.action: evalEntry.action.execute() else: result.write(evalEntry.content) stopIndex = self.getStopIndex(removeMainElems) if currentIndex < (stopIndex-1): result.write(self.content[currentIndex:stopIndex])
def reifyNote(self): '''Recreate the note as close to the original as possible''' # Use some fake buffer and dump the note in it. Reuse the code for # dumping an error, also dumped as a note. r = self.StringBuffer() PodError.dump(r, '</text:p>\n<text:p>'.join(self.statements), dumpTb=False) return r
def writeError(self, errorMessage, dumpTb=True): # Empty the buffer self.buffer.__init__(self.buffer.env, self.buffer.parent) PodError.dump(self.buffer, errorMessage, withinElement=self.elem, dumpTb=dumpTb) self.buffer.evaluate()
def importDocument(self, content=None, at=None, format=None, anchor='as-char', wrapInPara=True, size=None, sizeUnit='cm', style=None): '''If p_at is not None, it represents a path or url allowing to find the document. If p_at is None, the content of the document is supposed to be in binary format in p_content. The document p_format may be: odt or any format in imageFormats. p_anchor, p_wrapInPara and p_size are only relevant for images: * p_anchor defines the way the image is anchored into the document; Valid values are 'page','paragraph', 'char' and 'as-char'; * p_wrapInPara, if true, wraps the resulting 'image' tag into a 'p' tag; * p_size, if specified, is a tuple of float or integers (width, height) expressing size in p_sizeUnit (see below). If not specified, size will be computed from image info. * p_sizeUnit is the unit for p_size elements, it can be "cm" (centimeters) or "px" (pixels). * If p_style is given, it is the content of a "style" attribute, containing CSS attributes. If "width" and "heigth" attributes are found there, they will override p_size and p_sizeUnit. ''' importer = None # Is there someting to import? if not content and not at: raise PodError(DOC_NOT_SPECIFIED) # Guess document format if isinstance(content, FileWrapper): format = content.mimeType elif hasattr(content, 'filename') and content.filename: format = os.path.splitext(content.filename)[1][1:] content = content.data if not format: # It should be deduced from p_at if not at: raise PodError(DOC_FORMAT_ERROR) format = os.path.splitext(at)[1][1:] else: # If format is a mimeType, convert it to an extension if mimeTypesExts.has_key(format): format = mimeTypesExts[format] isImage = False if format in self.ooFormats: importer = OdtImporter self.forceOoCall = True elif (format in self.imageFormats) or not format: # If the format can't be guessed, we suppose it is an image. importer = ImageImporter isImage = True elif format == 'pdf': importer = PdfImporter else: raise PodError(DOC_WRONG_FORMAT % format) imp = importer(content, at, format, self) # Initialise image-specific parameters if isImage: imp.setImageInfo(anchor, wrapInPara, size, sizeUnit, style) res = imp.run() return res
def createPodActions(self, statements): '''Tries to create action(s) based on p_statements. If the statement is not correct, r_ is -1. Else, r_ is the index of the element within the buffer that is the object of the action(s).''' r = -1 try: # Check that the statement group is not empty if not statements: raise ParsingError(EMPTY_NOTE) # Get the main statement (starting with "do...") and check it main = statements[0] aRes = self.Rex.action.match(main) if not aRes: raise ParsingError(BAD_STATEMENT % main) statementName, podElem, minus, actionType, subExpr = aRes.groups() if not (podElem in PodElement.POD_ELEMS): raise ParsingError(BAD_ELEMENT % podElem) if minus and (not podElem in PodElement.MINUS_ELEMS): raise ParsingError(BAD_MINUS % (podElem,PodElement.MINUS_ELEMS)) # Find the target element in the buffer i = self.getIndex(podElem) if i == -1: raise ParsingError(ELEMENT_NOT_FOUND % (podElem, str([ e.__class__.__name__.lower() \ for e in self.elements.values()]))) podElem = self.elements[i] # Create the main action self.action = self.createPodAction(actionType, statements, statementName, subExpr, podElem, minus) # Parse the remaining statements, that can contain any number of # secondary actions and a from clause. fromClause = last = None for statement in statements[1:]: # Get the "from" clause if statement.startswith('from') or \ statement.startswith('from+'): fromInfo = self.Rex.from_.match(statement) if not fromInfo: raise ParsingError(BAD_FROM_CLAUSE % fromClause) fromClause = fromInfo.groups() # Get any secondary statement else: info = self.Rex.subAction.match(statement) if not info: raise ParsingError(BAD_SUB_STATEMENT % statement) actionType, subExpr = info.groups() last = self.createPodAction(actionType, statements, '', subExpr, podElem, None, main=False) self.action.addSubAction(last) # Link the "from" clause if fromClause: target = last or self.action target.setFrom(*fromClause) success, msg = self.action.check() if not success: raise ParsingError(msg) r = i except ParsingError as ppe: PodError.dump(self, ppe, removeFirstLine=True) return r
def addExpression(self, expression, tiedHook=None): # At 2013-02-06, this method was not called within the whole test suite. try: expr = Expression(expression, self.pod) if tiedHook: tiedHook.tiedExpression = expr res, escape = expr.evaluate(self.env.context) if escape: self.dumpContent(res) else: self.write(res) except Exception, e: PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False)
def prepareFolders(self): # Check if I can write the result if not self.overwriteExisting and os.path.exists(self.result): raise PodError(RESULT_FILE_EXISTS % self.result) try: f = open(self.result, 'w') f.write('Hello') f.close() except OSError, oe: raise PodError(CANT_WRITE_RESULT % (self.result, oe))
def importDocument(self, content=None, at=None, format=None, anchor='as-char', wrapInPara=True, size=None): '''If p_at is not None, it represents a path or url allowing to find the document. If p_at is None, the content of the document is supposed to be in binary format in p_content. The document p_format may be: odt or any format in imageFormats. p_anchor, p_wrapInPara and p_size are only relevant for images: * p_anchor defines the way the image is anchored into the document; Valid values are 'page','paragraph', 'char' and 'as-char'; * p_wrapInPara, if true, wraps the resulting 'image' tag into a 'p' tag; * p_size, if specified, is a tuple of float or integers (width, height) expressing size in centimeters. If not specified, size will be computed from image info.''' ns = self.currentParser.env.namespaces importer = None # Is there someting to import? if not content and not at: raise PodError(DOC_NOT_SPECIFIED) # Guess document format if isinstance(content, FileWrapper): format = content.mimeType if not format: # It should be deduced from p_at if not at: raise PodError(DOC_FORMAT_ERROR) format = os.path.splitext(at)[1][1:] else: # If format is a mimeType, convert it to an extension if mimeTypesExts.has_key(format): format = mimeTypesExts[format] isImage = False if format in self.ooFormats: importer = OdtImporter self.forceOoCall = True elif format in self.imageFormats: importer = ImageImporter isImage = True elif format == 'pdf': importer = PdfImporter else: raise PodError(DOC_WRONG_FORMAT % format) imp = importer(content, at, format, self.tempFolder, ns, self.fileNames) # Initialise image-specific parameters if isImage: imp.setImageInfo(anchor, wrapInPara, size) res = imp.run() return res
def addExpression(self, expression, elem=None, tiedHook=None): try: expr = Expression(expression, self.pod) if tiedHook: tiedHook.tiedExpression = expr res, escape = expr.evaluate(self.env.context) if escape: self.dumpContent(res) else: self.write(res) except Exception as e: if not self.env.raiseOnError: PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False) else: raise Exception(EVAL_EXPR_ERROR % (expression, e))
def finalize(self): '''Re-zip the result and potentially call LibreOffice if target format is not among self.templateTypes or if forceOoCall is True.''' for innerFile in ('content.xml', 'styles.xml'): shutil.copy(os.path.join(self.tempFolder, innerFile), os.path.join(self.unzipFolder, innerFile)) # Insert dynamic styles contentXml = os.path.join(self.unzipFolder, 'content.xml') f = open(contentXml, 'r+', encoding='utf-8') dynamicStyles = ''.join(self.dynamicStyles) content = f.read().replace('<!DYNAMIC_STYLES!>', dynamicStyles) f.seek(0) f.truncate(0) f.write(content) f.close() # Call the user-defined "finalize" function when present if self.finalizeFunction: try: self.finalizeFunction(self.unzipFolder) except Exception as e: print((WARNING_FINALIZE_ERROR % str(e))) # Re-zip the result, first as an OpenDocument file of the same type as # the POD template (odt, ods...) resultExt = self.getTemplateType() resultName = os.path.join(self.tempFolder, 'result.%s' % resultExt) zip(resultName, self.unzipFolder, odf=True) resultType = os.path.splitext(self.result)[1].strip('.') if (resultType in self.templateTypes) and not self.forceOoCall: # Simply move the ODT result to the result os.rename(resultName, self.result) else: if resultType not in FILE_TYPES: raise PodError(BAD_RESULT_TYPE % (self.result, FILE_TYPES.keys())) # Call LibreOffice to perform the conversion or document update. output = self.callLibreOffice(resultName, resultType) # I (should) have the result. Move it to the correct name. resPrefix = os.path.splitext(resultName)[0] if resultType in self.templateTypes: # converter.py has (normally!) created a second file # suffixed .res.[resultType] finalResultName = '%s.res.%s' % (resPrefix, resultType) if not os.path.exists(finalResultName): finalResultName = resultName # In this case OO in server mode could not be called to # update indexes, sections, etc. else: finalResultName = '%s.%s' % (resPrefix, resultType) if not os.path.exists(finalResultName): raise PodError(CONVERT_ERROR % output) os.rename(finalResultName, self.result)
def evaluate(self, result, context, subElements=True, removeMainElems=False): '''Evaluates this buffer given the current p_context and add the result into p_result. With pod, p_result is the root file buffer; with px it is a memory buffer.''' if not subElements: # Dump the root tag in this buffer, but not its content res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1), g(2), g(3), g(1), g(2))) else: if removeMainElems: self.removeAutomaticExpressions() iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = next(iter) result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: res, escape = evalEntry.evaluate(context) if escape: result.dumpContent(res) else: result.write(res) except EvaluationError as e: # This exception has already been treated (see the # "except" block below). Simply re-raise it when needed. if self.env.raiseOnError: raise e except Exception as e: if not self.env.raiseOnError: PodError.dump( result, EVAL_EXPR_ERROR % (evalEntry.expr, e)) else: raise EvaluationError(EVAL_EXPR_ERROR % \ (evalEntry.expr, '\n'+Traceback.get(5))) elif isinstance(evalEntry, Attributes) or \ isinstance(evalEntry, Attribute): result.write(evalEntry.evaluate(context)) else: # It is a subBuffer if evalEntry.action: evalEntry.action.execute(result, context) else: result.write(evalEntry.content) stopIndex = self.getStopIndex(removeMainElems) if currentIndex < (stopIndex - 1): result.write(self.content[currentIndex:stopIndex])
def evaluate(self, result, context, subElements=True, removeMainElems=False): '''Evaluates this buffer given the current p_context and add the result into p_result. With pod, p_result is the root file buffer; with px it is a memory buffer.''' if not subElements: # Dump the root tag in this buffer, but not its content. res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1), g(2), g(3), g(1), g(2))) else: iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = iter.next() result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: res, escape = evalEntry.evaluate(context) if escape: result.dumpContent(res) else: result.write(res) except (Exception, e): #print "OHHH YEAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" #result.dumpContent('') if not self.env.raiseOnError: PodError.dump(result, EVAL_EXPR_ERROR % (evalEntry.expr, e), dumpTb=False) else: raise Exception(EVAL_EXPR_ERROR % (evalEntry.expr, e)) elif isinstance(evalEntry, Attributes) or \ isinstance(evalEntry, Attribute): result.write(evalEntry.evaluate(context)) else: # It is a subBuffer if evalEntry.action: evalEntry.action.execute(result, context) else: result.write(evalEntry.content) stopIndex = self.getStopIndex(removeMainElems) if currentIndex < (stopIndex - 1): result.write(self.content[currentIndex:stopIndex])
def importPod(self, content=None, at=None, format='odt', context=None, pageBreakBefore=False, pageBreakAfter=False): '''Similar to m_importDocument, but allows to import the result of executing the POD template specified in p_content or p_at, and include it in the POD result.''' # Is there a pod template defined? if not content and not at: raise PodError(DOC_NOT_SPECIFIED) # If the POD template is specified as a Zope file, convert it into a # Appy FileWrapper. if content.__class__.__name__ == 'File': content = FileWrapper(content) imp = PodImporter(content, at, format, self) self.forceOoCall = True # Define the context to use: either the current context of the current # POD renderer, or p_context if given. if context: ctx = context else: ctx = self.contentParser.env.context imp.init(ctx, pageBreakBefore, pageBreakAfter) return imp.run()
def setImageInfo(self, anchor, wrapInPara, size): # Initialise anchor if anchor not in self.anchorTypes: raise PodError(self.WRONG_ANCHOR % str(self.anchorTypes)) self.anchor = anchor self.wrapInPara = wrapInPara self.size = size
def createPodParser(self, odtFile, context, inserts=None): '''Creates the parser with its environment for parsing the given p_odtFile (content.xml or styles.xml). p_context is given by the pod user, while p_inserts depends on the ODT file we must parse.''' # The default evaluation context evalContext = {} if hasattr(context, '__dict__'): evalContext.update(context.__dict__) elif isinstance(context, dict) or isinstance(context, UserDict): evalContext.update(context) else: raise PodError(BAD_CONTEXT) # Incorporate the default, unalterable, context evalContext.update({'xhtml': self.renderXhtml, 'test': self.evalIfExpression, 'document': self.importDocument, 'pod': self.importPod, 'TableProperties': TableProperties, 'BulletedProperties': BulletedProperties, 'NumberedProperties': NumberedProperties, 'pageBreak': self.insertPageBreak, 'columnBreak': self.insertColumnBreak, # Variables to use for representing pod-reserved chars 'PIPE': '|', 'SEMICOLON': ';'}) # Developer, forget the following line if '_ctx_' not in evalContext: evalContext['_ctx_'] = evalContext env = PodEnvironment(evalContext, inserts) fileBuffer = FileBuffer(env, os.path.join(self.tempFolder,odtFile)) env.currentBuffer = fileBuffer return PodParser(env, self)
def run(self): # Split the PDF into images with Ghostscript imagesFolder = os.path.dirname(self.importPath) cmd = 'gs -dNOPAUSE -dBATCH -sDEVICE=jpeg -r125x125 ' \ '-sOutputFile=%s/%s%%d.jpg %s' % \ (imagesFolder, self.imagePrefix, self.importPath) os.system(cmd) # Check that at least one image was generated succeeded = False firstImage = '%s1.jpg' % self.imagePrefix for fileName in os.listdir(imagesFolder): if fileName == firstImage: succeeded = True break if not succeeded: raise PodError(PDF_TO_IMG_ERROR) # Insert images into the result. noMoreImages = False i = 0 while not noMoreImages: i += 1 nextImage = '%s/%s%d.jpg' % (imagesFolder, self.imagePrefix, i) if os.path.exists(nextImage): # Use internally an Image importer for doing this job. imgImporter =ImageImporter(None, nextImage, 'jpg',self.renderer) imgImporter.setImageInfo('paragraph', True, None, None, None) self.res += imgImporter.run() os.remove(nextImage) else: noMoreImages = True return self.res
def evaluate(self, result, context, subElements=True, removeMainElems=False): '''Evaluates this buffer given the current p_context and add the result into p_result. With pod, p_result is the root file buffer; with px it is a memory buffer.''' if not subElements: # Dump the root tag in this buffer, but not its content res = self.reTagContent.match(self.content.strip()) if not res: result.write(self.content) else: g = res.group result.write('<%s:%s%s></%s:%s>' % (g(1),g(2),g(3),g(1),g(2))) else: if removeMainElems: self.removeAutomaticExpressions() iter = BufferIterator(self) currentIndex = self.getStartIndex(removeMainElems) while iter.hasNext(): index, evalEntry = next(iter) result.write(self.content[currentIndex:index]) currentIndex = index + 1 if isinstance(evalEntry, Expression): try: res, escape = evalEntry.evaluate(context) if escape: result.dumpContent(res) else: result.write(res) except EvaluationError as e: # This exception has already been treated (see the # "except" block below). Simply re-raise it when needed. if self.env.raiseOnError: raise e except Exception as e: if not self.env.raiseOnError: PodError.dump(result, EVAL_EXPR_ERROR % ( evalEntry.expr, e)) else: raise EvaluationError(EVAL_EXPR_ERROR % \ (evalEntry.expr, '\n'+Traceback.get(5))) elif isinstance(evalEntry, Attributes) or \ isinstance(evalEntry, Attribute): result.write(evalEntry.evaluate(context)) else: # It is a subBuffer if evalEntry.action: evalEntry.action.execute(result, context) else: result.write(evalEntry.content) stopIndex = self.getStopIndex(removeMainElems) if currentIndex < (stopIndex-1): result.write(self.content[currentIndex:stopIndex])
def checkAt(self, at, raiseOnError=True): '''Check and apply some transform to p_at''' # Resolve relative path if at.startswith('./'): at = os.path.join(os.getcwd(), at[2:]) # Checks that p_at corresponds to an existing file if given if raiseOnError and not os.path.isfile(at): raise PodError(FILE_NOT_FOUND % at) return at
def run(self): # Convert the document into PDF with LibreOffice output = self.renderer.callLibreOffice(self.importPath, 'pdf') if output: raise PodError(TO_PDF_ERROR % output) pdfFile = '%s.pdf' % os.path.splitext(self.importPath)[0] # Launch a PdfImporter to import this PDF into the POD result. pdfImporter = PdfImporter(None, pdfFile, 'pdf', self.renderer) return pdfImporter.run()
def callLibreOffice(self, resultName, resultType): '''Call LibreOffice in server mode to convert or update the result.''' loOutput = '' try: if (not isinstance(self.ooPort, int)) and \ (not isinstance(self.ooPort, int)): raise PodError(BAD_OO_PORT % str(self.ooPort)) try: from appy.pod.converter import Converter, ConverterError try: Converter(resultName, resultType, self.ooPort, self.stylesTemplate).run() except ConverterError as ce: raise PodError(CONVERT_ERROR % str(ce)) except ImportError: # I do not have UNO. So try to launch a UNO-enabled Python # interpreter which should be in self.pyPath. if not self.pyPath: raise PodError(NO_PY_PATH % resultType) if self.pyPath.find(' ') != -1: raise PodError(BLANKS_IN_PATH % self.pyPath) if not os.path.isfile(self.pyPath): raise PodError(PY_PATH_NOT_FILE % self.pyPath) if resultName.find(' ') != -1: qResultName = '"%s"' % resultName else: qResultName = resultName convScript = '%s/converter.py' % \ os.path.dirname(appy.pod.__file__) if convScript.find(' ') != -1: convScript = '"%s"' % convScript cmd = '%s %s %s %s -p%d' % \ (self.pyPath, convScript, qResultName, resultType, self.ooPort) if self.stylesTemplate: cmd += ' -t%s' % self.stylesTemplate loOutput = executeCommand(cmd) except PodError as pe: # When trying to call LO in server mode for producing ODT or ODS # (=forceOoCall=True), if an error occurs we have nevertheless # an ODT or ODS to return to the user. So we produce a warning # instead of raising an error. if (resultType in self.templateTypes) and self.forceOoCall: print((WARNING_INCOMPLETE_OD % str(pe))) else: raise pe return loOutput
def callLibreOffice(self, resultName, resultType): '''Call LibreOffice in server mode to convert or update the result''' loOutput = '' try: if (not isinstance(self.ooPort, int)) and \ (not isinstance(self.ooPort, long)): raise PodError(BAD_OO_PORT % str(self.ooPort)) try: from appy.pod.converter import Converter, ConverterError try: Converter(resultName, resultType, self.ooPort, self.stylesTemplate, self.optimalColumnWidths, self.script).run() except ConverterError as ce: raise PodError(CONVERT_ERROR % str(ce)) except ImportError: # I do not have UNO. So try to launch a UNO-enabled Python # interpreter which should be in self.pyPath. if not self.pyPath: raise PodError(NO_PY_PATH % resultType) if not os.path.isfile(self.pyPath): raise PodError(PY_PATH_NOT_FILE % self.pyPath) convScript = '%s/converter.py' % \ os.path.dirname(appy.pod.__file__) cmd = [self.pyPath, convScript, resultName, resultType, '-p%d' % self.ooPort] if self.stylesTemplate: cmd.append('-t%s' % self.stylesTemplate) if self.optimalColumnWidths: cmd.append('-o') cmd.append('%s' % str(self.optimalColumnWidths)) if self.script: cmd.append('-s') cmd.append('%s' % self.script) out, loOutput = utils.executeCommand(cmd) except PodError as pe: # When trying to call LO in server mode for producing ODT or ODS # (=forceOoCall=True), if an error occurs we have nevertheless # an ODT or ODS to return to the user. So we produce a warning # instead of raising an error. if (resultType in self.templateTypes) and self.forceOoCall: print(WARNING_INCOMPLETE_OD % str(pe)) else: raise pe return loOutput
def callOpenOffice(self, resultOdtName, resultType): '''Call Open Office in server mode to convert or update the ODT result.''' ooOutput = '' try: if (not isinstance(self.ooPort, int)) and \ (not isinstance(self.ooPort, long)): raise PodError(BAD_OO_PORT % str(self.ooPort)) try: from appy.pod.converter import Converter, ConverterError try: Converter(resultOdtName, resultType, self.ooPort).run() except ConverterError, ce: raise PodError(CONVERT_ERROR % str(ce)) except ImportError: # I do not have UNO. So try to launch a UNO-enabled Python # interpreter which should be in self.pyPath. if not self.pyPath: raise PodError(NO_PY_PATH % resultType) if self.pyPath.find(' ') != -1: raise PodError(BLANKS_IN_PATH % self.pyPath) if not os.path.isfile(self.pyPath): raise PodError(PY_PATH_NOT_FILE % self.pyPath) if resultOdtName.find(' ') != -1: qResultOdtName = '"%s"' % resultOdtName else: qResultOdtName = resultOdtName convScript = '%s/converter.py' % \ os.path.dirname(appy.pod.__file__) if convScript.find(' ') != -1: convScript = '"%s"' % convScript cmd = '%s %s %s %s -p%d' % \ (self.pyPath, convScript, qResultOdtName, resultType, self.ooPort) ooOutput = executeCommand(cmd) except PodError, pe: # When trying to call OO in server mode for producing # ODT (=forceOoCall=True), if an error occurs we still # have an ODT to return to the user. So we produce a # warning instead of raising an error. if (resultType == 'odt') and self.forceOoCall: print WARNING_INCOMPLETE_ODT % str(pe) else: raise pe
def manageError(self, result, context, errorMessage, dumpTb=True): '''Manage the encountered error: dump it into the buffer or raise an exception.''' if self.buffer.env.raiseOnError: if not self.buffer.pod: # Add in the error message the line nb where the errors occurs # within the PX. locator = self.buffer.env.parser.locator # The column number may not be given. col = locator.getColumnNumber() if col == None: col = '' else: col = ', column %d' % col errorMessage += ' (line %s%s)' % (locator.getLineNumber(), col) raise Exception(errorMessage) # Empty the buffer (pod-only) self.buffer.__init__(self.buffer.env, self.buffer.parent) PodError.dump(self.buffer, errorMessage, withinElement=self.elem, dumpTb=dumpTb) self.buffer.evaluate(result, context)
def run(self): # This feature is only available in the open source version if utils.commercial: raise utils.CommercialError() # Convert the document into PDF with LibreOffice output = self.renderer.callLibreOffice(self.importPath, 'pdf') if output: raise PodError(TO_PDF_ERROR % output) pdfFile = '%s.pdf' % os.path.splitext(self.importPath)[0] # Launch a PdfImporter to import this PDF into the POD result pdfImporter = PdfImporter(None, pdfFile, 'pdf', self.renderer) return pdfImporter.run()
def prepareFolders(self): # Check if I can write the result if not self.overwriteExisting and os.path.exists(self.result): raise PodError(RESULT_FILE_EXISTS % self.result) try: f = open(self.result, 'w') f.write('Hello') f.close() except OSError as oe: raise PodError(CANT_WRITE_RESULT % (self.result, oe)) except IOError as ie: raise PodError(CANT_WRITE_RESULT % (self.result, ie)) self.result = os.path.abspath(self.result) os.remove(self.result) # Create a temp folder for storing temporary files absResult = os.path.abspath(self.result) self.tempFolder = '%s.%f' % (absResult, time.time()) try: os.mkdir(self.tempFolder) except OSError as oe: raise PodError(CANT_WRITE_TEMP_FOLDER % (self.result, oe))
def setImageInfo(self, anchor, wrapInPara, size, sizeUnit, style): # Initialise anchor if anchor not in self.anchorTypes: raise PodError(self.WRONG_ANCHOR % str(self.anchorTypes)) self.anchor = anchor self.wrapInPara = wrapInPara self.size = size self.sizeUnit = sizeUnit # Put CSS attributes from p_style in a dict. self.cssAttrs = {} if style: for attr in style.split(';'): if not attr.strip(): continue name, value = attr.strip().split(':') value = value.strip() if value.endswith('px'): value = value[:-2] if value.isdigit(): value=int(value) self.cssAttrs[name.strip()] = value
def createPodParser(self, odtFile, context, inserts): '''Creates the parser with its environment for parsing the given p_odtFile (content.xml or styles.xml). p_context is given by the pod user, while p_inserts depends on the ODT file we must parse.''' evalContext = {'xhtml': self.renderXhtml, 'text': self.renderText, 'test': self.evalIfExpression, 'document': self.importDocument} # Default context if hasattr(context, '__dict__'): evalContext.update(context.__dict__) elif isinstance(context, dict) or isinstance(context, UserDict): evalContext.update(context) else: raise PodError(BAD_CONTEXT) env = PodEnvironment(evalContext, inserts) fileBuffer = FileBuffer(env, os.path.join(self.tempFolder,odtFile)) env.currentBuffer = fileBuffer return PodParser(env, self)
def run(self): # This feature is only available in the open source version if utils.commercial: raise utils.CommercialError() imagePrefix = os.path.splitext(os.path.basename(self.importPath))[0] # Split the PDF into images with Ghostscript. Create a sub-folder in the # OS temp folder to store those images. imagesFolder = getOsTempFolder(sub=True) device = 'png16m' ext = PdfImporter.gsDevices[device] dpi = '125' cmd = [ 'gs', '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=%s' % device, '-r%s' % dpi, '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sOutputFile=%s/%s%%d.%s' % (imagesFolder, imagePrefix, ext), self.importPath ] utils.executeCommand(cmd) # Check that at least one image was generated succeeded = False firstImage = '%s1.%s' % (imagePrefix, ext) for fileName in os.listdir(imagesFolder): if fileName == firstImage: succeeded = True break if not succeeded: raise PodError(PDF_TO_IMG_ERROR) # Insert images into the result noMoreImages = False i = 0 while not noMoreImages: i += 1 nextImage = '%s/%s%d.%s' % (imagesFolder, imagePrefix, i, ext) if os.path.exists(nextImage): # Use internally an Image importer for doing this job imgImporter = ImageImporter(None, nextImage, ext, self.renderer) imgImporter.init('paragraph', True, None, None, None, True, None) self.res += imgImporter.run() os.remove(nextImage) else: noMoreImages = True os.rmdir(imagesFolder) return self.res
def __init__(self, content, at, format, renderer): self.content = content # If content is None, p_at tells us where to find it (file system path, # url, etc) self.at = at # Ensure this path exists, if it is a local path. if at and not at.startswith('http') and not os.path.isfile(at): raise PodError(FILE_NOT_FOUND % at) self.format = format self.res = u'' self.renderer = renderer self.ns = renderer.currentParser.env.namespaces # Unpack some useful namespaces self.textNs = self.ns[OdfEnvironment.NS_TEXT] self.linkNs = self.ns[OdfEnvironment.NS_XLINK] self.drawNs = self.ns[OdfEnvironment.NS_DRAW] self.svgNs = self.ns[OdfEnvironment.NS_SVG] self.tempFolder = renderer.tempFolder self.importFolder = self.getImportFolder() # Create the import folder if it does not exist. if not os.path.exists(self.importFolder): os.mkdir(self.importFolder) self.importPath = self.getImportPath(at, format) # A link to the global fileNames dict (explained in renderer.py) self.fileNames = renderer.fileNames if at: # Move the file within the ODT, if it is an image and if this image # has not already been imported. self.importPath = self.moveFile(at, self.importPath) else: # We need to dump the file content (in self.content) in a temp file # first. self.content may be binary, a file handler or a # FileWrapper. if isinstance(self.content, FileWrapper): self.content.dump(self.importPath) else: if isinstance(self.content, file): fileContent = self.content.read() else: fileContent = self.content f = file(self.importPath, 'wb') f.write(fileContent) f.close()
def addExpression(self, expression, tiedHook=None): # At 2013-02-06, this method was not called within the whole test suite. try: self.dumpContent(Expression(expression).evaluate(self.env.context)) except Exception, e: PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False)
def createAction(self, statementGroup): '''Tries to create an action based on p_statementGroup. If the statement is not correct, r_ is -1. Else, r_ is the index of the element within the buffer that is the object of the action.''' res = -1 try: # Check the whole statement group if not statementGroup or (len(statementGroup) > 2): raise ParsingError(BAD_STATEMENT_GROUP % str(statementGroup)) # Check the statement statement = statementGroup[0] aRes = self.actionRex.match(statement) if not aRes: raise ParsingError(BAD_STATEMENT % statement) statementName, podElem, minus, actionType, subExpr = aRes.groups() if not (podElem in PodElement.POD_ELEMS): raise ParsingError(BAD_ELEMENT % podElem) if minus and (not podElem in PodElement.MINUS_ELEMS): raise ParsingError( BAD_MINUS % (podElem, PodElement.MINUS_ELEMS)) indexPodElem = self.getIndex(podElem) if indexPodElem == -1: raise ParsingError( ELEMENT_NOT_FOUND % (podElem, str([ e.__class__.__name__.lower() \ for e in self.elements.values()]))) podElem = self.elements[indexPodElem] # Check the 'from' clause fromClause = None source = 'buffer' if len(statementGroup) > 1: fromClause = statementGroup[1] source = 'from' if not fromClause.startswith('from '): raise ParsingError(BAD_FROM_CLAUSE % fromClause) fromClause = fromClause[5:] # Create the action if actionType == 'if': self.action = IfAction(statementName, self, subExpr, podElem, minus, source, fromClause) self.env.ifActions.append(self.action) if self.action.name: # We must register this action as a named action if self.env.namedIfActions.has_key(self.action.name): raise ParsingError(DUPLICATE_NAMED_IF) self.env.namedIfActions[self.action.name] = self.action elif actionType == 'else': if not self.env.ifActions: raise ParsingError(ELSE_WITHOUT_IF) # Does the "else" action reference a named "if" action? ifReference = subExpr.strip() if ifReference: if not self.env.namedIfActions.has_key(ifReference): raise ParsingError(ELSE_WITHOUT_NAMED_IF % ifReference) linkedIfAction = self.env.namedIfActions[ifReference] # This "else" action "consumes" the "if" action: this way, # it is not possible to define two "else" actions related to # the same "if". del self.env.namedIfActions[ifReference] self.env.ifActions.remove(linkedIfAction) else: linkedIfAction = self.env.ifActions.pop() self.action = ElseAction(statementName, self, None, podElem, minus, source, fromClause, linkedIfAction) elif actionType == 'for': forRes = MemoryBuffer.forRex.match(subExpr.strip()) if not forRes: raise ParsingError(BAD_FOR_EXPRESSION % subExpr) iter, subExpr = forRes.groups() self.action = ForAction(statementName, self, subExpr, podElem, minus, iter, source, fromClause) elif actionType == 'with': variables = self._getVariables(subExpr) self.action = VariablesAction(statementName, self, podElem, minus, variables, source, fromClause) else: # null action if not fromClause: raise ParsingError(NULL_ACTION_ERROR) self.action = NullAction(statementName, self, None, podElem, None, source, fromClause) res = indexPodElem except ParsingError, ppe: PodError.dump(self, ppe, removeFirstLine=True)