networkx-query


Namenetworkx-query JSON
Version 2.0.0 PyPI version JSON
download
home_pagehttps://pypi.org/project/networkx_query
SummaryNetworkX Query Tool
upload_time2023-06-02 14:23:07
maintainer
docs_urlNone
authorJerome Guibert
requires_python>=3.8,<3.12
licenseMIT
keywords networkx graph query
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # networkx-query

[![Coverage Status](https://img.shields.io/coveralls/geronimo-iia/networkx-query/master.svg)](https://coveralls.io/r/geronimo-iia/networkx-query)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fe669a02b4aa46b5b1faf619ba2bf382)](https://www.codacy.com/app/geronimo-iia/networkx-query?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=geronimo-iia/networkx-query&amp;utm_campaign=Badge_Grade)[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/geronimo-iia/networkx-query.svg)](https://scrutinizer-ci.com/g/geronimo-iia/networkx-query/?branch=master)
[![PyPI Version](https://img.shields.io/pypi/v/networkx-query.svg)](https://pypi.org/project/networkx-query)
[![PyPI License](https://img.shields.io/pypi/l/networkx-query.svg)](https://pypi.org/project/networkx-query)

Versions following [Semantic Versioning](https://semver.org/)

## Overview

NetworkX Query Tool

See [documentation](https://geronimo-iia.github.io/networkx-query).


## Installation

Install this library directly into an activated virtual environment:

```text
$ pip install networkx-query
```

or add it to your [Poetry](https://poetry.eustace.io/) project:

```text
$ poetry add networkx-query
```

## Usage

### Searching nodes

```python
import networkx as nx
from networkx_query import search_nodes, search_edges

g = nx.DiGraph()
g.add_node(1, product="chocolate")
g.add_node(2, product="milk")
g.add_node(3, product="coat")
g.add_edge(1, 2, action="shake")
g.add_edge(3, 2, action="produce")


for node_id in search_nodes(g, {"==": [("product",), "chocolate"]}):
    print(node_id)

>> 1
```

### Searching edges

```python
for edge_id in search_edges(g, {"eq": [("action",), "produce"]}):
    print(edge_id)

>> (3, 2)
```

### Searching direct relation ship

With ```search_direct_relationships``` you can made a query which filter edges on their :
 - source node attributes
 - edge attributes
 - target node attributes

With this graph:

```python
import networkx as nx
from networkx_query import search_direct_relationships

g = nx.DiGraph()
for i in range(30):
    g.add_node(i, data=i)

for i in range(10, 30):
    g.add_edge(i - 10, i, data=i)
```

We can filtering all edges with source node with data < 3:

```python
list(search_direct_relationships(graph=g, source={"lt": ["data", 3]}))

[(0, 10), (1, 11), (2, 12)]
```


We can filtering all edges with:
 - source node with data < 8
 - edge with data > 15

```python
list(search_direct_relationships(graph=g, source={"lt": ["data", 8]}, edge={"gt": ["data", 15]}))

>> [(6, 16), (7, 17)]
```

We can filtering all edges with:
 - source node with data > 9
 - edge with data > 15
 - target node with data < 22

```python
search_direct_relationships(
            graph=g, source={"gt": ["data", 9]}, edge={"gt": ["data", 15]}, target={'lt': ["data", 22]}
        )
    )

>> [(10, 20), (11, 21)]
```



### search_relationships

With :

```python
    g = nx.DiGraph()
    g.add_node(1, product="a")
    g.add_node(2, product="b")
    g.add_node(3, product="c")
    g.add_node(4, product="d")

    g.add_edge(1, 2)
    g.add_edge(1, 3, weight=2)
    g.add_edge(1, 4)

    g.add_edge(2, 4)
    g.add_edge(3, 4)
```


You could find all path with multiple constraints:

```python
    list(search_relationships(
            g,
            {"eq": [("product",), "a"]},
            PathCriteria(target={"eq": [("product",), "b"]}),
            PathCriteria(target={"eq": [("product",), "d"]}),
        )) 
    # output: [[1, 2, 4]]

     list(search_relationships(g, {"eq": [("product",), "a"]}, PathCriteria(target={"eq": [("product",), "c"]})))
     # outptu: [[1, 3]]
```

or something more complex:

```python

    g.add_node(5, product="d")
    g.add_node(6, product="d")
    g.add_node(7, product="a")
    g.add_node(8, product="a")

    g.add_edge(7, 5, weight=2)
    g.add_edge(7, 6, weight=2)
    g.add_edge(8, 5, weight=2)

    list(
        search_relationships(
            g,
            {"eq": [("product",), "a"]},  # node 1, 7, 8
            PathCriteria(
                target={"eq": [("product",), "d"]}, edge={"eq": [("weight",), 2]}
            ),  # edge 1-3, 7-5, 7-6, 8-5  node 4, 5, 6 -> no 1, 3, 4
        )
    )
    # output: [[7, 5], [7, 6], [8, 5]]

    list(
        search_relationships(
            g,
            {"eq": [("product",), "a"]},  # node 1, 7, 8
            PathCriteria(target={}, edge={"eq": [("weight",), 2]}),  # edge 1-3, 7-5, 7-6, 8-5
            PathCriteria(target={"eq": [("product",), "d"]}),  # node 4, 5, 6 -> no 1, 3, 4
        )
    )
    # output: [[1, 3, 4]]
```

Note the usage of `PathCriteria(target={}, ..` to define a constraint based only on edge. `{}` act as a wildcard.

## API

Actually, we have:

- [search_edges](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_edges)
- [search_nodes](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_nodes) 
- [search_direct_relationships](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_direct_relationships) 
- [search_relationships](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_relationships) 


All this function are based on [prepare_query](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.prepare_query) which return an Evaluator.

Quickly, ```Evaluator``` are function with this signature: (context) -> bool, and ```Context``` is a dictionary like structure (with in and [] methods, and support __contains__ or  (__iter__ and __getitem__))
With networkX, node and edge attributes are dictionary like, so implementation of this three methods are very simple.



## Query language

We define a little json query language like [json-query-language](https://github.com/clue/json-query-language/blob/master/SYNTAX.md) 
against nodes or edges attributes.


### Expressions

Main expression syntax turn around this:

```
{
    operator_name : parameters
}
```

### Basic matching expression

Test if a node/edge has an attribute named "my_property":
```
{
    "has" : "my_property"
}
```


Test if a node/edge has an attribute product : { "definition": { "name": xxx }} with xxx equals to "chocolate".
```
{
    "eq" : [ ("product", "definition", "name"), "chocolate"]
}
```

The tuple ```("product", "definition", "name")``` is a path in attribut dictionnary.
A Path is a single string or a tuple of string which represente a path in a tree (here a dictionary).

We support this operators:

| Name     | Alias | Parameters      | Description                                                                   |
| -------- | :---: | --------------- | ----------------------------------------------------------------------------- |
| has      |       | Path            | Check if path exists in context.                                              |
| contains |       | Path, str       | Check if an attribut path exists and contains specified value.                |
| eq       | `==`  | Path, Any       | Check if an attribut path exists and equals specified value.                  |
| neq      | `!=`  | Path, Any       | Check if an attribut path did not exists or not equals specified value.       |
| gt       |  `>`  | Path, Any       | Check if an attribut path exists and greather that specified value.           |
| lt       |  `<`  | Path, Any       | Check if an attribut path exists and lower that specified value.              |
| gte      | `>=`  | Path, Any       | Check if an attribut path exists and greather or equals that specified value. |
| lte      | `<=`  | Path, Any       | Check if an attribut path exists and lower or equals that specified value.    |
| in       | `:=`  | Path, List[Any] | Check if an attribut path exists and attribut value in specified values.      |


### Boolean composition of matching expression

We support this operators:

| Name | Alias | Parameters    | Description    |
| ---- | :---: | ------------- | -------------- |
| and  | `&&`  | list of query | And operator.  |
| or   | \|\|  | list of query | Or operator.   |
| xor  |       | list of query | xor operator.  |
| nxor |       | list of query | nxor operator. |
| not  |  `!`  | query         | Not operator.  |


By default, a list of expressions is equivalent of an "AND" of this expressions.

Example:
```
{
    'not': {
        'has': ['group']
    },
    'has': 'application',
    'eq': [('_link', 'other', 'weight'), 2]
}
```
is equivalent to:

```
{
    'and': [
        {
            'not': [
                {
                    'has': ['group']
                }
            ]
        },
        {
            'has': ['application']
        },
        {
            'eq': [('_link', 'other', 'weight'), 2]
        }
    ]
}
```

## Wished Features

- add projection expression (a return like statement)
- add join relation ship 



            

Raw data

            {
    "_id": null,
    "home_page": "https://pypi.org/project/networkx_query",
    "name": "networkx-query",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<3.12",
    "maintainer_email": "",
    "keywords": "networkx,graph,query",
    "author": "Jerome Guibert",
    "author_email": "jguibert@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/56/85/e88a264ab2d2d9cf34d471b2e16552e79f73953c496a672414497ee9d6a9/networkx_query-2.0.0.tar.gz",
    "platform": null,
    "description": "# networkx-query\n\n[![Coverage Status](https://img.shields.io/coveralls/geronimo-iia/networkx-query/master.svg)](https://coveralls.io/r/geronimo-iia/networkx-query)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fe669a02b4aa46b5b1faf619ba2bf382)](https://www.codacy.com/app/geronimo-iia/networkx-query?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=geronimo-iia/networkx-query&amp;utm_campaign=Badge_Grade)[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/geronimo-iia/networkx-query.svg)](https://scrutinizer-ci.com/g/geronimo-iia/networkx-query/?branch=master)\n[![PyPI Version](https://img.shields.io/pypi/v/networkx-query.svg)](https://pypi.org/project/networkx-query)\n[![PyPI License](https://img.shields.io/pypi/l/networkx-query.svg)](https://pypi.org/project/networkx-query)\n\nVersions following [Semantic Versioning](https://semver.org/)\n\n## Overview\n\nNetworkX Query Tool\n\nSee [documentation](https://geronimo-iia.github.io/networkx-query).\n\n\n## Installation\n\nInstall this library directly into an activated virtual environment:\n\n```text\n$ pip install networkx-query\n```\n\nor add it to your [Poetry](https://poetry.eustace.io/) project:\n\n```text\n$ poetry add networkx-query\n```\n\n## Usage\n\n### Searching nodes\n\n```python\nimport networkx as nx\nfrom networkx_query import search_nodes, search_edges\n\ng = nx.DiGraph()\ng.add_node(1, product=\"chocolate\")\ng.add_node(2, product=\"milk\")\ng.add_node(3, product=\"coat\")\ng.add_edge(1, 2, action=\"shake\")\ng.add_edge(3, 2, action=\"produce\")\n\n\nfor node_id in search_nodes(g, {\"==\": [(\"product\",), \"chocolate\"]}):\n    print(node_id)\n\n>> 1\n```\n\n### Searching edges\n\n```python\nfor edge_id in search_edges(g, {\"eq\": [(\"action\",), \"produce\"]}):\n    print(edge_id)\n\n>> (3, 2)\n```\n\n### Searching direct relation ship\n\nWith ```search_direct_relationships``` you can made a query which filter edges on their :\n - source node attributes\n - edge attributes\n - target node attributes\n\nWith this graph:\n\n```python\nimport networkx as nx\nfrom networkx_query import search_direct_relationships\n\ng = nx.DiGraph()\nfor i in range(30):\n    g.add_node(i, data=i)\n\nfor i in range(10, 30):\n    g.add_edge(i - 10, i, data=i)\n```\n\nWe can filtering all edges with source node with data < 3:\n\n```python\nlist(search_direct_relationships(graph=g, source={\"lt\": [\"data\", 3]}))\n\n[(0, 10), (1, 11), (2, 12)]\n```\n\n\nWe can filtering all edges with:\n - source node with data < 8\n - edge with data > 15\n\n```python\nlist(search_direct_relationships(graph=g, source={\"lt\": [\"data\", 8]}, edge={\"gt\": [\"data\", 15]}))\n\n>> [(6, 16), (7, 17)]\n```\n\nWe can filtering all edges with:\n - source node with data > 9\n - edge with data > 15\n - target node with data < 22\n\n```python\nsearch_direct_relationships(\n            graph=g, source={\"gt\": [\"data\", 9]}, edge={\"gt\": [\"data\", 15]}, target={'lt': [\"data\", 22]}\n        )\n    )\n\n>> [(10, 20), (11, 21)]\n```\n\n\n\n### search_relationships\n\nWith :\n\n```python\n    g = nx.DiGraph()\n    g.add_node(1, product=\"a\")\n    g.add_node(2, product=\"b\")\n    g.add_node(3, product=\"c\")\n    g.add_node(4, product=\"d\")\n\n    g.add_edge(1, 2)\n    g.add_edge(1, 3, weight=2)\n    g.add_edge(1, 4)\n\n    g.add_edge(2, 4)\n    g.add_edge(3, 4)\n```\n\n\nYou could find all path with multiple constraints:\n\n```python\n    list(search_relationships(\n            g,\n            {\"eq\": [(\"product\",), \"a\"]},\n            PathCriteria(target={\"eq\": [(\"product\",), \"b\"]}),\n            PathCriteria(target={\"eq\": [(\"product\",), \"d\"]}),\n        )) \n    # output: [[1, 2, 4]]\n\n     list(search_relationships(g, {\"eq\": [(\"product\",), \"a\"]}, PathCriteria(target={\"eq\": [(\"product\",), \"c\"]})))\n     # outptu: [[1, 3]]\n```\n\nor something more complex:\n\n```python\n\n    g.add_node(5, product=\"d\")\n    g.add_node(6, product=\"d\")\n    g.add_node(7, product=\"a\")\n    g.add_node(8, product=\"a\")\n\n    g.add_edge(7, 5, weight=2)\n    g.add_edge(7, 6, weight=2)\n    g.add_edge(8, 5, weight=2)\n\n    list(\n        search_relationships(\n            g,\n            {\"eq\": [(\"product\",), \"a\"]},  # node 1, 7, 8\n            PathCriteria(\n                target={\"eq\": [(\"product\",), \"d\"]}, edge={\"eq\": [(\"weight\",), 2]}\n            ),  # edge 1-3, 7-5, 7-6, 8-5  node 4, 5, 6 -> no 1, 3, 4\n        )\n    )\n    # output: [[7, 5], [7, 6], [8, 5]]\n\n    list(\n        search_relationships(\n            g,\n            {\"eq\": [(\"product\",), \"a\"]},  # node 1, 7, 8\n            PathCriteria(target={}, edge={\"eq\": [(\"weight\",), 2]}),  # edge 1-3, 7-5, 7-6, 8-5\n            PathCriteria(target={\"eq\": [(\"product\",), \"d\"]}),  # node 4, 5, 6 -> no 1, 3, 4\n        )\n    )\n    # output: [[1, 3, 4]]\n```\n\nNote the usage of `PathCriteria(target={}, ..` to define a constraint based only on edge. `{}` act as a wildcard.\n\n## API\n\nActually, we have:\n\n- [search_edges](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_edges)\n- [search_nodes](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_nodes) \n- [search_direct_relationships](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_direct_relationships) \n- [search_relationships](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.search_relationships) \n\n\nAll this function are based on [prepare_query](https://geronimo-iia.github.io/networkx-query/reference/#networkx_query.prepare_query) which return an Evaluator.\n\nQuickly, ```Evaluator``` are function with this signature: (context) -> bool, and ```Context``` is a dictionary like structure (with in and [] methods, and support __contains__ or  (__iter__ and __getitem__))\nWith networkX, node and edge attributes are dictionary like, so implementation of this three methods are very simple.\n\n\n\n## Query language\n\nWe define a little json query language like [json-query-language](https://github.com/clue/json-query-language/blob/master/SYNTAX.md) \nagainst nodes or edges attributes.\n\n\n### Expressions\n\nMain expression syntax turn around this:\n\n```\n{\n    operator_name : parameters\n}\n```\n\n### Basic matching expression\n\nTest if a node/edge has an attribute named \"my_property\":\n```\n{\n    \"has\" : \"my_property\"\n}\n```\n\n\nTest if a node/edge has an attribute product : { \"definition\": { \"name\": xxx }} with xxx equals to \"chocolate\".\n```\n{\n    \"eq\" : [ (\"product\", \"definition\", \"name\"), \"chocolate\"]\n}\n```\n\nThe tuple ```(\"product\", \"definition\", \"name\")``` is a path in attribut dictionnary.\nA Path is a single string or a tuple of string which represente a path in a tree (here a dictionary).\n\nWe support this operators:\n\n| Name     | Alias | Parameters      | Description                                                                   |\n| -------- | :---: | --------------- | ----------------------------------------------------------------------------- |\n| has      |       | Path            | Check if path exists in context.                                              |\n| contains |       | Path, str       | Check if an attribut path exists and contains specified value.                |\n| eq       | `==`  | Path, Any       | Check if an attribut path exists and equals specified value.                  |\n| neq      | `!=`  | Path, Any       | Check if an attribut path did not exists or not equals specified value.       |\n| gt       |  `>`  | Path, Any       | Check if an attribut path exists and greather that specified value.           |\n| lt       |  `<`  | Path, Any       | Check if an attribut path exists and lower that specified value.              |\n| gte      | `>=`  | Path, Any       | Check if an attribut path exists and greather or equals that specified value. |\n| lte      | `<=`  | Path, Any       | Check if an attribut path exists and lower or equals that specified value.    |\n| in       | `:=`  | Path, List[Any] | Check if an attribut path exists and attribut value in specified values.      |\n\n\n### Boolean composition of matching expression\n\nWe support this operators:\n\n| Name | Alias | Parameters    | Description    |\n| ---- | :---: | ------------- | -------------- |\n| and  | `&&`  | list of query | And operator.  |\n| or   | \\|\\|  | list of query | Or operator.   |\n| xor  |       | list of query | xor operator.  |\n| nxor |       | list of query | nxor operator. |\n| not  |  `!`  | query         | Not operator.  |\n\n\nBy default, a list of expressions is equivalent of an \"AND\" of this expressions.\n\nExample:\n```\n{\n    'not': {\n        'has': ['group']\n    },\n    'has': 'application',\n    'eq': [('_link', 'other', 'weight'), 2]\n}\n```\nis equivalent to:\n\n```\n{\n    'and': [\n        {\n            'not': [\n                {\n                    'has': ['group']\n                }\n            ]\n        },\n        {\n            'has': ['application']\n        },\n        {\n            'eq': [('_link', 'other', 'weight'), 2]\n        }\n    ]\n}\n```\n\n## Wished Features\n\n- add projection expression (a return like statement)\n- add join relation ship \n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "NetworkX Query Tool",
    "version": "2.0.0",
    "project_urls": {
        "Documentation": "https://geronimo-iia.github.io/networkx-query/",
        "Homepage": "https://pypi.org/project/networkx_query",
        "Repository": "https://github.com/geronimo-iia/networkx-query"
    },
    "split_keywords": [
        "networkx",
        "graph",
        "query"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "85ea474361cf794dd8addd904ede666a1fdbe72cde5d9120bd2be944ac579d8f",
                "md5": "5285cc45b35a8b124953c254f0ef295e",
                "sha256": "05cb1a8fd655abbb03d82f794fa81054d480424d6a1d16edbb240b82b56e66f2"
            },
            "downloads": -1,
            "filename": "networkx_query-2.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5285cc45b35a8b124953c254f0ef295e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<3.12",
            "size": 12296,
            "upload_time": "2023-06-02T14:23:06",
            "upload_time_iso_8601": "2023-06-02T14:23:06.165607Z",
            "url": "https://files.pythonhosted.org/packages/85/ea/474361cf794dd8addd904ede666a1fdbe72cde5d9120bd2be944ac579d8f/networkx_query-2.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5685e88a264ab2d2d9cf34d471b2e16552e79f73953c496a672414497ee9d6a9",
                "md5": "3eb00c7f9150e23d03513bb5472c0a9c",
                "sha256": "f3b98f05460b4a9a7a305857c410712bdc8fb33ceb20cfbf959822853b4be1a0"
            },
            "downloads": -1,
            "filename": "networkx_query-2.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "3eb00c7f9150e23d03513bb5472c0a9c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<3.12",
            "size": 12923,
            "upload_time": "2023-06-02T14:23:07",
            "upload_time_iso_8601": "2023-06-02T14:23:07.339569Z",
            "url": "https://files.pythonhosted.org/packages/56/85/e88a264ab2d2d9cf34d471b2e16552e79f73953c496a672414497ee9d6a9/networkx_query-2.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-02 14:23:07",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "geronimo-iia",
    "github_project": "networkx-query",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "networkx-query"
}
        
Elapsed time: 2.06647s