3.1 --- a/micropython/inspect.py Sat Feb 23 21:25:03 2008 +0100
3.2 +++ b/micropython/inspect.py Sun Feb 24 01:27:16 2008 +0100
3.3 @@ -108,7 +108,6 @@
3.4 self.namespace = {}
3.5 self.globals = set()
3.6 self.global_namespace = global_namespace
3.7 - self.attr_position = 0
3.8
3.9 def __getitem__(self, name):
3.10 return self.namespace[name]
3.11 @@ -157,8 +156,7 @@
3.12 "The underlying set operation associating 'name' with 'value'."
3.13
3.14 if not self.namespace.has_key(name):
3.15 - self.namespace[name] = Attr(self.attr_position, self, name, value)
3.16 - self.attr_position += 1
3.17 + self.namespace[name] = Attr(None, self, name, value)
3.18 return self.namespace[name]
3.19
3.20 def __delitem__(self, name):
3.21 @@ -188,12 +186,22 @@
3.22 else:
3.23 return None
3.24
3.25 - def to_list(self, d):
3.26 - l = [None] * len(d.keys())
3.27 - for attr in d.values():
3.28 + def attributes_as_list(self):
3.29 + self.finalise_attributes()
3.30 + l = [None] * len(self.keys())
3.31 + for attr in self.values():
3.32 l[attr.position] = attr
3.33 return l
3.34
3.35 + def finalise_attributes(self):
3.36 +
3.37 + "Make sure all attributes are fully defined."
3.38 +
3.39 + # The default action is to assign attribute positions sequentially.
3.40 +
3.41 + for i, attr in enumerate(self.values()):
3.42 + attr.position = i
3.43 +
3.44 class Naming:
3.45
3.46 "A mix-in providing naming conveniences."
3.47 @@ -284,9 +292,9 @@
3.48
3.49 self.bases = []
3.50 self.instattr = set() # instance attributes
3.51 - self.instattr_relocated = set() # instance attributes which do not have
3.52 - # the same position as those of the same
3.53 - # name in some superclasses
3.54 + self.relocated = set() # attributes which do not have the same
3.55 + # position as those of the same name in
3.56 + # some superclasses
3.57
3.58 # Caches.
3.59
3.60 @@ -308,6 +316,15 @@
3.61 else:
3.62 return "Class(%r, %r)" % (self.name, self.parent_name)
3.63
3.64 + def finalise_attributes(self):
3.65 +
3.66 + "Make sure that all attributes are fully defined."
3.67 +
3.68 + self.finalise_class_attributes()
3.69 + self.finalise_instance_attributes()
3.70 +
3.71 + # Class-specific methods.
3.72 +
3.73 def add_base(self, base):
3.74 self.bases.append(base)
3.75
3.76 @@ -322,6 +339,7 @@
3.77
3.78 "Return class attributes provided by this class only."
3.79
3.80 + self.finalise_class_attributes()
3.81 return self
3.82
3.83 def all_class_attribute_names(self):
3.84 @@ -336,19 +354,46 @@
3.85
3.86 "Return all class attributes, indicating the class which provides them."
3.87
3.88 + self.finalise_class_attributes()
3.89 + return self.all_classattr
3.90 +
3.91 + def finalise_class_attributes(self):
3.92 +
3.93 + "Make sure that the class attributes are fully defined."
3.94 +
3.95 if self.all_classattr is None:
3.96 self.all_classattr = {}
3.97 + clsattr = {}
3.98 +
3.99 + # Record provisional position information for attributes of this
3.100 + # class.
3.101 +
3.102 + for name in self.class_attributes().keys():
3.103 + clsattr[name] = set() # position not yet defined
3.104
3.105 reversed_bases = self.bases[:]
3.106 reversed_bases.reverse()
3.107 +
3.108 + # For the bases in reverse order, acquire class attribute details.
3.109 +
3.110 for cls in reversed_bases:
3.111 - self.all_classattr.update(cls.all_class_attributes())
3.112 + for name, attr in cls.all_class_attributes().items():
3.113 + self.all_classattr[name] = attr
3.114
3.115 - # Record attributes provided by this class, along with their
3.116 - # positions.
3.117 + # Record previous attribute information.
3.118 +
3.119 + if clsattr.has_key(name):
3.120 + clsattr[name].add(attr.position)
3.121 +
3.122 + # Record class attributes provided by this class and its bases,
3.123 + # along with their positions.
3.124
3.125 self.all_classattr.update(self.class_attributes())
3.126
3.127 + if clsattr:
3.128 + for i, name in enumerate(self._get_position_list(clsattr)):
3.129 + self.all_classattr[name].position = i
3.130 +
3.131 return self.all_classattr
3.132
3.133 def instance_attribute_names(self):
3.134 @@ -363,10 +408,23 @@
3.135
3.136 "Return instance-only attributes for instances of this class."
3.137
3.138 + self.finalise_instance_attributes()
3.139 + return self.all_instattr
3.140 +
3.141 + def finalise_instance_attributes(self):
3.142 +
3.143 + "Make sure that the instance attributes are fully defined."
3.144 +
3.145 if self.all_instattr is None:
3.146 self.all_instattr = {}
3.147 instattr = {}
3.148
3.149 + # Record provisional position information for attributes of this
3.150 + # instance.
3.151 +
3.152 + for name in self.instattr:
3.153 + instattr[name] = set() # position not yet defined
3.154 +
3.155 reversed_bases = self.bases[:]
3.156 reversed_bases.reverse()
3.157
3.158 @@ -375,16 +433,11 @@
3.159
3.160 for cls in reversed_bases:
3.161 for name, attr in cls.instance_attributes().items():
3.162 - if not instattr.has_key(name):
3.163 - instattr[name] = set()
3.164 - instattr[name].add(attr.position)
3.165 +
3.166 + # Record previous attribute information.
3.167
3.168 - # Record instance attributes provided by this class and its bases,
3.169 - # along with their positions.
3.170 -
3.171 - for name in self.instattr:
3.172 - if not instattr.has_key(name):
3.173 - instattr[name] = set([-1]) # position not yet defined
3.174 + if instattr.has_key(name):
3.175 + instattr[name].add(attr.position)
3.176
3.177 # Cache the attributes by converting the positioned attributes into
3.178 # a dictionary.
3.179 @@ -392,48 +445,63 @@
3.180 if not instattr:
3.181 self.all_instattr = {}
3.182 else:
3.183 - self.all_instattr = dict(self._get_position_list(instattr))
3.184 + self.all_instattr = self._get_attributes(instattr)
3.185
3.186 self.all_instattr_names = self.all_instattr.keys()
3.187
3.188 return self.all_instattr
3.189
3.190 - def _get_position_list(self, instattr):
3.191 + def _get_position_list(self, positions):
3.192
3.193 """
3.194 - Return the instance attributes, 'instattr', as a list indicating the
3.195 - positions of the attributes in the final instance structure.
3.196 + Return a list of attribute names for the given 'positions' mapping from
3.197 + names to positions, indicating the positions of the attributes in the
3.198 + final instance structure.
3.199 """
3.200
3.201 - positions = instattr.items()
3.202 - instarray = [None] * len(positions)
3.203 + position_items = positions.items()
3.204 + namearray = [None] * len(position_items)
3.205
3.206 # Get the positions in ascending order of list size, with lists
3.207 # of the same size ordered according to their smallest position
3.208 # value.
3.209
3.210 - positions.sort(self._cmp_positions)
3.211 - #print self.name, positions
3.212 + position_items.sort(self._cmp_positions)
3.213
3.214 # Get the names in position order.
3.215
3.216 held = []
3.217
3.218 - for name, pos in positions:
3.219 + for name, pos in position_items:
3.220 pos = list(pos)
3.221 - if pos[0] != -1 and instarray[pos[0]] is None:
3.222 - instarray[pos[0]] = name, Attr(pos[0], None, name)
3.223 + if pos and namearray[pos[0]] is None:
3.224 + namearray[pos[0]] = name
3.225 else:
3.226 - if pos[0] != -1 or len(pos) > 1:
3.227 - self.instattr_relocated.add(name)
3.228 + if pos:
3.229 + self.relocated.add(name)
3.230 held.append((name, pos))
3.231
3.232 - for i, attr in enumerate(instarray):
3.233 + for i, attr in enumerate(namearray):
3.234 if attr is None:
3.235 name, pos = held.pop()
3.236 - instarray[i] = name, Attr(i, None, name)
3.237 + namearray[i] = name
3.238 +
3.239 + #print self.name, positions
3.240 + #print "->", namearray
3.241 + return namearray
3.242 +
3.243 + def _get_attributes(self, positions):
3.244
3.245 - return instarray
3.246 + """
3.247 + For the given 'positions' mapping from names to positions, return a
3.248 + dictionary mapping names to Attr instances incorporating information
3.249 + about their positions in the final instance structure.
3.250 + """
3.251 +
3.252 + d = {}
3.253 + for i, name in enumerate(self._get_position_list(positions)):
3.254 + d[name] = Attr(i, None, None, name)
3.255 + return d
3.256
3.257 def _cmp_positions(self, a, b):
3.258
3.259 @@ -445,6 +513,8 @@
3.260 return -1
3.261 elif len(list_a) > len(list_b):
3.262 return 1
3.263 + elif not list_a:
3.264 + return 0
3.265 else:
3.266 return cmp(min(list_a), min(list_b))
3.267