~ubuntu-branches/ubuntu/wily/spyder/wily-proposed

« back to all changes in this revision

Viewing changes to spyderlib/utils/iofuncs.py

  • Committer: Package Import Robot
  • Author(s): Ghislain Antony Vaillant, Ghislain Antony Vaillant, Picca Frédéric-Emmanuel
  • Date: 2014-10-19 11:42:57 UTC
  • mfrom: (1.2.8)
  • Revision ID: package-import@ubuntu.com-20141019114257-st1rz4fmmscgphhm
Tags: 2.3.1+dfsg-1
* Team upload

[Ghislain Antony Vaillant]
* New upstream release. (Closes: #765963)
* Bump Standards-Version to 3.9.6 (no changes required).
* d/control: fix pedantic lintian warning regarding capitalization in
  packages' description.

[Picca Frédéric-Emmanuel]
* Update the homepage now that upstream moved to bitbucket.
* debian/copyright
  - updated for 2.3.1 version
* debian/control
  + Recommends: python-pandas and python3-pandas

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os.path as osp
20
20
import shutil
21
21
import warnings
 
22
import json
 
23
import inspect
 
24
import dis
 
25
try:
 
26
    import pandas as pd
 
27
except ImportError:
 
28
    pd = None
22
29
 
23
30
# Local imports
24
 
from spyderlib.py3compat import pickle, to_text_string, getcwd
 
31
from spyderlib.py3compat import pickle, to_text_string, getcwd, PY2
 
32
 
 
33
 
 
34
class MatlabStruct(dict):
 
35
    """
 
36
    Matlab style struct, enhanced.
 
37
 
 
38
    Supports dictionary and attribute style access.  Can be pickled,
 
39
    and supports code completion in a REPL.
 
40
 
 
41
    Examples
 
42
    ========
 
43
    >>> from spyderlib.utils.iofuncs import MatlabStruct
 
44
    >>> a = MatlabStruct()
 
45
    >>> a.b = 'spam'  # a["b"] == 'spam'
 
46
    >>> a.c["d"] = 'eggs'  # a.c.d == 'eggs'
 
47
    >>> print(a)
 
48
    {'c': {'d': 'eggs'}, 'b': 'spam'}
 
49
 
 
50
    """
 
51
    def __getattr__(self, attr):
 
52
        """Access the dictionary keys for unknown attributes."""
 
53
        try:
 
54
            return self[attr]
 
55
        except KeyError:
 
56
            msg = "'MatlabStruct' object has no attribute %s" % attr
 
57
            raise AttributeError(msg)
 
58
 
 
59
    def __getitem__(self, attr):
 
60
        """
 
61
        Get a dict value; create a MatlabStruct if requesting a submember.
 
62
 
 
63
        Do not create a key if the attribute starts with an underscore.
 
64
        """
 
65
        if attr in self.keys() or attr.startswith('_'):
 
66
            return dict.__getitem__(self, attr)
 
67
        frame = inspect.currentframe()
 
68
        # step into the function that called us
 
69
        if frame.f_back.f_back and self._is_allowed(frame.f_back.f_back):
 
70
            dict.__setitem__(self, attr, MatlabStruct())
 
71
        elif self._is_allowed(frame.f_back):
 
72
            dict.__setitem__(self, attr, MatlabStruct())
 
73
        return dict.__getitem__(self, attr)
 
74
 
 
75
    def _is_allowed(self, frame):
 
76
        """Check for allowed op code in the calling frame"""
 
77
        allowed = [dis.opmap['STORE_ATTR'], dis.opmap['LOAD_CONST'],
 
78
                   dis.opmap.get('STOP_CODE', 0)]
 
79
        bytecode = frame.f_code.co_code
 
80
        instruction = bytecode[frame.f_lasti + 3]
 
81
        instruction = ord(instruction) if PY2 else instruction
 
82
        return instruction in allowed
 
83
 
 
84
    __setattr__ = dict.__setitem__
 
85
    __delattr__ = dict.__delitem__
 
86
 
 
87
    @property
 
88
    def __dict__(self):
 
89
        """Allow for code completion in a REPL"""
 
90
        return self.copy()
 
91
 
 
92
 
 
93
def get_matlab_value(val):
 
94
    """
 
95
    Extract a value from a Matlab file
 
96
 
 
97
    From the oct2py project, see
 
98
    http://pythonhosted.org/oct2py/conversions.html
 
99
    """
 
100
    import numpy as np
 
101
    if not isinstance(val, np.ndarray):
 
102
        return val
 
103
    # check for objects
 
104
    if "'|O" in str(val.dtype) or "O'" in str(val.dtype):
 
105
        data = MatlabStruct()
 
106
        for key in val.dtype.fields.keys():
 
107
            data[key] = get_matlab_value(val[key][0])
 
108
        return data
 
109
    # handle cell arrays
 
110
    if val.dtype == np.object:
 
111
        if val.size == 1:
 
112
            val = val[0]
 
113
            if "'|O" in str(val.dtype) or "O'" in str(val.dtype):
 
114
                val = get_matlab_value(val)
 
115
            if isinstance(val, MatlabStruct):
 
116
                return val
 
117
            if val.size == 1:
 
118
                val = val.flatten()
 
119
    if val.dtype == np.object:
 
120
        if len(val.shape) > 2:
 
121
            val = val.T
 
122
            val = np.array([get_matlab_value(val[i].T)
 
123
                            for i in range(val.shape[0])])
 
124
        if len(val.shape) > 1:
 
125
            if len(val.shape) == 2:
 
126
                val = val.T
 
127
            try:
 
128
                return val.astype(val[0][0].dtype)
 
129
            except ValueError:
 
130
                # dig into the cell type
 
131
                for row in range(val.shape[0]):
 
132
                    for i in range(val[row].size):
 
133
                        if not np.isscalar(val[row][i]):
 
134
                            if val[row][i].size > 1:
 
135
                                val[row][i] = val[row][i].squeeze()
 
136
                            else:
 
137
                                val[row][i] = val[row][i][0]
 
138
        else:
 
139
            val = np.array([get_matlab_value(val[i])
 
140
                            for i in range(val.size)])
 
141
        if len(val.shape) == 1 or val.shape[0] == 1 or val.shape[1] == 1:
 
142
            val = val.flatten()
 
143
        val = val.tolist()
 
144
    elif val.size == 1:
 
145
        if hasattr(val, 'flatten'):
 
146
            val = val.flatten()[0]
 
147
    if isinstance(val, MatlabStruct) and isinstance(val.size, MatlabStruct):
 
148
        del val['size']
 
149
        del val['dtype']
 
150
    return val
25
151
 
26
152
 
27
153
try:
35
161
        import scipy.io as spio  # analysis:ignore
36
162
    def load_matlab(filename):
37
163
        try:
38
 
            out = spio.loadmat(filename, struct_as_record=True,
39
 
                               squeeze_me=True)
 
164
            out = spio.loadmat(filename)
40
165
            for key, value in list(out.items()):
41
 
                if isinstance(value, np.ndarray):
42
 
                    if value.shape == ():
43
 
                        out[key] = value.tolist()
44
 
                    # The following would be needed if squeeze_me=False:
45
 
#                    elif value.shape == (1,):
46
 
#                        out[key] = value[0]
47
 
#                    elif value.shape == (1, 1):
48
 
#                        out[key] = value[0][0]
 
166
                out[key] = get_matlab_value(value)
49
167
            return out, None
50
168
        except Exception as error:
51
169
            return None, str(error)
64
182
    def load_array(filename):
65
183
        try:
66
184
            name = osp.splitext(osp.basename(filename))[0]
67
 
            return {name: np.load(filename)}, None
 
185
            data = np.load(filename)
 
186
            if hasattr(data, 'keys'):
 
187
                return data, None
 
188
            else:
 
189
                return {name: data}, None
68
190
        except Exception as error:
69
 
            return None, str(error)    
 
191
            return None, str(error)
70
192
    def __save_array(data, basename, index):
71
193
        """Save numpy array"""
72
194
        fname = basename + '_%04d.npy' % index
116
238
    load_image = None
117
239
 
118
240
 
 
241
def load_pickle(filename):
 
242
    """Load a pickle file as a dictionary"""
 
243
    try:
 
244
        if pd:
 
245
            return pd.read_pickle(data), None
 
246
        else:
 
247
            with open(filename, 'rb') as fid:
 
248
                data = pickle.load(fid)
 
249
            return data, None
 
250
    except Exception as err:
 
251
        return None, str(err)
 
252
 
 
253
 
 
254
def load_json(filename):
 
255
    """Load a json file as a dictionary"""
 
256
    try:
 
257
        with open(filename, 'rb') as fid:
 
258
            data = json.load(fid)
 
259
        return data, None
 
260
    except Exception as err:
 
261
        return None, str(err)
 
262
 
 
263
 
119
264
def save_dictionary(data, filename):
120
265
    """Save dictionary in a single file .spydata file"""
121
266
    filename = osp.abspath(filename)
258
403
    try:
259
404
        tar = tarfile.open(filename, "r")
260
405
        extracted_files = tar.getnames()
261
 
        
 
406
 
262
407
        # Rename original config files
263
408
        for fname in extracted_files:
264
409
            orig_name = get_conf_path(fname)
268
413
            if osp.isfile(orig_name):
269
414
                os.rename(orig_name, bak_name)
270
415
        renamed = True
271
 
        
 
416
 
272
417
        tar.extractall()
273
 
        
 
418
 
274
419
        for fname in extracted_files:
275
420
            shutil.move(fname, get_conf_path(fname))
276
 
            
 
421
 
277
422
    except Exception as error:
278
423
        error_message = to_text_string(error)
279
424
        if renamed:
285
430
                    os.remove(orig_name)
286
431
                if osp.isfile(bak_name):
287
432
                    os.rename(bak_name, orig_name)
288
 
                    
 
433
 
289
434
    finally:
290
435
        # Removing backup config files
291
436
        for fname in extracted_files:
292
437
            bak_name = get_conf_path(fname+'.bak')
293
438
            if osp.isfile(bak_name):
294
439
                os.remove(bak_name)
295
 
        
 
440
 
296
441
    os.chdir(old_cwd)
297
442
    return error_message
298
443
 
307
452
        self.save_filters = None
308
453
        self.load_funcs = None
309
454
        self.save_funcs = None
310
 
        
 
455
 
311
456
    def setup(self):
312
457
        iofuncs = self.get_internal_funcs()+self.get_3rd_party_funcs()
313
458
        load_extensions = {}
330
475
                save_funcs[ext] = savefunc
331
476
        load_filters.insert(0, to_text_string(_("Supported files")+" (*"+\
332
477
                                              " *".join(load_ext)+")"))
 
478
        load_filters.append(to_text_string(_("All files (*.*)")))
333
479
        self.load_filters = "\n".join(load_filters)
334
480
        self.save_filters = "\n".join(save_filters)
335
481
        self.load_funcs = load_funcs
336
482
        self.save_funcs = save_funcs
337
483
        self.load_extensions = load_extensions
338
484
        self.save_extensions = save_extensions
339
 
        
 
485
 
340
486
    def get_internal_funcs(self):
341
487
        return [
342
488
                ('.spydata', _("Spyder data files"),
343
489
                             load_dictionary, save_dictionary),
344
490
                ('.npy', _("NumPy arrays"), load_array, None),
 
491
                ('.npz', _("NumPy zip arrays"), load_array, None),
345
492
                ('.mat', _("Matlab files"), load_matlab, save_matlab),
346
493
                ('.csv', _("CSV text files"), 'import_wizard', None),
347
494
                ('.txt', _("Text files"), 'import_wizard', None),
349
496
                ('.png', _("PNG images"), load_image, None),
350
497
                ('.gif', _("GIF images"), load_image, None),
351
498
                ('.tif', _("TIFF images"), load_image, None),
 
499
                ('.pkl', _("Pickle files"), load_pickle, None),
 
500
                ('.pickle', _("Pickle files"), load_pickle, None),
 
501
                ('.json', _("JSON files"), load_json, None),
352
502
                ]
353
 
        
 
503
 
354
504
    def get_3rd_party_funcs(self):
355
505
        other_funcs = []
356
506
        from spyderlib.otherplugins import get_spyderplugins_mods
361
511
            except AttributeError as error:
362
512
                print("%s: %s" % (mod, str(error)), file=STDERR)
363
513
        return other_funcs
364
 
        
 
514
 
365
515
    def save(self, data, filename):
366
516
        ext = osp.splitext(filename)[1].lower()
367
517
        if ext in self.save_funcs:
368
518
            return self.save_funcs[ext](data, filename)
369
519
        else:
370
520
            return _("<b>Unsupported file type '%s'</b>") % ext
371
 
    
 
521
 
372
522
    def load(self, filename):
373
523
        ext = osp.splitext(filename)[1].lower()
374
524
        if ext in self.load_funcs:
410
560
    print("Data loaded in %.3f seconds" % (time.time()-t0))
411
561
#    for key in example:
412
562
#        print key, ":", example[key] == example2[key]
 
563
 
 
564
    a = MatlabStruct()
 
565
    a.b = 'spam'
 
566
    assert a["b"] == 'spam'
 
567
    a.c["d"] = 'eggs'
 
568
    assert a.c.d == 'eggs'
 
569
    assert a == {'c': {'d': 'eggs'}, 'b': 'spam'}