<commit_before># -*- coding: utf-8 -*-

"""
Graph axis methods

Class for traversing and querying (sub)graph hierarchy with respect to a root
node.
"""

from lie_graph.graph import Graph
from lie_graph.graph_helpers import GraphException
from lie_graph.graph_query.query_xpath import XpathExpressionEvaluator
from lie_graph.graph_axis.graph_axis_methods import (node_ancestors, node_children, node_descendants, node_neighbors,
    node_parent, node_all_parents, node_siblings, node_leaves)


class GraphAxis(Graph):
    """
    Hierarchical graph query and traversal with respect to a root node.

    The GraphAxis class extends the Graph base class with methods that enable
    query and traversal of graphs that have a hierachy with respect to a
    certain root node.
    A root node is chosen by node ID (nid) and is the one with the lowest ID
    (number) by default or any other one chosen at a later time.
    Hierarchy is queried with respect to the root node by means of axis that
    include: children, descendants, leaves, neighours, siblings, parents and
    ancestors.

    These methods return selections, or sub-graphs, that represent the
    respective axis. By default these selections maintain full connectivity to
    the full graphs and thus represent a selective 'view' on the full graph.
    This behaviour can be changed by enabling a 'mask' on the selection or by
    copying the selection into a new independent graph. The behaviour of both
    options are the same, connectivity is maintained with the selection but
    outside of it. The benefit of a mask, enabled by settings 'is_masked' to
    True, is that it is non-destructive to the data and can be easily lifted
    again.

    The behaviour of axis methods is furthermore affected by the directivity
    of the graph. The default non-directive graphs can be fully traversed
    forwards and backwards. Directed graphs or mixed graphs block traversal
    to parts of the graph by lack of an edge to traverse over.

    All of the axis methods are wrappers around their respective function in
    lie_graph.graph_axis.graph_axis_methods. These functions return node ID's
    that are used by the wrapper method to return the respective sub-graph or
    node ID's with 'return_nids' equals True.
    """

    def _resolve_nid(self):
        """
        Return the node ID (nid) of the current node

        When using single node graph objects this method will return the nid of
        the given node, in multi-node graphs it will return the first nid in
        the keys list and in empty graphs it will return None.
        """

        if self.root is None:
            raise GraphException('Graph node descendant requires a root node')

        try:
            return self.nid
        except AttributeError:
            return self.root

    def ancestors(self, node=None, include_self=False, return_nids=False):
        """
        Return the ancestors of the source node

        Traversal path is determined as the shortest path between the root node
        and the target node (Dijkstra shortest path).

        Directed graphs and/or is_masked behaviour: if the target node is not
        reachable using the Dijkstra shortest path method, the selection will
        remain empty.

        :param node:         source node to start search from
        :type node:          mixed<commit_msg>Add convenience method to quickly get root node of graph<commit_after># -*- coding: utf-8 -*-

"""
Graph axis methods

Class for traversing and querying (sub)graph hierarchy with respect to a root
node.
"""

from lie_graph.graph import Graph
from lie_graph.graph_helpers import GraphException
from lie_graph.graph_query.query_xpath import XpathExpressionEvaluator
from lie_graph.graph_axis.graph_axis_methods import (node_ancestors, node_children, node_descendants, node_neighbors,
    node_parent, node_all_parents, node_siblings, node_leaves)


class GraphAxis(Graph):
    """
    Hierarchical graph query and traversal with respect to a root node.

    The GraphAxis class extends the Graph base class with methods that enable
    query and traversal of graphs that have a hierachy with respect to a
    certain root node.
    A root node is chosen by node ID (nid) and is the one with the lowest ID
    (number) by default or any other one chosen at a later time.
    Hierarchy is queried with respect to the root node by means of axis that
    include: children, descendants, leaves, neighours, siblings, parents and
    ancestors.

    These methods return selections, or sub-graphs, that represent the
    respective axis. By default these selections maintain full connectivity to
    the full graphs and thus represent a selective 'view' on the full graph.
    This behaviour can be changed by enabling a 'mask' on the selection or by
    copying the selection into a new independent graph. The behaviour of both
    options are the same, connectivity is maintained with the selection but
    outside of it. The benefit of a mask, enabled by settings 'is_masked' to
    True, is that it is non-destructive to the data and can be easily lifted
    again.

    The behaviour of axis methods is furthermore affected by the directivity
    of the graph. The default non-directive graphs can be fully traversed
    forwards and backwards. Directed graphs or mixed graphs block traversal
    to parts of the graph by lack of an edge to traverse over.

    All of the axis methods are wrappers around their respective function in
    lie_graph.graph_axis.graph_axis_methods. These functions return node ID's
    that are used by the wrapper method to return the respective sub-graph or
    node ID's with 'return_nids' equals True.
    """

    def _resolve_nid(self):
        """
        Return the node ID (nid) of the current node

        When using single node graph objects this method will return the nid of
        the given node, in multi-node graphs it will return the first nid in
        the keys list and in empty graphs it will return None.
        """

        if self.root is None:
            raise GraphException('Graph node descendant requires a root node')

        try:
            return self.nid
        except AttributeError:
            return self.root

    def get_root(self):
        """
        Convenience method for returning the root node of a graph
        """

        return self._full_graph.getnodes(self.root)

    def ancestors(self, node=None, include_self=False, return_nids=False):
        """
        Return the ancestors of the source node

        Traversal path is determined as the shortest path between the root node
        and the target node (Dijkstra shortest path).

        Directed graphs and/or is_masked behaviour: if the target node is not
        reachable using the Dijkstra shortest path method, the selection will
        remain empty.

        :param node:         source node to start search from
        :type node:          mixed
{'fraction_non_alphanumeric': 0.041266657114199745, 'fraction_numerical': 0.0002865740077374982, 'mean_word_length': 3.0323512420566145, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '255798', 'n_tokens_mistral': 1769, 'n_tokens_neox': 1716, 'n_words': 914}