Package mvpa :: Package misc :: Package io :: Module hamster

[hide private]
[frames] | no frames]

# Source Code for Module mvpa.misc.io.hamster

      1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
      2  # vi: set ft=python sts=4 ts=4 sw=4 et:
      3  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      4  #
      5  #   See COPYING file distributed along with the PyMVPA package for the
      6  #   copyright and license terms.
      7  #
      8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      9  """Helper for simple storage facility via cPickle and optionally zlib"""
     10
     11  __docformat__ = 'restructuredtext'
     12
     13  import os
     14
     15  from mvpa.base import externals
     16
     17  _d_geti_ = dict.__getitem__
     18  _d_seti_ = dict.__setitem__
     19
     20  _o_geta_ = dict.__getattribute__
     21  _o_seta_ = dict.__setattr__
     22
     23  if externals.exists('cPickle', raiseException=True) and \
     24     externals.exists('gzip', raiseException=True):
     25      import cPickle, gzip
     26
     27  if __debug__:
     28      from mvpa.base import debug
     29
     30 -class Hamster(object):
     31      """Simple container class with basic IO capabilities.
     32
     33      It is capable of storing itself in a file, or loading from a file using
     34      cPickle (optionally via zlib from compressed files). Any serializable
     35      object can be bound to a hamster to be stored.
     36
     37      To undig burried hamster use Hamster(filename). Here is an example:
     38
     39        >>> h = Hamster(bla='blai')
     40        >>> h.boo = N.arange(5)
     41        >>> h.dump(filename)
     42        ...
     43        >>> h = Hamster(filename)
     44
     45      Since Hamster introduces methods `dump`, `asdict` and property
     46      'registered', those names cannot be used to assign an attribute,
     47      nor provided in among constructor arguments.
     48      """
     49
     50      __ro_attr = set(object.__dict__.keys() +
     51                      ['dump', 'registered', 'asdict'])
     52      """Attributes which come with being an object"""
     53
     54 -    def __new__(cls, *args, **kwargs):
     55          if len(args) > 0:
     56              if len(kwargs) > 0:
     57                  raise ValueError, \
     58                        "Do not mix positional and keyword arguments. " \
     59                        "Use a single positional argument -- filename, " \
     60                        "or any number of keyword arguments, without having " \
     61                        "filename specified"
     62              if len(args) == 1 and isinstance(args[0], basestring):
     63                  filename = args[0]
     64                  args = args[1:]
     65                  if __debug__:
     66                      debug('IOH', 'Undigging hamster from %s' % filename)
     67                  # compressed or not -- that is the question
     68                  if filename.endswith('.gz'):
     69                      f = gzip.open(filename)
     70                  else:
     71                      f = open(filename)
     72                  result = cPickle.load(f)
     73                  if not isinstance(result, Hamster):
     74                      warning("Loaded other than Hamster class from %s" % filename)
     75                  return result
     76              else:
     77                  raise ValueError, "Hamster accepts only a single positional " \
     78                        "argument and it must be a filename. Got %d " \
     79                        "arguments" % (len(args),)
     80          else:
     81              return object.__new__(cls)
     82
     83
     84 -    def __init__(self, *args, **kwargs):
     85          """Initialize Hamster.
     86
     87          Providing a single parameter string would treat it as a
     88          filename from which to undig the data. Otherwise all keyword
     89          parameters are assigned into the attributes of the object.
     90          """
     91          if len(args) > 0:
     92              if len(args) == 1 and isinstance(args[0], basestring):
     93                  # it was a filename
     94                  args = args[1:]
     95              else:
     96                  raise RuntimeError, "Should not get here"
     97
     98          # assign provided attributes
     99          for k,v in kwargs.iteritems():
    100              setattr(self, k, v)
    101
    102          object.__init__(self)
    103
    104
    105 -    def dump(self, filename, compresslevel='auto'):
    106          """Bury the hamster into the file
    107
    108          :Parameter:
    109            filename: str
    110              Name of the target file. When writing to a compressed file the
    111              filename gets a '.gz' extension if not already specified. This
    112              is necessary as the constructor uses the extension to decide
    113              whether it loads from a compressed or uncompressed file.
    114            compresslevel: 'auto' or int
    115              Compression level setting passed to gzip. When set to
    116              'auto', if filename ends with '.gz' `compresslevel` is set
    117              to 5, 0 otherwise.  However, when `compresslevel` is set to
    118              0 gzip is bypassed completely and everything is written to
    119              an uncompressed file.
    120          """
    121          if compresslevel == 'auto':
    122              compresslevel = (0, 5)[int(filename.endswith('.gz'))]
    123          if compresslevel > 0 and not filename.endswith('.gz'):
    124              filename += '.gz'
    125          if __debug__:
    126              debug('IOH', 'Burying hamster into %s' % filename)
    127          if compresslevel == 0:
    128              f = open(filename, 'w')
    129          else:
    130              f = gzip.open(filename, 'w', compresslevel)
    131          cPickle.dump(self, f)
    132          f.close()
    133
    134
    135 -    def __repr__(self):
    136          reg_attr = ["%s=%s" % (k, repr(getattr(self, k)))
    137                      for k in self.registered]
    138          return "%s(%s)" % (self.__class__.__name__,
    139                             ", ".join(reg_attr))
    140
    141      # ??? actually seems to be ugly
    142      #def __str__(self):
    143      #    registered = self.registered
    144      #    return "%s with %d elements: %s" \
    145      #           % (self.__class__.__name__,
    146      #              len(registered),
    147      #              ", ".join(self.registered))
    148
    149      @property
    150 -    def registered(self):
    151          """List registered attributes.
    152          """
    153          reg_attr = [k for k in self.__dict__.iterkeys()
    154                      if not k in self.__ro_attr]
    155          reg_attr.sort()
    156          return reg_attr
    157
    158
    159 -    def __setattr__(self, k, v):
    160          """Just to prevent resetting read-only attributes, such as methods
    161          """
    162          if k in self.__ro_attr:
    163              raise ValueError, "'%s' object attribute '%s' is read-only" \
    164                    % (self.__class__.__name__, k)
    165          object.__setattr__(self, k, v)
    166
    167
    168 -    def asdict(self):
    169          """Return registered data as dictionary
    170          """
    171          return dict([(k, getattr(self, k))
    172                       for k in self.registered])
    173