# -*- coding: utf-8 -*-
"""Summary functions for errors and warnings encountered during the compilation of BEL script."""
import typing
from collections import Counter, defaultdict
from typing import Iterable, List, Mapping, Set
from ..filters.edge_predicates import edge_has_annotation
from ..graph import BELGraph, WarningTuple
from ...constants import ANNOTATIONS
from ...exceptions import (
BELSyntaxError,
MissingNamespaceNameWarning,
MissingNamespaceRegexWarning,
NakedNameWarning,
)
__all__ = [
"get_syntax_errors",
"count_error_types",
"count_naked_names",
"get_naked_names",
"calculate_incorrect_name_dict",
"calculate_error_by_annotation",
]
[docs]def get_syntax_errors(graph: BELGraph) -> List[WarningTuple]:
"""List the syntax errors encountered during compilation of a BEL script."""
return [(path, exc, an) for path, exc, an in graph.warnings if isinstance(exc, BELSyntaxError)]
[docs]def count_error_types(graph: BELGraph) -> typing.Counter[str]:
"""Count the occurrence of each type of error in a graph.
:return: A Counter of {error type: frequency}
"""
return Counter(exc.__class__.__name__ for _, exc, _ in graph.warnings)
def _naked_names_iter(graph: BELGraph) -> Iterable[str]:
"""Iterate over naked name warnings from a graph."""
for _, exc, _ in graph.warnings:
if isinstance(exc, NakedNameWarning):
yield exc.name
[docs]def count_naked_names(graph: BELGraph) -> typing.Counter[str]:
"""Count the frequency of each naked name (names without namespaces).
:return: A Counter from {name: frequency}
"""
return Counter(_naked_names_iter(graph))
[docs]def get_naked_names(graph: BELGraph) -> Set[str]:
"""Get the set of naked names in the graph."""
return set(_naked_names_iter(graph))
def _iterate_namespace_name(graph: BELGraph) -> Iterable[typing.Tuple[str, str]]:
for _, exc, _ in graph.warnings:
if not isinstance(exc, (MissingNamespaceNameWarning, MissingNamespaceRegexWarning)):
continue
yield exc.namespace, exc.name
[docs]def calculate_incorrect_name_dict(graph: BELGraph) -> Mapping[str, List[str]]:
"""Get missing names grouped by namespace."""
missing = defaultdict(list)
for namespace, name in _iterate_namespace_name(graph):
missing[namespace].append(name)
return dict(missing)
[docs]def calculate_error_by_annotation(graph: BELGraph, annotation: str) -> Mapping[str, List[str]]:
"""Group error names by a given annotation."""
results = defaultdict(list)
for _, exc, ctx in graph.warnings:
if not ctx or not edge_has_annotation(ctx, annotation):
continue
values = ctx[ANNOTATIONS][annotation]
if isinstance(values, str):
results[values].append(exc.__class__.__name__)
elif isinstance(values, Iterable):
for value in values:
results[value].append(exc.__class__.__name__)
return dict(results)