def getCallableString(callable): ''' Returns a translated human readable string representing a callable. Parameters ---------- callable: callable *function*, *method*, *class* or *instance* to inspect Returns -------- string: type and name of the callable ''' if inspect.isfunction(callable): name = _('function %s') % (callable.__name__, ) elif inspect.ismethod(callable): name = _('method %s') % ( six.get_method_self(callable).__class__.__name__ + '.' + callable.__name__, ) elif inspect.isclass(callable): name = _('class %s') % (callable.__name__, ) else: name = str(callable) return name
def startElement(self, parser, name, attributes): if parser._minfStarted: nameAttr = attributes.pop(nameAttribute, None) if nameAttr is None: if self._obsoleteFormat: parser.parseError( _('%s attribute required for minf_1.0') % (nameAttribute, )) else: if self._obsoleteFormat: parser._nodesToProduce.append(nameAttr) else: parser.parseError( _('Unexpected attribute %s') % (nameAttribute, )) newHandler = MinfXMLHandler.getHandler(parser, self, name, attributes) if newHandler is None: parser.parseError(_('Unexpected tag "%s"') % (name, )) parser._handler = newHandler else: if name != minfTag: # Document is not a minf file parser.parseError( _('Wrong document type, expecting "%(minf)s" instead of ' '"%(other)s>"') % { 'minf': minfTag, 'other': name }) # Checking minf format self._obsoleteFormat = False expanderName = attributes.pop(expanderAttribute, None) if expanderName is None: # Compatibility with obsolete minf 1.0 XML format version = attributes.pop('version', None) if version is None: expanderName = 'minf_2.0' else: if version != '1.0': parser.parseError( _('Wrong value for attribute "version", found ' '"%s" but only "1.0" is accepted') % (version, )) self._obsoleteFormat = True expanderName = 'minf_1.0' parser._nodesToProduce.append( StartStructure(minfStructure, reduction=expanderName)) # Compatibility with obsolete minf 1.0 XML format if self._obsoleteFormat: parser._nodesToProduce.append(StartStructure(dictStructure)) parser._minfStarted = True # Check attributes parser.checkNoMoreAttributes(attributes)
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 __init__(self, parser, parent, name, attributes): identifier = attributes.pop(identifierAttribute, None) if self.type is None: parser.parseError( _('%s attribute missing') % (identifierAttribute, )) parser._nodesToProduce.append(Reference(identifier=identifier)) XMLHandler.__init__(self, parser, parent, name, attributes)
def startElement(self, parser, name, attributes): nameAttr = attributes.pop(nameAttribute, None) parser._nodesToProduce.append(nameAttr) newHandler = MinfXMLHandler.getHandler(parser, self, name, attributes) if newHandler is None: parser.parseError(_('Unexpected tag "%s"') % (name, )) parser._handler = newHandler
def createWriter(destFile, format, reducer): ''' This static method create a L{MinfWriter} instance by looking for a registered L{MinfWriter} derived classe named C{format}. Parameters C{destFile} and C{reducer} are passed to the derived class constructor. @param format: name of the minf format. @type format: string @returns: L{MinfWriter} derived class instance. @param file: file name or file object (opened for writing) where the minf file is written. If it is a file name, it is opened with C{open( destFile, 'wb' )}. @type file: string or any object respecting Python file object API @param reducer: name of the reducer to use (see L{soma.minf.tree} for more information about reducers). @type reducer: string ''' writer = MinfWriter._allWriterClasses.get(format) if writer is None: raise ValueError( _('No minf writer for format "%(format)s", possible formats are: %(possible)s') % {'format': format, 'possible': ', '.join(['"' + i + '"' for i in MinfWriter._allWriterClasses])}) if not hasattr(destFile, 'write'): destFile = open(destFile, 'w') return writer(destFile, reducer, )
def timeDifferenceToString(difference): days = int(difference / 86400) difference -= days * 86400 hours = int(difference / 3600) difference -= hours * 3600 minutes = int(difference / 60) seconds = int(difference - minutes * 60) result = '' if days: return (_('%d days %d hours %d minutes %d seconds') % (days, hours, minutes, seconds)) if hours: return (_('%d hours %d minutes %d seconds') % (hours, minutes, seconds)) if minutes: return (_('%d minutes %d seconds') % (minutes, seconds)) return (_('%d seconds') % (seconds, ))
def __init__(self, parser, parent, name, attributes): self.type = attributes.pop(objectTypeAttribute, None) if self.type is None: parser.parseError( _('%s attribute missing') % (objectTypeAttribute, )) identifier = attributes.pop(identifierAttribute, None) parser._nodesToProduce.append( StartStructure(self.type, identifier=identifier)) XMLHandler.__init__(self, parser, parent, name, attributes)
def getArgumentsSpecification(callable): ''' This is an extension of Python module :py:mod:`inspect.getargspec` that accepts classes and returns only information about the parameters that can be used in a call to *callable* (*e.g.* the first *self* parameter of bound methods is ignored). If *callable* has not an appropriate type, a :class:`TypeError <exceptions.TypeError>` exception is raised. Parameters ---------- callable: callable *function*, *method*, *class* or *instance* to inspect Returns ------- tuple: As :func:`inspect.getargspec`, returns *(args, varargs, varkw, defaults)* where *args* is a list of the argument names (it may contain nested lists). *varargs* and *varkw* are the names of the ``*`` and ``**`` arguments or *None*. *defaults* is a n-tuple of the default values of the last *n* arguments. ''' if inspect.isfunction(callable): return getfullargspec(callable)[:4] elif inspect.ismethod(callable): args, varargs, varkw, defaults = getfullargspec(callable)[:4] args = args[1:] # ignore the first "self" parameter return args, varargs, varkw, defaults elif inspect.isclass(callable): try: init = callable.__init__ except AttributeError: return [], None, None, None return getArgumentsSpecification(init) elif isinstance(callable, (partial, SomaPartial)): args, varargs, varkw, defaults = getArgumentsSpecification( callable.func) if defaults: d = dict(zip(reversed(args), reversed(defaults))) else: d = {} d.update(zip(reversed(args), reversed(callable.args))) if callable.keywords: d.update(callable.keywords) if len(d): defaults = tuple((d[i] for i in args[-len(d):])) else: defaults = d return (args, varargs, varkw, defaults) else: try: call = callable.__call__ except AttributeError: raise TypeError(_('%s is not callable') % repr(callable)) return getArgumentsSpecification(call)
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 createMinfExpander(name): ''' Return an instance of L{MinfExpander} previously registered. @param name: name of the expander @type name: string ''' expander = MinfExpander._allExpanders.get(name) if expander is None: raise KeyError(_('Unknown Minf expander: %s') % (name, )) return expander
def xml(item): ''' Build an XML unicode string based on either an XML string (in that case it is returned as is) or an XHTML instance. @param item: value to convert in XML. @type item: XHTML instance or unicode containing XML ''' if isinstance(item, six.string_types): return item elif isinstance(item, XHTML): return item._itemXML(item) else: raise RuntimeError( _('Cannot use XHTML converter for %s') % (str(item), ))
def html(item): ''' Build an HTML unicode string based on either an HTML string (in that case it is returned as is) or an XHTML instance. @param item: value to convert in HTML. @type item: XHTML instance or unicode containing HTML ''' if isinstance(item, basestring): return item elif isinstance(item, XHTML): return item._contentXML(item.content) else: raise RuntimeError( _('Cannot use XHTML converter for %s') % (unicode(item),))
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 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 createReader(format): ''' This static method create a L{MinfReader} instance by looking for a registered L{MinfReader} derived classes named C{format}. @param format: name of the minf format. @type format: string @returns: L{MinfReader} derived class instance. ''' reader = MinfReader._allReaderClasses.get(format) if reader is None: raise ValueError( _('No minf reader for format "%(format)s", possible formats are: %(possible)s' ) % { 'format': format, 'possible': ', '.join( ['"' + i + '"' for i in MinfReader._allReaderClasses]) }) return reader()
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 checkParameterCount(callable, paramCount): ''' Checks that a callable can be called with *paramCount* arguments. If not, a RuntimeError is raised. .. seealso:: :func:`getArgumentsSpecification` Parameters ---------- callable: callable *function*, *method*, *class* or *instance* to inspect paramCount: int number of parameters ''' minimum, maximum = numberOfParameterRange(callable) if ( maximum is not None and paramCount > maximum ) or \ paramCount < minimum: raise RuntimeError( _('%(callable)s cannot be called with %(paramCount)d arguments') % { 'callable': getCallableString(callable), 'paramCount': paramCount })
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 fatalError(self, error): raise MinfError(_('XML parse error: %s') % (unicode(error), ) + ' (stack = ' + ','.join(['"' + i + '"' for i in self._stack]) + ')')
def checkNoMoreAttributes(self, attributes): if attributes: self.parseError(_('Invalid attribute": %(attributes)s') % {'attributes': ', '.join(['"' + n + '"' for n in attributes])})
def startElement(self, parser, name, attributes): parser.parseError(_('Unexpected tag "%s"') % (name, ))
def startElement(self, parser, name, attributes): newHandler = MinfXMLHandler.getHandler(parser, self, name, attributes) if newHandler is None: parser.parseError(_('Unexpected tag "%s"') % (name, )) parser._handler = newHandler
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)), ))