def sequenceExpander(expander, minfNode, minfNodeIterator, target, targetType, stop_on_error=True, exceptions=[]): if target is None: result = [] else: result = target while len(result) != 0: result.pop() if isinstance(targetType, Sequence) and targetType.elementType.mutable: length = minfNode.attributes.get('length') if length and len(result) < int(length): result += [ targetType.elementType.createValue() for i in xrange(int(length) - len(result)) ] itTarget = iter(result) for minfNode in minfNodeIterator: if isinstance(minfNode, EndStructure): if minfNode.type != listStructure: raise MinfError( _('Wrong Minf structure ending, expecting %(exp)s instead of %(rcv)s' ) % { 'exp': listStructure, 'rcv': minfNode.type }) break else: target = None if itTarget is not None: try: target = next(itTarget) except StopIteration: itTarget = None if target is not None: r = expander.expand(minfNodeIterator, minfNode, target=target, targetType=targetType.elementType, stop_on_error=stop_on_error, exceptions=exceptions) result.append(r) else: try: result.append( expander.expand(minfNodeIterator, minfNode, stop_on_error=stop_on_error, exceptions=exceptions)) except Exception as e: if stop_on_error: raise e else: result.append(None) exceptions.append(sys.exc_info()) return result
def createMinfReducer(name): ''' Return an instance of L{MinfReducer} previously registered. @param name: name of the reducer @type name: string ''' reducer = MinfReducer._allReducers.get(name) if reducer is None: raise MinfError(_('Unknown Minf reducer: %s') % (name, )) return reducer
def getTypeExpander(self, structureName): expander = self.typeExpanders.get(structureName) if expander is None: for base in self.bases: expander = base.getTypeExpander(structureName) if expander is not None: break else: raise MinfError( _('Minf structure %(struct)s cannot be expanded ' 'from Minf "%(minf)s" structure') % { 'struct': structureName, 'minf': self.name }) return expander
def getTypeReducer(self, classOrName): if not isinstance(classOrName, six.string_types): className = classOrName.__module__ + '.' + classOrName.__name__ else: className = classOrName reducer = self.typeReducers.get(className) if reducer is None: for base in self.bases: reducer = base.getTypeReducer(className) if reducer is not None: break else: if issubclass(classOrName, HasSignature): return self.hasSignatureReducer raise MinfError( _('Automatic reduction of HasSignature not implemented' )) raise MinfError( _('Object of type %(class)s cannot be reduced ' 'in Minf "%(minf)s" structure') % { 'class': className, 'minf': self.name }) return reducer
def expand(self, minfNodeIterator, minfNode=Undefined, target=None, targetType=Undefined, stop_on_error=True, exceptions=[]): if minfNode is Undefined: if sys.version_info[0] >= 3: minfNode = next(minfNodeIterator) else: minfNode = minfNodeIterator.next() if isinstance(minfNode, StartStructure): identifier = minfNode.identifier typeExpander = self.getTypeExpander(minfNode.type) try: result = typeExpander(self, minfNode, minfNodeIterator, target=target, targetType=targetType, stop_on_error=stop_on_error, exceptions=exceptions) except Exception as e: if stop_on_error: raise else: result = None exceptions.append(sys.exc_info()) if identifier is not None: self.objectsWithIdentifier[identifier] = result return result elif isinstance(minfNode, EndStructure): raise MinfError( _('Minf structure %s ended but not started') % (minfNode.type, )) elif isinstance(minfNode, Reference): return self.objectsWithIdentifier[minfNode.identifier] else: return minfNode
def __call__(self, expander, minfNode, minfNodeIterator, target, targetType, stop_on_error=True, exceptions=[]): structureName = minfNode.type args = [] kwargs = {} for minfNode in minfNodeIterator: if isinstance(minfNode, EndStructure): if minfNode.type != structureName: raise MinfError( _('Wrong Minf structure ending, expecting %(exp)s instead of %(rcv)s' ) % { 'exp': structureName, 'rcv': minfNode.type }) break else: key = expander.expand(minfNodeIterator, minfNode, stop_on_error=stop_on_error, exceptions=exceptions) try: value = expander.expand(minfNodeIterator, stop_on_error=stop_on_error, exceptions=exceptions) if key is None: args.append(value) else: kwargs[str(key)] = value except Exception as e: if stop_on_error: raise e else: exceptions.append(sys.exc_info()) return self.factory(*args, **kwargs)
def minfFormat(source): ''' Return a pair (format, reduction) identifying the minf format. If source is not a minf file, (None, None) is returned. Otherwise, format is a string representing the format of the minf file: 'XML' or 'python'. reduction is the name of the reducer used to write the minf file or None if format is 'python'. Example: :: from soma.minf.api import minfFormat format, reduction = minfFormat('/home/me/test.minf') If source is a :class:`BufferAndFile` instance, this call behave as if nothing has been read from the file. This can be useful if you have an opened file that cannot be seeked backward: Example: :: from soma.bufferandfile import BufferAndFile from soma.minf.api import minfFormat, readMinf bf = BufferAndFile(stream_file_object) format, reduction = minfFormat(bf) if format is not None: minfContent = readMinf(bf) Parameters ---------- source: string Input file name or file object. If it is a file name, it is opened with open(source). ''' if not hasattr(source, 'readline'): source = BufferAndFile(open(source)) elif not isinstance(source, BufferAndFile): source.seek(0) source = BufferAndFile(source) # Check first non white character to see if the minf file is XML or not start = source.read(5) if start == 'attri': source.unread(start) return ('python', None) elif start != '<?xml': # Try gzip compressed file gzipSource = source.clone() gzipSource.unread(start) gunzipSource = gzip.GzipFile(source.name) try: start = gunzipSource.read(5) except IOError: start = '' if start != '<?xml': raise MinfError(_('Invalid minf file: %s') % (source.name, )) source.change_file(gunzipSource) source.unread(start) else: source.unread(start) r = MinfReader.createReader('XML') reduction, buffer = r.reduction(source) source.unread(buffer) return ('XML', reduction)
def iterateMinf(source, targets=None, stop_on_error=True, exceptions=[]): ''' Returns an iterator over all objects stored in a minf file. Example: :: from soma.minf.api import iterateMinf for item in iterateMinf('test.minf'): print(repr(item)) Parameters ---------- source: string Input file name or file object. If it is a file name, it is opened with C{open( source )}. ''' if targets is not None: targets = iter(targets) initial_source = source if sys.version_info[0] >= 3 and not hasattr(initial_source, 'readline'): # in python3 the encoding of a file should be specified when opening # it: it cannot be changed afterwards. So in python3 we cannot read # the encoding within the file (for instance in a XML file). # This is completely silly, but here it is... # So we just have to try several encodings... try_encodings = ['UTF-8', 'latin1'] else: try_encodings = [None] for encoding in try_encodings: if not hasattr(initial_source, 'readline'): if sys.version_info[0] >= 3: source = BufferAndFile(open(initial_source, encoding=encoding)) else: source = BufferAndFile(open(initial_source)) elif not isinstance(source, BufferAndFile): source.seek(0) source = BufferAndFile(source) try: # Check first non white character to see if the minf file is XML or not start = source.read(5) source.unread(start) if sys.version_info[0] >= 3: def next(it): return it.__next__() else: def next(it): return it.next() if start == 'attri': try: import numpy d = {'nan': numpy.nan} except: d = {'nan': None} try: six.exec_(source.read().replace("\r\n", "\n"), d) except Exception as e: x = source if hasattr(source, '_BufferAndFile__file'): x = source._BufferAndFile__file x = 'Error in iterateMinf while reading ' + str(x) + ': ' msg = x + e.message # e.message = msg # e.args = ( x + e.args[0], ) + e.args[1:] print(x) raise minf = d['attributes'] if targets is not None: result = next(targets) _setTarget(result, minf) yield result else: yield minf return elif start != '<?xml': # Try gzip compressed file gzSource = gzip.GzipFile(source.name) if gzSource.read(5) != '<?xml': raise MinfError( _('Invalid minf file: %s') % (source.name, )) source = BufferAndFile(gzSource) source.unread('<?xml') r = MinfReader.createReader('XML') iterator = r.nodeIterator(source) minfNode = next(iterator) expander = createMinfExpander(minfNode.attributes['reduction']) count = 0 for nodeItem in iterator: count += 1 if isinstance(nodeItem, EndStructure): break target = None if targets is not None: try: target = next(targets) except StopIteration: targets = None yield expander.expand(iterator, nodeItem, target=target, stop_on_error=stop_on_error, exceptions=exceptions) except UnicodeDecodeError as e: if encoding == try_encodings[-1]: raise continue break # no error, don't process next encoding
def dictExpander(expander, minfNode, minfNodeIterator, target, targetType, stop_on_error=True, exceptions=[]): if target is None: result = {} else: result = target for minfNode in minfNodeIterator: if isinstance(minfNode, EndStructure): if minfNode.type != dictStructure: raise MinfError( _('Wrong Minf structure ending, expectinf %(exp)s instead of %(rcv)s' ) % { 'exp': dictStructure, 'rcv': minfNode.type }) break else: key = expander.expand(minfNodeIterator, minfNode, stop_on_error=stop_on_error, exceptions=exceptions) if isinstance(key, list): # list objects are unhashable and cannot be used as dictionary key # in this case they are converted to tuple key = tuple(key) if isinstance(result, HasSignature): targetType = result.signature.get(key, Undefined) if targetType is not Undefined: targetType = targetType.type target = getattr(result, key, None) try: if isinstance(target, HasSignature) or isinstance( targetType, Sequence): value = expander.expand( minfNodeIterator, target=target, targetType=targetType, stop_on_error=stop_on_error, exceptions=exceptions) else: value = expander.expand( minfNodeIterator, stop_on_error=stop_on_error, exceptions=exceptions) setattr(result, key, value) except Exception as e: if stop_on_error: raise else: exceptions.append(sys.exc_info()) else: try: value = expander.expand(minfNodeIterator, stop_on_error=stop_on_error, exceptions=exceptions) result[key] = value except Exception as e: if stop_on_error: raise else: exceptions.append(sys.exc_info()) return result
def _write(self, minfNodeIterator, minfNode, level, name): if minfNode is Undefined: if sys.version_info[0] >= 3: minfNode = next(minfNodeIterator) else: minfNode = minfNodeIterator.next() attributes = {} if name is not None: attributes[nameAttribute] = name if isinstance(minfNode, StartStructure): if minfNode.type == listStructure: naming = False stringNaming = False length = minfNode.attributes.get('length') if length: attributes[lengthAttribute] = length tag = listTag elif minfNode.type == dictStructure: naming = True stringNaming = False length = minfNode.attributes.get('length') if length: attributes[lengthAttribute] = length tag = dictionaryTag else: naming = True stringNaming = True tag = factoryTag attributes[objectTypeAttribute] = minfNode.type if attributes: attributes = ' ' + \ ' '.join([n + '=' + xml_quoteattr(unicode(v)) for n, v in six.iteritems(attributes)]) else: attributes = '' self._encodeAndWriteLine('<' + tag + attributes + '>', level) ntype = minfNode.type for minfNode in minfNodeIterator: if isinstance(minfNode, EndStructure): if ntype != minfNode.type: raise MinfError( _('Wrong Minf structure ending, expecting %(exp)s instead of %(rcv)s' ) % { 'exp': ntype, 'rcv': minfNode.type }) self._encodeAndWriteLine('</' + tag + '>', level) break elif naming: if isinstance(minfNode, six.string_types): self._write(minfNodeIterator, Undefined, level + 1, minfNode) elif minfNode is None: if not stringNaming: self._write(minfNodeIterator, minfNode, level + 1, None) self._write(minfNodeIterator, Undefined, level + 1, None) else: self._write(minfNodeIterator, minfNode, level + 1, None) self._write(minfNodeIterator, Undefined, level + 1, None) else: self._write(minfNodeIterator, minfNode, level + 1, None) elif isinstance(minfNode, EndStructure): raise MinfError( _('Unexpected Minf structure ending: %s') % (minfNode.type, )) level -= 1 else: if attributes: attributesXML = ' ' + \ ' '.join([n + '=' + xml_quoteattr(unicode(v)) for n, v in six.iteritems(attributes)]) else: attributesXML = '' if minfNode is None: self._encodeAndWriteLine('<' + noneTag + attributesXML + '/>', level) elif isinstance(minfNode, bool): if minfNode: self._encodeAndWriteLine( '<' + trueTag + attributesXML + '/>', level) else: self._encodeAndWriteLine( '<' + falseTag + attributesXML + '/>', level) elif isinstance(minfNode, (int, float, long)): self._encodeAndWriteLine( '<' + numberTag + attributesXML + '>' + unicode(minfNode) + '</' + numberTag + '>', level) elif isinstance(minfNode, six.string_types): if type(minfNode) is byte_type: try: minfNode = minfNode.decode("utf-8") except UnicodeDecodeError: minfNode = minfNode.decode("iso-8859-1") self._encodeAndWriteLine( '<' + stringTag + attributesXML + '>' + xml_escape(minfNode, xml_replacement) + '</' + stringTag + '>', level) elif hasattr(minfNode, '__minfxml__'): minfNode.__minfxml__(self, attributes, level) else: raise MinfError( _('Cannot save an object of type %s as an XML atom') % (str(type(minfNode)), ))
def fatalError(self, error): raise MinfError(_('XML parse error: %s') % (unicode(error), ) + ' (stack = ' + ','.join(['"' + i + '"' for i in self._stack]) + ')')