[SciPy-dev] some scipy.io.mio problems

Alexander Schmolck a.schmolck at gmx.net
Thu Nov 24 13:54:39 CST 2005


Hi,

I've recently patched mio.py in my ubuntu install of scipy with svn repository
code because I needed to read v6 matlab files. I think I've found some
problems that are still present in the latest svn version (just checked)

Firstly

line 557 (in _parse_mimatrix)

         if type == mxCHAR_CLASS:

should read 

         if dclass == mxCHAR_CLASS

I also suspect line 624 should be s/KeyError/(KeyError,AttributeError)/, i.e.

            try:
                res = res + _unit_imag[imag.dtypechar] * imag
            except (KeyError,AttributeError):
                res = res + 1j*imag

Finally loadmat searches sys.path for the mat file. It's not obvious to me why
that would be a good idea, but shouldn't it at least return the *first* match?
I.e. shouldn't that be (in line 735):

  full_name = test_name; break

as opposed to just

  full_name = test_name


Finally, as a mere suggestion, I'd find it convenient if mat_struct were
either made a bit more featureful or a part of the official interface for
which the user is free to supply a drop-in replacement (with a __repr__
method, for example).

For example, I currently use my somewhat baroque `EasyStruct' class (which
includes __repr__ and most of the features of a dict) to get a more covenient
container for the loaded mat file as follows:

    scipy.io.mio.mat_struct = EasyStruct
    res = EasyStruct(**loadmat(bla))


'as

----8<----Code for EasyStruct----8<------


class EasyStruct(object):
    r"""
    Examples:
    
        >>> brian = EasyStruct(name="Brian", age=30)
        >>> brian.name
        'Brian'
        >>> brian.age
        30
        >>> brian.life = "short"
        >>> brian
        EasyStruct(age=30, life='short', name='Brian')
        >>> del brian.life
        >>> brian == EasyStruct(name="Brian", age=30)
        True
        >>> brian != EasyStruct(name="Jesus", age=30)
        True
        >>> len(brian)
        2

    Call the object to create a clone:
    
        >>> brian() is not brian and brian(name="Jesus") ==
        >>> EasyStruct(name="Jesus", age=30)
        True

    Conversion to/from dict:

        >>> EasyStruct(**dict(brian)) == brian
        True

    Evil Stuff:
    
        >>> brian['name', 'age']
        ('Brian', 30)
        >>> brian['name', 'age'] = 'BRIAN', 'XXX'
        >>> brian
        EasyStruct(age='XXX', name='BRIAN')
    """
    def __init__(self,**kwargs):
        self.__dict__.update(kwargs)
    def __call__(self, **kwargs):
        import copy
        res = copy.copy(self)
        res.__init__(**kwargs)
        return res
    def __eq__(self, other):
        return self.__dict__ == other.__dict__
    def __ne__(self, other):
        return not self.__eq__(other)
    def __len__(self):
        return len([k for k in self.__dict__.iterkeys() if not
        (k.startswith('__') or k.endswith('__'))])
    # FIXME rather perverse
    def __getitem__(self, nameOrNames):
        if isString(nameOrNames):
            return self.__dict__[nameOrNames]
        else:
            return tuple([self.__dict__[n] for n in nameOrNames])
    # FIXME rather perverse
    def __setitem__(self, nameOrNames, valueOrValues):
        if isString(nameOrNames):
            self.__dict__[nameOrNames] = valueOrValues
        else:
            for (n,v) in zip(nameOrNames, valueOrValues):
                self.__dict__[n] = v
    def __contains__(self, key):
        return key in self.__dict__ and not (key.startswith('__') or
        key.endswith('__'))
    def __iter__(self):
        for (k,v) in self.__dict__.iteritems():
            if not (k.startswith('__') or k.endswith('__')):
                yield k,v
    def __repr__(self):
        return mkRepr(self, **vars(self))

def isString(obj):
    return isinstance(obj, basestring)

def mkRepr(instance, *argls, **kwargs):
    r"""Convinience function to implement ``__repr__``. `kwargs` values are
        ``repr`` ed. Special behaviour for ``instance=None``: just the
        arguments are formatted.

    Example:
    
        >>> class Thing:
        ...     def __init__(self, color, shape, taste=None):
        ...         self.color, self.shape, self.taste = color, shape, taste
        ...     def __repr__(self):
        ...         return mkRepr(self, self.color, self.shape,
        taste=self.taste)
        ...
        >>> maggot = Thing('white', 'cylindrical', 'chicken')
        >>> maggot
        Thing('white', 'cylindrical', taste='chicken')
        >>> Thing('Color # 132942430-214809804-412430988081-241234', 'unkown',
        >>> taste=maggot)
        Thing('Color # 132942430-214809804-412430988081-241234',
              'unkown',
              taste=Thing('white', 'cylindrical', taste='chicken'))
    """
    width=79
    maxIndent=15
    minIndent=2
    args = map(repr, argls) + ["%s=%r" % (k, v)
                               for (k,v) in ipsort(kwargs.items())]
    if instance is not None:
        start = "%s(" % instance.__class__.__name__
        args[-1] += ")"
    else:
        start = ""
    if len(start) <= maxIndent and len(start) + len(args[0]) <= width and \
           max(map(len,args)) <= width: # XXX mag of last condition bit
           arbitrary
        indent = len(start)
        args[0] = start + args[0]
        if sum(map(len, args)) + 2*(len(args) - 1) <= width:
            return ", ".join(args)
    else:
        indent = minIndent
        args[0] = start + "\n" + " " * indent + args[0]
    return (",\n" + " " * indent).join(args)




More information about the Scipy-dev mailing list