Source code for pybel.struct.filters.edge_predicates

# -*- coding: utf-8 -*-

"""Predicates for edge data from BEL graphs."""

from functools import wraps
from typing import Any, Callable, Optional

from .typing import EdgePredicate
from .utils import part_has_modifier
from ..graph import BELGraph
from ...constants import (
    ACTIVITY,
    ANNOTATIONS,
    ASSOCIATION,
    CAUSAL_RELATIONS,
    CITATION,
    CITATION_AUTHORS,
    DEGRADATION,
    DIRECT_CAUSAL_RELATIONS,
    EVIDENCE,
    NAMESPACE,
    POLAR_RELATIONS,
    RELATION,
    SOURCE_MODIFIER,
    TARGET_MODIFIER,
    TRANSLOCATION,
)
from ...dsl import BaseEntity, BiologicalProcess, Pathology
from ...typing import EdgeData

__all__ = [
    "edge_predicate",
    "true_edge_predicate",
    "false_edge_predicate",
    "has_provenance",
    "has_pubmed",
    "has_pmc",
    "has_authors",
    "is_causal_relation",
    "not_causal_relation",
    "is_direct_causal_relation",
    "is_associative_relation",
    "has_polarity",
    "edge_has_activity",
    "edge_has_degradation",
    "edge_has_translocation",
    "edge_has_annotation",
    "has_pathology_causal",
]

DictEdgePredicate = Callable[[EdgeData], bool]


[docs]def edge_predicate(func: DictEdgePredicate) -> EdgePredicate: # noqa: D202 """Decorate an edge predicate function that only takes a dictionary as its singular argument. Apply this as a decorator to a function that takes a single argument, a PyBEL node data dictionary, to make sure that it can also accept a pair of arguments, a BELGraph and a PyBEL node tuple as well. """ @wraps(func) def _wrapped(*args): x = args[0] if isinstance(x, BELGraph): u, v, k = args[1:4] return func(x[u][v][k]) return func(*args) return _wrapped
[docs]def true_edge_predicate(graph: BELGraph, u: BaseEntity, v: BaseEntity, k: str) -> bool: """Return true for all edges.""" return True
[docs]def false_edge_predicate(graph: BELGraph, u: BaseEntity, v: BaseEntity, k: str) -> bool: """Return false for all edges.""" return False
[docs]@edge_predicate def has_provenance(edge_data: EdgeData) -> bool: """Check if the edge has provenance information (i.e. citation and evidence).""" return CITATION in edge_data and EVIDENCE in edge_data
[docs]@edge_predicate def has_pubmed(edge_data: EdgeData) -> bool: """Check if the edge has a PubMed citation.""" return CITATION in edge_data and edge_data[CITATION][NAMESPACE].lower() in ( "pubmed", "pmid", )
[docs]@edge_predicate def has_pmc(edge_data: EdgeData) -> bool: """Check if the edge has a PMC citation.""" return CITATION in edge_data and edge_data[CITATION][NAMESPACE].lower() in ( "pmc", "pmcid", )
CITATION_PREDICATES = { "pubmed": has_pubmed, "pmc": has_pmc, }
[docs]@edge_predicate def has_authors(edge_data: EdgeData) -> bool: """Check if the edge contains author information for its citation.""" return CITATION in edge_data and CITATION_AUTHORS in edge_data[CITATION] and edge_data[CITATION][CITATION_AUTHORS]
[docs]@edge_predicate def is_causal_relation(edge_data: EdgeData) -> bool: """Check if the given relation is causal.""" return edge_data[RELATION] in CAUSAL_RELATIONS
[docs]@edge_predicate def not_causal_relation(edge_data: EdgeData) -> bool: """Check if the given relation is not causal.""" return edge_data[RELATION] not in CAUSAL_RELATIONS
[docs]@edge_predicate def is_direct_causal_relation(edge_data: EdgeData) -> bool: """Check if the edge is a direct causal relation.""" return edge_data[RELATION] in DIRECT_CAUSAL_RELATIONS
[docs]@edge_predicate def is_associative_relation(edge_data: EdgeData) -> bool: """Check if the edge has an association relation.""" return edge_data[RELATION] == ASSOCIATION
[docs]@edge_predicate def has_polarity(edge_data: EdgeData) -> bool: """Check if the edge has polarity.""" return edge_data[RELATION] in POLAR_RELATIONS
def _has_modifier(edge_data: EdgeData, modifier: str) -> bool: """Check if the edge has the given modifier. :param edge_data: The edge data dictionary :param modifier: The modifier to check. One of :data:`pybel.constants.ACTIVITY`, :data:`pybel.constants.DEGRADATION`, or :data:`pybel.constants.TRANSLOCATION`. :return: Does either the subject or object have the given modifier """ return part_has_modifier(edge_data, SOURCE_MODIFIER, modifier) or part_has_modifier( edge_data, TARGET_MODIFIER, modifier )
[docs]@edge_predicate def edge_has_activity(edge_data: EdgeData) -> bool: """Check if the edge contains an activity in either the subject or object.""" return _has_modifier(edge_data, ACTIVITY)
[docs]@edge_predicate def edge_has_translocation(edge_data: EdgeData) -> bool: """Check if the edge has a translocation in either the subject or object.""" return _has_modifier(edge_data, TRANSLOCATION)
[docs]@edge_predicate def edge_has_degradation(edge_data: EdgeData) -> bool: """Check if the edge contains a degradation in either the subject or object.""" return _has_modifier(edge_data, DEGRADATION)
[docs]def edge_has_annotation(edge_data: EdgeData, key: str) -> Optional[Any]: """Check if an edge has the given annotation. :param edge_data: The data dictionary from a BELGraph's edge :param key: An annotation key :return: If the annotation key is present in the current data dictionary For example, it might be useful to print all edges that are annotated with 'Subgraph': >>> from pybel.examples import sialic_acid_graph >>> from pybel.examples.sialic_acid_example import sialic_acid_cd33_complex, cd33 >>> edges = { ... (u, v) ... for u, v, data in sialic_acid_graph.edges(data=True) ... if edge_has_annotation(data, 'Species') ... } >>> assert (sialic_acid_cd33_complex, cd33) in edges """ annotations = edge_data.get(ANNOTATIONS) if annotations is None: return None return annotations.get(key)
[docs]def has_pathology_causal(graph: BELGraph, u: BaseEntity, v: BaseEntity, k: str) -> bool: """Check if the subject is a pathology and has a causal relationship with a non bioprocess/pathology. :return: If the subject of this edge is a pathology and it participates in a causal reaction. """ return ( isinstance(u, Pathology) and is_causal_relation(graph, u, v, k) and not isinstance(v, (Pathology, BiologicalProcess)) )