pytilities.attributecollectionbase

Package pytilities :: Module attributecollectionbase |
[hide private]
[frames] | no frames]

# Source Code for Module pytilities.attributecollectionbase

      1  # Copyright (C) 2010 Tim Diels <limyreth@users.sourceforge.net>
      2  #
      3  # This file is part of pytilities.
      4  #
      5  # pytilities is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # pytilities is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with pytilities.  If not, see <http://www.gnu.org/licenses/>.
     17  #
     18
     19  __docformat__ = 'reStructuredText'
     20
     21 -class AttributeCollectionBase(object):
     22      """
     23      Mixin, allows extension of instance attributes with `AttributeCollection`s
     24
     25      This mixin allows a class' instances' attributes and set of supported
     26      operators to be extended with `AttributeCollection`s.
     27
     28      Note: this class provides a base for using `AttributeCollection`s, it is not
     29      a base class of `AttributeCollection`. This have been a misnomer.
     30
     31      Methods:
     32
     33          - `_append_attribute_collection`: Append a new `AttributeCollection`
     34
     35      Class invariants:
     36
     37          1. an `AttributeCollectionBase` never contains two identical
     38          `AttributeCollection`s
     39      """
     40
     41 -    def __init__(self):
     42          object.__setattr__(self,
     43                  "_AttributeCollectionBase__collections", [])
     44
     45 -    def _append_attribute_collection(self, collection):
     46          """
     47          Append a new `AttributeCollection`.
     48
     49          When attributes of collections overlap, the first of overlapping
     50          attributes found in the lookup process is used and the others are
     51          ignored. Lookup happens in the same order as collections were added. (It
     52          is probably best to avoid overlaps.)
     53
     54          Parameters:
     55
     56              collection :: AttributeCollection
     57                  the collection to add
     58          """
     59          assert collection not in self.__collections, \
     60              "Collection can appear only once in the list of collections of" + \
     61              "the attribute collection base"
     62
     63          self.__collections.append(collection)
     64
     65 -    def __getattr__(self, name):
     66          # NOTE: if you're getting exceptions about this, you probably still
     67          # need to call __init__
     68          collections = object.__getattribute__(self,
     69                                                "_AttributeCollectionBase__collections")
     70          for collection in collections:
     71              (found, value) = collection.getattr_(name)
     72              if found: return value
     73
     74          # reaching this point means no collection contains the attrib
     75          raise AttributeError("'%s' object has no attribute '%s'" %
     76                               (object.__getattribute__(self, "__class__").__name__, name))
     77
     78 -    def __setattr__(self, name, value):
     79          try:
     80              for collection in self.__collections:
     81                  found = collection.setattr_(name, value)
     82                  if found: return
     83          except AttributeError:
     84              # caused by our init not having been called yet
     85              # this can happen when C inherits from A, B and B inherits from us
     86              # thus self.__collections doesn't exist yet
     87              # or we are createing __colections for the first time
     88              pass
     89
     90          # reaching this point means no collection contains the attrib
     91          # let object take care of this one
     92          object.__setattr__(self, name, value)
     93
     94 -    def __delattr__(self, name):
     95          try:
     96              for collection in self.__collections:
     97                  found = collection.detattr_(name)
     98                  if found: return
     99          except AttributeError:
    100              # see __setattr__
    101              pass
    102
    103          # reaching this point means no collection contains the attrib
    104          # let object take care of this one
    105          object.__delattr__(self, name)
    106
    107
    108      ########################################################################
    109      # A big bunch of things aren't searched for on the instance, but on the
    110      # class Thus, they don't call __getattr__, __getattribute__, ... We'll just
    111      # 'fix' that by placing them on our class and routing them through to the
    112      # __getattr__ methods etc.
    113
    114 -    def __str__(self):
    115          return self.__getattr__("__str__")()
    116
    117 -    def __copy__(self):
    118          return self.__getattr__("__copy__")()
    119
    120 -    def __eq__(self, other):
    121          return self.__getattr__("__eq__")(other)
    122
    123 -    def __neq__(self, other):
    124          return self.__getattr__("__neq__")(other)
    125
    126 -    def __nonzero__(self):
    127          try:
    128              return self.__getattr__("__nonzero__")()
    129          except AttributeError:
    130              return True  # the default behaviour
    131
    132 -    def __len__(self):
    133          return self.__getattr__("__len__")()
    134
    135 -    def __getitem__(self, key):
    136          return self.__getattr__("__getitem__")(key)
    137
    138 -    def __setitem__(self, key, value):
    139          self.__getattr__("__setitem__")(key, value)
    140
    141 -    def __iter__(self):
    142          return self.__getattr__("__iter__")()
    143
    144 -    def __add__(self, other):
    145          return self.__getattr__("__add__")(other)
    146
    147 -    def __iadd__(self, other):
    148          return self.__getattr__("__iadd__")(other)
    149
    150 -    def __sub__(self, other):
    151          return self.__getattr__("__sub__")(other)
    152
    153 -    def __mul__(self, other):
    154          return self.__getattr__("__mul__")(other)
    155
    156 -    def __rmul__(self, other):
    157          return self.__getattr__("__rmul__")(other)
    158
    159 -    def __imul__(self, other):
    160          return self.__getattr__("__imul__")(other)
    161
    162 -    def __div__(self, other):
    163          return self.__getattr__("__div__")(other)
    164
    165 -    def __rdiv__(self, other):
    166          return self.__getattr__("__rdiv__")(other)
    167
    168 -    def __floordiv__(self, other):
    169          return self.__getattr__("__floordiv__")(other)
    170
    171 -    def __rfloordiv__(self, other):
    172          return self.__getattr__("__rfloordiv__")(other)
    173
    174 -    def __truediv__(self, other):
    175          return self.__getattr__("__truediv__")(other)
    176
    177 -    def __rtruediv__(self, other):
    178          return self.__getattr__("__rtruediv__")(other)
    179
    180 -    def __neg__(self):
    181          return self.__getattr__("__neg__")()
    182
    183 -    def __pos__(self):
    184          return self.__getattr__("__pos__")()
    185
    186 -    def __abs__(self):
    187          return self.__getattr__("__abs__")()
    188
    189  # TODO: test all ops for the expected fail, just like with an object, for
    190  # unimplemented ops
    191