[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - Settings.py:1.1.2.6

Steve Alexander steve@cat-box.net
Wed, 20 Mar 2002 17:50:57 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/App/Security
In directory cvs.zope.org:/tmp/cvs-serv7531

Modified Files:
      Tag: Zope-3x-branch
	Settings.py 
Log Message:
Reimplemented symbolic constants class for security settings.
Added test to check that a setting retains its identity on pickling
and unpickling.


=== Zope3/lib/python/Zope/App/Security/Settings.py 1.1.2.5 => 1.1.2.6 ===
 """ Security setting constants """
 
-# PermissionSettingMetaClass and PermissionSetting function together to produce
-# typed constants. These constants (such as Allow, Deny, etc. below) can be
-# compared by identity, even when pickled and unpickled. This is because they
-# are stored in pickles just as the fully-qualified names of the classes
-# we're using for the constants.
-#
-# Methods and properties for PermissionSetting classes are set in the 
-# PermissionSettingMetaClass. See _setDescription and getDescription
-# for an example.
-#
-# Except in the case of __str__ and __repr__, adding a method to the
-# metaclass is equivalent to adding a classmethod to the class.
-# So, _setDescription and getDescription could have been added
-# to PermissionSetting as classmethods.
-
-class PermissionSettingMetaClass(type):
-    def __init__(self, name, bases, namespace):
-        type.__init__(self, name, bases, namespace)
-        self._name=name
-        
-    def __str__(self):
-        return "PermissionSetting: %s" % self._name
-        
-    def _setDescription(self, description):
-        self._description=description
+
+class PermissionSetting(object):
+    """PermissionSettings should be considered as immutable.
+    They can be compared by identity. They are identified by
+    their name.
+    """
+
+    def __new__(cls, name, description=None):
+        """Keep a dict of PermissionSetting instances, indexed by
+        name. If the name already exists in the dict, return that
+        instance rather than creating a new one.
+        """
+        instances = cls.__dict__.get('__instances__')
+        if instances is None:
+            cls.__instances__ = instances = {}
+        it = instances.get(name)
+        if it is None:
+            instances[name] = it = object.__new__(cls)
+            it._init(name, description)
+        return it
+                
+    def _init(self, name, description):
+        self.__name = name
+        self.__description = description    
     
     def getDescription(self):
-        return self._description
-           
-class PermissionSetting(object):
-    __metaclass__=PermissionSettingMetaClass
-    def __init__(self):
-        raise TypeError, "Cannot instantiate PermissionSetting objects"
+        return self.__description
+        
+    def getName(self):
+        return self.__name
+        
+    def __str__(self):
+        return "PermissionSetting: %s" % self.__name
 
+# register PermissionSettings to be symbolic constants by identity, 
+# even when pickled and unpickled.
+import copy_reg
+copy_reg.constructor(PermissionSetting)
+copy_reg.pickle(PermissionSetting,
+                PermissionSetting.getName,
+                PermissionSetting)
 
 
-class Allow(PermissionSetting): pass
-Allow._setDescription('Explicit allow setting for permissions')
+        
+Allow = PermissionSetting('Allow',
+    'Explicit allow setting for permissions')
 
-class Deny(PermissionSetting): pass
-Deny._setDescription('Explicit deny setting for permissions')
+Deny = PermissionSetting('Deny',
+    'Explicit deny setting for permissions')
 
-class Unset(PermissionSetting): pass
-Unset._setDescription(
-  'Unset constant that denotes no setting for permission and role')
+Unset = PermissionSetting('Unset',
+    'Unset constant that denotes no setting for permission and role')
 
-class Assign(PermissionSetting): pass
-Assign._setDescription('Explicit assign setting for roles')
+Assign = PermissionSetting('Assign',
+    'Explicit assign setting for roles')
 
-class Remove(PermissionSetting): pass
-Remove._setDescription('Explicit remove setting for roles')
+Remove = PermissionSetting('Remove',
+    'Explicit remove setting for roles')