Example #1
0
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())
Example #2
0
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
    ])
Example #3
0
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])
Example #4
0
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