Source code for pybel.struct.filters.node_predicates.utils

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

"""Pre-defined predicates for nodes."""

from functools import wraps
from typing import Callable, Iterable

from ..typing import NodePredicate, NodePredicates
from ...graph import BELGraph
from ....dsl import BaseEntity

__all__ = [
    "node_predicate",
    "invert_node_predicate",
    "concatenate_node_predicates",
    "true_node_predicate",
    "false_node_predicate",
]


[docs]def node_predicate(f: Callable[[BaseEntity], bool]) -> NodePredicate: # noqa: D202 """Tag a node predicate that takes a dictionary to also accept a pair of (BELGraph, node). Apply this as a decorator to a function that takes a single argument, a PyBEL node, to make sure that it can also accept a pair of arguments, a BELGraph and a PyBEL node as well. """ @wraps(f) def wrapped(*args): x = args[0] if isinstance(x, BELGraph): return f(args[1], *args[2:]) elif isinstance(x, BaseEntity): return f(*args) else: raise TypeError return wrapped
[docs]def invert_node_predicate(f: NodePredicate) -> NodePredicate: # noqa: D202 """Build a node predicate that is the inverse of the given node predicate.""" def inverse_predicate(graph: BELGraph, node: BaseEntity) -> bool: """Return the inverse of the enclosed node predicate applied to the graph and node.""" return not f(graph, node) return inverse_predicate
[docs]def concatenate_node_predicates(node_predicates: NodePredicates) -> NodePredicate: """Concatenate multiple node predicates to a new predicate that requires all predicates to be met. Example usage: >>> from pybel import BELGraph >>> from pybel.dsl import Protein >>> from pybel.struct.filters import not_gene, not_rna >>> app_protein = Protein(name='APP', namespace='hgnc', identifier='620') >>> app_rna = app_protein.get_rna() >>> app_gene = app_rna.get_gene() >>> graph = BELGraph() >>> _ = graph.add_transcription(app_gene, app_rna) >>> _ = graph.add_translation(app_rna, app_protein) >>> node_predicate = concatenate_node_predicates([not_rna, not_gene]) >>> assert node_predicate(graph, app_protein) >>> assert not node_predicate(graph, app_rna) >>> assert not node_predicate(graph, app_gene) """ # If a predicate outside a list is given, just return it if not isinstance(node_predicates, Iterable): return node_predicates node_predicates = tuple(node_predicates) # If only one predicate is given, don't bother wrapping it if 1 == len(node_predicates): return node_predicates[0] def concatenated_node_predicate(graph: BELGraph, node: BaseEntity) -> bool: """Pass only for a nodes that pass all enclosed predicates.""" return all(node_predicate(graph, node) for node_predicate in node_predicates) return concatenated_node_predicate
[docs]@node_predicate def true_node_predicate(_: BaseEntity) -> bool: """Return true for all nodes. Given BEL graph :code:`graph`, applying :func:`true_predicate` with a predicate on the nodes iterable as in :code:`filter(keep_node_permissive, graph)` will result in the same iterable as iterating directly over a :class:`BELGraph` """ return True
[docs]@node_predicate def false_node_predicate(_: BaseEntity) -> bool: """Return false for all nodes.""" return False