Beispiel #1
0
def get_ast_obj(belstr, bel_version, component_type: str = ''):
    """Convert AST partialparse dict to BELAst"""

    ast_dict, errors = get_ast_dict(belstr, component_type)

    spec = bel_specification.get_specification(bel_version)

    subj = ast_dict['subject']
    subj_ast = add_ast_fn(subj, spec)

    relation = None
    obj = None

    if 'relation' in ast_dict:
        relation = ast_dict['relation']['name']

    if 'object' in ast_dict:
        obj = ast_dict['object']
        obj_ast = add_ast_fn(obj, spec)

        return BELAst(subj_ast, relation, obj_ast, spec)
    elif 'nested' in ast_dict:
        nested_subj = ast_dict['nested']['subject']
        nested_subj_ast = add_ast_fn(nested_subj, spec)
        nested_relation = ast_dict['nested']['relation']['name']
        nested_obj = ast_dict['nested']['object']
        nested_obj_ast = add_ast_fn(nested_obj, spec)

        return BELAst(subj_ast, relation, BELAst(nested_subj_ast, nested_relation, nested_obj_ast, spec), spec)

    return BELAst(subj_ast, None, None, spec)
Beispiel #2
0
def get_ast_obj(belstr, bel_version, component_type: str = ""):
    """Convert AST partialparse dict to BELAst"""

    ast_dict, errors = get_ast_dict(belstr, component_type)

    spec = bel_specification.get_specification(bel_version)

    subj = ast_dict["subject"]
    subj_ast = add_ast_fn(subj, spec)

    relation = None
    obj = None

    if "relation" in ast_dict:
        relation = ast_dict["relation"]["name"]

    if "object" in ast_dict:
        obj = ast_dict["object"]
        obj_ast = add_ast_fn(obj, spec)

        return BELAst(subj_ast, relation, obj_ast, spec)
    elif "nested" in ast_dict:
        nested_subj = ast_dict["nested"]["subject"]
        nested_subj_ast = add_ast_fn(nested_subj, spec)
        nested_relation = ast_dict["nested"]["relation"]["name"]
        nested_obj = ast_dict["nested"]["object"]
        nested_obj_ast = add_ast_fn(nested_obj, spec)

        return BELAst(
            subj_ast, relation,
            BELAst(nested_subj_ast, nested_relation, nested_obj_ast, spec),
            spec)

    return BELAst(subj_ast, None, None, spec)
Beispiel #3
0
    def parse(self, assertion: AssertionStr = None) -> "BEL":
        """Parse BEL Assertion string"""

        # Add or override assertion string object in parse method
        if assertion is not None:
            self.assertion = assertion
            self.clean_assertion()

        self.ast = BELAst(assertion=assertion, version=self.version)

        return self
Beispiel #4
0
    def __init__(self,
                 assertion: AssertionStr = None,
                 version: str = "latest") -> None:
        """Initialize BEL object used for validating/processing/etc BEL statements

        Args:
            assertion: BEL Assertion
            version: BEL Version - defaults to settings.BEL_DEFAULT_VERSION or latest version
        """

        self.assertion = assertion

        self.clean_assertion()

        self.version = bel.belspec.crud.check_version(version)

        # Validation error/warning messages
        # List[Tuple[str, str]], e.g. [('ERROR', 'this is an error msg'), ('WARNING', 'this is a warning'), ]
        self.validation_messages = []

        self.ast: Optional[BELAst] = None

        if self.assertion:
            self.ast = BELAst(assertion=assertion, version=version)
Beispiel #5
0
def validate_functions(ast: BELAst, bo):
    """Recursively validate function signatures

    Determine if function matches one of the available signatures. Also,

    1. Add entity types to AST NSArg, e.g. Abundance, ...
    2. Add optional to  AST Arg (optional means it is not a
        fixed, required argument and needs to be sorted for
        canonicalization, e.g. reactants(A, B, C) )

    Args:
        bo: bel object

    Returns:
        bel object
    """

    if isinstance(ast, Function):
        log.debug(f"Validating: {ast.name}, {ast.function_type}, {ast.args}")
        function_signatures = bo.spec["functions"]["signatures"][ast.name]["signatures"]

        function_name = ast.name
        (valid_function, messages) = check_function_args(
            ast.args, function_signatures, function_name
        )
        if not valid_function:
            message = ", ".join(messages)
            bo.validation_messages.append(
                (
                    "ERROR",
                    "Invalid BEL Assertion function {} - problem with function signatures: {}".format(
                        ast.to_string(), message
                    ),
                )
            )
            bo.parse_valid = False

    # Recursively process every NSArg by processing BELAst and Functions
    if hasattr(ast, "args"):
        for arg in ast.args:
            validate_functions(arg, bo)

    return bo
Beispiel #6
0
def process_ast(edges, ast, spec):

    if isinstance(ast, BELAst):
        pass

    # TODO composite is not being addressed right now
    # TODO
    elif isinstance(ast, Function):
        if ast.name in ("complex", "complexAbundance"):
            for arg in ast.args:
                edges.append(BELAst(ast, "hasComponent", arg, spec))

        elif ast.name in ("composite", "compositeAbundance"):
            for arg in ast.args:
                edges.append(BELAst(ast, "hasAssociation", arg, spec))

        elif ast.name in ("act", "activity"):
            subject = ast.args[0]
            edge = BELAst(subject, "hasActivity", ast, spec)
            edges.append(edge)

        elif ast.name in ("pmod", "proteinModification"):
            parent = ast.parent_function
            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(parent.args[0])
            edges.append(BELAst(src_abundance, "hasModification", parent,
                                spec))

        elif ast.name in ("var", "variant"):
            parent = ast.parent_function
            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(parent.args[0])
            edges.append(BELAst(src_abundance, "hasVariant", parent, spec))

        elif ast.name in ("frag", "fragment"):
            parent = ast.parent_function
            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(parent.args[0])
            edges.append(BELAst(src_abundance, "hasFragment", parent, spec))

        elif ast.name in ("loc", "location"):
            parent = ast.parent_function
            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(parent.args[0])
            edges.append(BELAst(src_abundance, "hasLocation", parent, spec))

        elif ast.name in ("tloc", "translocation"):
            src_abundance = ast.args[0]
            from_abundance = copy.deepcopy(src_abundance)
            from_loc = Function("loc", spec)
            from_loc.add_argument(ast.args[1].args[0])
            from_abundance.add_argument(from_loc)

            to_abundance = copy.deepcopy(src_abundance)
            to_loc = Function("loc", spec)
            to_loc.add_argument(ast.args[2].args[0])
            to_abundance.add_argument(to_loc)

            edges.append(BELAst(ast, "decreases", from_abundance, spec))
            edges.append(BELAst(ast, "increases", to_abundance, spec))
            edges.append(
                BELAst(src_abundance, "hasLocation", from_abundance, spec))
            edges.append(
                BELAst(src_abundance, "hasLocation", to_abundance, spec))

        elif ast.name in ("sec", "cellSecretion", "surf",
                          "cellSurfaceExpression"):
            target_loc = locations["extracellular"]
            if ast.name in ("surf", "cellSurfaceExpression"):
                target_loc = locations["cellsurface"]

            src_abundance = ast.args[0]
            to_abundance = copy.deepcopy(src_abundance)
            to_loc = Function("loc", spec)
            to_loc.add_argument(target_loc)
            to_abundance.add_argument(to_loc)
            edges.append(BELAst(ast, "increases", to_abundance, spec))
            edges.append(
                BELAst(src_abundance, "hasLocation", to_abundance, spec))

        elif ast.name in ("deg", "degradation"):
            edges.append(BELAst(ast, "directlyDecreases", ast.args[0], spec))

        elif ast.name in ("fus", "fusion"):
            parent = ast.parent_function

            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(ast.args[0])
            edges.append(BELAst(src_abundance, "hasFusion", parent, spec))

            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(ast.args[2])
            edges.append(BELAst(src_abundance, "hasFusion", parent, spec))

        elif ast.name in ("reactants", "products"):
            parent = ast.parent_function

            relation = "hasProduct"
            if ast.name == "reactants":
                relation = "hasReactant"

            for arg in ast.args:
                edges.append(BELAst(parent, relation, arg, spec))

        elif ast.name in ("product", "fusion"):
            parent = ast.parent_function

            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(ast.args[0])
            edges.append(BELAst(src_abundance, "hasFusion", parent, spec))

            src_abundance = Function(parent.name, spec)
            src_abundance.add_argument(ast.args[2])
            edges.append(BELAst(src_abundance, "hasFusion", parent, spec))

    # Recursively process every element by processing BELAst and Functions
    if hasattr(ast, "args"):
        for arg in ast.args:
            process_ast(edges, arg, spec)
Beispiel #7
0
def process_rule(edges: Edges, ast: Function, rule: Mapping[str, Any],
                 spec: BELSpec):
    """Process computed edge rule

    Recursively processes BELAst versus a single computed edge rule

    Args:
        edges (List[Tuple[Union[Function, str], str, Function]]): BEL Edge ASTs
        ast (Function): BEL Function AST
        rule (Mapping[str, Any]: computed edge rule
    """
    ast_type = ast.__class__.__name__
    trigger_functions = rule.get("trigger_function", [])
    trigger_types = rule.get("trigger_type", [])
    rule_subject = rule.get("subject")
    rule_relation = rule.get("relation")
    rule_object = rule.get("object")

    log.debug(f"Running {rule_relation}  Type: {ast_type}")

    if isinstance(ast, Function):
        function_name = ast.name
        args = ast.args
        parent_function = ast.parent_function

        if function_name in trigger_functions:
            if rule_subject == "trigger_value":
                subject = ast

            if rule_object == "args":
                for arg in args:
                    log.debug(f"1: {subject} {arg}")
                    edge_ast = BELAst(subject, rule_relation, arg, spec)
                    edges.append(edge_ast)
            elif rule_object == "parent_function" and parent_function:
                log.debug(f"2: {subject} {parent_function}")
                edge_ast = BELAst(subject, rule_relation, parent_function,
                                  spec)
                edges.append(edge_ast)

        elif ast_type in trigger_types:
            if rule_subject == "trigger_value":
                subject = ast

            if rule_object == "args":
                for arg in args:
                    log.debug(f"3: {subject} {arg}")
                    edge_ast = BELAst(subject, rule_relation, arg, spec)
                    edges.append(edge_ast)
            elif rule_object == "parent_function" and parent_function:
                log.debug(f"4: {subject} {parent_function}")
                edge_ast = BELAst(subject, rule_relation, parent_function,
                                  spec)
                edges.append(edge_ast)

    if isinstance(ast, NSArg):
        term = "{}:{}".format(ast.namespace, ast.value)
        parent_function = ast.parent_function

        if ast_type in trigger_types:
            if rule_subject == "trigger_value":
                subject = term

            if rule_object == "args":
                for arg in args:
                    log.debug(f"5: {subject} {arg}")
                    edge_ast = BELAst(subject, rule_relation, arg, spec)
                    edges.append(edge_ast)
            elif rule_object == "parent_function" and parent_function:
                log.debug(f"6: {subject} {parent_function}")
                edge_ast = BELAst(subject, rule_relation, parent_function,
                                  spec)
                edges.append(edge_ast)

    # Recursively process every element by processing BELAst and Functions
    if hasattr(ast, "args"):
        for arg in ast.args:
            process_rule(edges, arg, rule, spec)
Beispiel #8
0
class BEL(object):
    """BEL Language object

    This object handles BEL statement/triple processing, parsing, (de)canonicalization,
    orthologization and other purposes.
    """
    def __init__(self,
                 assertion: AssertionStr = None,
                 version: str = "latest") -> None:
        """Initialize BEL object used for validating/processing/etc BEL statements

        Args:
            assertion: BEL Assertion
            version: BEL Version - defaults to settings.BEL_DEFAULT_VERSION or latest version
        """

        self.assertion = assertion

        self.clean_assertion()

        self.version = bel.belspec.crud.check_version(version)

        # Validation error/warning messages
        # List[Tuple[str, str]], e.g. [('ERROR', 'this is an error msg'), ('WARNING', 'this is a warning'), ]
        self.validation_messages = []

        self.ast: Optional[BELAst] = None

        if self.assertion:
            self.ast = BELAst(assertion=assertion, version=version)

    def clean_assertion(self):
        """Various tasks to clean the assertion component strings"""

        # Remove smart quotes
        if self.assertion:
            self.assertion.subject = (self.assertion.subject.replace(
                "“", '"').replace("”", '"').strip())
            self.assertion.relation = (self.assertion.relation.replace(
                "“", '"').replace("”", '"').strip())
            self.assertion.object = (self.assertion.object.replace(
                "“", '"').replace("”", '"').strip())
            self.assertion.entire = (self.assertion.entire.replace(
                "“", '"').replace("”", '"').strip())

    def parse(self, assertion: AssertionStr = None) -> "BEL":
        """Parse BEL Assertion string"""

        # Add or override assertion string object in parse method
        if assertion is not None:
            self.assertion = assertion
            self.clean_assertion()

        self.ast = BELAst(assertion=assertion, version=self.version)

        return self

    def canonicalize(self) -> "BEL":
        """
        Takes an AST and returns a canonicalized BEL statement string.

        Returns:
            BEL: returns self
        """

        # TODO Need to order position independent args

        if self.ast:
            self.ast.canonicalize()

        return self

    def decanonicalize(self) -> "BEL":
        """
        Takes an AST and returns a decanonicalized BEL statement string.

        Returns:
            BEL: returns self
        """

        if self.ast:
            self.ast.decanonicalize()

        return self

    def orthologize(self, species_key: Key) -> "BEL":
        """Orthologize BEL AST to given species_id

        Will return original entity (ns:value) if no ortholog found.

        Args:
            species_id (str): species id to convert genes/rna/proteins into

        Returns:
            BEL: returns self
        """

        if self.ast:
            self.ast.orthologize(species_key)

        return self

    def to_string(self, fmt: str = "medium") -> str:
        """Convert AST object to string

        Args:
            fmt (str): short, medium, long formatted BEL statements
                short = short function and short relation format
                medium = short function and long relation format
                long = long function and long relation format

        Returns:
            str: string version of BEL AST
        """

        if self.ast:
            return f"{self.ast.to_string(fmt=fmt)}"

    def to_triple(self, fmt: str = "medium") -> dict:
        """Convert AST object to BEL triple

        Args:
            fmt (str): short, medium, long formatted BEL statements
                short = short function and short relation format
                medium = short function and long relation format
                long = long function and long relation format

        Returns:
            dict: {'subject': <subject>, 'relation': <relations>, 'object': <object>}
        """

        if self.ast:
            return self.ast.to_triple(fmt=fmt)
        else:
            return {}

    def print_tree(self) -> str:
        """Convert AST object to tree view of BEL AST

        Returns:
            printed tree of BEL AST
        """

        if self.ast:
            return self.ast.print_tree(ast_obj=self.ast)
        else:
            return ""

    def dump(self) -> str:
        """Dump out the BEL object"""

        # Standard Library
        import textwrap

        s = f"""
            BEL Object dump:
                version: {self.version}
                assertion: {self.assertion.entire}
                species: {self.ast.species}
                ast: {self.ast.print_tree()}
        """

        print(textwrap.dedent(s))