Source code for pybel.struct.filters.node_predicate_builders

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

"""Functions for building node predicates."""

from typing import Any, Callable, Iterable, List, Union

from .node_predicates import concatenate_node_predicates, invert_node_predicate
from .typing import NodePredicate
from ..graph import BELGraph
from ...constants import CONCEPT, NAME
from ...dsl import BaseConcept, BaseEntity
from ...typing import Strings

__all__ = [
    "function_inclusion_filter_builder",
    "function_exclusion_filter_builder",
    "data_missing_key_builder",
    "build_node_data_search",
    "build_node_graph_data_search",
    "build_node_key_search",
    "build_node_name_search",
    "namespace_inclusion_builder",
]


[docs]def function_inclusion_filter_builder(func: Strings) -> NodePredicate: """Build a filter that only passes on nodes of the given function(s). :param func: A BEL Function or list/set/tuple of BEL functions """ if isinstance(func, str): return _single_function_inclusion_filter_builder(func) elif isinstance(func, Iterable): return _collection_function_inclusion_builder(func) raise TypeError("Invalid type for argument: {}".format(func))
def _single_function_inclusion_filter_builder(func: str) -> NodePredicate: # noqa: D202 """Build a function inclusion filter for a single function.""" def function_inclusion_filter(_: BELGraph, node: BaseEntity) -> bool: """Pass only for a node that has the enclosed function.""" return node.function == func return function_inclusion_filter def _collection_function_inclusion_builder(funcs: Iterable[str]) -> NodePredicate: """Build a function inclusion filter for a collection of functions.""" funcs = set(funcs) if not funcs: raise ValueError("can not build function inclusion filter with empty list of functions") def functions_inclusion_filter(_: BELGraph, node: BaseEntity) -> bool: """Pass only for a node that is one of the enclosed functions.""" return node.function in funcs return functions_inclusion_filter
[docs]def function_exclusion_filter_builder(func: Strings) -> NodePredicate: """Build a filter that fails on nodes of the given function(s). :param func: A BEL Function or list/set/tuple of BEL functions """ return invert_node_predicate(function_inclusion_filter_builder(func))
[docs]def data_missing_key_builder(key: str) -> NodePredicate: # noqa: D202 """Build a filter that passes only on nodes that don't have the given key in their data dictionary. :param str key: A key for the node's data dictionary """ def data_does_not_contain_key(graph: BELGraph, node: BaseEntity) -> bool: """Pass only for a node that doesn't contain the enclosed key in its data dictionary.""" return key not in graph.nodes[node] return data_does_not_contain_key
def _get_multi_value(d, keys): value = d.get(keys[0]) for key in keys[1:]: if value is None: return value = value.get(key) return value def _get_single_value(d, key): return d.get(key)
[docs]def namespace_inclusion_builder(namespace: Strings) -> NodePredicate: """Build a predicate for namespace inclusion.""" if isinstance(namespace, str): def namespace_filter(_: BELGraph, node: BaseEntity) -> bool: """Pass only for a node that has the enclosed namespace.""" return isinstance(node, BaseConcept) and node.namespace == namespace elif isinstance(namespace, Iterable): namespaces = set(namespace) def namespace_filter(_: BELGraph, node: BaseEntity) -> bool: """Pass only for a node that has a namespace in the enclosed set.""" return isinstance(node, BaseConcept) and node.namespace in namespaces else: raise TypeError("Invalid type for argument: {}".format(namespace)) return namespace_filter