def copy_component_and_dependencies(target, c): c.copy(target) for f in id_sort(c.features): if isinstance(f, sbol3.SubComponent): copy_toplevel_and_dependencies(target, f.instance_of.lookup()) for s in id_sort(c.sequences): copy_toplevel_and_dependencies(target, s.lookup())
def all_in_role(interaction: sbol3.Interaction, role: str) -> List[sbol3.Feature]: """Find the features with a given role in the interaction :param interaction: interaction to search :param role: role to search for :return sorted list of Features playing that role """ return id_sort([ p.participant.lookup() for p in interaction.participations if role in p.roles ])
def sort_owned_objects(self): """Patch to stabilize order returned in cloning, part of the pySBOL3 issue #231 workaround""" for k in self._owned_objects.keys(): self._owned_objects[k] = id_sort(self._owned_objects[k])
def copy_collection_and_dependencies(target, c): c.copy(target) for m in id_sort(c.members): copy_toplevel_and_dependencies(target, m.lookup())
def order_subcomponents( component: sbol3.Component ) -> Union[Tuple[List[sbol3.Feature], bool], None]: """Attempt to find a sorted order of features in an SBOL Component, so its sequence can be calculated from theirs Conduct the sort by walking through one meet relation at a time (excepting a circular component) :param component: Component whose features are to be oreered :return: if the features can be ordered, return a list of features in the order that they should be joined and a boolean indicating if it's circular. If the features cannot be ordered, return None """ # first, check for circularity of the construct circular_components = id_sort(f for f in component.features if is_plasmid(f)) circular = len(circular_components) > 0 # if there are no features, then no sequence can be computed if not component.features: return None # if there's precisely one feature, it doesn't need ordering if len(component.features) == 1: return [component.features[0]], circular # otherwise, for N components, we should have a chain of N-1 meetings (possibly excepting one circular) order = [] meetings = { c for c in component.constraints if c.restriction == sbol3.SBOL_MEETS } # given a potential loop, designate the first circular component as the loop and remove any meetings starting there if circular and len(meetings) == len(component.features): meetings -= { m for m in meetings if m.subject == circular_components[0].identity } unordered = list(component.features) while meetings: # Meetings that can go next are any that are a subject and not an object unblocked = {m.subject.lookup() for m in meetings } - {m.object.lookup() for m in meetings} if len(unblocked ) != 1: # if it's not an unambiguous single, we're sunk return None # add to the order subject = unblocked.pop() subject_meetings = { m for m in meetings if m.subject.lookup() is subject } assert len( subject_meetings) == 1 # should be precisely one with the subject order.append(subject) unordered.remove(subject) meetings -= subject_meetings if len( meetings ) == 0: # if we just did the final meeting, add the object on the end object = subject_meetings.pop().object.lookup() order.append(object) # add the last one unordered.remove(object) # if all components have been ordered, then return the order assert unordered or (len(order) == len(component.features)) return (order if not unordered else None), circular