00001 """
00002 TODO: doc
00003 """
00004
00005 __copyright__ = """
00006 Copyright 2008 Sean Ross-Ross
00007 """
00008 __license__ = """
00009 This file is part of SLIMpy .
00010
00011 SLIMpy is free software: you can redistribute it and/or modify
00012 it under the terms of the GNU Lesser General Public License as published by
00013 the Free Software Foundation, either version 3 of the License, or
00014 (at your option) any later version.
00015
00016 SLIMpy is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 GNU Lesser General Public License for more details.
00020
00021 You should have received a copy of the GNU Lesser General Public License
00022 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00023 """
00024
00025 from inspect import getmro
00026
00027 class Singleton(object):
00028 """
00029 Singleton class conforms to singleton
00030 design pattern
00031 """
00032
00033 def __new__(cls, *p):
00034 """
00035 sets class attributs _default_instance and
00036 _instance_map if not set.
00037 and checks that no subclass overloads the
00038 __init__ method.
00039 """
00040 if '_default_instance' not in cls.__dict__:
00041 cls._default_instance = 'default'
00042
00043 if '_instance_map' not in cls.__dict__:
00044 cls._instance_map = dict()
00045
00046 name = "__init__"
00047 if name in cls.__dict__:
00048 obj = cls.__dict__[name]
00049 else:
00050 obj = getattr(cls, name)
00051
00052
00053 homecls = getattr(obj, "__objclass__", None)
00054 if homecls is None:
00055 mro = getmro( cls )
00056
00057 for base in mro:
00058 if name in base.__dict__:
00059 homecls = base
00060 break
00061
00062 if homecls is not Singleton:
00063 msg = ( "can not overload '__init__' method of Singleton class.\n"
00064 "class %(homecls)s defines new '__init__'" %vars() )
00065
00066 raise TypeError(msg)
00067
00068 return object.__new__( cls )
00069
00070 def __init__( self, *p ):
00071 """
00072 should not be called by subclasses
00073 """
00074 if not p:
00075 instance_name = self.__class__._default_instance
00076 else:
00077 instance_name = p[0]
00078
00079
00080 if self._instance_map.has_key(instance_name):
00081 shared_state = self._instance_map[instance_name]
00082 self.__dict__ = shared_state
00083 return
00084 else:
00085 shared_state = self._instance_map.setdefault(instance_name,{})
00086 self.__dict__ = shared_state
00087 self.__new_instance__( instance_name )
00088
00089
00090 def __new_instance__( self, name ):
00091 """
00092 to be initialize class instead of __init__
00093 """
00094 self.__i_name = name
00095
00096 @classmethod
00097 def __del_instance__( cls, name ):
00098 """
00099 delete the instance 'name'
00100 """
00101 if cls._instance_map.has_key(name):
00102 del cls._instance_map[ name ]
00103
00104 def __clean__(self):
00105 'to be used instead of __del__ to delete and instance'
00106 pass
00107
00108 @classmethod
00109 def _num_instances(cls):
00110 'get the number of instances of this class'
00111 return len( cls._instance_map )
00112
00113 def _get_instance_name(self):
00114 '''
00115 returns the name if this instance.
00116 not that singl.__class__( singl._get_instance_name() )
00117 returns 'singl'
00118 '''
00119 return self.__i_name
00120
00121 def _set_instance_name(self, val):
00122 'dont use this'
00123 self.__i_name = val
00124
00125 _instance_name = property( _get_instance_name, _set_instance_name )
00126
00127
00128