def add_branch(self, node, branch, test_repeating=True, update_stats=True): """ add branch to node as child only limitation is that the same attribute does not appear multiple times along the path from top to bottom """ # assert valid condition if not self.finalized: raise StatisticError('stat must be finalized before modification') if test_repeating: self.test_repeated_attribute(node, branch) self.test_repeated_value(node, branch) # no exception means no repeating attributes or repeating not checked # add branch to node as child # clone branch branch_to_add = branch.clone branch_to_add.set_level_recursive(node.level+1) branch_to_add.parent = node node.children.append(branch_to_add) # adjust weights proportionally if update_stats: node.balance_weights()
def test_repeated_value(self, dest_node, branch): """ test if value in root node of branch conflict with values in dest_node's child """ for child in dest_node.children: if child.value == branch.value: raise StatisticError("Source node value [%s] already exists as destination node's children" % branch.value)
def set_child_weights(self, node, weights): """ change the weight for a node in the tree. """ # assert valid condition if not self.finalized: raise StatisticError('stat must be finalized before modification') # recursively set weights, see StatisticNodes.set_child_weights node.set_child_weights(weights)
def from_xml(self, xmlnode): """ construct statistic tree from given XML document """ # perform checking on the node if not isinstance(xmlnode, ElementTree._ElementInterface): raise StatisticError('input must be of type xml.etree.ElementTree.Element'); # clean existing stats del self.root # create new stats tree self.root = StatisticNode(None, 'root') self.root.from_xml(xmlnode)
def delete_branch(self, node): """ recursively delete node and all its children redistribute its weight amongst its siblings """ # assert valid condition if not self.finalized: raise StatisticError('stat must be finalized before modification') parent = node.parent parent.children.remove(node) parent.balance_weights()
def delete_node(self, node): """ delete given node, distribute its weight to sibling nodes equally throws exception if node is only child """ # assert valid condition if not self.finalized: raise StatisticError('stat must be finalized before modification') # recursive delete, see StatisticNodes.delete_node parent = node.parent parent.delete_node(node)
def add_case(self, taxstr, parse_order=None, parse_modifiers=True, additional_data={}, add_times=1): """ add new case of the structural type (taxstr) to the distribution tree using given parse_order additional_data is aggregated at the leaf node only """ # assert valid condition if self.finalized: raise StatisticError('Statistics is already finalized and cannot be modified') # set parse_order if parse_order is None: parse_order = self.default_parse_order # parse string bldg_attrs = self.taxonomy.parse(taxstr) # update tree starting from root for i in range(add_times): self.root.add(bldg_attrs, parse_order, 0, additional_data)
def test_repeated_attribute(self, dest_node, branch): """ test if node from is already child node """ # make sure attributes above node does not have the attribute # already defined existing_attributes = dest_node.ancestor_names existing_attributes.append(dest_node.name) attributes_to_insert = branch.descendant_names attributes_to_insert.insert(0, branch.name) for attr in attributes_to_insert: try: existing_attributes.index(attr) # if attr already in attribute list, it means repeat # which in this case is an error raise StatisticError('Repeating attribute [%s] already exists in source and destination' % attr) except ValueError: # error means attr not in attributes # which is the acceptable condition pass
def set_attribute_skip(self, level, skip): """ change skip condition for given level """ if level > len(self.skips): raise StatisticError("index exceeds number of attributes") self.skips[level] = skip
def from_xml_str(self, xmlstr): """ construct statistic tree from given XML string """ if not isinstance(xmlstr, str): raise StatisticError('input must be string') self.from_xml(ElementTree.fromstring(xmlstr))