compat zope-2.12
[GroupUserFolder.git] / class_utility.py
1 # -*- coding: utf-8 -*-
2 ## GroupUserFolder
3 ## Copyright (C)2006 Ingeniweb
4
5 ## This program 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 2 of the License, or
8 ## (at your option) any later version.
9
10 ## This program 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 this program; see the file COPYING. If not, write to the
17 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 """
19
20 """
21 __version__ = "$Revision: $"
22 # $Source: $
23 # $Id: class_utility.py 30098 2006-09-08 12:35:01Z encolpe $
24 __docformat__ = 'restructuredtext'
25
26 import string
27 import re
28 import threading
29 import string
30
31 # Base classes global vars management
32 _BASECLASSESLOCK = threading.RLock()
33 _BASECLASSES = {}
34 _BASEMETALOCK = threading.RLock()
35 _BASEMETA = {}
36
37 def showaq(self, indent=''):
38 "showaq"
39 rval = ""
40 obj = self
41 base = getattr(obj, 'aq_base', obj)
42 try: id = base.id
43 except: id = str(base)
44 try: id = id()
45 except: pass
46
47 if hasattr(obj, 'aq_self'):
48 if hasattr(obj.aq_self, 'aq_self'):
49 rval = rval + indent + "(" + id + ")\n"
50 rval = rval + indent + "| \\\n"
51 rval = rval + showaq(obj.aq_self, '| ' + indent)
52 rval = rval + indent + "|\n"
53 if hasattr(obj, 'aq_parent'):
54 rval = rval + indent + id + "\n"
55 rval = rval + indent + "|\n"
56 rval = rval + showaq(obj.aq_parent, indent)
57 else:
58 rval = rval + indent + id + "\n"
59 return rval
60
61
62 def listBaseMetaTypes(cl, reverse = 0):
63 """
64 listBaseMetaTypes(cl, reverse = 0) => list of strings
65
66 List all base meta types for this class.
67 """
68 # Look for the class in _BASEMETA cache
69 try:
70 return _BASEMETA[cl][reverse]
71
72 except KeyError:
73 _populateBaseMetaTypes(cl)
74 return listBaseMetaTypes(cl, reverse)
75
76 def isBaseMetaType(meta, cl):
77 try:
78 return _BASEMETA[cl][2].has_key(meta)
79
80 except KeyError:
81 _populateBaseMetaTypes(cl)
82 return isBaseMetaType(meta, cl)
83
84 def _populateBaseMetaTypes(cl):
85 """Fill the base classes structure"""
86 # Fill the base classes list
87 try:
88 ret = [cl.meta_type]
89 except AttributeError:
90 ret = []
91
92 for b in cl.__bases__:
93 ret = list(listBaseMetaTypes(b, 1)) + ret
94
95 # Fill the base classes dict
96 bases = {}
97 for b in ret:
98 bases[b] = 1
99
100 _BASEMETALOCK.acquire()
101 try:
102 rev = ret[:]
103 rev.reverse()
104 _BASEMETA[cl] = (tuple(rev), tuple(ret), bases)
105 finally:
106 _BASEMETALOCK.release()
107
108 def objectIds(container, meta_types = []):
109 """
110 """
111 return map(lambda x: x[0], objectItems(container, meta_types))
112
113 def objectValues(container, meta_types = []):
114 """
115 """
116 return map(lambda x: x[1], objectItems(container, meta_types))
117
118 def objectItems(container, meta_types = []):
119 """
120 objectItems(container, meta_types = [])
121 Same as a container's objectItem method, meta_types are scanned in the base classes too.
122 Ie. all objects derivated from Folder will be returned by objectItem(x, ['Folder'])
123 """
124 # Convert input type
125 if type(meta_types) not in (type(()), type([])):
126 meta_types = [meta_types]
127
128 # Special case where meta_types is empty
129 if not meta_types:
130 return container.objectItems()
131
132 # Otherwise : check parent for each meta_type
133 ret = []
134 for (id, obj) in container.objectItems():
135 for mt in meta_types:
136 if isBaseMetaType(mt, obj.__class__):
137 ret.append((id, obj))
138 break
139
140 return ret
141
142
143
144 def listBaseClasses(cl, reverse = 0):
145 """
146 listBaseClasses(cl, reverse = 0) => list of classes
147
148 List all the base classes of an object.
149 When reverse is 0, return the self class first.
150 When reverse is 1, return the self class last.
151
152 WARNING : reverse is 0 or 1, it is an integer, NOT A BOOLEAN ! (optim issue)
153
154 CACHE RESULTS
155
156 WARNING : for optimization issues, the ORIGINAL tuple is returned : please do not change it !
157 """
158 # Look for the class in _BASECLASSES cache
159 try:
160 return _BASECLASSES[cl][reverse]
161
162 except:
163 _populateBaseClasses(cl)
164 return listBaseClasses(cl, reverse)
165
166
167 def isBaseClass(base, cl):
168 """
169 isBaseClass(base, cl) => Boolean
170 Return true if base is a base class of cl
171 """
172 try:
173 return _BASECLASSES[cl][2].has_key(base)
174 except:
175 _populateBaseClasses(cl)
176 return isBaseClass(base, cl)
177
178
179 def _populateBaseClasses(cl):
180 """Fill the base classes structure"""
181 # Fill the base classes list
182 ret = [cl]
183 for b in cl.__bases__:
184 ret = list(listBaseClasses(b, 1)) + ret
185
186 # Fill the base classes dict
187 bases = {}
188 for b in ret:
189 bases[b] = 1
190
191 _BASECLASSESLOCK.acquire()
192 try:
193 rev = ret[:]
194 rev.reverse()
195 _BASECLASSES[cl] = (tuple(rev), tuple(ret), bases)
196 finally:
197 _BASECLASSESLOCK.release()