1.1 --- a/micropython/inspect.py Sat Feb 23 21:25:03 2008 +0100
1.2 +++ b/micropython/inspect.py Sun Feb 24 01:27:16 2008 +0100
1.3 @@ -108,7 +108,6 @@
1.4 self.namespace = {}
1.5 self.globals = set()
1.6 self.global_namespace = global_namespace
1.7 - self.attr_position = 0
1.8
1.9 def __getitem__(self, name):
1.10 return self.namespace[name]
1.11 @@ -157,8 +156,7 @@
1.12 "The underlying set operation associating 'name' with 'value'."
1.13
1.14 if not self.namespace.has_key(name):
1.15 - self.namespace[name] = Attr(self.attr_position, self, name, value)
1.16 - self.attr_position += 1
1.17 + self.namespace[name] = Attr(None, self, name, value)
1.18 return self.namespace[name]
1.19
1.20 def __delitem__(self, name):
1.21 @@ -188,12 +186,22 @@
1.22 else:
1.23 return None
1.24
1.25 - def to_list(self, d):
1.26 - l = [None] * len(d.keys())
1.27 - for attr in d.values():
1.28 + def attributes_as_list(self):
1.29 + self.finalise_attributes()
1.30 + l = [None] * len(self.keys())
1.31 + for attr in self.values():
1.32 l[attr.position] = attr
1.33 return l
1.34
1.35 + def finalise_attributes(self):
1.36 +
1.37 + "Make sure all attributes are fully defined."
1.38 +
1.39 + # The default action is to assign attribute positions sequentially.
1.40 +
1.41 + for i, attr in enumerate(self.values()):
1.42 + attr.position = i
1.43 +
1.44 class Naming:
1.45
1.46 "A mix-in providing naming conveniences."
1.47 @@ -284,9 +292,9 @@
1.48
1.49 self.bases = []
1.50 self.instattr = set() # instance attributes
1.51 - self.instattr_relocated = set() # instance attributes which do not have
1.52 - # the same position as those of the same
1.53 - # name in some superclasses
1.54 + self.relocated = set() # attributes which do not have the same
1.55 + # position as those of the same name in
1.56 + # some superclasses
1.57
1.58 # Caches.
1.59
1.60 @@ -308,6 +316,15 @@
1.61 else:
1.62 return "Class(%r, %r)" % (self.name, self.parent_name)
1.63
1.64 + def finalise_attributes(self):
1.65 +
1.66 + "Make sure that all attributes are fully defined."
1.67 +
1.68 + self.finalise_class_attributes()
1.69 + self.finalise_instance_attributes()
1.70 +
1.71 + # Class-specific methods.
1.72 +
1.73 def add_base(self, base):
1.74 self.bases.append(base)
1.75
1.76 @@ -322,6 +339,7 @@
1.77
1.78 "Return class attributes provided by this class only."
1.79
1.80 + self.finalise_class_attributes()
1.81 return self
1.82
1.83 def all_class_attribute_names(self):
1.84 @@ -336,19 +354,46 @@
1.85
1.86 "Return all class attributes, indicating the class which provides them."
1.87
1.88 + self.finalise_class_attributes()
1.89 + return self.all_classattr
1.90 +
1.91 + def finalise_class_attributes(self):
1.92 +
1.93 + "Make sure that the class attributes are fully defined."
1.94 +
1.95 if self.all_classattr is None:
1.96 self.all_classattr = {}
1.97 + clsattr = {}
1.98 +
1.99 + # Record provisional position information for attributes of this
1.100 + # class.
1.101 +
1.102 + for name in self.class_attributes().keys():
1.103 + clsattr[name] = set() # position not yet defined
1.104
1.105 reversed_bases = self.bases[:]
1.106 reversed_bases.reverse()
1.107 +
1.108 + # For the bases in reverse order, acquire class attribute details.
1.109 +
1.110 for cls in reversed_bases:
1.111 - self.all_classattr.update(cls.all_class_attributes())
1.112 + for name, attr in cls.all_class_attributes().items():
1.113 + self.all_classattr[name] = attr
1.114
1.115 - # Record attributes provided by this class, along with their
1.116 - # positions.
1.117 + # Record previous attribute information.
1.118 +
1.119 + if clsattr.has_key(name):
1.120 + clsattr[name].add(attr.position)
1.121 +
1.122 + # Record class attributes provided by this class and its bases,
1.123 + # along with their positions.
1.124
1.125 self.all_classattr.update(self.class_attributes())
1.126
1.127 + if clsattr:
1.128 + for i, name in enumerate(self._get_position_list(clsattr)):
1.129 + self.all_classattr[name].position = i
1.130 +
1.131 return self.all_classattr
1.132
1.133 def instance_attribute_names(self):
1.134 @@ -363,10 +408,23 @@
1.135
1.136 "Return instance-only attributes for instances of this class."
1.137
1.138 + self.finalise_instance_attributes()
1.139 + return self.all_instattr
1.140 +
1.141 + def finalise_instance_attributes(self):
1.142 +
1.143 + "Make sure that the instance attributes are fully defined."
1.144 +
1.145 if self.all_instattr is None:
1.146 self.all_instattr = {}
1.147 instattr = {}
1.148
1.149 + # Record provisional position information for attributes of this
1.150 + # instance.
1.151 +
1.152 + for name in self.instattr:
1.153 + instattr[name] = set() # position not yet defined
1.154 +
1.155 reversed_bases = self.bases[:]
1.156 reversed_bases.reverse()
1.157
1.158 @@ -375,16 +433,11 @@
1.159
1.160 for cls in reversed_bases:
1.161 for name, attr in cls.instance_attributes().items():
1.162 - if not instattr.has_key(name):
1.163 - instattr[name] = set()
1.164 - instattr[name].add(attr.position)
1.165 +
1.166 + # Record previous attribute information.
1.167
1.168 - # Record instance attributes provided by this class and its bases,
1.169 - # along with their positions.
1.170 -
1.171 - for name in self.instattr:
1.172 - if not instattr.has_key(name):
1.173 - instattr[name] = set([-1]) # position not yet defined
1.174 + if instattr.has_key(name):
1.175 + instattr[name].add(attr.position)
1.176
1.177 # Cache the attributes by converting the positioned attributes into
1.178 # a dictionary.
1.179 @@ -392,48 +445,63 @@
1.180 if not instattr:
1.181 self.all_instattr = {}
1.182 else:
1.183 - self.all_instattr = dict(self._get_position_list(instattr))
1.184 + self.all_instattr = self._get_attributes(instattr)
1.185
1.186 self.all_instattr_names = self.all_instattr.keys()
1.187
1.188 return self.all_instattr
1.189
1.190 - def _get_position_list(self, instattr):
1.191 + def _get_position_list(self, positions):
1.192
1.193 """
1.194 - Return the instance attributes, 'instattr', as a list indicating the
1.195 - positions of the attributes in the final instance structure.
1.196 + Return a list of attribute names for the given 'positions' mapping from
1.197 + names to positions, indicating the positions of the attributes in the
1.198 + final instance structure.
1.199 """
1.200
1.201 - positions = instattr.items()
1.202 - instarray = [None] * len(positions)
1.203 + position_items = positions.items()
1.204 + namearray = [None] * len(position_items)
1.205
1.206 # Get the positions in ascending order of list size, with lists
1.207 # of the same size ordered according to their smallest position
1.208 # value.
1.209
1.210 - positions.sort(self._cmp_positions)
1.211 - #print self.name, positions
1.212 + position_items.sort(self._cmp_positions)
1.213
1.214 # Get the names in position order.
1.215
1.216 held = []
1.217
1.218 - for name, pos in positions:
1.219 + for name, pos in position_items:
1.220 pos = list(pos)
1.221 - if pos[0] != -1 and instarray[pos[0]] is None:
1.222 - instarray[pos[0]] = name, Attr(pos[0], None, name)
1.223 + if pos and namearray[pos[0]] is None:
1.224 + namearray[pos[0]] = name
1.225 else:
1.226 - if pos[0] != -1 or len(pos) > 1:
1.227 - self.instattr_relocated.add(name)
1.228 + if pos:
1.229 + self.relocated.add(name)
1.230 held.append((name, pos))
1.231
1.232 - for i, attr in enumerate(instarray):
1.233 + for i, attr in enumerate(namearray):
1.234 if attr is None:
1.235 name, pos = held.pop()
1.236 - instarray[i] = name, Attr(i, None, name)
1.237 + namearray[i] = name
1.238 +
1.239 + #print self.name, positions
1.240 + #print "->", namearray
1.241 + return namearray
1.242 +
1.243 + def _get_attributes(self, positions):
1.244
1.245 - return instarray
1.246 + """
1.247 + For the given 'positions' mapping from names to positions, return a
1.248 + dictionary mapping names to Attr instances incorporating information
1.249 + about their positions in the final instance structure.
1.250 + """
1.251 +
1.252 + d = {}
1.253 + for i, name in enumerate(self._get_position_list(positions)):
1.254 + d[name] = Attr(i, None, None, name)
1.255 + return d
1.256
1.257 def _cmp_positions(self, a, b):
1.258
1.259 @@ -445,6 +513,8 @@
1.260 return -1
1.261 elif len(list_a) > len(list_b):
1.262 return 1
1.263 + elif not list_a:
1.264 + return 0
1.265 else:
1.266 return cmp(min(list_a), min(list_b))
1.267