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 .typing import NodePredicate
from ..graph import BELGraph
from ...constants import CONCEPT, NAME, NAMESPACE
from ...dsl import BaseEntity
from ...typing import Strings

__all__ = [
    'function_inclusion_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 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 CONCEPT in node and node[CONCEPT][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 CONCEPT in node and node[CONCEPT][NAMESPACE] in namespaces else: raise TypeError('Invalid type for argument: {}'.format(namespace)) return namespace_filter