Deleted code:

30 December 2017 (Saturday)—7:39:09 PM

In Wikiweb:
    def get_pin_ancestors(self, pin): #e.g. context_name="tags", node_name="fruit" will yield what tags fruit, and all ancestral pins that are meant to automatically tag fruit as a result (rather than what fruit is tagged by)
        ancestors=set();
        node_name=pin[0];
        context_name=pin[1];
        nobj=self.nnno[node_name];
        cobj=self.cnco[context_name];
        for x in nobj.relations[cobj.cross].node_objects:
            ancestors.add(x);
            ancestors.update(self.get_pin_ancestors((x.name, context_name)));
        return ancestors;
    def get_pin_descendants(self, pin): #e.g. node_name=fruit, context_name=tags (this tells us all the nodes that fruit tags, and all the descendant nodes that are meant to automatically be pinned by this pin as a result of being pinned by fruit, tags)
        #Gets a list of all nodes that are pinned with this pin (or any of its descendant pins: e.g. a pin whose primary node is pinned by the aforementioned pin).
        node_name=pin[0];
        context_name=pin[1];
        descendants=set();
        nobj=self.nnno[node_name];
        cobj=self.cnco[context_name];
        for x in nobj.relations[cobj].node_objects:
            descendants.add(x);
            descendants.update(self.get_pin_descendants((x.name, context_name)));
        return descendants;

At the end of Wikiweb.make_relation():
            if relation_func==False and inheritance==True: #We don’t want to do this when we’re calling make_relation from within self.INHERIT_ANCESTORS and self.INHERIT_DESCENDANTS, as that would be redundant.
                for x in relative_node_names_copy:
                    if len(relative_node_names)==0:
                        #x itself needs to inherit, too; it doesn’t here.
                        
                        print(node_name, context_name);
                        print(relative_node_names_copy);
                        print(relative_node_names);
                        #print("Inheritance is "+str(inheritance)); #Remove this when you’ve fixed the data entry methods so they support optional inheritance (rather than enforced inheritance).
                        #&&&&raise ValueError("Remove this error when you finish the above debugging.");
                        
                        self.INHERIT_ANCESTORS((node_name, context_name, x));
                        self.INHERIT_DESCENDANTS((node_name, context_name, x));
                    else:
                        self.INHERIT_ANCESTORS((node_name, context_name, x));
                        self.INHERIT_DESCENDANTS((node_name, context_name, x));
    
In Wikiweb
    def INHERIT_ANCESTORS(self, pin):
        #This causes the secondary node to inherit all the heritable ancestral pins of (primary_node, context). Note: all pins are heritable by default. Use self.set_pin_inheritance to change that per pin.
        pobj, cobj, sobj=self.opin(pin);
        to_add=set();
        if cobj.cross in pobj.relations:
            for x in pobj.relations[cobj.cross].node_objects:
                if self.get_pin_ancestor_inheritance((x.name, cobj.name))==True:
                    if self.is_related(x.name, cobj.name, sobj.name)==False:
                        to_add.add((x.name, cobj.name, sobj.name));
                        #self.make_relation(x.name, cobj.name, sobj.name, relation_func=True);
                    self.INHERIT_ANCESTORS((x.name, cobj.name, sobj.name));
        for x in to_add:
            self.make_relation(*x, relation_func=True);
    def INHERIT_DESCENDANTS(self, pin):
        #This makes it so when you add an ancestor relation, it makes all the heritable descendants inherit its pins.
        """
        USA-Idaho-Payette-New Plymouth
        if Idaho already pins Payette and Payette already pins New Plymouth, we need USA to pin all of them if we add USA after the fact.
        INHERIT_ANCESTORS, however, would just make it so when you add New Plymouth to Payette, it’ll add Idaho and USA to New Plymouth, too.
        
        USA, includes, Idaho should make USA include Payette and New Plymouth
        """
        pobj, cobj, sobj=self.opin(pin);
        to_add=set();
        if cobj in sobj.relations:
            for x in sobj.relations[cobj].node_objects:
                if self.get_pin_descendant_inheritance((x.name, cobj.cross.name))==True:
                    if self.is_related(x.name, cobj.cross.name, pobj.name)==False:
                        to_add.add((x.name, cobj.cross.name, pobj.name));
                        #self.make_relation(x.name, cobj.cross.name, pobj.name, relation_func=True);
                    self.INHERIT_DESCENDANTS((pobj.name, cobj.name, x.name));
        for x in to_add:
            self.make_relation(*x, relation_func=True);







Oldest:

    constructor:
    #self.implied_pins=DictRequireExistence(self.nnno, self.cnco); #Keys are object pins, and values are sets of object pins that they imply. Whenever you add one of these pins, add the others. Whenever you remove a key, optionally remove the pins they imply (have methods for this). Deleting a node or context will delete any implied pins that use it.
    #self.implied_pin_removal=DictRequireExistence(self.nnno, self.cnco); #This is like implied_pins, but these pins are removed when you remove a pin (they aren’t necessarily the same pins added with implied_pins (but generally they would be). Deleting a node or context will delete any implied pin removal pins that use it (and unpin anything pinned with those pins).

    in make_relation:
        #self.pin_implied((node_name, context_name));
    
    in disconnect:
        """
        #Remove any pin references to this node in self.implied_pins and self.implied_pin_removal.
        for pin in self.implied_pins.copy():
            if pin[0].name==name:
                del self.implied_pins[pin];
            else:
                for pin2 in self.implied_pins[pin].copy():
                    if pin2[0].name==name:
                        self.implied_pins[pin].remove(pin2);
        for pin in self.implied_pin_removal.copy():
            if pin[0].name==name:
                del self.implied_pin_removal[pin];
            else:
                for pin2 in self.implied_pin_removal[pin].copy():
                    if pin2[0].name==name:
                        self.implied_pin_removal[pin].remove(pin2);
        """
    
    in del_context:
        """
        #Delete any implied pins that involve the deleted context or crossed context.
        for x in self.implied_pins.copy():
            if x[1]==obj or x[1]==cross_obj:
                del self.implied_pins[x];
            else:
                for y in self.implied_pins[x].copy():
                    if y[1]==obj or y[1]==cross_obj:
                        self.implied_pins[x].remove(y);
        for x in self.implied_pin_removal.copy():
            if x[1]==obj or x[1]==cross_obj:
                del self.implied_pin_removal[x];
            else:
                for y in self.implied_pin_removal[x].copy():
                    if y[1]==obj or y[1]==cross_obj:
                        self.implied_pin_removal[x].remove(y);
        """

    def get_ancestral_implied_pins(self, pin, include_self=True):
        #Get pin ancestors and then get all their implied pins (you may want to include the implied pins of the source pin, too). Do removal methods, too.
        ancestors=self.get_pin_ancestors(pin);
        implied=set();
        if include_self==True:
            implied.update(self.get_implied_pins(pin));
        for x in ancestors:
            if (x, self.cnco[pin[1]]) in self.implied_pins:
                implied.update(self.implied_pins[(x, self.cnco[pin[1]])]);
        return implied;
    def get_descendant_implied_pins(self, pin, include_self=True):
        #Get pin descendants and then get all their implied pins (you may want to include the implied pins of the source pin, too). Do removal methods, too.
        descendants=self.get_pin_descendants(pin);
        implied=set();
        if include_self==True:
            implied.update(self.get_implied_pins(pin));
        for x in descendants:
            if (x, self.cnco[pin[1]]) in self.implied_pins:
                implied.update(self.implied_pins[(x, self.cnco[pin[1]])]);
        return implied;
    def get_implied_pins(self, pin, kind=None):
        #Get the implied pins for a particular pin (if kind is "asc" then include ancestral implied pins; if kind is "desc" then include descendant implied pins; if None, just give it’s own implied pins; if "all", give them all)
        if kind=="asc": #Ascending (ancestral)
            return self.get_ancestral_implied_pins(pin);
        elif kind=="desc": #Descending (descendant)
            return self.get_descendant_implied_pins(pin);
        elif kind=="all":
            return self.get_ancestral_implied_pins(pin) + self.get_descendant_implied_pins(pin, include_self=False);
        elif ancestral==None:
            return self.implied_pins[(self.nnno[pin[0]], self.cnco[pin[0]])];
    def imply_pin(self, pin, *implied_pins, two_way=False):
        #This allows you to make it so when you add a specific pin, other specific pins are automatically added.
        #two_way makes it so these are also mirrored in implied_pin_removal.
        #two_way is False by default because the program doesn’t keep track of how the pin was added (so, it may remove some pins that you wouldn’t want removed).
        #&&&&Make it so it can optionally pin nodes that have previously been related, too (as long as they fall under this pin). Same for imply_pin_removal.
        if two_way==True:
            self.imply_pin_removal(pin, *implied_pins);
        if isinstance(pin, tuple)==False:
            raise ValueError("Pins must be tuples.");
        pin=(self.nnno[pin[0]], self.cnco[pin[1]]);
        if pin not in self.implied_pins:
            self.implied_pins[pin]=set();
        for implied_pin in implied_pins:
            if isinstance(implied_pin, tuple)==False:
                raise ValueError("Implied pins must be tuples.");
            implied_pin=(self.nnno[implied_pin[0]], self.cnco[implied_pin[1]]);
            self.implied_pins[pin].add(implied_pin);
    def imply_pins(self, pin, *implied_pins, two_way=True):
        self.imply_pin(pin, *implied_pins, two_way);
    def pin_implied(self, pin):
        #This takes a pin and make sure every node that is pinned with it is also pinned with all of this pin’s implied pins.
        nobj=self.nnno[pin[0]];
        cobj=self.cnco[pin[1]];
        if (nobj, cobj) in self.implied_pins:
            for implied in self.implied_pins[(nobj, cobj)]:
                for node in nobj.relations[cobj].node_objects:
                    if implied[1] not in implied[0].relations:
                        #raise KeyError("You have a pin in self.implied_pins where the relation between the primary node and the context does not exist.");
                        self.make_relation(implied[0].name, implied[1].name, node.name);
                    else:
                        if node not in implied[0].relations[implied[1]].node_objects:
                            self.make_relation(implied[0].name, implied[1].name, node.name);
    def get_ancestral_implied_pin_removal(self, pin, include_self=True):
        #Get pin ancestors and then get all their implied pin removal (you may want to include the implied pin removal of the source pin, too).
        ancestors=self.get_pin_ancestors(pin);
        implied=set();
        if include_self==True:
            implied.update(self.get_implied_pin_removal(pin));
        for x in ancestors:
            if (x, self.cnco[pin[1]]) in self.implied_pin_removal:
                implied.update(self.implied_pin_removal[(x, self.cnco[pin[1]])]);
        return implied;
    def get_descendant_implied_pin_removal(self, pin, include_self=True):
        #Get pin descendants and then get all their implied pin removal (you may want to include the implied pin removal of the source pin, too).
        descendants=self.get_pin_descendants(pin);
        implied=set();
        if include_self==True:
            implied.update(self.get_implied_pin_removal(pin));
        for x in descendants:
            if (x, self.cnco[pin[1]]) in self.implied_pin_removal:
                implied.update(self.implied_pin_removal[(x, self.cnco[pin[1]])]);
        return implied;
    def get_implied_pin_removal(self, pin, kind=None):
        #Get the implied pin removal for a particular pin (if kind is "asc" then include ancestral implied pins; if kind is "desc" then include descendant implied pins; if None, just give it’s own implied pins; if "all", give them all)
        if kind=="asc": #Ascending (ancestral)
            return self.get_ancestral_implied_pin_removal(pin);
        elif kind=="desc": #Descending (descendant)
            return self.get_descendant_implied_pin_removal(pin);
        elif kind=="all":
            return self.get_ancestral_implied_pin_removal(pin) + self.get_descendant_implied_pin_removal(pin, include_self=False);
        elif ancestral==None:
            return self.implied_pin_removal[(self.nnno[pin[0]], self.cnco[pin[0]])];
    def imply_pin_removal(self, pin, *implied_pins):
        #This allows you to make it so when you remove a specific pin that other specific pins are automatically removed. This adds implied pins to the list of implied pins (unpin_implied is what actually unpins them).
        if isinstance(pin, tuple)==False:
            raise ValueError("Pins must be tuples.");
        pin=(self.nnno[pin[0]], self.cnco[pin[1]]);
        if pin not in self.implied_pin_removal:
            self.implied_pin_removal[pin]=set();
        for implied_pin in implied_pins:
            if isinstance(implied_pin, tuple)==False:
                raise ValueError("Implied pins must be tuples.");
            implied_pin=(self.nnno[implied_pin[0]], self.cnco[implied_pin[1]]);
            self.implied_pin_removal[pin].add(implied_pin);
    def unpin_implied(self, pin, node_name):
        pin=self.opin(pin);
        nobj=self.nnno[node_name];
        for implied in self.pin_removal[pin]:
            if nobj in implied[0].relations[implied[1]].node_objects:
                self.remove_relation(implied[0].name, implied[1].name, nobj.name);
    def unpin_implied_all(self, pin):
        #This takes a pin and unpins all of its implied pin removal pins from all pins that are pinned with it.
        nobj=self.nnno[pin[0]];
        cobj=self.cnco[pin[1]];
        if (nobj, cobj) in self.implied_pin_removal:
            for implied in self.implied_pin_removal[(nobj, cobj)]:
                for node in nobj.relations[cobj].node_objects:
                    if implied[1] not in implied[0].relations:
                        #raise KeyError("You have a pin in self.implied_pin_removal where the relation between the primary node and the context does not exist.");
                        pass;
                    else:
                        if node in implied[0].relations[implied[1]].node_objects:
                            self.remove_relation(implied[0].name, implied[1].name, node.name);

From dp_wikiweb.py:
                elif kind in {"imply pin", "set implied pins", "imply pins"}:
                    for line in instructions:
                        if line.startswith("[") and line.endswith("]"):
                            line=ast.literal_eval(line.strip());
                        else:
                            line=ast.literal_eval("["+line.strip()+"]");
                        self.imply_pin(*line);
                elif kind in {"imply pin removal", "set implied pin removal", "imply pin removal pins"}:
                    for line in instructions:
                        if line.startswith("[") and line.endswith("]"):
                            line=ast.literal_eval(line.strip());
                        else:
                            line=ast.literal_eval("["+line.strip()+"]");
                        self.imply_pin_removal(*line);