From 7e8236986b62e06a130ff6fb38a3b1e239731c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Ta=C5=A1evski?= <36607228+BorisTasevski@users.noreply.github.com> Date: Mon, 12 Dec 2022 14:17:09 +0100 Subject: [PATCH 1/8] Add ubuntu 20.04 explicitly to the pipeline yaml (#211) --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7081f30d..f9bfe18e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: python-version: ["3.7", "3.8", "3.9"] - os: [ubuntu-latest] + os: [ubuntu-20.04] runs-on: ${{ matrix.os }} steps: - name: Checkout Repository From 75b410585aac0be9c849d5a7e93a5eb14554e79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Sa=C4=8Dari=C4=87?= Date: Mon, 2 Jan 2023 18:19:11 +0100 Subject: [PATCH 2/8] [develop < T0122] add AllShortest support (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add algorithm and tests * black format * black 2 * Added Support for numpy ndarrays and scalars * katelate comments * kate late Co-authored-by: Boris Taševski <36607228+BorisTasevski@users.noreply.github.com> --- .../graph_algorithms/integrated_algorithms.py | 77 +++++++++++++++---- gqlalchemy/utilities.py | 7 +- .../test_memgraph_query_builder.py | 71 ++++++++++++++++- tests/test_utilities.py | 5 ++ 4 files changed, 143 insertions(+), 17 deletions(-) diff --git a/gqlalchemy/graph_algorithms/integrated_algorithms.py b/gqlalchemy/graph_algorithms/integrated_algorithms.py index cfda0966..f8722eca 100644 --- a/gqlalchemy/graph_algorithms/integrated_algorithms.py +++ b/gqlalchemy/graph_algorithms/integrated_algorithms.py @@ -17,6 +17,7 @@ BFS_EXPANSION = " *BFS" DFS_EXPANSION = " *" WSHORTEST_EXPANSION = " *WSHORTEST" +ALLSHORTEST_EXPANSION = " *ALLSHORTEST" DEFAULT_TOTAL_WEIGHT = "total_weight" DEFAULT_WEIGHT_PROPERTY = "r.weight" @@ -72,10 +73,10 @@ def __init__( ) -> None: """ Args: - lower_bound: Lower bound for path depth. Defaults to `None`. - upper_bound: Upper bound for path depth. Defaults to `None`. + lower_bound: Lower bound for path depth. + upper_bound: Upper bound for path depth. condition: Filter through nodes and relationships that pass this - condition. Defaults to `None`. + condition. """ super().__init__() self.lower_bound = str(lower_bound) if lower_bound is not None else "" @@ -123,10 +124,10 @@ def __init__( ) -> None: """ Args: - lower_bound: Lower bound for path depth. Defaults to None. - upper_bound: Upper bound for path depth. Defaults to None. + lower_bound: Lower bound for path depth. + upper_bound: Upper bound for path depth. condition: Filter through nodes and relationships that pass this - condition. Defaults to None. + condition. """ super().__init__() self.lower_bound = str(lower_bound) if lower_bound is not None else "" @@ -156,7 +157,8 @@ def to_cypher_bounds(self) -> str: class WeightedShortestPath(IntegratedAlgorithm): - """Build a Djikstra shortest path call for a Cypher query + """Build a Djikstra shortest path call for a Cypher query. + The weighted shortest path algorithm can be called in Memgraph with Cypher queries such as: " MATCH (a {id: 723})-[r *WSHORTEST 10 (r, n | r.weight) weight_sum @@ -175,19 +177,18 @@ def __init__( ) -> None: """ Args: - upper_bound: Upper bound for path depth. Defaults to None. + upper_bound: Upper bound for path depth. condition: Filter through nodes and relationships that pass this - condition. Defaults to None. + condition. total_weight_var: Variable defined as the sum of all weights on - path being returned. Defaults to "total_weight". - weight_property: property being used as weight. Defaults to - "r.weight". + path being returned. + weight_property: property being used as weight. """ super().__init__() - self.weight_property = f"r.{weight_property}" if "." not in weight_property else weight_property + self.weight_property = weight_property if "." in weight_property else f"r.{weight_property}" self.total_weight_var = total_weight_var self.condition = condition - self.upper_bound = str(upper_bound) if upper_bound is not None else "" + self.upper_bound = "" if upper_bound is None else str(upper_bound) def __str__(self) -> str: algo_str = WSHORTEST_EXPANSION @@ -201,3 +202,51 @@ def __str__(self) -> str: algo_str = f"{algo_str} {filter_lambda}" return algo_str + + +class AllShortestPath(IntegratedAlgorithm): + """Build a Djikstra shortest path call for a Cypher query. + + The weighted shortest path algorithm can be called in Memgraph with Cypher + queries such as: + " MATCH (a {id: 723})-[r *ALLSHORTEST 10 (r, n | r.weight) total_weight + (r, n | r.x > 12 AND r.y < 3)]-(b {id: 882}) RETURN * " + It is called inside the relationship clause, "*ALLSHORTEST" naming the + algorithm, "10" specifying search depth bounds, and "(r, n | )" + is a filter lambda, used to filter which relationships and nodes to use. + """ + + def __init__( + self, + upper_bound: int = None, + condition: str = None, + total_weight_var: str = DEFAULT_TOTAL_WEIGHT, + weight_property: str = DEFAULT_WEIGHT_PROPERTY, + ) -> None: + """ + Args: + upper_bound: Upper bound for path depth. + condition: Filter through nodes and relationships that pass this + condition. + total_weight_var: Variable defined as the sum of all weights on + path being returned. + weight_property: Property being used as weight. + """ + super().__init__() + self.weight_property = weight_property if "." in weight_property else f"r.{weight_property}" + self.total_weight_var = total_weight_var + self.condition = condition + self.upper_bound = "" if upper_bound is None else str(upper_bound) + + def __str__(self) -> str: + algo_str = ALLSHORTEST_EXPANSION + if self.upper_bound != "": + algo_str = f"{algo_str} {self.upper_bound}" + + algo_str = f"{algo_str} {super().to_cypher_lambda(self.weight_property)} {self.total_weight_var}" + + filter_lambda = super().to_cypher_lambda(self.condition) + if filter_lambda != "": + algo_str = f"{algo_str} {filter_lambda}" + + return algo_str diff --git a/gqlalchemy/utilities.py b/gqlalchemy/utilities.py index 65bb84f4..f66f81b5 100644 --- a/gqlalchemy/utilities.py +++ b/gqlalchemy/utilities.py @@ -13,6 +13,8 @@ # limitations under the License. import math +import numpy as np + from datetime import datetime, date, time, timedelta from enum import Enum from typing import Any, Dict, List, Optional, Tuple, Union @@ -88,13 +90,16 @@ def to_cypher_value(value: Any, config: NetworkXCypherConfig = None) -> str: if value_type in [int, float, bool]: return str(value) - if value_type in [list, set, tuple]: + if value_type in [list, set, tuple, np.ndarray]: return f"[{', '.join(map(to_cypher_value, value))}]" if value_type == dict: lines = ", ".join(f"{k}: {to_cypher_value(v)}" for k, v in value.items()) return f"{{{lines}}}" + if isinstance(value, np.generic): + return to_cypher_value(value.item()) + if value is None: return "null" diff --git a/tests/query_builders/test_memgraph_query_builder.py b/tests/query_builders/test_memgraph_query_builder.py index 27eb2b46..e8b85c03 100644 --- a/tests/query_builders/test_memgraph_query_builder.py +++ b/tests/query_builders/test_memgraph_query_builder.py @@ -27,7 +27,12 @@ Unwind, With, ) -from gqlalchemy.graph_algorithms.integrated_algorithms import BreadthFirstSearch, DepthFirstSearch, WeightedShortestPath +from gqlalchemy.graph_algorithms.integrated_algorithms import ( + BreadthFirstSearch, + DepthFirstSearch, + WeightedShortestPath, + AllShortestPath, +) from gqlalchemy.utilities import PropertyVariable @@ -244,7 +249,7 @@ def test_dfs_bounds(lower_bound, upper_bound, expected_query): mock.assert_called_with(expected_query) -def test_wshortest(): +def test_wShortest(): weighted_shortest = WeightedShortestPath(weight_property="r.weight") query_builder = ( @@ -306,6 +311,68 @@ def test_wShortest_filter_label(): mock.assert_called_with(expected_query) +def test_allShortest(): + all_shortest = AllShortestPath(weight_property="r.weight") + + query_builder = ( + QueryBuilder() + .match() + .node(variable="a", id=723) + .to(variable="r", directed=False, algorithm=all_shortest) + .node(variable="b", id=882) + .return_() + ) + + expected_query = " MATCH (a {id: 723})-[r *ALLSHORTEST (r, n | r.weight) total_weight]-(b {id: 882}) RETURN * " + + with patch.object(Memgraph, "execute_and_fetch", return_value=None) as mock: + query_builder.execute() + + mock.assert_called_with(expected_query) + + +def test_allShortest_bound(): + all_shortest = AllShortestPath(upper_bound=10, weight_property="weight") + + query_builder = ( + QueryBuilder() + .match() + .node(variable="a", id=723) + .to(variable="r", directed=False, algorithm=all_shortest) + .node(variable="b", id=882) + .return_() + ) + + expected_query = " MATCH (a {id: 723})-[r *ALLSHORTEST 10 (r, n | r.weight) total_weight]-(b {id: 882}) RETURN * " + + with patch.object(Memgraph, "execute_and_fetch", return_value=None) as mock: + query_builder.execute() + + mock.assert_called_with(expected_query) + + +def test_allShortest_filter_label(): + all_shortest = AllShortestPath( + upper_bound=10, weight_property="weight", condition="r.x > 12 AND n.y < 3", total_weight_var="weight_sum" + ) + + query_builder = ( + QueryBuilder() + .match() + .node(variable="a", id=723) + .to(variable="r", directed=False, algorithm=all_shortest) + .node(variable="b", id=882) + .return_() + ) + + expected_query = " MATCH (a {id: 723})-[r *ALLSHORTEST 10 (r, n | r.weight) weight_sum (r, n | r.x > 12 AND n.y < 3)]-(b {id: 882}) RETURN * " + + with patch.object(Memgraph, "execute_and_fetch", return_value=None) as mock: + query_builder.execute() + + mock.assert_called_with(expected_query) + + class TestMemgraphBaseClasses: def test_base_class_call(self): query_builder = Call("pagerank.get").yield_().return_() diff --git a/tests/test_utilities.py b/tests/test_utilities.py index e2072923..ed2b6f31 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -14,6 +14,7 @@ import datetime import math +import numpy as np import pytest from gqlalchemy.utilities import ( @@ -37,6 +38,10 @@ ({"k1": 123, "k2": {"subkey1": "abc"}}, "{k1: 123, k2: {subkey1: 'abc'}}"), (None, "null"), (True, "True"), + (np.array([1, 2, 3]), "[1, 2, 3]"), + (np.array([1.23, 2.34, 3.45]), "[1.23, 2.34, 3.45]"), + (np.array(["1", "2", "3"]), "['1', '2', '3']"), + (np.array([[1, 2], [3, 4], [4, 5]]), "[[1, 2], [3, 4], [4, 5]]"), ], ) def test_to_cypher_value(value, cypher_value): From 43832c07b5275de7244e3e220c81d881fc16c21e Mon Sep 17 00:00:00 2001 From: Katarina Supe <61758502+katarinasupe@users.noreply.github.com> Date: Fri, 17 Feb 2023 12:26:51 +0100 Subject: [PATCH 3/8] [develop < update-docstring-and-pyproject] Update docstring (#219) * Update docstring --- gqlalchemy/query_builders/declarative_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqlalchemy/query_builders/declarative_base.py b/gqlalchemy/query_builders/declarative_base.py index 5ae50f8c..db20de60 100644 --- a/gqlalchemy/query_builders/declarative_base.py +++ b/gqlalchemy/query_builders/declarative_base.py @@ -707,7 +707,7 @@ def call( Call procedure with arguments: - Python: `call('json_util.load_from_url', 'https://some-url.com').yield_('objects').return_(results='objects').execute() + Python: `call('json_util.load_from_url', "'https://some-url.com'").yield_('objects').return_(results='objects').execute() Cypher: `CALL json_util.load_from_url(https://some-url.com) YIELD objects RETURN objects;` """ self._query.append(CallPartialQuery(procedure, arguments)) From 0b0fd5fc7606019c53ce07b1746054d12d764e58 Mon Sep 17 00:00:00 2001 From: lcorcodilos Date: Tue, 21 Feb 2023 10:07:07 -0500 Subject: [PATCH 4/8] Add parameters to execute methods (#217) Add functionality for Connection and DatabaseClient to support paramters with a query to execute. Co-authored-by: Lucas Corcodilos --- gqlalchemy/connection.py | 20 ++++++++++---------- gqlalchemy/vendors/database_client.py | 10 ++++++---- tests/test_query.py | 27 +++++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/gqlalchemy/connection.py b/gqlalchemy/connection.py index bf3c41e1..0f4a8699 100644 --- a/gqlalchemy/connection.py +++ b/gqlalchemy/connection.py @@ -45,12 +45,12 @@ def __init__( self.client_name = client_name @abstractmethod - def execute(self, query: str) -> None: + def execute(self, query: str, parameters: Dict[str, Any] = {}) -> None: """Executes Cypher query without returning any results.""" pass @abstractmethod - def execute_and_fetch(self, query: str) -> Iterator[Dict[str, Any]]: + def execute_and_fetch(self, query: str, parameters: Dict[str, Any] = {}) -> Iterator[Dict[str, Any]]: """Executes Cypher query and returns iterator of results.""" pass @@ -78,17 +78,17 @@ def __init__( self._connection = self._create_connection() @database_error_handler - def execute(self, query: str) -> None: + def execute(self, query: str, parameters: Dict[str, Any] = {}) -> None: """Executes Cypher query without returning any results.""" cursor = self._connection.cursor() - cursor.execute(query) + cursor.execute(query, parameters) cursor.fetchall() @database_error_handler - def execute_and_fetch(self, query: str) -> Iterator[Dict[str, Any]]: + def execute_and_fetch(self, query: str, parameters: Dict[str, Any] = {}) -> Iterator[Dict[str, Any]]: """Executes Cypher query and returns iterator of results.""" cursor = self._connection.cursor() - cursor.execute(query) + cursor.execute(query, parameters) while True: row = cursor.fetchone() if row is None: @@ -166,15 +166,15 @@ def __init__( self.lazy = lazy self._connection = self._create_connection() - def execute(self, query: str) -> None: + def execute(self, query: str, parameters: Dict[str, Any] = {}) -> None: """Executes Cypher query without returning any results.""" with self._connection.session() as session: - session.run(query) + session.run(query, parameters) - def execute_and_fetch(self, query: str) -> Iterator[Dict[str, Any]]: + def execute_and_fetch(self, query: str, parameters: Dict[str, Any] = {}) -> Iterator[Dict[str, Any]]: """Executes Cypher query and returns iterator of results.""" with self._connection.session() as session: - results = session.run(query) + results = session.run(query, parameters) columns = results.keys() for result in results: yield {column: _convert_neo4j_value(result[column]) for column in columns} diff --git a/gqlalchemy/vendors/database_client.py b/gqlalchemy/vendors/database_client.py index 6de27037..df907f67 100644 --- a/gqlalchemy/vendors/database_client.py +++ b/gqlalchemy/vendors/database_client.py @@ -51,15 +51,17 @@ def host(self): def port(self): return self._port - def execute_and_fetch(self, query: str, connection: Connection = None) -> Iterator[Dict[str, Any]]: + def execute_and_fetch( + self, query: str, parameters: Dict[str, Any] = {}, connection: Connection = None + ) -> Iterator[Dict[str, Any]]: """Executes Cypher query and returns iterator of results.""" connection = connection or self._get_cached_connection() - return connection.execute_and_fetch(query) + return connection.execute_and_fetch(query, parameters) - def execute(self, query: str, connection: Connection = None) -> None: + def execute(self, query: str, parameters: Dict[str, Any] = {}, connection: Connection = None) -> None: """Executes Cypher query without returning any results.""" connection = connection or self._get_cached_connection() - connection.execute(query) + connection.execute(query, parameters) def create_index(self, index: Index) -> None: """Creates an index (label or label-property type) in the database.""" diff --git a/tests/test_query.py b/tests/test_query.py index 5921b207..700d2987 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -18,10 +18,10 @@ from gqlalchemy import Memgraph, Node -def query(command: str) -> Iterator[Dict[str, Any]]: +def query(command: str, parameters: Dict[str, Any] = {}) -> Iterator[Dict[str, Any]]: """Queries Memgraph database and returns iterator of results""" db = Memgraph() - yield from db.execute_and_fetch(command) + yield from db.execute_and_fetch(command, parameters) @pytest.fixture @@ -54,3 +54,26 @@ def test_query_create_count(clear_db): count_command = "MATCH (n) RETURN count(n) as cnt" assert list(query(count_command)) == [{"cnt": 2}] + + +def test_query_with_params(clear_db): + parameters = { + "data": [ + {"source": "uid1", "destination": "uid2", "operation": "op1"}, + {"source": "uid2", "destination": "uid1", "operation": "op2"}, + {"source": "uid1", "destination": "uid1", "operation": "op3"}, + ] + } + + unwind_command = """ + UNWIND $data AS row + MERGE (n {uid: row.source})-[e:OPERATION {operation: row.operation}]->(m {uid: row.destination}) + RETURN n, e, m + """ + + unwind_results = list(query(unwind_command, parameters)) + assert len(unwind_results) == 3 + assert set(unwind_results[0].keys()) == {"n", "m", "e"} + + get_operations_command = "MATCH (n)-[e]->(m) RETURN collect(e.operation) as ops" + assert list(query(get_operations_command)) == [{"ops": ["op1", "op2", "op3"]}] From 7c9092a3b9d23feba3e4fa0742f13cccca9f66c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Sa=C4=8Dari=C4=87?= Date: Wed, 1 Mar 2023 19:45:50 +0100 Subject: [PATCH 5/8] [develop < T0123] Graph project implementation (#210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Support for numpy ndarrays and scalars * add initial functionality * formatting * tests * KateLatte changes * katelatte proposed CypherObject classes * add support for two labels * docstring edit * kate late * kate rename * whoops * mrma suggestions * remake all --------- Co-authored-by: Boris Taševski <36607228+BorisTasevski@users.noreply.github.com> --- .../query_builders/memgraph_query_builder.py | 144 +++++++++++++++++- gqlalchemy/utilities.py | 82 +++++++++- .../test_memgraph_query_builder.py | 81 +++++++++- .../test_neo4j_query_builder.py | 4 +- tests/query_builders/test_query_builders.py | 12 +- 5 files changed, 308 insertions(+), 15 deletions(-) diff --git a/gqlalchemy/query_builders/memgraph_query_builder.py b/gqlalchemy/query_builders/memgraph_query_builder.py index f967e5f0..e07ae27b 100644 --- a/gqlalchemy/query_builders/memgraph_query_builder.py +++ b/gqlalchemy/query_builders/memgraph_query_builder.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Optional +from typing import Optional, Union, Tuple, List +from string import ascii_lowercase from gqlalchemy.query_builders.declarative_base import ( # noqa F401 Call, @@ -31,6 +32,7 @@ ) from gqlalchemy.vendors.database_client import DatabaseClient from gqlalchemy.vendors.memgraph import Memgraph +from gqlalchemy.utilities import CypherVariable, CypherNode, CypherRelationship, RelationshipDirection class MemgraphQueryBuilderTypes(DeclarativeBaseTypes): @@ -79,8 +81,148 @@ def load_csv(self, path: str, header: bool, row: str) -> "DeclarativeBase": return self + def _construct_subgraph_path( + self, + relationship_types: Optional[Union[str, List[List[str]]]] = None, + relationship_directions: Optional[ + Union[RelationshipDirection, List[RelationshipDirection]] + ] = RelationshipDirection.RIGHT, + ) -> str: + """Constructs a MATCH query defining a subgraph using node labels and relationship types. + + Args: + relationship_types: A string or list of lists of types of relationships used in the subgraph. + relationship_directions: Enums representing directions. + + Returns: + a string representing a MATCH query for a path with given node labels and relationship types. + """ + + query = f"{CypherNode(variable=ascii_lowercase[0])}" + for i in range(len(relationship_types)): + query += f"{CypherRelationship(relationship_types[i], relationship_directions[i])}{CypherNode()}" + + return query + + def call( + self, + procedure: str, + arguments: Optional[Union[str, Tuple[Union[str, int, float]]]] = None, + node_labels: Optional[Union[str, List[List[str]]]] = None, + relationship_types: Optional[Union[str, List[List[str]]]] = None, + relationship_directions: Optional[ + Union[RelationshipDirection, List[RelationshipDirection]] + ] = RelationshipDirection.RIGHT, + subgraph_path: str = None, + ) -> "DeclarativeBase": + """Override of base class method to support Memgraph's subgraph functionality. + + Method can be called with node labels and relationship types, both being optional, which are used to construct + a subgraph, or if neither is provided, a subgraph query is used, which can be passed as a string representing a + Cypher query defining the MATCH clause which selects the nodes and relationships to use. + + Args: + procedure: A string representing the name of the procedure in the + format `query_module.procedure`. + arguments: A string representing the arguments of the procedure in + text format. + node_labels: Either a string, which is then used as the label for all nodes, or + a list of lists defining all labels for every node + relationship_types: Types of relationships to be used in the subgraph. Either a + single type or a list of lists defining all types for every relationship + relationship_directions: Directions of the relationships. + subgraph_path: Optional way to define the subgraph via a Cypher MATCH clause. + + Returns: + A `DeclarativeBase` instance for constructing queries. + + Examples: + Python: `call('export_util.json', '/home/user', "LABEL", ["TYPE1", "TYPE2"]).execute() + Cypher: `MATCH p=(a)-[:TYPE1 | :TYPE2]->(b) WHERE (a:LABEL) AND (b:LABEL) + WITH project(p) AS graph CALL export_util.json(graph, '/home/user')` + + or + + Python: `call('export_util.json', '/home/user', subgraph_path="(:LABEL)-[:TYPE]->(:LABEL)").execute() + Cypher: `MATCH p=(:LABEL)-[:TYPE1]->(:LABEL) WITH project(p) AS graph + CALL export_util.json(graph, '/home/user')` + """ + + if not (node_labels is None and relationship_types is None): + if isinstance(relationship_types, str): + relationship_types = [[relationship_types]] * ( + len(node_labels) - 1 if isinstance(node_labels, list) else 1 + ) + + if isinstance(node_labels, str): + node_labels = [[node_labels]] * (len(relationship_types) + 1 if relationship_types else 2) + + if isinstance(relationship_directions, RelationshipDirection): + relationship_directions = [relationship_directions] * ( + len(relationship_types) if relationship_types else 1 + ) + + if ( + node_labels + and relationship_types + and ( + len(node_labels) != len(relationship_types) + 1 + or len(relationship_types) != len(relationship_directions) + ) + ): + raise ValueError( + "number of items in node_labels should be one more than in relationship_types and relationship_directions" + ) + + subgraph_path = f"{CypherNode(variable=ascii_lowercase[0])}" + for i in range(len(relationship_directions)): + rel_types = relationship_types[i] if relationship_types else None + subgraph_path += f"{CypherRelationship(rel_types, relationship_directions[i])}{CypherNode(variable=ascii_lowercase[i + 1])}" + + if subgraph_path is not None: + self._query.append(ProjectPartialQuery(subgraph_path=subgraph_path, node_labels=node_labels)) + + if isinstance(arguments, str): + arguments = (CypherVariable(name="graph"), arguments) + elif isinstance(arguments, tuple): + arguments = (CypherVariable(name="graph"), *arguments) + else: + arguments = CypherVariable(name="graph") + + super().call(procedure=procedure, arguments=arguments) + + return self + class LoadCsv(DeclarativeBase): def __init__(self, path: str, header: bool, row: str, connection: Optional[DatabaseClient] = None): super().__init__(connection) self._query.append(LoadCsvPartialQuery(path, header, row)) + + +class ProjectPartialQuery(PartialQuery): + def __init__(self, subgraph_path: str, node_labels: Optional[List[List[str]]] = None): + super().__init__(DeclarativeBaseTypes.MATCH) + self._subgraph_path = subgraph_path + self._node_labels = node_labels + + @property + def subgraph_path(self) -> str: + return self._subgraph_path + + @property + def node_labels(self) -> Optional[List[List[str]]]: + return self._node_labels + + def construct_query(self) -> str: + """Constructs a Project partial querty. + + Given path part of a query (e.g. (:LABEL)-[:TYPE]->(:LABEL2)), + adds MATCH, a path identifier and appends the WITH clause.""" + query = f" MATCH p={self.subgraph_path}" + if self.node_labels: + query += f" WHERE ({ascii_lowercase[0]}:" + f" or {ascii_lowercase[0]}:".join(self.node_labels[0]) + ")" + for i in range(1, len(self.node_labels)): + query += f" AND ({ascii_lowercase[i]}:" + f" or {ascii_lowercase[i]}:".join(self.node_labels[i]) + ")" + + return query + " WITH project(p) AS graph " diff --git a/gqlalchemy/utilities.py b/gqlalchemy/utilities.py index f66f81b5..d4f1936c 100644 --- a/gqlalchemy/utilities.py +++ b/gqlalchemy/utilities.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from abc import ABC, abstractmethod import math import numpy as np @@ -72,7 +73,7 @@ def to_cypher_value(value: Any, config: NetworkXCypherConfig = None) -> str: value_type = type(value) - if value_type == PropertyVariable: + if value_type == CypherVariable: return str(value) if isinstance(value, (timedelta, time, datetime, date)): @@ -139,9 +140,82 @@ def to_cypher_qm_arguments(arguments: Optional[Union[str, Tuple[Union[str, int, return arguments -class PropertyVariable: - """Class for support of using a variable as a node or edge property. Used - to avoid the quotes given to property values. +class CypherObject(ABC): + """Abstract method representing an object in cypher syntax, such as nodes + and relationships. + """ + + @abstractmethod + def __str__(self) -> str: + pass + + +class CypherNode(CypherObject): + """Represents a node in Cypher syntax.""" + + def __init__(self, variable: str = None, labels: Optional[Union[str, list]] = None) -> None: + super().__init__() + if isinstance(labels, str) and labels: + self._labels = [labels] + else: + self._labels = labels + self._variable = variable + + def __str__(self) -> str: + s = "(" + + if self._variable: + s += self._variable + + if not self._labels: + return s + ")" + + s += ":" + ":".join(self._labels) + ")" + return s + + +class RelationshipDirection(Enum): + """Defines the direction of CypherRelationship object.""" + + UNDIRECTED = 1 + LEFT = 2 + RIGHT = 3 + + +class CypherRelationship(CypherObject): + """Represents a relationship in Cypher syntax. Multiple types can not be + set on a relationship, only queried. + """ + + def __init__( + self, + types: Optional[Union[str, list]] = None, + direction: Optional[RelationshipDirection] = RelationshipDirection.UNDIRECTED, + ) -> None: + super().__init__() + if isinstance(types, str): + self.types = [types] + else: + self.types = types + self.direction = direction + + def __str__(self) -> str: + if self.types: + cypher_relationship = "-[:" + " | :".join(self.types) + "]-" + else: + cypher_relationship = "--" + + if self.direction == RelationshipDirection.LEFT: + return "<" + cypher_relationship + elif self.direction == RelationshipDirection.RIGHT: + return cypher_relationship + ">" + else: + return cypher_relationship + + +class CypherVariable: + """Class for support of using a variable as value in Cypher. Used + to avoid the quotes given to property values and query module arguments. """ def __init__(self, name: str) -> None: diff --git a/tests/query_builders/test_memgraph_query_builder.py b/tests/query_builders/test_memgraph_query_builder.py index e8b85c03..10eb54ef 100644 --- a/tests/query_builders/test_memgraph_query_builder.py +++ b/tests/query_builders/test_memgraph_query_builder.py @@ -27,13 +27,14 @@ Unwind, With, ) + from gqlalchemy.graph_algorithms.integrated_algorithms import ( BreadthFirstSearch, DepthFirstSearch, WeightedShortestPath, AllShortestPath, ) -from gqlalchemy.utilities import PropertyVariable +from gqlalchemy.utilities import CypherVariable, RelationshipDirection def test_invalid_match_chain_throws_exception(): @@ -57,6 +58,82 @@ def test_load_csv_no_header(memgraph): mock.assert_called_with(expected_query) +def test_call_subgraph_with_labels_and_types(memgraph): + label = "LABEL" + types = [["TYPE1", "TYPE2"]] + query_builder = QueryBuilder().call("export_util.json", "/home/user", node_labels=label, relationship_types=types) + expected_query = " MATCH p=(a)-[:TYPE1 | :TYPE2]->(b) WHERE (a:LABEL) AND (b:LABEL) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') " + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + +def test_call_subgraph_with_labels(memgraph): + label = "LABEL" + query_builder = QueryBuilder().call("export_util.json", "/home/user", node_labels=label) + expected_query = " MATCH p=(a)-->(b) WHERE (a:LABEL) AND (b:LABEL) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') " + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + +def test_call_subgraph_with_multiple_labels(memgraph): + labels = [["LABEL1"], ["LABEL2"]] + query_builder = QueryBuilder().call( + "export_util.json", "/home/user", node_labels=labels, relationship_directions=RelationshipDirection.LEFT + ) + expected_query = " MATCH p=(a)<--(b) WHERE (a:LABEL1) AND (b:LABEL2) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') " + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + +def test_call_subgraph_with_type(memgraph): + relationship_type = "TYPE1" + query_builder = QueryBuilder().call("export_util.json", "/home/user", relationship_types=relationship_type) + expected_query = " MATCH p=(a)-[:TYPE1]->(b) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') " + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + +def test_call_subgraph_with_many(memgraph): + node_labels = [["COMP", "DEVICE"], ["USER"], ["SERVICE", "GATEWAY"]] + relationship_types = [["OWNER", "RENTEE"], ["USES", "MAKES"]] + relationship_directions = [RelationshipDirection.LEFT, RelationshipDirection.RIGHT] + query_builder = QueryBuilder().call( + "export_util.json", + "/home/user", + relationship_types=relationship_types, + node_labels=node_labels, + relationship_directions=relationship_directions, + ) + expected_query = " MATCH p=(a)<-[:OWNER | :RENTEE]-(b)-[:USES | :MAKES]->(c) WHERE (a:COMP or a:DEVICE) AND (b:USER) AND (c:SERVICE or c:GATEWAY) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') " + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + +@pytest.mark.parametrize( + "subgraph_path, expected_query", + [ + ( + "(n:LABEL1)-[:TYPE1]->(m:LABEL2)", + " MATCH p=(n:LABEL1)-[:TYPE1]->(m:LABEL2) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') ", + ), + ( + "(n:LABEL1)-[:TYPE1 | :TYPE2]->(m:LABEL2)", + " MATCH p=(n:LABEL1)-[:TYPE1 | :TYPE2]->(m:LABEL2) WITH project(p) AS graph CALL export_util.json(graph, '/home/user') ", + ), + ], +) +def test_call_subgraph_with_query(memgraph, subgraph_path, expected_query): + query_builder = QueryBuilder().call("export_util.json", "/home/user", subgraph_path=subgraph_path) + with patch.object(Memgraph, "execute", return_value=None) as mock: + query_builder.execute() + mock.assert_called_with(expected_query) + + def test_call_procedure_pagerank(memgraph): query_builder = ( QueryBuilder() @@ -393,7 +470,7 @@ def test_base_class_create(self): mock.assert_called_with(expected_query) def test_base_class_foreach(self, memgraph): - update_clause = Create().node(variable="n", id=PropertyVariable(name="i")) + update_clause = Create().node(variable="n", id=CypherVariable(name="i")) query_builder = Foreach(variable="i", expression="[1, 2, 3]", update_clauses=update_clause.construct_query()) expected_query = " FOREACH ( i IN [1, 2, 3] | CREATE (n {id: i}) ) " diff --git a/tests/query_builders/test_neo4j_query_builder.py b/tests/query_builders/test_neo4j_query_builder.py index ecec3c62..453c5d6d 100644 --- a/tests/query_builders/test_neo4j_query_builder.py +++ b/tests/query_builders/test_neo4j_query_builder.py @@ -25,7 +25,7 @@ Unwind, With, ) -from gqlalchemy.utilities import PropertyVariable +from gqlalchemy.utilities import CypherVariable class TestNeo4jBaseClasses: @@ -50,7 +50,7 @@ def test_base_class_create(self, neo4j): mock.assert_called_with(expected_query) def test_base_class_foreach(self, neo4j): - update_clause = Neo4jQueryBuilder(connection=neo4j).create().node(variable="n", id=PropertyVariable(name="i")) + update_clause = Neo4jQueryBuilder(connection=neo4j).create().node(variable="n", id=CypherVariable(name="i")) query_builder = Foreach( variable="i", expression="[1, 2, 3]", update_clauses=update_clause.construct_query(), connection=neo4j ) diff --git a/tests/query_builders/test_query_builders.py b/tests/query_builders/test_query_builders.py index 06c3e390..7e4ae429 100644 --- a/tests/query_builders/test_query_builders.py +++ b/tests/query_builders/test_query_builders.py @@ -28,7 +28,7 @@ from gqlalchemy import Field, InvalidMatchChainException, Node, QueryBuilder, Relationship from gqlalchemy.exceptions import GQLAlchemyMissingOrder, GQLAlchemyOrderByTypeError from gqlalchemy.query_builders.declarative_base import Operator, Order, _ResultPartialQuery -from gqlalchemy.utilities import PropertyVariable +from gqlalchemy.utilities import CypherVariable @pytest.mark.parametrize("vendor", ["neo4j_query_builder", "memgraph_query_builder"], indirect=True) @@ -1600,7 +1600,7 @@ def test_property_variable(self, vendor): .with_(results={"[1,2,3]": "list"}) .unwind("list", "element") .create() - .node(num=PropertyVariable(name="element")) + .node(num=CypherVariable(name="element")) ) expected_query = " WITH [1,2,3] AS list UNWIND list AS element CREATE ( {num: element})" @@ -1616,7 +1616,7 @@ def test_property_variable_edge(self, vendor): .with_(results={"15": "number"}) .create() .node(variable="n") - .to(relationship_type="REL", num=PropertyVariable(name="number")) + .to(relationship_type="REL", num=CypherVariable(name="number")) .node(variable="m") ) @@ -1628,7 +1628,7 @@ def test_property_variable_edge(self, vendor): mock.assert_called_with(expected_query) def test_foreach(self, vendor): - update_clause = QueryBuilder().create().node(variable="n", id=PropertyVariable(name="i")) + update_clause = QueryBuilder().create().node(variable="n", id=CypherVariable(name="i")) query_builder = vendor[1].foreach( variable="i", expression="[1, 2, 3]", update_clause=update_clause.construct_query() ) @@ -1640,7 +1640,7 @@ def test_foreach(self, vendor): mock.assert_called_with(expected_query) def test_foreach_multiple_update_clauses(self, vendor): - variable_li = PropertyVariable(name="li") + variable_li = CypherVariable(name="li") update_clause_1 = QueryBuilder().create().node(labels="F4", prop=variable_li) update_clause_2 = QueryBuilder().create().node(labels="F5", prop2=variable_li) query = ( @@ -1664,7 +1664,7 @@ def test_foreach_multiple_update_clauses(self, vendor): mock.assert_called_with(expected_query) def test_foreach_nested(self, vendor): - create_query = QueryBuilder().create().node(variable="u", prop=PropertyVariable(name="j")) + create_query = QueryBuilder().create().node(variable="u", prop=CypherVariable(name="j")) nested_query = QueryBuilder().foreach( variable="j", expression="i", update_clause=create_query.construct_query() ) From c628463b5ef5cfebc9e4fa63075d35adb704058b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Sa=C4=8Dari=C4=87?= Date: Thu, 9 Mar 2023 14:53:45 +0100 Subject: [PATCH 6/8] [develop < main] update develop branch (#212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Support for numpy ndarrays and scalars * Update CODEOWNERS * Update CODEOWNERS * [main < ] change Ubuntu and MG version in workflow (#214) * bump to 2.5 * try 2.2 * change ubuntu to 20.04 * revert to MG 2.3.0 * bump to mg 2.5.0 and update qm signatures * Update versioning in pyproject.toml (#220) * Update codeowners (#221) --------- Co-authored-by: Boris Taševski <36607228+BorisTasevski@users.noreply.github.com> Co-authored-by: Katarina Supe <61758502+katarinasupe@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- .github/workflows/build-and-test.yml | 2 +- gqlalchemy/graph_algorithms/query_builder.py | 4 ++-- pyproject.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4418e2fa..02716fb0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @Josipmrden @BorisTasevski @katarinasupe @brunos252 @niko4299 +* @Josipmrden @katarinasupe @brunos252 @as51340 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f9bfe18e..007893b7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,7 +1,7 @@ name: Build and Test env: - MG_VERSION: "2.3.0" + MG_VERSION: "2.5.0" POETRY_VERSION: "1.2.2" on: diff --git a/gqlalchemy/graph_algorithms/query_builder.py b/gqlalchemy/graph_algorithms/query_builder.py index 22fed3b7..f3aa8b85 100644 --- a/gqlalchemy/graph_algorithms/query_builder.py +++ b/gqlalchemy/graph_algorithms/query_builder.py @@ -29,10 +29,10 @@ class MemgraphQueryBuilder(QueryBuilder): def __init__(self, connection: Optional[Union[Connection, Memgraph]] = None): super().__init__(connection) - def example_procedure(self, required_arg: Any, optional_arg=None) -> DeclarativeBase: + def example_c_procedure(self, required_arg: Any, optional_arg=None) -> DeclarativeBase: return self.call("example.procedure", (required_arg, optional_arg)) - def example_write_procedure(self, required_arg: str) -> DeclarativeBase: + def example_c_write_procedure(self, required_arg: str) -> DeclarativeBase: return self.call("example.write_procedure", (required_arg)) def graph_analyzer_analyze(self, analyses: Optional[List[str]] = None) -> DeclarativeBase: diff --git a/pyproject.toml b/pyproject.toml index c0b85b0a..83cfd054 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "GQLAlchemy" -version = "1.3.2" +version = "1.3.3" description = "GQLAlchemy is library developed with purpose of assisting writing and running queries on Memgraph." repository = "https://github.com/memgraph/gqlalchemy" authors = [ From f5302275072f51f14701f8e547d53c2653a29ef4 Mon Sep 17 00:00:00 2001 From: Andi Date: Thu, 9 Mar 2023 15:20:56 +0100 Subject: [PATCH 7/8] [develop < T541-FL] Import and export strategies (#215) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Support for numpy ndarrays and scalars * Update CODEOWNERS * Update CODEOWNERS * [main < ] change Ubuntu and MG version in workflow (#214) * bump to 2.5 * try 2.2 * change ubuntu to 20.04 * revert to MG 2.3.0 * bump to mg 2.5.0 and update qm signatures * DGL basic exporter * Added export strategies * Added import strategies * Started adding DGL tests, fixed few bugs * DGL translator done with tests added :rocket * Added PyG tests, NX functional and test skelet * Added tests and poetry dependency management * Added graph_importers and exporters * Added Memgraph connection info + functional programming * Fix PR comments * Added new test functionalities, isolated nodes support for nx * Torch packages pipeline fix #1 * Install pyg fix * Fix installation order and test loaders * Debug feather test * Old path fix * Added test files for data loaders * Win build * PR comments * PR fixes for constants --------- Co-authored-by: Boris Taševski <36607228+BorisTasevski@users.noreply.github.com> Co-authored-by: Katarina Supe <61758502+katarinasupe@users.noreply.github.com> Co-authored-by: Bruno Sačarić --- .github/workflows/build-and-test.yml | 4 + gqlalchemy/memgraph_constants.py | 9 + gqlalchemy/transformations.py | 228 -- gqlalchemy/transformations/__init__.py | 0 gqlalchemy/transformations/constants.py | 11 + .../transformations/export}/__init__.py | 0 .../export/graph_transporter.py | 60 + .../transformations/export/transporter.py | 28 + gqlalchemy/transformations/graph_type.py | 3 + .../transformations/importing/__init__.py | 13 + .../importing/graph_importer.py | 63 + .../transformations/importing/importer.py | 24 + .../importing}/loaders.py | 6 +- .../transformations/translators/__init__.py | 13 + .../translators/dgl_translator.py | 160 ++ .../translators/nx_translator.py | 292 +++ .../translators/pyg_translator.py | 194 ++ .../transformations/translators/translator.py | 216 ++ gqlalchemy/utilities.py | 17 + gqlalchemy/vendors/memgraph.py | 23 +- poetry.lock | 2176 +++++++++-------- pyproject.toml | 8 +- tests/integration/test_networkx.py | 21 +- tests/test_transformations.py | 175 -- tests/transformations/common.py | 16 + tests/transformations/export/test_export.py | 15 + tests/transformations/importing/__init__.py | 13 + .../transformations/importing/test_import.py | 29 + tests/transformations/loaders/__init__.py | 13 + .../loaders/data/example.csv | 0 .../loaders/data/example.feather | Bin .../loaders/data/example.orc | Bin .../loaders/data/example.parquet | Bin .../loaders/test_loaders.py | 26 +- tests/transformations/translators/__init__.py | 13 + .../translators/test_dgl_transformations.py | 907 +++++++ .../translators/test_nx_transformations.py | 493 ++++ .../translators/test_pyg_transformations.py | 1003 ++++++++ 38 files changed, 4817 insertions(+), 1455 deletions(-) create mode 100644 gqlalchemy/memgraph_constants.py delete mode 100644 gqlalchemy/transformations.py create mode 100644 gqlalchemy/transformations/__init__.py create mode 100644 gqlalchemy/transformations/constants.py rename {tests/loaders => gqlalchemy/transformations/export}/__init__.py (100%) create mode 100644 gqlalchemy/transformations/export/graph_transporter.py create mode 100644 gqlalchemy/transformations/export/transporter.py create mode 100644 gqlalchemy/transformations/graph_type.py create mode 100644 gqlalchemy/transformations/importing/__init__.py create mode 100644 gqlalchemy/transformations/importing/graph_importer.py create mode 100644 gqlalchemy/transformations/importing/importer.py rename gqlalchemy/{ => transformations/importing}/loaders.py (99%) create mode 100644 gqlalchemy/transformations/translators/__init__.py create mode 100644 gqlalchemy/transformations/translators/dgl_translator.py create mode 100644 gqlalchemy/transformations/translators/nx_translator.py create mode 100644 gqlalchemy/transformations/translators/pyg_translator.py create mode 100644 gqlalchemy/transformations/translators/translator.py delete mode 100644 tests/test_transformations.py create mode 100644 tests/transformations/common.py create mode 100644 tests/transformations/export/test_export.py create mode 100644 tests/transformations/importing/__init__.py create mode 100644 tests/transformations/importing/test_import.py create mode 100644 tests/transformations/loaders/__init__.py rename tests/{ => transformations}/loaders/data/example.csv (100%) rename tests/{ => transformations}/loaders/data/example.feather (100%) rename tests/{ => transformations}/loaders/data/example.orc (100%) rename tests/{ => transformations}/loaders/data/example.parquet (100%) rename tests/{ => transformations}/loaders/test_loaders.py (86%) create mode 100644 tests/transformations/translators/__init__.py create mode 100644 tests/transformations/translators/test_dgl_transformations.py create mode 100644 tests/transformations/translators/test_nx_transformations.py create mode 100644 tests/transformations/translators/test_pyg_transformations.py diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 007893b7..f5086edd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -31,6 +31,7 @@ jobs: run: | python -m pip install -U pip sudo -H pip install networkx numpy scipy + sudo -H pip install poethepoet==0.18.1 - name: Setup poetry uses: abatilo/actions-poetry@v2.0.0 with: @@ -49,6 +50,7 @@ jobs: - name: Test project run: | poetry install + poe install-pyg-cpu poetry run pytest -vvv -m "not slow and not ubuntu and not docker" - name: Use the Upload Artifact GitHub Action uses: actions/upload-artifact@v3 @@ -75,6 +77,7 @@ jobs: run: | python -m pip install -U pip python -m pip install networkx numpy scipy + python -m pip install poethepoet==0.18.1 - uses: Vampire/setup-wsl@v1 with: distribution: Ubuntu-20.04 @@ -112,6 +115,7 @@ jobs: - name: Test project run: | poetry install + poe install-pyg-cpu poetry run pytest -vvv -m "not slow and not ubuntu and not docker" - name: Save Memgraph Logs uses: actions/upload-artifact@v3 diff --git a/gqlalchemy/memgraph_constants.py b/gqlalchemy/memgraph_constants.py new file mode 100644 index 00000000..21ede339 --- /dev/null +++ b/gqlalchemy/memgraph_constants.py @@ -0,0 +1,9 @@ +import os + +MG_HOST = os.getenv("MG_HOST", "127.0.0.1") +MG_PORT = int(os.getenv("MG_PORT", "7687")) +MG_USERNAME = os.getenv("MG_USERNAME", "") +MG_PASSWORD = os.getenv("MG_PASSWORD", "") +MG_ENCRYPTED = os.getenv("MG_ENCRYPT", "false").lower() == "true" +MG_CLIENT_NAME = os.getenv("MG_CLIENT_NAME", "GQLAlchemy") +MG_LAZY = os.getenv("MG_LAZY", "false").lower() == "true" diff --git a/gqlalchemy/transformations.py b/gqlalchemy/transformations.py deleted file mode 100644 index 3f664821..00000000 --- a/gqlalchemy/transformations.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import multiprocessing as mp -from typing import Any, Dict, Iterator, List, Union - -import mgclient -import networkx as nx - -from gqlalchemy import Memgraph -from gqlalchemy.models import MemgraphIndex -from gqlalchemy.utilities import NetworkXCypherConfig, to_cypher_labels, to_cypher_properties, to_cypher_value - -__all__ = ("nx_to_cypher", "nx_graph_to_memgraph_parallel") - - -class NetworkXGraphConstants: - LABELS = "labels" - TYPE = "type" - ID = "id" - - -def nx_to_cypher(graph: nx.Graph, config: NetworkXCypherConfig = None) -> Iterator[str]: - """Generates a Cypher query for creating a graph.""" - - if config is None: - config = NetworkXCypherConfig() - - builder = NetworkXCypherBuilder(config=config) - - yield from builder.yield_queries(graph) - - -def nx_graph_to_memgraph_parallel( - graph: nx.Graph, - host: str = "127.0.0.1", - port: int = 7687, - username: str = "", - password: str = "", - encrypted: bool = False, - config: NetworkXCypherConfig = None, -) -> None: - """Generates Cypher queries and inserts data into Memgraph in parallel.""" - if config is None: - config = NetworkXCypherConfig() - - builder = NetworkXCypherBuilder(config=config) - query_groups = builder.yield_query_groups(graph) - - if not config.create_index: - _check_for_index_hint( - host, - port, - username, - password, - encrypted, - ) - - for query_group in query_groups: - _start_parallel_execution(query_group, host, port, username, password, encrypted) - - -def _start_parallel_execution( - queries_gen: Iterator[str], host: str, port: int, username: str, password: str, encrypted: bool -) -> None: - num_of_processes = mp.cpu_count() // 2 - queries = list(queries_gen) - chunk_size = len(queries) // num_of_processes - processes = [] - - for i in range(num_of_processes): - process_queries = queries[i * chunk_size : chunk_size * (i + 1)] - processes.append( - mp.Process( - target=_insert_queries, - args=( - process_queries, - host, - port, - username, - password, - encrypted, - ), - ) - ) - for p in processes: - p.start() - for p in processes: - p.join() - - -def _check_for_index_hint( - host: str = "127.0.0.1", - port: int = 7687, - username: str = "", - password: str = "", - encrypted: bool = False, -): - """Check if the there are indexes, if not show warnings.""" - memgraph = Memgraph(host, port, username, password, encrypted) - indexes = memgraph.get_indexes() - if len(indexes) == 0: - logging.getLogger(__file__).warning( - "Be careful you do not have any indexes set up, the queries will take longer than expected!" - ) - - -def _insert_queries(queries: List[str], host: str, port: int, username: str, password: str, encrypted: bool) -> None: - """Used by multiprocess insertion of nx into memgraph, works on a chunk of queries.""" - memgraph = Memgraph(host, port, username, password, encrypted) - while len(queries) > 0: - try: - query = queries.pop() - memgraph.execute(query) - except mgclient.DatabaseError as e: - queries.append(query) - logging.getLogger(__file__).warning(f"Ignoring database error: {e}") - continue - - -class NetworkXCypherBuilder: - def __init__(self, config: NetworkXCypherConfig): - if config is None: - raise NoNetworkXConfigException("No NetworkX configuration provided!") - - self._config = config - - def yield_queries(self, graph: nx.Graph) -> Iterator[str]: - """Generates Cypher queries for creating a graph.""" - - if self._config.create_index: - yield from self._nx_nodes_to_cypher_with_index(graph) - else: - yield from self._nx_nodes_to_cypher(graph) - yield from self._nx_edges_to_cypher(graph) - - def yield_query_groups(self, graph: nx.Graph) -> List[Iterator[str]]: - """Generates Cypher queries for creating a graph by query groups.""" - - query_groups = [] - - if self._config.create_index: - query_groups.append(self._nx_nodes_to_cypher_with_index(graph)) - else: - query_groups.append(self._nx_nodes_to_cypher(graph)) - - query_groups.append(self._nx_edges_to_cypher(graph)) - - return query_groups - - def _nx_nodes_to_cypher(self, graph: nx.Graph) -> Iterator[str]: - """Generates Cypher queries for creating nodes.""" - for nx_id, data in graph.nodes(data=True): - yield self._create_node(nx_id, data) - - def _nx_nodes_to_cypher_with_index(self, graph: nx.Graph) -> Iterator[str]: - """Generates Cypher queries for creating nodes and indexes.""" - labels = set() - for nx_id, data in graph.nodes(data=True): - node_labels = data.get(NetworkXGraphConstants.LABELS, None) - if isinstance(node_labels, (list, set)): - labels |= set(node_labels) - else: - labels.add(node_labels) - yield self._create_node(nx_id, data) - labels.discard(None) - for label in labels: - yield self._create_index(label) - - def _nx_edges_to_cypher(self, graph: nx.Graph) -> Iterator[str]: - """Generates Cypher queries for creating edges.""" - for n1, n2, data in graph.edges(data=True): - from_label = graph.nodes[n1].get(NetworkXGraphConstants.LABELS, "") - to_label = graph.nodes[n2].get(NetworkXGraphConstants.LABELS, "") - - n1_id = graph.nodes[n1].get(NetworkXGraphConstants.ID, n1) - n2_id = graph.nodes[n2].get(NetworkXGraphConstants.ID, n2) - yield self._create_edge(n1_id, n2_id, from_label, to_label, data) - - def _create_node(self, nx_id: int, properties: Dict[str, Any]) -> str: - """Returns Cypher query for node creation.""" - if "id" not in properties: - properties["id"] = nx_id - labels_str = to_cypher_labels(properties.get(NetworkXGraphConstants.LABELS, "")) - properties_without_labels = {k: v for k, v in properties.items() if k != NetworkXGraphConstants.LABELS} - properties_str = to_cypher_properties(properties_without_labels, self._config) - - return f"CREATE ({labels_str} {properties_str});" - - def _create_edge( - self, - from_id: Union[int, str], - to_id: Union[int, str], - from_label: Union[str, List[str]], - to_label: Union[str, List[str]], - properties: Dict[str, Any], - ) -> str: - """Returns Cypher query for edge creation.""" - edge_type = to_cypher_labels(properties.get(NetworkXGraphConstants.TYPE, "TO")) - properties.pop(NetworkXGraphConstants.TYPE, None) - properties_str = to_cypher_properties(properties, self._config) - from_label_str = to_cypher_labels(from_label) - to_label_str = to_cypher_labels(to_label) - from_id_str = to_cypher_value(from_id) - to_id_str = to_cypher_value(to_id) - - return f"MATCH (n{from_label_str} {{id: {from_id_str}}}), (m{to_label_str} {{id: {to_id_str}}}) CREATE (n)-[{edge_type} {properties_str}]->(m);" - - def _create_index(self, label: str, property: str = None): - """Returns Cypher query for index creation.""" - index = MemgraphIndex(label, property) - return f"CREATE INDEX ON {index.to_cypher()}(id);" - - -class NoNetworkXConfigException(Exception): - pass diff --git a/gqlalchemy/transformations/__init__.py b/gqlalchemy/transformations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gqlalchemy/transformations/constants.py b/gqlalchemy/transformations/constants.py new file mode 100644 index 00000000..e60db034 --- /dev/null +++ b/gqlalchemy/transformations/constants.py @@ -0,0 +1,11 @@ +LABELS_CONCAT = ":" +LABEL = "label" +EDGE_TYPE = "type" +DGL_ID = "dgl_id" +DGL_DEFAULT_NODE_LABEL = "_N" +DGL_DEFAULT_EDGE_TYPE = "_E" +PYG_ID = "pyg_id" +EDGE_INDEX = "edge_index" +NUM_NODES = "num_nodes" +DEFAULT_NODE_LABEL = "NODE" +DEFAULT_EDGE_TYPE = "RELATIONSHIP" diff --git a/tests/loaders/__init__.py b/gqlalchemy/transformations/export/__init__.py similarity index 100% rename from tests/loaders/__init__.py rename to gqlalchemy/transformations/export/__init__.py diff --git a/gqlalchemy/transformations/export/graph_transporter.py b/gqlalchemy/transformations/export/graph_transporter.py new file mode 100644 index 00000000..7b0626ea --- /dev/null +++ b/gqlalchemy/transformations/export/graph_transporter.py @@ -0,0 +1,60 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gqlalchemy.transformations.export.transporter import Transporter +from gqlalchemy.transformations.translators.dgl_translator import DGLTranslator +from gqlalchemy.transformations.translators.nx_translator import NxTranslator +from gqlalchemy.transformations.translators.pyg_translator import PyGTranslator +from gqlalchemy.transformations.graph_type import GraphType +import gqlalchemy.memgraph_constants as mg_consts + + +class GraphTransporter(Transporter): + """Here is a possible example for using this module: + >>> transporter = GraphTransporter("dgl") + graph = transporter.export() + """ + + def __init__( + self, + graph_type: str, + host: str = mg_consts.MG_HOST, + port: int = mg_consts.MG_PORT, + username: str = mg_consts.MG_USERNAME, + password: str = mg_consts.MG_PASSWORD, + encrypted: bool = mg_consts.MG_ENCRYPTED, + client_name: str = mg_consts.MG_CLIENT_NAME, + lazy: bool = mg_consts.MG_LAZY, + ) -> None: + """Initializes GraphTransporter. It is used for converting Memgraph graph to the specific graph type offered by some Python package (PyG, DGL, NX...) + Here is a possible example for using this module: + >>> transporter = GraphTransporter("dgl") + graph = transporter.export() + Args: + graph_type: dgl, pyg or nx + """ + super().__init__() + self.graph_type = graph_type.upper() + if self.graph_type == GraphType.DGL.name: + self.translator = DGLTranslator(host, port, username, password, encrypted, client_name, lazy) + elif self.graph_type == GraphType.PYG.name: + self.translator = PyGTranslator(host, port, username, password, encrypted, client_name, lazy) + elif self.graph_type == GraphType.NX.name: + self.translator = NxTranslator(host, port, username, password, encrypted, client_name, lazy) + else: + raise ValueError("Unknown export option. Currently supported are DGL, PyG and Networkx.") + + def export(self): + """Creates graph instance for the wanted export option.""" + return self.translator.get_instance() diff --git a/gqlalchemy/transformations/export/transporter.py b/gqlalchemy/transformations/export/transporter.py new file mode 100644 index 00000000..181a077d --- /dev/null +++ b/gqlalchemy/transformations/export/transporter.py @@ -0,0 +1,28 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from abc import ABC, abstractmethod + + +class Transporter(ABC): + def __init__(self) -> None: + super().__init__() + + @abstractmethod + def export(query_results): + """Abstract method that will be overriden by subclasses that will know which correct graph type to create. + Raises: + NotImplementedError: The method must be override by a specific translator. + """ + raise NotImplementedError("Subclasses must override this method in order to produce graph of a correct type.") diff --git a/gqlalchemy/transformations/graph_type.py b/gqlalchemy/transformations/graph_type.py new file mode 100644 index 00000000..9f7be8d3 --- /dev/null +++ b/gqlalchemy/transformations/graph_type.py @@ -0,0 +1,3 @@ +from enum import Enum + +GraphType = Enum("GraphType", ["DGL", "PYG", "NX"]) diff --git a/gqlalchemy/transformations/importing/__init__.py b/gqlalchemy/transformations/importing/__init__.py new file mode 100644 index 00000000..34ce70e6 --- /dev/null +++ b/gqlalchemy/transformations/importing/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/gqlalchemy/transformations/importing/graph_importer.py b/gqlalchemy/transformations/importing/graph_importer.py new file mode 100644 index 00000000..733c87a7 --- /dev/null +++ b/gqlalchemy/transformations/importing/graph_importer.py @@ -0,0 +1,63 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gqlalchemy import Memgraph +from gqlalchemy.transformations.graph_type import GraphType +from gqlalchemy.transformations.importing.importer import Importer +from gqlalchemy.transformations.translators.dgl_translator import DGLTranslator +from gqlalchemy.transformations.translators.nx_translator import NxTranslator +from gqlalchemy.transformations.translators.pyg_translator import PyGTranslator +import gqlalchemy.memgraph_constants as mg_consts + + +class GraphImporter(Importer): + """Imports dgl, pyg or networkx graph representations to Memgraph. + The following code will suffice for importing queries. + >>> importer = GraphImporter("dgl") + graph = DGLGraph(...) + importer.translate(graph) # queries are inserted in this step + Args: + graph_type: The type of the graph. + """ + + def __init__( + self, + graph_type: str, + host: str = mg_consts.MG_HOST, + port: int = mg_consts.MG_PORT, + username: str = mg_consts.MG_USERNAME, + password: str = mg_consts.MG_PASSWORD, + encrypted: bool = mg_consts.MG_ENCRYPTED, + client_name: str = mg_consts.MG_CLIENT_NAME, + lazy: bool = mg_consts.MG_LAZY, + ) -> None: + super().__init__() + self.graph_type = graph_type.upper() + if self.graph_type == GraphType.DGL.name: + self.translator = DGLTranslator(host, port, username, password, encrypted, client_name, lazy) + elif self.graph_type == GraphType.PYG.name: + self.translator = PyGTranslator(host, port, username, password, encrypted, client_name, lazy) + elif self.graph_type == GraphType.NX.name: + self.translator = NxTranslator(host, port, username, password, encrypted, client_name, lazy) + else: + raise ValueError("Unknown import option. Currently supported options are: DGL, PyG and Networkx.") + + def translate(self, graph) -> None: + """Gets cypher queries using the underlying translator and then inserts all queries to Memgraph DB. + Args: + graph: dgl, pytorch geometric or nx graph instance. + """ + memgraph = Memgraph() + for query in self.translator.to_cypher_queries(graph): + memgraph.execute(query) diff --git a/gqlalchemy/transformations/importing/importer.py b/gqlalchemy/transformations/importing/importer.py new file mode 100644 index 00000000..0dd6f36e --- /dev/null +++ b/gqlalchemy/transformations/importing/importer.py @@ -0,0 +1,24 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from abc import ABC, abstractmethod + + +class Importer(ABC): + def __init__(self) -> None: + super().__init__() + + @abstractmethod + def translate(self, graph): + raise NotImplementedError("Correct import strategy must be provided by subclasses.") diff --git a/gqlalchemy/loaders.py b/gqlalchemy/transformations/importing/loaders.py similarity index 99% rename from gqlalchemy/loaders.py rename to gqlalchemy/transformations/importing/loaders.py index ab17131c..82d9d042 100644 --- a/gqlalchemy/loaders.py +++ b/gqlalchemy/transformations/importing/loaders.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ TriggerExecutionPhase, ) from gqlalchemy.query_builders.memgraph_query_builder import Operator, QueryBuilder, Unwind - +from gqlalchemy.transformations.importing.importer import Importer NAME_MAPPINGS_KEY = "name_mappings" ONE_TO_MANY_RELATIONS_KEY = "one_to_many_relations" @@ -372,7 +372,7 @@ def load_data( print("Data loaded.") -class TableToGraphImporter: +class TableToGraphImporter(Importer): """Implements translation of table data to graph data, and imports it to Memgraph.""" _DIRECTION = { diff --git a/gqlalchemy/transformations/translators/__init__.py b/gqlalchemy/transformations/translators/__init__.py new file mode 100644 index 00000000..34ce70e6 --- /dev/null +++ b/gqlalchemy/transformations/translators/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/gqlalchemy/transformations/translators/dgl_translator.py b/gqlalchemy/transformations/translators/dgl_translator.py new file mode 100644 index 00000000..c9440beb --- /dev/null +++ b/gqlalchemy/transformations/translators/dgl_translator.py @@ -0,0 +1,160 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Union + +import dgl +import torch + +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.transformations.constants import DGL_ID +from gqlalchemy.utilities import to_cypher_value +from gqlalchemy.memgraph_constants import ( + MG_HOST, + MG_PORT, + MG_USERNAME, + MG_PASSWORD, + MG_ENCRYPTED, + MG_CLIENT_NAME, + MG_LAZY, +) + + +class DGLTranslator(Translator): + """Performs conversion from cypher queries to the DGL graph representation. DGL assigns to each edge a unique integer, called the edge ID, + based on the order in which it was added to the graph. In DGL, all the edges are directed, and an edge (u,v) indicates that the direction goes + from node u to node v. Only features of numerical types (e.g., float, double, and int) are allowed. They can be scalars, vectors or multi-dimensional + tensors (DQL requirement). Each node feature has a unique name and each edge feature has a unique name. The features of nodes and edges can have + the same name. A feature is created via tensor assignment, which assigns a feature to each node/edge in the graph. The leading dimension of that + tensor must be equal to the number of nodes/edges in the graph. You cannot assign a feature to a subset of the nodes/edges in the graph. Features of the + same name must have the same dimensionality and data type. + """ + + def __init__( + self, + host: str = MG_HOST, + port: int = MG_PORT, + username: str = MG_USERNAME, + password: str = MG_PASSWORD, + encrypted: bool = MG_ENCRYPTED, + client_name: str = MG_CLIENT_NAME, + lazy: bool = MG_LAZY, + ) -> None: + super().__init__(host, port, username, password, encrypted, client_name, lazy) + + def to_cypher_queries(self, graph: Union[dgl.DGLGraph, dgl.DGLHeteroGraph]): + """Produce cypher queries for data saved as part of the DGL graph. The method handles both homogeneous and heterogeneous graph. If the graph is homogeneous, a default DGL's labels will be used. + _N as a node label and _E as edge label. The method converts 1D as well as multidimensional features. If there are some isolated nodes inside DGL graph, they won't get transferred. Nodes and edges + created in Memgraph DB will, for the consistency reasons, have property `dgl_id` set to the id they have as part of the DGL graph. Note that this method doesn't insert anything inside the database, + it just creates cypher queries. To insert queries the following code can be used: + >>> memgraph = Memgraph() + dgl_graph = DGLGraph(...) + for query in DGLTranslator().to_cypher_queries(dgl_graph): + memgraph.execute(query) + + Args: + graph: A reference to the DGL graph. + Returns: + cypher queries. + """ + queries = [] + if graph is None: + return queries + for etype in graph.canonical_etypes: + source_node_label, edge_type, dest_node_label = etype + source_nodes, dest_nodes, eids = graph.edges(etype=etype, form="all") + # Get label and type properties + node_src_label_properties = graph.nodes[source_node_label].data + node_dest_label_properties = graph.nodes[dest_node_label].data + etype_properties = graph.edges[etype].data + for source_node_id, dest_node_id, eid in zip(source_nodes, dest_nodes, eids): + # Handle properties + source_node_properties, dest_node_properties, edge_properties = {}, {}, {} + # Copy source node properties + source_node_properties = dict( + map( + lambda pair: (pair[0], to_cypher_value(pair[1][source_node_id])), + node_src_label_properties.items(), + ) + ) + source_node_properties[DGL_ID] = int(source_node_id) + # Copy destination node properties + dest_node_properties = dict( + map( + lambda pair: (pair[0], to_cypher_value(pair[1][dest_node_id])), + node_dest_label_properties.items(), + ) + ) + dest_node_properties[DGL_ID] = int(dest_node_id) + # Copy edge features + edge_properties = dict( + map(lambda pair: (pair[0], to_cypher_value(pair[1][eid])), etype_properties.items()) + ) + edge_properties[DGL_ID] = int(eid) + + # Create query + queries.append( + self.create_insert_query( + source_node_label, + source_node_properties, + edge_type, + edge_properties, + dest_node_label, + dest_node_properties, + ) + ) + return queries + + def get_instance(self) -> dgl.DGLHeteroGraph: + """Create instance of DGL graph from all edges that are inside Memgraph. Currently, isolated nodes are ignored because they don't contribute in message passing neural networks. Only numerical features + that are set on all nodes or all edges are transferred to the DGL instance since this is DGL's requirement. That means thay any string values properties won't be transferred, as well as numerical properties + that aren't set on all nodes. However, features of type list are transferred to the DGL and can be used as any other feature in the DGL graph. Regardless of data residing inside Memgraph database, the created + DGL graph is a heterograph instance. + Returns: + DGL heterograph instance. + """ + # Parse it into nice data structures + src_nodes, dest_nodes, node_features, edge_features, _ = self._parse_memgraph() + + graph_data = {} + # Iterating over src_nodes and dest_nodes should be the same + for type_triplet in src_nodes.keys(): + graph_data[type_triplet] = ( + torch.tensor(src_nodes[type_triplet], dtype=torch.int32), + torch.tensor(dest_nodes[type_triplet], dtype=torch.int32), + ) + + # Fail safely when graph is empty + if len(graph_data) == 0: + return None + + # Create heterograph + graph = dgl.heterograph(graph_data) + # Set node features + for node_label, features_dict in node_features.items(): + for feature_name, features in features_dict.items(): + translated_features = Translator.validate_features(features, graph.num_nodes(node_label)) + if translated_features is None: + continue + graph.nodes[node_label].data[feature_name] = translated_features + + # Set edge features + for edge_triplet, features_dict in edge_features.items(): + for feature_name, features in features_dict.items(): + translated_features = Translator.validate_features(features, graph.num_edges(edge_triplet)) + if translated_features is None: + continue + graph.edges[edge_triplet].data[feature_name] = translated_features + + return graph diff --git a/gqlalchemy/transformations/translators/nx_translator.py b/gqlalchemy/transformations/translators/nx_translator.py new file mode 100644 index 00000000..db5e0fa5 --- /dev/null +++ b/gqlalchemy/transformations/translators/nx_translator.py @@ -0,0 +1,292 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterator, List, Dict, Any, Union +import logging +import multiprocessing as mp + +import networkx as nx +import mgclient + + +from gqlalchemy import Memgraph +from gqlalchemy.transformations.constants import LABEL, EDGE_TYPE, DEFAULT_EDGE_TYPE, DEFAULT_NODE_LABEL +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.models import Node, Relationship, MemgraphIndex +from gqlalchemy.utilities import NetworkXCypherConfig, to_cypher_labels, to_cypher_properties, to_cypher_value +from gqlalchemy.memgraph_constants import ( + MG_HOST, + MG_PORT, + MG_USERNAME, + MG_PASSWORD, + MG_ENCRYPTED, + MG_CLIENT_NAME, + MG_LAZY, +) + + +class NetworkXGraphConstants: + LABELS = "labels" + TYPE = "type" + ID = "id" + + +class NetworkXCypherBuilder: + def __init__(self, config: NetworkXCypherConfig): + if config is None: + raise NoNetworkXConfigException("No NetworkX configuration provided!") + + self._config = config + + def yield_queries(self, graph: nx.Graph) -> Iterator[str]: + """Generates Cypher queries for creating a graph.""" + if graph is None: + return [] + + if self._config.create_index: + yield from self._nx_nodes_to_cypher_with_index(graph) + else: + yield from self._nx_nodes_to_cypher(graph) + yield from self._nx_edges_to_cypher(graph) + + def yield_query_groups(self, graph: nx.Graph) -> List[Iterator[str]]: + """Generates Cypher queries for creating a graph by query groups.""" + + query_groups = [] + + if self._config.create_index: + query_groups.append(self._nx_nodes_to_cypher_with_index(graph)) + else: + query_groups.append(self._nx_nodes_to_cypher(graph)) + + query_groups.append(self._nx_edges_to_cypher(graph)) + + return query_groups + + def _nx_nodes_to_cypher(self, graph: nx.Graph) -> Iterator[str]: + """Generates Cypher queries for creating nodes.""" + for nx_id, data in graph.nodes(data=True): + yield self._create_node(nx_id, data) + + def _nx_nodes_to_cypher_with_index(self, graph: nx.Graph) -> Iterator[str]: + """Generates Cypher queries for creating nodes and indexes.""" + labels = set() + for nx_id, data in graph.nodes(data=True): + node_labels = data.get(NetworkXGraphConstants.LABELS, None) + if isinstance(node_labels, (list, set)): + labels |= set(node_labels) + else: + labels.add(node_labels) + yield self._create_node(nx_id, data) + labels.discard(None) + for label in labels: + yield self._create_index(label) + + def _nx_edges_to_cypher(self, graph: nx.Graph) -> Iterator[str]: + """Generates Cypher queries for creating edges.""" + for n1, n2, data in graph.edges(data=True): + from_label = graph.nodes[n1].get(NetworkXGraphConstants.LABELS, "") + to_label = graph.nodes[n2].get(NetworkXGraphConstants.LABELS, "") + + n1_id = graph.nodes[n1].get(NetworkXGraphConstants.ID, n1) + n2_id = graph.nodes[n2].get(NetworkXGraphConstants.ID, n2) + yield self._create_edge(n1_id, n2_id, from_label, to_label, data) + + def _create_node(self, nx_id: int, properties: Dict[str, Any]) -> str: + """Returns Cypher query for node creation.""" + if "id" not in properties: + properties["id"] = nx_id + labels_str = to_cypher_labels(properties.get(NetworkXGraphConstants.LABELS, "")) + properties_without_labels = {k: v for k, v in properties.items() if k != NetworkXGraphConstants.LABELS} + properties_str = to_cypher_properties(properties_without_labels, self._config) + + return f"CREATE ({labels_str} {properties_str});" + + def _create_edge( + self, + from_id: Union[int, str], + to_id: Union[int, str], + from_label: Union[str, List[str]], + to_label: Union[str, List[str]], + properties: Dict[str, Any], + ) -> str: + """Returns Cypher query for edge creation.""" + edge_type = to_cypher_labels(properties.get(NetworkXGraphConstants.TYPE, "TO")) + properties.pop(NetworkXGraphConstants.TYPE, None) + properties_str = to_cypher_properties(properties, self._config) + from_label_str = to_cypher_labels(from_label) + to_label_str = to_cypher_labels(to_label) + from_id_str = to_cypher_value(from_id) + to_id_str = to_cypher_value(to_id) + + return f"MATCH (n{from_label_str} {{id: {from_id_str}}}), (m{to_label_str} {{id: {to_id_str}}}) CREATE (n)-[{edge_type} {properties_str}]->(m);" + + def _create_index(self, label: str, property: str = None): + """Returns Cypher query for index creation.""" + index = MemgraphIndex(label, property) + return f"CREATE INDEX ON {index.to_cypher()}(id);" + + +class NoNetworkXConfigException(Exception): + pass + + +class NxTranslator(Translator): + """Uses original ids from Memgraph. Labels are encoded as properties. Since Networkx allows + that nodes have properties of different dimensionality, this modules makes use of it and stores properties + as dictionary entries. All properties are saved to Networkx data structure. + """ + + def __init__( + self, + host: str = MG_HOST, + port: int = MG_PORT, + username: str = MG_USERNAME, + password: str = MG_PASSWORD, + encrypted: bool = MG_ENCRYPTED, + client_name: str = MG_CLIENT_NAME, + lazy: bool = MG_LAZY, + ) -> None: + self.__all__ = ("nx_to_cypher", "nx_graph_to_memgraph_parallel") + super().__init__(host, port, username, password, encrypted, client_name, lazy) + + def to_cypher_queries(self, graph: nx.Graph, config: NetworkXCypherConfig = None) -> Iterator[str]: + """Generates a Cypher query for creating a graph.""" + + if config is None: + config = NetworkXCypherConfig() + + builder = NetworkXCypherBuilder(config=config) + + yield from builder.yield_queries(graph) + + def nx_graph_to_memgraph_parallel( + self, + graph: nx.Graph, + config: NetworkXCypherConfig = None, + ) -> None: + """Generates Cypher queries and inserts data into Memgraph in parallel.""" + if config is None: + config = NetworkXCypherConfig() + + builder = NetworkXCypherBuilder(config=config) + query_groups = builder.yield_query_groups(graph) + + if not config.create_index: + self._check_for_index_hint( + self.host, + self.port, + self.username, + self.password, + self.encrypted, + ) + + for query_group in query_groups: + self._start_parallel_execution( + query_group, self.host, self.port, self.username, self.password, self.encrypted + ) + + def _start_parallel_execution(self, queries_gen: Iterator[str]) -> None: + num_of_processes = mp.cpu_count() // 2 + queries = list(queries_gen) + chunk_size = len(queries) // num_of_processes + processes = [] + + for i in range(num_of_processes): + process_queries = queries[i * chunk_size : chunk_size * (i + 1)] + processes.append( + mp.Process( + target=self._insert_queries, + args=( + process_queries, + self.host, + self.port, + self.username, + self.password, + self.encrypted, + ), + ) + ) + for p in processes: + p.start() + for p in processes: + p.join() + + def _insert_queries( + self, queries: List[str], host: str, port: int, username: str, password: str, encrypted: bool + ) -> None: + """Used by multiprocess insertion of nx into memgraph, works on a chunk of queries.""" + memgraph = Memgraph(host, port, username, password, encrypted) + while len(queries) > 0: + try: + query = queries.pop() + memgraph.execute(query) + except mgclient.DatabaseError as e: + queries.append(query) + logging.getLogger(__file__).warning(f"Ignoring database error: {e}") + continue + + def _check_for_index_hint( + self, + host: str = "127.0.0.1", + port: int = 7687, + username: str = "", + password: str = "", + encrypted: bool = False, + ): + """Check if the there are indexes, if not show warnings.""" + memgraph = Memgraph(host, port, username, password, encrypted) + indexes = memgraph.get_indexes() + if len(indexes) == 0: + logging.getLogger(__file__).warning( + "Be careful you do not have any indexes set up, the queries will take longer than expected!" + ) + + def get_instance(self): + """Creates Networx instance of the graph from the data residing inside Memgraph. Since Networkx doesn't support labels in a way Memgraph does, labels + are encoded as a node and edge properties. + """ + # Get all nodes and edges from the database (connected nodes) + rel_results = self.get_all_edges_from_db() + # Data structures + graph_data = [] # List[Tuple[source_node_id, dest_node_id]] + node_info = dict() # Dict[id, Dict[prop: value]] + edge_info = dict() # Dict[(source_node_id, dest_node_id), Dict[prop: value]] + + # Parse each row from query results + for row in rel_results: + row_values = row.values() + for entity in row_values: + entity_properties = entity._properties + if isinstance(entity, Node) and entity._id not in node_info: + entity_properties[LABEL] = Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL) + node_info[entity._id] = entity_properties + elif isinstance(entity, Relationship): + entity_properties[EDGE_TYPE] = entity._type if entity._type else DEFAULT_EDGE_TYPE + edge_info[(entity._start_node_id, entity._end_node_id)] = entity_properties + graph_data.append((entity._start_node_id, entity._end_node_id)) + + # Create Nx graph + graph = nx.DiGraph(graph_data) + nx.set_node_attributes(graph, node_info) + nx.set_edge_attributes(graph, edge_info) + # Process all isolated nodes + isolated_nodes_results = self.get_all_isolated_nodes_from_db() + for isolated_node in isolated_nodes_results: + isolated_node = isolated_node["n"] # + entity_properties = isolated_node._properties + entity_properties[LABEL] = Translator.merge_labels(isolated_node._labels, DEFAULT_NODE_LABEL) + graph.add_node(isolated_node._id, **entity_properties) # unpack dictionary + + return graph diff --git a/gqlalchemy/transformations/translators/pyg_translator.py b/gqlalchemy/transformations/translators/pyg_translator.py new file mode 100644 index 00000000..32db9e5b --- /dev/null +++ b/gqlalchemy/transformations/translators/pyg_translator.py @@ -0,0 +1,194 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from torch_geometric.data import HeteroData, Data +import torch + +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.transformations.constants import EDGE_INDEX, PYG_ID, NUM_NODES, DEFAULT_NODE_LABEL, DEFAULT_EDGE_TYPE +from gqlalchemy.memgraph_constants import ( + MG_HOST, + MG_PORT, + MG_USERNAME, + MG_PASSWORD, + MG_ENCRYPTED, + MG_CLIENT_NAME, + MG_LAZY, +) + + +class PyGTranslator(Translator): + def __init__( + self, + host: str = MG_HOST, + port: int = MG_PORT, + username: str = MG_USERNAME, + password: str = MG_PASSWORD, + encrypted: bool = MG_ENCRYPTED, + client_name: str = MG_CLIENT_NAME, + lazy: bool = MG_LAZY, + ) -> None: + super().__init__(host, port, username, password, encrypted, client_name, lazy) + + @classmethod + def get_node_properties(cls, graph, node_label: str, node_id: int): + """Extracts node properties from heterogeneous graph based on the node_label. + Args: + graph: A reference to the PyG graph. + node_label: Node label + node_id: Node_id + """ + node_properties = {} + for iter_node_label, iter_node_properties in graph.node_items(): + if iter_node_label != node_label: + continue + for property_name, property_values in iter_node_properties.items(): + if property_name == NUM_NODES: + continue + node_properties[property_name] = property_values[node_id] + return node_properties + + @classmethod + def extract_node_edge_properties_from_homogeneous_graph(cls, graph): + """Homogenous graph don't have node and etype properties so it is hard to extract node and edge attributes. + Args: + graph: Data = reference to the PyG graph. + Returns: + node and edge attributes as dictionaries + """ + graph_data = graph.to_dict() + graph_data.pop(EDGE_INDEX, None) + node_properties = dict(filter(lambda pair: graph.is_node_attr(pair[0]), graph_data.items())) + etype_properties = dict(filter(lambda pair: graph.is_edge_attr(pair[0]), graph_data.items())) + return node_properties, etype_properties + + def to_cypher_queries(self, graph): + """Produce cypher queries for data saved as part of thePyG graph. The method handles both homogeneous and heterogeneous graph. + The method converts 1D as well as multidimensional features. If there are some isolated nodes inside the graph, they won't get transferred. Nodes and edges + created in Memgraph DB will, for the consistency reasons, have property `pyg_id` set to the id they have as part of the PyG graph. Note that this method doesn't insert anything inside + the database, it just creates cypher queries. To insert queries the following code can be used: + >>> memgraph = Memgraph() + pyg_graph = HeteroData(...) + for query in PyGTranslator().to_cypher_queries(pyg_graph): + memgraph.execute(query) + + Args: + graph: A reference to the PyG graph. + Returns: + cypher queries. + """ + queries = [] + if graph is None: + return queries + + if isinstance(graph, HeteroData): + for etype, etype_features in graph.edge_items(): + source_node_label, edge_type, dest_node_label = etype + # Get edges + edge_index = etype_features[EDGE_INDEX] + etype_features.pop(EDGE_INDEX, None) + src_nodes, dest_nodes = edge_index[0], edge_index[1] + eid = 0 + for src_node_id, dest_node_id in zip(src_nodes, dest_nodes): + # Get src node properties + source_node_properties = PyGTranslator.get_node_properties(graph, source_node_label, src_node_id) + source_node_properties[PYG_ID] = int(src_node_id) + # Destination node properties + dest_node_properties = PyGTranslator.get_node_properties(graph, dest_node_label, dest_node_id) + dest_node_properties[PYG_ID] = int(dest_node_id) + # Get edge features + edge_properties = Translator.get_properties(etype_features, eid) + edge_properties[PYG_ID] = eid + eid += 1 + # Create query + queries.append( + self.create_insert_query( + source_node_label, + source_node_properties, + edge_type, + edge_properties, + dest_node_label, + dest_node_properties, + ) + ) + elif isinstance(graph, Data): + # Get edges + src_nodes, dest_nodes = graph.edge_index + # Get graph data + node_properties, etype_properties = PyGTranslator.extract_node_edge_properties_from_homogeneous_graph(graph) + # Process edges + eid = 0 + for src_node_id, dest_node_id in zip(src_nodes, dest_nodes): + # Get node properties + source_node_properties = Translator.get_properties(node_properties, src_node_id) + source_node_properties[PYG_ID] = int(src_node_id) + dest_node_properties = Translator.get_properties(node_properties, dest_node_id) + dest_node_properties[PYG_ID] = int(dest_node_id) + edge_properties = Translator.get_properties(etype_properties, eid) + edge_properties[PYG_ID] = eid + eid += 1 + queries.append( + self.create_insert_query( + DEFAULT_NODE_LABEL, + source_node_properties, + DEFAULT_EDGE_TYPE, + edge_properties, + DEFAULT_NODE_LABEL, + dest_node_properties, + ) + ) + + return queries + + def get_instance(self): + """Create instance of PyG graph from all edges that are inside Memgraph. Currently, isolated nodes are ignored because they don't contribute in message passing neural networks. Only numerical features + that are set on all nodes or all edges are transferred to the PyG instance since this is PyG's requirement. That means thay any string values properties won't be transferred, as well as numerical properties + that aren't set on all nodes. However, features thata re of type list are transferred to the PyG instance and can be used as any other feature in the PyG graph. Regardless of data residing inside Memgraph database, the created + PyG graph is a heterograph instance. + Returns: + PyG heterograph instance. + """ + # Parse into nice data structures + src_nodes, dest_nodes, node_features, edge_features, mem_indexes = self._parse_memgraph() + + # Create PyG heterograph + graph = HeteroData() + + # Create edges in COO format + for type_triplet in src_nodes.keys(): + graph[type_triplet].edge_index = torch.tensor( + [src_nodes[type_triplet], dest_nodes[type_triplet]], dtype=torch.int32 + ) + + # Set number of nodes, otherwise PyG inferes automatically and warnings can occur + for node_label, num_nodes_label in mem_indexes.items(): + graph[node_label].num_nodes = num_nodes_label + + # Set node features + for node_label, features_dict in node_features.items(): + for feature_name, features in features_dict.items(): + features = Translator.validate_features(features, graph[node_label].num_nodes) + if features is not None: + setattr(graph[node_label], feature_name, torch.tensor(features, dtype=torch.float32)) + + # Set edge features + for edge_triplet, features_dict in edge_features.items(): + for feature_name, features in features_dict.items(): + features = Translator.validate_features(features, graph[edge_triplet].num_edges) + if features is not None: + setattr(graph[edge_triplet], feature_name, torch.tensor(features, dtype=torch.float32)) + + # PyG offers a method to validate graph so if something is wrong an error will occur + graph.validate(raise_on_error=True) + return graph diff --git a/gqlalchemy/transformations/translators/translator.py b/gqlalchemy/transformations/translators/translator.py new file mode 100644 index 00000000..c3dba4ee --- /dev/null +++ b/gqlalchemy/transformations/translators/translator.py @@ -0,0 +1,216 @@ +# Copyright (c) 2016-2023 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from abc import ABC, abstractmethod +from typing import Callable, List, Set, Dict, Tuple +from collections import defaultdict +from numbers import Number + +import torch + +from gqlalchemy.transformations.constants import LABELS_CONCAT, DEFAULT_NODE_LABEL, DEFAULT_EDGE_TYPE +from gqlalchemy.memgraph_constants import ( + MG_HOST, + MG_PORT, + MG_USERNAME, + MG_PASSWORD, + MG_ENCRYPTED, + MG_CLIENT_NAME, + MG_LAZY, +) +from gqlalchemy.models import Node, Relationship +from gqlalchemy.utilities import to_cypher_properties +from gqlalchemy import Memgraph, Match + + +class Translator(ABC): + + # Lambda function to concat list of labels + merge_labels: Callable[[Set[str]], str] = ( + lambda labels, default_node_label: LABELS_CONCAT.join([label for label in sorted(labels)]) + if len(labels) + else default_node_label + ) + + @abstractmethod + def __init__( + self, + host: str = MG_HOST, + port: int = MG_PORT, + username: str = MG_USERNAME, + password: str = MG_PASSWORD, + encrypted: bool = MG_ENCRYPTED, + client_name: str = MG_CLIENT_NAME, + lazy: bool = MG_LAZY, + ) -> None: + super().__init__() + self.connection = Memgraph(host, port, username, password, encrypted, client_name, lazy) + + @abstractmethod + def to_cypher_queries(graph): + """Abstract method which doesn't know how to produce cypher queries for a specific graph type and thus needs to be overriden. + Args: + graph: Can be of any type supported by the derived Translator object. + + Raises: + NotImplementedError: The method must be override by a specific translator. + """ + raise NotImplementedError( + "Subclasses must override this method to produce cypher queries for specific graph type." + ) + + @abstractmethod + def get_instance(): + """Abstract method which doesn't know how to create the concrete instance so it needs to be overriden. + + Raises: + NotImplementedError: The method must be override by a specific translator. + """ + raise NotImplementedError( + "Subclasses must override this method to correctly parse query results for specific graph type." + ) + + @classmethod + def _is_most_inner_type_number(cls, obj): + """Checks if the most inner object type is a type derived from Number. E.g For a List[List[int]] return True + Args: + obj: Object that will be checked. + + Returns: + None if the object is empty(type cannot be inferred) or the type of the most inner object. + """ + if isinstance(obj, list): + return len(obj) and Translator._is_most_inner_type_number(obj[0]) + # Try to parser string into number + return isinstance(obj, Number) + + @classmethod + def validate_features(cls, features: List, expected_num: int): + """Return true if features are okay to be set on all nodes/features. + Args: + features: To be set on all nodes. It can be anything that can be converted to torch tensor. + expected_num: This can be number of nodes or number of edges depending on whether features will be set on nodes or edges. + Returns: + None if features cannot be set or tensor of same features. + """ + if len(features) != expected_num: + return None + try: + return torch.tensor(features, dtype=torch.float32) + except ValueError: + return None + + @classmethod + def get_properties(cls, properties, entity_id): + properties_ret = {} + for property_key, property_values in properties.items(): + properties_ret[property_key] = property_values[entity_id] + return properties_ret + + def _parse_memgraph(self): + """Returns Memgraph's data parsed in a nice way to be used for creating DGL and PyG graphs.""" + mem_indexes: Dict[str, int] = defaultdict(int) # track current counter for the node type + node_features: Dict[str, Dict[str, List[int]]] = defaultdict( + lambda: defaultdict(list) + ) # node_label to prop_name to list of features for all nodes of that label + edge_features: Dict[Tuple[str, str, str], Dict[str, List[int]]] = defaultdict( + lambda: defaultdict(list) + ) # (source_node_label, edge_type, dest_node_label) to prop_name to list of features for all edges of that type + src_nodes: Dict[Tuple[str, str, str], List[int]] = defaultdict( + list + ) # key=(source_node_label, edge_type, destination_node_label), value=list of source nodes + dest_nodes: Dict[Tuple[str, str, str], List[int]] = defaultdict( + list + ) # key=(source_node_label, edge_type, destination_node_label), value=list of dest nodes + reindex: Dict[str, Dict[int, int]] = defaultdict( + dict + ) # Reindex structure for saving node_label to old_index to new_index + + rel_results = self.get_all_edges_from_db() + + for row in rel_results: + row_values = row.values() + for entity in row_values: + entity_num_features = dict( + filter(lambda pair: Translator._is_most_inner_type_number(pair[1]), entity._properties.items()) + ) + if isinstance(entity, Node): + # Extract node label and all numeric features + node_label = Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL) + # Index node to a new index + if entity._id not in reindex[node_label]: + reindex[node_label][entity._id] = mem_indexes[node_label] + mem_indexes[node_label] += 1 + # Copy numeric features of a node + for num_feature_key, num_feature_val in entity_num_features.items(): + node_features[node_label][num_feature_key].append(num_feature_val) # this should fail + elif isinstance(entity, Relationship): + # Extract edge type and all numeric features + edge_type = entity._type if entity._type else DEFAULT_EDGE_TYPE + # Find descriptions of source and destination nodes. Cheap because we search only over row values, this is better than querying the database again. + source_node_index, dest_node_index = None, None + source_node_label, dest_node_label = None, None + for new_entity in row_values: + if new_entity._id == entity._start_node_id and isinstance(new_entity, Node): + source_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + source_node_index = reindex[source_node_label][new_entity._id] + elif new_entity._id == entity._end_node_id and isinstance(new_entity, Node): + dest_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + dest_node_index = reindex[dest_node_label][new_entity._id] + # Append to the graph data + edge_triplet = (source_node_label, edge_type, dest_node_label) + src_nodes[edge_triplet].append(source_node_index) + dest_nodes[edge_triplet].append(dest_node_index) + # Save edge features + for num_feature_key, num_feature_val in entity_num_features.items(): + edge_features[edge_triplet][num_feature_key].append(num_feature_val) + + return src_nodes, dest_nodes, node_features, edge_features, mem_indexes + + def create_insert_query( + self, + source_node_label, + source_node_properties, + edge_type, + edge_properties, + dest_node_label, + dest_node_properties, + ): + return ( + f"MERGE (n:{source_node_label} {to_cypher_properties(source_node_properties)}) " + f"MERGE (m:{dest_node_label} {to_cypher_properties(dest_node_properties)}) " + f"MERGE (n)-[r:{edge_type} {to_cypher_properties(edge_properties)}]->(m)" + ) + + def get_all_edges_from_db(self): + """Returns all edges from the database. + Returns: + Query results when finding all edges. + """ + return ( + Match(connection=self.connection).node(variable="n").to(variable="r").node(variable="m").return_().execute() + ) + + def get_all_isolated_nodes_from_db(self): + """Returns all isolated nodes from the database. + Returns: + Query results for finding all isolated nodes. + """ + return ( + Match(connection=self.connection) + .node(variable="n") + .add_custom_cypher("WHERE degree(n) = 0") + .return_() + .execute() + ) diff --git a/gqlalchemy/utilities.py b/gqlalchemy/utilities.py index d4f1936c..2826f01a 100644 --- a/gqlalchemy/utilities.py +++ b/gqlalchemy/utilities.py @@ -15,6 +15,7 @@ from abc import ABC, abstractmethod import math import numpy as np +import torch from datetime import datetime, date, time, timedelta from enum import Enum @@ -72,6 +73,14 @@ def to_cypher_value(value: Any, config: NetworkXCypherConfig = None) -> str: config = NetworkXCypherConfig() value_type = type(value) + if isinstance(value, torch.Tensor): + if value.squeeze().size() == 1: + return value.squeeze().item() + else: + return value.tolist() + + if isinstance(value_type, str) and is_numeric(value): + return float(value) if value_type == CypherVariable: return str(value) @@ -107,6 +116,14 @@ def to_cypher_value(value: Any, config: NetworkXCypherConfig = None) -> str: return f"'{value}'" +def is_numeric(value): + try: + float(value) + return True + except ValueError: + return False + + def to_cypher_properties(properties: Optional[Dict[str, Any]] = None, config=None) -> str: """Converts properties to a Cypher key-value properties.""" if config is None: diff --git a/gqlalchemy/vendors/memgraph.py b/gqlalchemy/vendors/memgraph.py index adaa035f..5b06dd05 100644 --- a/gqlalchemy/vendors/memgraph.py +++ b/gqlalchemy/vendors/memgraph.py @@ -35,17 +35,10 @@ ) from gqlalchemy.vendors.database_client import DatabaseClient from gqlalchemy.graph_algorithms.query_modules import QueryModule +import gqlalchemy.memgraph_constants as mg_consts __all__ = ("Memgraph",) -MG_HOST = os.getenv("MG_HOST", "127.0.0.1") -MG_PORT = int(os.getenv("MG_PORT", "7687")) -MG_USERNAME = os.getenv("MG_USERNAME", "") -MG_PASSWORD = os.getenv("MG_PASSWORD", "") -MG_ENCRYPTED = os.getenv("MG_ENCRYPT", "false").lower() == "true" -MG_CLIENT_NAME = os.getenv("MG_CLIENT_NAME", "GQLAlchemy") -MG_LAZY = os.getenv("MG_LAZY", "false").lower() == "true" - class MemgraphConstants: CONSTRAINT_TYPE = "constraint type" @@ -59,13 +52,13 @@ class MemgraphConstants: class Memgraph(DatabaseClient): def __init__( self, - host: str = MG_HOST, - port: int = MG_PORT, - username: str = MG_USERNAME, - password: str = MG_PASSWORD, - encrypted: bool = MG_ENCRYPTED, - client_name: str = MG_CLIENT_NAME, - lazy: bool = MG_LAZY, + host: str = mg_consts.MG_HOST, + port: int = mg_consts.MG_PORT, + username: str = mg_consts.MG_USERNAME, + password: str = mg_consts.MG_PASSWORD, + encrypted: bool = mg_consts.MG_ENCRYPTED, + client_name: str = mg_consts.MG_CLIENT_NAME, + lazy: bool = mg_consts.MG_LAZY, ): super().__init__( host=host, port=port, username=username, password=password, encrypted=encrypted, client_name=client_name diff --git a/poetry.lock b/poetry.lock index 67fc327d..f309e2cd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + [[package]] name = "adal" version = "1.2.7" @@ -5,6 +7,10 @@ description = "Note: This library is already replaced by MSAL Python, available category = "main" optional = false python-versions = "*" +files = [ + {file = "adal-1.2.7-py2.py3-none-any.whl", hash = "sha256:2a7451ed7441ddbc57703042204a3e30ef747478eea022c70f789fc7f084bc3d"}, + {file = "adal-1.2.7.tar.gz", hash = "sha256:d74f45b81317454d96e982fd1c50e6fb5c99ac2223728aea8764433a39f566f1"}, +] [package.dependencies] cryptography = ">=1.1.0" @@ -19,6 +25,9 @@ description = "Access Azure Datalake Gen1 with fsspec and dask" category = "main" optional = false python-versions = ">3.6" +files = [ + {file = "adlfs-2022.2.0.tar.gz", hash = "sha256:8543d29ce5b994d49831ad5f86b76b90809a540302b4f24e027591b740127942"}, +] [package.dependencies] aiohttp = "*" @@ -35,16 +44,88 @@ description = "Async http client/server framework (asyncio)" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"}, + {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"}, + {file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"}, + {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"}, + {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"}, + {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"}, + {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"}, + {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"}, + {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"}, + {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"}, + {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"}, + {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"}, + {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"}, + {file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"}, + {file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"}, + {file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"}, + {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"}, + {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"}, + {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"}, + {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"}, + {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"}, + {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"}, + {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"}, + {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"}, + {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"}, + {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"}, + {file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"}, + {file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"}, + {file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"}, + {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"}, + {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"}, + {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"}, + {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"}, + {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"}, + {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"}, + {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"}, + {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"}, + {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"}, + {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"}, + {file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"}, + {file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"}, + {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"}, + {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"}, + {file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"}, + {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"}, + {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"}, + {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"}, + {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"}, + {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"}, + {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"}, + {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"}, + {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"}, + {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"}, + {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"}, + {file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"}, + {file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"}, + {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"}, + {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"}, + {file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"}, + {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"}, + {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"}, + {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"}, + {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"}, + {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"}, + {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"}, + {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"}, + {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"}, + {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"}, + {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"}, + {file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"}, + {file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"}, + {file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"}, +] [package.dependencies] aiosignal = ">=1.1.2" async-timeout = ">=4.0.0a3,<5.0" -asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""} attrs = ">=17.3.0" charset-normalizer = ">=2.0,<3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} yarl = ">=1.0,<2.0" [package.extras] @@ -57,6 +138,10 @@ description = "aiosignal: a list of registered asynchronous callbacks" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, + {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, +] [package.dependencies] frozenlist = ">=1.1.0" @@ -68,17 +153,10 @@ description = "Timeout context manager for asyncio programs" category = "main" optional = false python-versions = ">=3.6" - -[package.dependencies] -typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} - -[[package]] -name = "asynctest" -version = "0.13.0" -description = "Enhance the standard unittest package with features for testing asyncio libraries" -category = "main" -optional = false -python-versions = ">=3.5" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] [[package]] name = "attrs" @@ -87,12 +165,16 @@ description = "Classes Without Boilerplate" category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] [package.extras] dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "azure-core" @@ -101,6 +183,10 @@ description = "Microsoft Azure Core Library for Python" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "azure-core-1.25.1.zip", hash = "sha256:3c1cf368650e76ec009c07cd1174a95cdcb471b247bb72d18245f7d56c1809b2"}, + {file = "azure_core-1.25.1-py3-none-any.whl", hash = "sha256:b0d62e67ec6d47365eebb12c50bc96f7b22d06b359f56ce7f904b095cb46b195"}, +] [package.dependencies] requests = ">=2.18.4" @@ -114,6 +200,10 @@ description = "Azure Data Lake Store Filesystem Client Library for Python" category = "main" optional = false python-versions = "*" +files = [ + {file = "azure-datalake-store-0.0.52.tar.gz", hash = "sha256:4198ddb32614d16d4502b43d5c9739f81432b7e0e4d75d30e05149fe6007fea2"}, + {file = "azure_datalake_store-0.0.52-py2.py3-none-any.whl", hash = "sha256:aaed72b9c856824aeab554f4dbe0ef2c6d0ff36700bdd8b93d8298793117c48e"}, +] [package.dependencies] adal = ">=0.4.2" @@ -127,6 +217,10 @@ description = "Microsoft Azure Identity Library for Python" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "azure-identity-1.10.0.zip", hash = "sha256:656e5034d9cef297cf9b35376ed620085273c18cfa52cea4a625bf0d5d2d6409"}, + {file = "azure_identity-1.10.0-py3-none-any.whl", hash = "sha256:b386f1ccbea6a48b9ab7e7f162adc456793c345193a7c1a713959562b08dcbbd"}, +] [package.dependencies] azure-core = ">=1.11.0,<2.0.0" @@ -142,6 +236,10 @@ description = "Microsoft Azure Blob Storage Client Library for Python" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "azure-storage-blob-12.13.1.zip", hash = "sha256:899c4b8e2671812d2cf78f107556a27dbb128caaa2bb06094e72a3d5836740af"}, + {file = "azure_storage_blob-12.13.1-py3-none-any.whl", hash = "sha256:726b86f733dc76218ce45b7a3254b61ba4f0cc3d68b7621be4985248c92ee483"}, +] [package.dependencies] azure-core = ">=1.23.1,<2.0.0" @@ -155,6 +253,31 @@ description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" +files = [ + {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, + {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, + {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, + {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, + {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, + {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, + {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, + {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, + {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, + {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, + {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, + {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, + {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, + {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, + {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, + {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, + {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, + {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, + {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, +] [package.dependencies] click = ">=8.0.0" @@ -162,7 +285,6 @@ mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -178,6 +300,10 @@ description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "certifi-2022.6.15.2-py3-none-any.whl", hash = "sha256:0aa1a42fbd57645fabeb6290a7687c21755b0344ecaeaa05f4e9f6207ae2e9a8"}, + {file = "certifi-2022.6.15.2.tar.gz", hash = "sha256:aa08c101214127b9b0472ca6338315113c9487d45376fd3e669201b477c71003"}, +] [[package]] name = "cffi" @@ -186,6 +312,72 @@ description = "Foreign Function Interface for Python calling C code." category = "main" optional = false python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] [package.dependencies] pycparser = "*" @@ -197,6 +389,10 @@ description = "Validate configuration and produce human readable error messages. category = "dev" optional = false python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] [[package]] name = "charset-normalizer" @@ -205,9 +401,13 @@ description = "The Real First Universal Charset Detector. Open, modern and activ category = "main" optional = false python-versions = ">=3.6.0" +files = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "click" @@ -216,18 +416,25 @@ description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" version = "0.4.5" description = "Cross-platform colored terminal text." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, + {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, +] [[package]] name = "coverage" @@ -236,55 +443,185 @@ description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "cryptography" -version = "38.0.1" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = ">=1.12" - -[package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools-rust (>=0.11.4)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] - -[[package]] -name = "dacite" -version = "1.6.0" -description = "Simple creation of data classes from dictionaries." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["black", "coveralls", "mypy", "pylint", "pytest (>=5)", "pytest-cov"] - -[[package]] -name = "distlib" -version = "0.3.6" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" - -[[package]] +files = [ + {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, + {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, + {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, + {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, + {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, + {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, + {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, + {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, + {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, + {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, + {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, + {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, + {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, + {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, + {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, + {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cryptography" +version = "38.0.1" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, + {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, + {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, + {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, + {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, + {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, + {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] + +[[package]] +name = "dacite" +version = "1.6.0" +description = "Simple creation of data classes from dictionaries." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "dacite-1.6.0-py3-none-any.whl", hash = "sha256:4331535f7aabb505c732fa4c3c094313fc0a1d5ea19907bf4726a7819a68b93f"}, + {file = "dacite-1.6.0.tar.gz", hash = "sha256:d48125ed0a0352d3de9f493bf980038088f45f3f9d7498f090b50a847daaa6df"}, +] + +[package.extras] +dev = ["black", "coveralls", "mypy", "pylint", "pytest (>=5)", "pytest-cov"] + +[[package]] +name = "dgl" +version = "0.9.1" +description = "Deep Graph Library" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "dgl-0.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b9848c2c643d7b4d4c1969d05e511aff776b101c69573defd3382107b25a5c9"}, + {file = "dgl-0.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:973d30b8d7aba76ad0fdc49c12f5c9359f0913be73708f9e1b6a71e40b181252"}, + {file = "dgl-0.9.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:1c4c0d3f3003cdda5b3ceffafb6246a821ee7ccbd4941dfef7826e99119218bb"}, + {file = "dgl-0.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:e51b9050eb4237b2c72e3e6f78511e65e4532dfc35fb70825ad42df1aee1ad8f"}, + {file = "dgl-0.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:76635838f09bef50684763d5ed81075f92e547d4c984c1cf840be16a86b5a409"}, + {file = "dgl-0.9.1-cp36-cp36m-macosx_11_0_arm64.whl", hash = "sha256:af42754a5ac2437e5b36a9aa04403f622b846f48a4ae4e4763f09c6b00fd00fb"}, + {file = "dgl-0.9.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b63fb0eb224c65113ef26cc68ef206565106b9aee6e221c7e6bfcc1cdacc5c9"}, + {file = "dgl-0.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b245d988954db65c002a77da3ad80f97b13cc3c1a9027799c7d239d8e7e4dbd8"}, + {file = "dgl-0.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e3ddfdbd0eca8401be2fc2ea18bef4d1c5bf9c844a67afacf54720d3a5d574da"}, + {file = "dgl-0.9.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:14acd668646cb214f6409da09874b4237d62deef3d48a0b1a02eeefd4f84cd17"}, + {file = "dgl-0.9.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:9d7b740db8f0b84a7d98c3557e60fb05965fe1c4ec7f91c606aa99e21f835b03"}, + {file = "dgl-0.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b09bd5e301b5483f9f4684fb19cfacc6d10333d54c28f345ffca3ce86afa66e1"}, + {file = "dgl-0.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71282ec77d99d2de439fcdbf3529a636b6ca80134b7ccd6926e7b5ec433d7cfe"}, + {file = "dgl-0.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10b940df11175001f0df016e004333c746b15bb22842cf1de863d20ec5b8740c"}, + {file = "dgl-0.9.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:4be35f9942b700603d730a770ab5b24a8ed11ad6c992051dc917ccf02fae70c1"}, + {file = "dgl-0.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:9fb788b4ba2df07b19a4982700e75a143c611847a52c3c5fd670a46d33f26061"}, + {file = "dgl-0.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c1efe436309ff7932aea1ecc2439baf8d82f478443a6a6d6e7372ab44315613"}, + {file = "dgl-0.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fecbd81a2fe1a15f3d2eb0952343ea33a406c9d3b24741e9d86cb0a5ce6946c0"}, + {file = "dgl-0.9.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:242a7cf52335fa91de35b80f5c1671b0f5aede10490cf9812bb4375aa1937620"}, + {file = "dgl-0.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:e4481112f528e8d2b74e20dee2b26d0ac67de3c1872814f595a865b5ad92a241"}, +] + +[package.dependencies] +networkx = ">=2.1" +numpy = ">=1.14.0" +psutil = ">=5.8.0" +requests = ">=2.19.0" +scipy = ">=1.1.0" +tqdm = "*" + +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] + +[[package]] name = "docker" version = "5.0.3" description = "A Python library for the Docker Engine API." category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "docker-5.0.3-py2.py3-none-any.whl", hash = "sha256:7a79bb439e3df59d0a72621775d600bc8bc8b422d285824cb37103eab91d1ce0"}, + {file = "docker-5.0.3.tar.gz", hash = "sha256:d916a26b62970e7c2f554110ed6af04c7ccff8e9f81ad17d0d40c75637e227fb"}, +] [package.dependencies] pywin32 = {version = "227", markers = "sys_platform == \"win32\""} @@ -302,6 +639,10 @@ description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, + {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, +] [package.extras] docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] @@ -314,9 +655,12 @@ description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] [package.dependencies] -importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" @@ -328,6 +672,67 @@ description = "A list-like structure which implements collections.abc.MutableSeq category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"}, + {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"}, + {file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"}, + {file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"}, + {file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"}, + {file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"}, + {file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"}, + {file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"}, + {file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"}, + {file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"}, + {file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"}, + {file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"}, + {file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"}, +] [[package]] name = "fsspec" @@ -336,6 +741,10 @@ description = "File-system specification" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "fsspec-2022.8.2-py3-none-any.whl", hash = "sha256:6374804a2c0d24f225a67d009ee1eabb4046ad00c793c3f6df97e426c890a1d9"}, + {file = "fsspec-2022.8.2.tar.gz", hash = "sha256:7f12b90964a98a7e921d27fb36be536ea036b73bf3b724ac0b0bd7b8e39c7c18"}, +] [package.extras] abfs = ["adlfs"] @@ -367,6 +776,10 @@ description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "identify-2.5.5-py2.py3-none-any.whl", hash = "sha256:ef78c0d96098a3b5fe7720be4a97e73f439af7cf088ebf47b620aeaa10fadf97"}, + {file = "identify-2.5.5.tar.gz", hash = "sha256:322a5699daecf7c6fd60e68852f36f2ecbb6a36ff6e6e973e0d2bb6fca203ee6"}, +] [package.extras] license = ["ukkonen"] @@ -378,22 +791,10 @@ description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.5" - -[[package]] -name = "importlib-metadata" -version = "4.2.0" -description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] [[package]] name = "iniconfig" @@ -402,6 +803,10 @@ description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" optional = false python-versions = "*" +files = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] [[package]] name = "isodate" @@ -410,6 +815,10 @@ description = "An ISO 8601 date/time/duration parser and formatter" category = "main" optional = false python-versions = "*" +files = [ + {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, + {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, +] [package.dependencies] six = "*" @@ -421,6 +830,10 @@ description = "McCabe checker, plugin for flake8" category = "dev" optional = false python-versions = "*" +files = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] [[package]] name = "msal" @@ -429,6 +842,10 @@ description = "The Microsoft Authentication Library (MSAL) for Python library en category = "main" optional = false python-versions = "*" +files = [ + {file = "msal-1.18.0-py2.py3-none-any.whl", hash = "sha256:9c10e6cb32e0b6b8eaafc1c9a68bc3b2ff71505e0c5b8200799582d8b9f22947"}, + {file = "msal-1.18.0.tar.gz", hash = "sha256:576af55866038b60edbcb31d831325a1bd8241ed272186e2832968fd4717d202"}, +] [package.dependencies] cryptography = ">=0.6,<40" @@ -442,12 +859,16 @@ description = "Microsoft Authentication Library extensions (MSAL EX) provides a category = "main" optional = false python-versions = "*" +files = [ + {file = "msal-extensions-1.0.0.tar.gz", hash = "sha256:c676aba56b0cce3783de1b5c5ecfe828db998167875126ca4b47dc6436451354"}, + {file = "msal_extensions-1.0.0-py2.py3-none-any.whl", hash = "sha256:91e3db9620b822d0ed2b4d1850056a0f133cba04455e62f11612e40f5502f2ee"}, +] [package.dependencies] msal = ">=0.4.1,<2.0.0" portalocker = [ - {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""}, {version = ">=1.0,<3", markers = "python_version >= \"3.5\" and platform_system != \"Windows\""}, + {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""}, ] [[package]] @@ -457,6 +878,10 @@ description = "AutoRest swagger generator Python client runtime." category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "msrest-0.7.1-py3-none-any.whl", hash = "sha256:21120a810e1233e5e6cc7fe40b474eeb4ec6f757a15d7cf86702c369f9567c32"}, + {file = "msrest-0.7.1.zip", hash = "sha256:6e7661f46f3afd88b75667b7187a92829924446c7ea1d169be8c4bb7eeb788b9"}, +] [package.dependencies] azure-core = ">=1.24.0" @@ -475,22 +900,90 @@ description = "multidict implementation" category = "main" optional = false python-versions = ">=3.7" - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "neo4j" -version = "4.4.7" -description = "Neo4j Bolt driver for Python" -category = "main" +files = [ + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, + {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, + {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, + {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, + {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, + {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, + {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, + {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, + {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, + {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, + {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, +] + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] + +[[package]] +name = "neo4j" +version = "4.4.7" +description = "Neo4j Bolt driver for Python" +category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "neo4j-4.4.7.tar.gz", hash = "sha256:4a7ec29156e7c55247eb146d7dd831833a63fb0842cfe4e04b31d482f5a9631b"}, +] [package.dependencies] pytz = "*" @@ -502,6 +995,10 @@ description = "Python package for creating and manipulating graphs and networks" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"}, + {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"}, +] [package.extras] default = ["matplotlib (>=3.3)", "numpy (>=1.19)", "pandas (>=1.1)", "scipy (>=1.5,!=1.6.1)"] @@ -517,17 +1014,116 @@ description = "Node.js virtual environment builder" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] [package.dependencies] setuptools = "*" [[package]] name = "numpy" -version = "1.21.1" -description = "NumPy is the fundamental package for array computing with Python." +version = "1.24.1" +description = "Fundamental package for array computing in Python" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, + {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, + {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, + {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, + {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, + {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, + {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, + {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, + {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, + {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, + {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, +] + +[[package]] +name = "nvidia-cublas-cu11" +version = "11.10.3.66" +description = "CUBLAS native runtime libraries" +category = "main" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-manylinux1_x86_64.whl", hash = "sha256:d32e4d75f94ddfb93ea0a5dda08389bcc65d8916a25cb9f37ac89edaeed3bded"}, + {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-win_amd64.whl", hash = "sha256:8ac17ba6ade3ed56ab898a036f9ae0756f1e81052a317bf98f8c6d18dc3ae49e"}, +] + +[package.dependencies] +setuptools = "*" +wheel = "*" + +[[package]] +name = "nvidia-cuda-nvrtc-cu11" +version = "11.7.99" +description = "NVRTC native runtime libraries" +category = "main" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_nvrtc_cu11-11.7.99-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:9f1562822ea264b7e34ed5930567e89242d266448e936b85bc97a3370feabb03"}, + {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:f7d9610d9b7c331fa0da2d1b2858a4a8315e6d49765091d28711c8946e7425e7"}, + {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:f2effeb1309bdd1b3854fc9b17eaf997808f8b25968ce0c7070945c4265d64a3"}, +] + +[package.dependencies] +setuptools = "*" +wheel = "*" + +[[package]] +name = "nvidia-cuda-runtime-cu11" +version = "11.7.99" +description = "CUDA Runtime native Libraries" +category = "main" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc768314ae58d2641f07eac350f40f99dcb35719c4faff4bc458a7cd2b119e31"}, + {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:bc77fa59a7679310df9d5c70ab13c4e34c64ae2124dd1efd7e5474b71be125c7"}, +] + +[package.dependencies] +setuptools = "*" +wheel = "*" + +[[package]] +name = "nvidia-cudnn-cu11" +version = "8.5.0.96" +description = "cuDNN runtime libraries" +category = "main" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cudnn_cu11-8.5.0.96-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:402f40adfc6f418f9dae9ab402e773cfed9beae52333f6d86ae3107a1b9527e7"}, + {file = "nvidia_cudnn_cu11-8.5.0.96-py3-none-manylinux1_x86_64.whl", hash = "sha256:71f8111eb830879ff2836db3cccf03bbd735df9b0d17cd93761732ac50a8a108"}, +] + +[package.dependencies] +setuptools = "*" +wheel = "*" [[package]] name = "oauthlib" @@ -536,6 +1132,10 @@ description = "A generic, spec-compliant, thorough implementation of the OAuth r category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "oauthlib-3.2.1-py3-none-any.whl", hash = "sha256:88e912ca1ad915e1dcc1c06fc9259d19de8deacd6fd17cc2df266decc2e49066"}, + {file = "oauthlib-3.2.1.tar.gz", hash = "sha256:1565237372795bf6ee3e5aba5e2a85bd5a65d0e2aa5c628b9a97b7d7a0da3721"}, +] [package.extras] rsa = ["cryptography (>=3.0.0)"] @@ -549,10 +1149,26 @@ description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +[[package]] +name = "pastel" +version = "0.2.1" +description = "Bring colors to your terminal." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"}, + {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"}, +] + [[package]] name = "pathspec" version = "0.10.1" @@ -560,6 +1176,10 @@ description = "Utility library for gitignore style pattern matching of file path category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, + {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, +] [[package]] name = "platformdirs" @@ -568,6 +1188,10 @@ description = "A small Python module for determining appropriate platform-specif category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, +] [package.extras] docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] @@ -580,14 +1204,34 @@ description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.6" - -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "poethepoet" +version = "0.18.1" +description = "A task runner that works well with poetry." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "poethepoet-0.18.1-py3-none-any.whl", hash = "sha256:e85727bf6f4a10bf6c1a43026bdeb40df689bea3c4682d03cbe531cabc8f2ba6"}, + {file = "poethepoet-0.18.1.tar.gz", hash = "sha256:5f3566b14c2f5dccdfbc3bb26f0096006b38dc0b9c74bd4f8dd1eba7b0e29f6a"}, +] + +[package.dependencies] +pastel = ">=0.2.1,<0.3.0" +tomli = ">=1.2.2" + +[package.extras] +poetry-plugin = ["poetry (>=1.0,<2.0)"] + [[package]] name = "portalocker" version = "2.5.1" @@ -595,6 +1239,10 @@ description = "Wraps the portalocker recipe for easy usage" category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "portalocker-2.5.1-py2.py3-none-any.whl", hash = "sha256:400bae275366e7b840d4baad0654c6ec5994e07c40c423d78e9e1340279b8352"}, + {file = "portalocker-2.5.1.tar.gz", hash = "sha256:ae8e9cc2660da04bf41fa1a0eef7e300bb5e4a5869adfb1a6d8551632b559b2b"}, +] [package.dependencies] pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} @@ -611,11 +1259,14 @@ description = "A framework for managing and maintaining multi-language pre-commi category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, + {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, +] [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" toml = "*" @@ -628,6 +1279,40 @@ description = "Cross-platform lib for process and system monitoring in Python." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"}, + {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"}, + {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"}, + {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"}, + {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"}, + {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"}, + {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"}, + {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"}, + {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"}, + {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"}, + {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"}, + {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"}, + {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"}, + {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"}, + {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"}, + {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"}, + {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"}, + {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"}, + {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"}, + {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"}, + {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"}, + {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"}, + {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"}, + {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"}, + {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"}, + {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"}, + {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"}, + {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"}, + {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"}, + {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"}, + {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"}, + {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"}, +] [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] @@ -639,6 +1324,10 @@ description = "library with cross-python path, ini-parsing, io, code, log facili category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] [[package]] name = "pyarrow" @@ -647,6 +1336,34 @@ description = "Python library for Apache Arrow" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_13_universal2.whl", hash = "sha256:767cafb14278165ad539a2918c14c1b73cf20689747c21375c38e3fe62884902"}, + {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0238998dc692efcb4e41ae74738d7c1234723271ccf520bd8312dca07d49ef8d"}, + {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:55328348b9139c2b47450d512d716c2248fd58e2f04e2fc23a65e18726666d42"}, + {file = "pyarrow-9.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc856628acd8d281652c15b6268ec7f27ebcb015abbe99d9baad17f02adc51f1"}, + {file = "pyarrow-9.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29eb3e086e2b26202f3a4678316b93cfb15d0e2ba20f3ec12db8fd9cc07cde63"}, + {file = "pyarrow-9.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e753f8fcf07d8e3a0efa0c8bd51fef5c90281ffd4c5637c08ce42cd0ac297de"}, + {file = "pyarrow-9.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:3eef8a981f45d89de403e81fb83b8119c20824caddf1404274e41a5d66c73806"}, + {file = "pyarrow-9.0.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:7fa56cbd415cef912677270b8e41baad70cde04c6d8a8336eeb2aba85aa93706"}, + {file = "pyarrow-9.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f8c46bde1030d704e2796182286d1c56846552c50a39ad5bf5a20c0d8159fc35"}, + {file = "pyarrow-9.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ad430cee28ebc4d6661fc7315747c7a18ae2a74e67498dcb039e1c762a2fb67"}, + {file = "pyarrow-9.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a60bb291a964f63b2717fb1b28f6615ffab7e8585322bfb8a6738e6b321282"}, + {file = "pyarrow-9.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9cef618159567d5f62040f2b79b1c7b38e3885f4ffad0ec97cd2d86f88b67cef"}, + {file = "pyarrow-9.0.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:5526a3bfb404ff6d31d62ea582cf2466c7378a474a99ee04d1a9b05de5264541"}, + {file = "pyarrow-9.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:da3e0f319509a5881867effd7024099fb06950a0768dad0d6873668bb88cfaba"}, + {file = "pyarrow-9.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c715eca2092273dcccf6f08437371e04d112f9354245ba2fbe6c801879450b7"}, + {file = "pyarrow-9.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11a645a41ee531c3a5edda45dea07c42267f52571f818d388971d33fc7e2d4a"}, + {file = "pyarrow-9.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b390bdcfb8c5b900ef543f911cdfec63e88524fafbcc15f83767202a4a2491"}, + {file = "pyarrow-9.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d9eb04db626fa24fdfb83c00f76679ca0d98728cdbaa0481b6402bf793a290c0"}, + {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_13_universal2.whl", hash = "sha256:4eebdab05afa23d5d5274b24c1cbeb1ba017d67c280f7d39fd8a8f18cbad2ec9"}, + {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:02b820ecd1da02012092c180447de449fc688d0c3f9ff8526ca301cdd60dacd0"}, + {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92f3977e901db1ef5cba30d6cc1d7942b8d94b910c60f89013e8f7bb86a86eef"}, + {file = "pyarrow-9.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f241bd488c2705df930eedfe304ada71191dcf67d6b98ceda0cc934fd2a8388e"}, + {file = "pyarrow-9.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c5a073a930c632058461547e0bc572da1e724b17b6b9eb31a97da13f50cb6e0"}, + {file = "pyarrow-9.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59bcd5217a3ae1e17870792f82b2ff92df9f3862996e2c78e156c13e56ff62e"}, + {file = "pyarrow-9.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fe2ce795fa1d95e4e940fe5661c3c58aee7181c730f65ac5dd8794a77228de59"}, + {file = "pyarrow-9.0.0.tar.gz", hash = "sha256:7fb02bebc13ab55573d1ae9bb5002a6d20ba767bf8569b52fce5301d42495ab7"}, +] [package.dependencies] numpy = ">=1.16.6" @@ -658,6 +1375,10 @@ description = "Python style guide checker" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] [[package]] name = "pycparser" @@ -666,6 +1387,10 @@ description = "C parser in Python" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] [[package]] name = "pydantic" @@ -674,38 +1399,84 @@ description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" - -[package.dependencies] -typing-extensions = ">=4.1.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - -[[package]] -name = "pyflakes" -version = "2.4.0" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "PyJWT" -version = "2.4.0" -description = "JSON Web Token implementation in Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cryptography = {version = ">=3.3.1", optional = true, markers = "extra == \"crypto\""} - -[package.extras] -crypto = ["cryptography (>=3.3.1)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.3.1)", "mypy", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] +files = [ + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, +] + +[package.dependencies] +typing-extensions = ">=4.1.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pyflakes" +version = "2.4.0" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, +] + +[[package]] +name = "PyJWT" +version = "2.4.0" +description = "JSON Web Token implementation in Python" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyJWT-2.4.0-py3-none-any.whl", hash = "sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf"}, + {file = "PyJWT-2.4.0.tar.gz", hash = "sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba"}, +] + +[package.dependencies] +cryptography = {version = ">=3.3.1", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.3.1)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.3.1)", "mypy", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymgclient" @@ -714,6 +1485,20 @@ description = "Memgraph database adapter for Python language" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "pymgclient-1.3.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:6d013f878658296c3e8b360f0be41b9741907249874bcb30ef17fd0481d595d5"}, + {file = "pymgclient-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6b5c6a1eda2f7178befe6c7ad9d31ba14845e672f3ef20ddb9ff46424b893ab"}, + {file = "pymgclient-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:af8edb3f5e57a6f35d6ec68dc147949ecdcc2020a910f7f961957fd224dcf235"}, + {file = "pymgclient-1.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:ed8cf8eeb31319f6f4a76c59f90de68a7a004daae801d6f1eee20fc067230383"}, + {file = "pymgclient-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1abd8dc4efbd5efd5c7074dd2efa88e89443cec23d04dfec1e4f6ff36861c67b"}, + {file = "pymgclient-1.3.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b340a8f4987ae0ef2e5d519232ad98d2baf8deb47e1720e487de646ddfb8253d"}, + {file = "pymgclient-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:79463f3578f0c4194c2f8f8d9386173ab2149ad16a0075af0deab840fbf7c482"}, + {file = "pymgclient-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:e30e03746b9a554b77801ac59ea0fd19fe85db11733d3350dfe1155f719c4e3a"}, + {file = "pymgclient-1.3.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d08aef9bde5f89853cf028b72b547f364b797f5f2fd2d13510817b21d04d210d"}, + {file = "pymgclient-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91faadc50d54ac4707e3b3239f77101d6610494658b1a16ecb4ef8976bb9aa0e"}, + {file = "pymgclient-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:1f9aec0deff251b4c7f7acd763caad193330a072ab29e090e2b60925439eb6da"}, + {file = "pymgclient-1.3.1.tar.gz", hash = "sha256:a409ee9c7ac714a96a86f9eeca9e71f19f36f11390b3fdbac447d65462e05037"}, +] [[package]] name = "pyparsing" @@ -722,6 +1507,10 @@ description = "pyparsing module - Classes and methods to define and execute pars category = "dev" optional = false python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] [package.extras] diagrams = ["jinja2", "railroad-diagrams"] @@ -733,11 +1522,14 @@ description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, +] [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -754,6 +1546,9 @@ description = "A pytest plugin to enable format checking with black" category = "dev" optional = false python-versions = ">=2.7" +files = [ + {file = "pytest-black-0.3.12.tar.gz", hash = "sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5"}, +] [package.dependencies] black = {version = "*", markers = "python_version >= \"3.6\""} @@ -767,6 +1562,10 @@ description = "Pytest plugin for measuring coverage." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, +] [package.dependencies] coverage = ">=5.2.1" @@ -783,6 +1582,10 @@ description = "pytest plugin to check FLAKE8 requirements" category = "dev" optional = false python-versions = "*" +files = [ + {file = "pytest-flake8-1.0.7.tar.gz", hash = "sha256:f0259761a903563f33d6f099914afef339c085085e643bee8343eb323b32dd6b"}, + {file = "pytest_flake8-1.0.7-py2.py3-none-any.whl", hash = "sha256:c28cf23e7d359753c896745fd4ba859495d02e16c84bac36caa8b1eec58f5bc1"}, +] [package.dependencies] flake8 = ">=3.5" @@ -795,6 +1598,10 @@ description = "py.test plugin to abort hanging tests" category = "dev" optional = false python-versions = "*" +files = [ + {file = "pytest-timeout-1.4.2.tar.gz", hash = "sha256:20b3113cf6e4e80ce2d403b6fb56e9e1b871b510259206d40ff8d609f48bda76"}, + {file = "pytest_timeout-1.4.2-py2.py3-none-any.whl", hash = "sha256:541d7aa19b9a6b4e475c759fd6073ef43d7cdc9a92d95644c260076eb257a063"}, +] [package.dependencies] pytest = ">=3.6.0" @@ -806,6 +1613,10 @@ description = "Extensions to the standard Python datetime module" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] [package.dependencies] six = ">=1.5" @@ -817,6 +1628,10 @@ description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" +files = [ + {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, + {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, +] [[package]] name = "pywin32" @@ -825,6 +1640,20 @@ description = "Python for Window Extensions" category = "main" optional = false python-versions = "*" +files = [ + {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, + {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, + {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, + {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, + {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, + {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, + {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, + {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, + {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, + {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, + {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, + {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, +] [[package]] name = "PyYAML" @@ -833,6 +1662,48 @@ description = "YAML parser and emitter for Python" category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] [[package]] name = "requests" @@ -841,6 +1712,10 @@ description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7, <4" +files = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] [package.dependencies] certifi = ">=2017.4.17" @@ -850,7 +1725,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-oauthlib" @@ -859,6 +1734,10 @@ description = "OAuthlib authentication support for Requests." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, + {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, +] [package.dependencies] oauthlib = ">=3.0.0" @@ -867,13 +1746,56 @@ requests = ">=2.0.0" [package.extras] rsa = ["oauthlib[signedtoken] (>=3.0.0)"] +[[package]] +name = "scipy" +version = "1.9.3" +description = "Fundamental algorithms for scientific computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, + {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, + {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, + {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, + {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, + {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, +] + +[package.dependencies] +numpy = ">=1.18.5,<1.26.0" + +[package.extras] +dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] +test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + [[package]] name = "setuptools" version = "65.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "setuptools-65.3.0-py3-none-any.whl", hash = "sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82"}, + {file = "setuptools-65.3.0.tar.gz", hash = "sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"}, +] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] @@ -887,6 +1809,10 @@ description = "Python 2 and 3 compatibility utilities" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] [[package]] name = "toml" @@ -895,22 +1821,84 @@ description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] [[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" +name = "torch" +version = "1.13.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7.0" +files = [ + {file = "torch-1.13.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:fd12043868a34a8da7d490bf6db66991108b00ffbeecb034228bfcbbd4197143"}, + {file = "torch-1.13.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d9fe785d375f2e26a5d5eba5de91f89e6a3be5d11efb497e76705fdf93fa3c2e"}, + {file = "torch-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:98124598cdff4c287dbf50f53fb455f0c1e3a88022b39648102957f3445e9b76"}, + {file = "torch-1.13.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:393a6273c832e047581063fb74335ff50b4c566217019cc6ace318cd79eb0566"}, + {file = "torch-1.13.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:0122806b111b949d21fa1a5f9764d1fd2fcc4a47cb7f8ff914204fd4fc752ed5"}, + {file = "torch-1.13.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:22128502fd8f5b25ac1cd849ecb64a418382ae81dd4ce2b5cebaa09ab15b0d9b"}, + {file = "torch-1.13.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:76024be052b659ac1304ab8475ab03ea0a12124c3e7626282c9c86798ac7bc11"}, + {file = "torch-1.13.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:ea8dda84d796094eb8709df0fcd6b56dc20b58fdd6bc4e8d7109930dafc8e419"}, + {file = "torch-1.13.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2ee7b81e9c457252bddd7d3da66fb1f619a5d12c24d7074de91c4ddafb832c93"}, + {file = "torch-1.13.1-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:0d9b8061048cfb78e675b9d2ea8503bfe30db43d583599ae8626b1263a0c1380"}, + {file = "torch-1.13.1-cp37-none-macosx_11_0_arm64.whl", hash = "sha256:f402ca80b66e9fbd661ed4287d7553f7f3899d9ab54bf5c67faada1555abde28"}, + {file = "torch-1.13.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:727dbf00e2cf858052364c0e2a496684b9cb5aa01dc8a8bc8bbb7c54502bdcdd"}, + {file = "torch-1.13.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:df8434b0695e9ceb8cc70650afc1310d8ba949e6db2a0525ddd9c3b2b181e5fe"}, + {file = "torch-1.13.1-cp38-cp38-win_amd64.whl", hash = "sha256:5e1e722a41f52a3f26f0c4fcec227e02c6c42f7c094f32e49d4beef7d1e213ea"}, + {file = "torch-1.13.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:33e67eea526e0bbb9151263e65417a9ef2d8fa53cbe628e87310060c9dcfa312"}, + {file = "torch-1.13.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:eeeb204d30fd40af6a2d80879b46a7efbe3cf43cdbeb8838dd4f3d126cc90b2b"}, + {file = "torch-1.13.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:50ff5e76d70074f6653d191fe4f6a42fdbe0cf942fbe2a3af0b75eaa414ac038"}, + {file = "torch-1.13.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2c3581a3fd81eb1f0f22997cddffea569fea53bafa372b2c0471db373b26aafc"}, + {file = "torch-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:0aa46f0ac95050c604bcf9ef71da9f1172e5037fdf2ebe051962d47b123848e7"}, + {file = "torch-1.13.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:6930791efa8757cb6974af73d4996b6b50c592882a324b8fb0589c6a9ba2ddaf"}, + {file = "torch-1.13.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:e0df902a7c7dd6c795698532ee5970ce898672625635d885eade9976e5a04949"}, +] + +[package.dependencies] +nvidia-cublas-cu11 = {version = "11.10.3.66", markers = "platform_system == \"Linux\""} +nvidia-cuda-nvrtc-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\""} +nvidia-cuda-runtime-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\""} +nvidia-cudnn-cu11 = {version = "8.5.0.96", markers = "platform_system == \"Linux\""} +typing-extensions = "*" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] + +[[package]] +name = "tqdm" +version = "4.64.1" +description = "Fast, Extensible Progress Meter" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "tqdm-4.64.1-py2.py3-none-any.whl", hash = "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"}, + {file = "tqdm-4.64.1.tar.gz", hash = "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] [[package]] name = "typing-extensions" @@ -919,6 +1907,10 @@ description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, + {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, +] [[package]] name = "urllib3" @@ -927,6 +1919,10 @@ description = "HTTP library with thread-safe connection pooling, file post, and category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +files = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] @@ -940,11 +1936,14 @@ description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "virtualenv-20.16.2-py2.py3-none-any.whl", hash = "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3"}, + {file = "virtualenv-20.16.2.tar.gz", hash = "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db"}, +] [package.dependencies] distlib = ">=0.3.1,<1" filelock = ">=3.2,<4" -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} platformdirs = ">=2,<3" [package.extras] @@ -958,6 +1957,10 @@ description = "WebSocket client for Python with low level API options" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "websocket-client-1.4.1.tar.gz", hash = "sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef"}, + {file = "websocket_client-1.4.1-py3-none-any.whl", hash = "sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090"}, +] [package.extras] docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] @@ -965,876 +1968,28 @@ optional = ["python-socks", "wsaccel"] test = ["websockets"] [[package]] -name = "yarl" -version = "1.8.1" -description = "Yet another URL library" +name = "wheel" +version = "0.38.4" +description = "A built-package format for Python" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "wheel-0.38.4-py3-none-any.whl", hash = "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8"}, + {file = "wheel-0.38.4.tar.gz", hash = "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac"}, +] -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} +[package.extras] +test = ["pytest (>=3.0.0)"] [[package]] -name = "zipp" -version = "3.8.1" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" +name = "yarl" +version = "1.8.1" +description = "Yet another URL library" +category = "main" optional = false python-versions = ">=3.7" - -[package.extras] -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.7" -content-hash = "c9698d9826c6cfbdd7c8866bdedc883c293f13d367bdc96ca8dcce95b883dc36" - -[metadata.files] -adal = [ - {file = "adal-1.2.7-py2.py3-none-any.whl", hash = "sha256:2a7451ed7441ddbc57703042204a3e30ef747478eea022c70f789fc7f084bc3d"}, - {file = "adal-1.2.7.tar.gz", hash = "sha256:d74f45b81317454d96e982fd1c50e6fb5c99ac2223728aea8764433a39f566f1"}, -] -adlfs = [ - {file = "adlfs-2022.2.0.tar.gz", hash = "sha256:8543d29ce5b994d49831ad5f86b76b90809a540302b4f24e027591b740127942"}, -] -aiohttp = [ - {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"}, - {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"}, - {file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"}, - {file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"}, - {file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"}, - {file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"}, - {file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"}, - {file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"}, - {file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"}, - {file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"}, - {file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"}, - {file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"}, - {file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"}, - {file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"}, - {file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"}, - {file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"}, -] -aiosignal = [ - {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, - {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, -] -async-timeout = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, -] -asynctest = [ - {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, - {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, -] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -azure-core = [ - {file = "azure-core-1.25.1.zip", hash = "sha256:3c1cf368650e76ec009c07cd1174a95cdcb471b247bb72d18245f7d56c1809b2"}, - {file = "azure_core-1.25.1-py3-none-any.whl", hash = "sha256:b0d62e67ec6d47365eebb12c50bc96f7b22d06b359f56ce7f904b095cb46b195"}, -] -azure-datalake-store = [ - {file = "azure-datalake-store-0.0.52.tar.gz", hash = "sha256:4198ddb32614d16d4502b43d5c9739f81432b7e0e4d75d30e05149fe6007fea2"}, - {file = "azure_datalake_store-0.0.52-py2.py3-none-any.whl", hash = "sha256:aaed72b9c856824aeab554f4dbe0ef2c6d0ff36700bdd8b93d8298793117c48e"}, -] -azure-identity = [ - {file = "azure-identity-1.10.0.zip", hash = "sha256:656e5034d9cef297cf9b35376ed620085273c18cfa52cea4a625bf0d5d2d6409"}, - {file = "azure_identity-1.10.0-py3-none-any.whl", hash = "sha256:b386f1ccbea6a48b9ab7e7f162adc456793c345193a7c1a713959562b08dcbbd"}, -] -azure-storage-blob = [ - {file = "azure-storage-blob-12.13.1.zip", hash = "sha256:899c4b8e2671812d2cf78f107556a27dbb128caaa2bb06094e72a3d5836740af"}, - {file = "azure_storage_blob-12.13.1-py3-none-any.whl", hash = "sha256:726b86f733dc76218ce45b7a3254b61ba4f0cc3d68b7621be4985248c92ee483"}, -] -black = [ - {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, - {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, - {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, - {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, - {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, - {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, - {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, - {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, - {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, - {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, - {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, - {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, - {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, - {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, - {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, - {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, - {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, - {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, - {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, -] -certifi = [ - {file = "certifi-2022.6.15.2-py3-none-any.whl", hash = "sha256:0aa1a42fbd57645fabeb6290a7687c21755b0344ecaeaa05f4e9f6207ae2e9a8"}, - {file = "certifi-2022.6.15.2.tar.gz", hash = "sha256:aa08c101214127b9b0472ca6338315113c9487d45376fd3e669201b477c71003"}, -] -cffi = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, -] -cfgv = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -coverage = [ - {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, - {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, - {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, - {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, - {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, - {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, - {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, - {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, - {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, - {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, - {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, - {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, - {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, - {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, - {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, - {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, -] -cryptography = [ - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, - {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, - {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, - {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, -] -dacite = [ - {file = "dacite-1.6.0-py3-none-any.whl", hash = "sha256:4331535f7aabb505c732fa4c3c094313fc0a1d5ea19907bf4726a7819a68b93f"}, - {file = "dacite-1.6.0.tar.gz", hash = "sha256:d48125ed0a0352d3de9f493bf980038088f45f3f9d7498f090b50a847daaa6df"}, -] -distlib = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, -] -docker = [ - {file = "docker-5.0.3-py2.py3-none-any.whl", hash = "sha256:7a79bb439e3df59d0a72621775d600bc8bc8b422d285824cb37103eab91d1ce0"}, - {file = "docker-5.0.3.tar.gz", hash = "sha256:d916a26b62970e7c2f554110ed6af04c7ccff8e9f81ad17d0d40c75637e227fb"}, -] -filelock = [ - {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, - {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, -] -flake8 = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, -] -frozenlist = [ - {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"}, - {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"}, - {file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"}, - {file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"}, - {file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"}, - {file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"}, - {file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"}, - {file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"}, - {file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"}, - {file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"}, - {file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"}, - {file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"}, - {file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"}, -] -fsspec = [ - {file = "fsspec-2022.8.2-py3-none-any.whl", hash = "sha256:6374804a2c0d24f225a67d009ee1eabb4046ad00c793c3f6df97e426c890a1d9"}, - {file = "fsspec-2022.8.2.tar.gz", hash = "sha256:7f12b90964a98a7e921d27fb36be536ea036b73bf3b724ac0b0bd7b8e39c7c18"}, -] -identify = [ - {file = "identify-2.5.5-py2.py3-none-any.whl", hash = "sha256:ef78c0d96098a3b5fe7720be4a97e73f439af7cf088ebf47b620aeaa10fadf97"}, - {file = "identify-2.5.5.tar.gz", hash = "sha256:322a5699daecf7c6fd60e68852f36f2ecbb6a36ff6e6e973e0d2bb6fca203ee6"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -importlib-metadata = [ - {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, - {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -isodate = [ - {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, - {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -msal = [ - {file = "msal-1.18.0-py2.py3-none-any.whl", hash = "sha256:9c10e6cb32e0b6b8eaafc1c9a68bc3b2ff71505e0c5b8200799582d8b9f22947"}, - {file = "msal-1.18.0.tar.gz", hash = "sha256:576af55866038b60edbcb31d831325a1bd8241ed272186e2832968fd4717d202"}, -] -msal-extensions = [ - {file = "msal-extensions-1.0.0.tar.gz", hash = "sha256:c676aba56b0cce3783de1b5c5ecfe828db998167875126ca4b47dc6436451354"}, - {file = "msal_extensions-1.0.0-py2.py3-none-any.whl", hash = "sha256:91e3db9620b822d0ed2b4d1850056a0f133cba04455e62f11612e40f5502f2ee"}, -] -msrest = [ - {file = "msrest-0.7.1-py3-none-any.whl", hash = "sha256:21120a810e1233e5e6cc7fe40b474eeb4ec6f757a15d7cf86702c369f9567c32"}, - {file = "msrest-0.7.1.zip", hash = "sha256:6e7661f46f3afd88b75667b7187a92829924446c7ea1d169be8c4bb7eeb788b9"}, -] -multidict = [ - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, - {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, - {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, - {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, - {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, - {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, - {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, - {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, - {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, - {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, - {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -neo4j = [ - {file = "neo4j-4.4.7.tar.gz", hash = "sha256:4a7ec29156e7c55247eb146d7dd831833a63fb0842cfe4e04b31d482f5a9631b"}, -] -networkx = [ - {file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"}, - {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"}, -] -nodeenv = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] -numpy = [ - {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, - {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, - {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, - {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, - {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, - {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, - {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, - {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, - {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, -] -oauthlib = [ - {file = "oauthlib-3.2.1-py3-none-any.whl", hash = "sha256:88e912ca1ad915e1dcc1c06fc9259d19de8deacd6fd17cc2df266decc2e49066"}, - {file = "oauthlib-3.2.1.tar.gz", hash = "sha256:1565237372795bf6ee3e5aba5e2a85bd5a65d0e2aa5c628b9a97b7d7a0da3721"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -portalocker = [ - {file = "portalocker-2.5.1-py2.py3-none-any.whl", hash = "sha256:400bae275366e7b840d4baad0654c6ec5994e07c40c423d78e9e1340279b8352"}, - {file = "portalocker-2.5.1.tar.gz", hash = "sha256:ae8e9cc2660da04bf41fa1a0eef7e300bb5e4a5869adfb1a6d8551632b559b2b"}, -] -pre-commit = [ - {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, - {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, -] -psutil = [ - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"}, - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"}, - {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"}, - {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"}, - {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"}, - {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"}, - {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"}, - {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"}, - {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"}, - {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"}, - {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"}, - {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"}, - {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"}, - {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"}, - {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"}, - {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"}, - {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"}, - {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"}, - {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"}, - {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pyarrow = [ - {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_13_universal2.whl", hash = "sha256:767cafb14278165ad539a2918c14c1b73cf20689747c21375c38e3fe62884902"}, - {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0238998dc692efcb4e41ae74738d7c1234723271ccf520bd8312dca07d49ef8d"}, - {file = "pyarrow-9.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:55328348b9139c2b47450d512d716c2248fd58e2f04e2fc23a65e18726666d42"}, - {file = "pyarrow-9.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc856628acd8d281652c15b6268ec7f27ebcb015abbe99d9baad17f02adc51f1"}, - {file = "pyarrow-9.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29eb3e086e2b26202f3a4678316b93cfb15d0e2ba20f3ec12db8fd9cc07cde63"}, - {file = "pyarrow-9.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e753f8fcf07d8e3a0efa0c8bd51fef5c90281ffd4c5637c08ce42cd0ac297de"}, - {file = "pyarrow-9.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:3eef8a981f45d89de403e81fb83b8119c20824caddf1404274e41a5d66c73806"}, - {file = "pyarrow-9.0.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:7fa56cbd415cef912677270b8e41baad70cde04c6d8a8336eeb2aba85aa93706"}, - {file = "pyarrow-9.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f8c46bde1030d704e2796182286d1c56846552c50a39ad5bf5a20c0d8159fc35"}, - {file = "pyarrow-9.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ad430cee28ebc4d6661fc7315747c7a18ae2a74e67498dcb039e1c762a2fb67"}, - {file = "pyarrow-9.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a60bb291a964f63b2717fb1b28f6615ffab7e8585322bfb8a6738e6b321282"}, - {file = "pyarrow-9.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9cef618159567d5f62040f2b79b1c7b38e3885f4ffad0ec97cd2d86f88b67cef"}, - {file = "pyarrow-9.0.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:5526a3bfb404ff6d31d62ea582cf2466c7378a474a99ee04d1a9b05de5264541"}, - {file = "pyarrow-9.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:da3e0f319509a5881867effd7024099fb06950a0768dad0d6873668bb88cfaba"}, - {file = "pyarrow-9.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c715eca2092273dcccf6f08437371e04d112f9354245ba2fbe6c801879450b7"}, - {file = "pyarrow-9.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11a645a41ee531c3a5edda45dea07c42267f52571f818d388971d33fc7e2d4a"}, - {file = "pyarrow-9.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b390bdcfb8c5b900ef543f911cdfec63e88524fafbcc15f83767202a4a2491"}, - {file = "pyarrow-9.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d9eb04db626fa24fdfb83c00f76679ca0d98728cdbaa0481b6402bf793a290c0"}, - {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_13_universal2.whl", hash = "sha256:4eebdab05afa23d5d5274b24c1cbeb1ba017d67c280f7d39fd8a8f18cbad2ec9"}, - {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:02b820ecd1da02012092c180447de449fc688d0c3f9ff8526ca301cdd60dacd0"}, - {file = "pyarrow-9.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92f3977e901db1ef5cba30d6cc1d7942b8d94b910c60f89013e8f7bb86a86eef"}, - {file = "pyarrow-9.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f241bd488c2705df930eedfe304ada71191dcf67d6b98ceda0cc934fd2a8388e"}, - {file = "pyarrow-9.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c5a073a930c632058461547e0bc572da1e724b17b6b9eb31a97da13f50cb6e0"}, - {file = "pyarrow-9.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59bcd5217a3ae1e17870792f82b2ff92df9f3862996e2c78e156c13e56ff62e"}, - {file = "pyarrow-9.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fe2ce795fa1d95e4e940fe5661c3c58aee7181c730f65ac5dd8794a77228de59"}, - {file = "pyarrow-9.0.0.tar.gz", hash = "sha256:7fb02bebc13ab55573d1ae9bb5002a6d20ba767bf8569b52fce5301d42495ab7"}, -] -pycodestyle = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, -] -pycparser = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] -pydantic = [ - {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, - {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, - {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, - {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, - {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, - {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, - {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, - {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, - {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, - {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, -] -pyflakes = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, -] -PyJWT = [ - {file = "PyJWT-2.4.0-py3-none-any.whl", hash = "sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf"}, - {file = "PyJWT-2.4.0.tar.gz", hash = "sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba"}, -] -pymgclient = [ - {file = "pymgclient-1.3.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:6d013f878658296c3e8b360f0be41b9741907249874bcb30ef17fd0481d595d5"}, - {file = "pymgclient-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6b5c6a1eda2f7178befe6c7ad9d31ba14845e672f3ef20ddb9ff46424b893ab"}, - {file = "pymgclient-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:af8edb3f5e57a6f35d6ec68dc147949ecdcc2020a910f7f961957fd224dcf235"}, - {file = "pymgclient-1.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:ed8cf8eeb31319f6f4a76c59f90de68a7a004daae801d6f1eee20fc067230383"}, - {file = "pymgclient-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1abd8dc4efbd5efd5c7074dd2efa88e89443cec23d04dfec1e4f6ff36861c67b"}, - {file = "pymgclient-1.3.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b340a8f4987ae0ef2e5d519232ad98d2baf8deb47e1720e487de646ddfb8253d"}, - {file = "pymgclient-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:79463f3578f0c4194c2f8f8d9386173ab2149ad16a0075af0deab840fbf7c482"}, - {file = "pymgclient-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:e30e03746b9a554b77801ac59ea0fd19fe85db11733d3350dfe1155f719c4e3a"}, - {file = "pymgclient-1.3.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d08aef9bde5f89853cf028b72b547f364b797f5f2fd2d13510817b21d04d210d"}, - {file = "pymgclient-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91faadc50d54ac4707e3b3239f77101d6610494658b1a16ecb4ef8976bb9aa0e"}, - {file = "pymgclient-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:1f9aec0deff251b4c7f7acd763caad193330a072ab29e090e2b60925439eb6da"}, - {file = "pymgclient-1.3.1.tar.gz", hash = "sha256:a409ee9c7ac714a96a86f9eeca9e71f19f36f11390b3fdbac447d65462e05037"}, -] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] -pytest = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, -] -pytest-black = [ - {file = "pytest-black-0.3.12.tar.gz", hash = "sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5"}, -] -pytest-cov = [ - {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, - {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, -] -pytest-flake8 = [ - {file = "pytest-flake8-1.0.7.tar.gz", hash = "sha256:f0259761a903563f33d6f099914afef339c085085e643bee8343eb323b32dd6b"}, - {file = "pytest_flake8-1.0.7-py2.py3-none-any.whl", hash = "sha256:c28cf23e7d359753c896745fd4ba859495d02e16c84bac36caa8b1eec58f5bc1"}, -] -pytest-timeout = [ - {file = "pytest-timeout-1.4.2.tar.gz", hash = "sha256:20b3113cf6e4e80ce2d403b6fb56e9e1b871b510259206d40ff8d609f48bda76"}, - {file = "pytest_timeout-1.4.2-py2.py3-none-any.whl", hash = "sha256:541d7aa19b9a6b4e475c759fd6073ef43d7cdc9a92d95644c260076eb257a063"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -pytz = [ - {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, - {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, -] -pywin32 = [ - {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, - {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, - {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, - {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, - {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, - {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, - {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, - {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, - {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, - {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, - {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, - {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, -] -PyYAML = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -requests = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, -] -requests-oauthlib = [ - {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, - {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, -] -setuptools = [ - {file = "setuptools-65.3.0-py3-none-any.whl", hash = "sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82"}, - {file = "setuptools-65.3.0.tar.gz", hash = "sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -typed-ast = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] -typing-extensions = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, -] -urllib3 = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, -] -virtualenv = [ - {file = "virtualenv-20.16.2-py2.py3-none-any.whl", hash = "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3"}, - {file = "virtualenv-20.16.2.tar.gz", hash = "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db"}, -] -websocket-client = [ - {file = "websocket-client-1.4.1.tar.gz", hash = "sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef"}, - {file = "websocket_client-1.4.1-py3-none-any.whl", hash = "sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090"}, -] -yarl = [ +files = [ {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"}, {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"}, {file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"}, @@ -1895,7 +2050,12 @@ yarl = [ {file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"}, {file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"}, ] -zipp = [ - {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, - {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, -] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "12af775519a25ecce98b684891f8ddcafbc7363ce0397129e9735fc40a50f440" diff --git a/pyproject.toml b/pyproject.toml index 83cfd054..6c9f48ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ exclude = ''' ''' [tool.poetry.dependencies] -python = "^3.7" +python = "^3.8" pymgclient = "1.3.1" networkx = "^2.5.1" pydantic = "^1.8.2" @@ -42,6 +42,9 @@ dacite = "^1.6.0" adlfs = "^2022.2.0" neo4j = "^4.4.3" docker = "^5.0.3" +torch = "^1.13.1" +numpy = "^1.24.1" +dgl = "^0.9.1" [tool.poetry.group.dev.dependencies] black = "^22.3.0" @@ -52,6 +55,9 @@ pytest-flake8 = "1.0.7" pytest-timeout = "^1.4.2" pre-commit = "^2.15.0" +[tool.poe.tasks] +install-pyg-cpu = "pip install torch-scatter torch-sparse torch-cluster torch-spline-conv torch-geometric -f https://data.pyg.org/whl/torch-1.13.0+cpu.html" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/tests/integration/test_networkx.py b/tests/integration/test_networkx.py index 93978c9a..8b896ce0 100644 --- a/tests/integration/test_networkx.py +++ b/tests/integration/test_networkx.py @@ -19,7 +19,7 @@ from gqlalchemy import Memgraph from gqlalchemy.models import MemgraphIndex -from gqlalchemy.transformations import nx_graph_to_memgraph_parallel, nx_to_cypher +from gqlalchemy.transformations.translators.nx_translator import NxTranslator from gqlalchemy.utilities import NetworkXCypherConfig @@ -50,7 +50,8 @@ def test_simple_nx_to_memgraph(memgraph: Memgraph): graph.add_nodes_from([1, 2, 3]) graph.add_edges_from([(1, 2), (1, 3)]) - for query in nx_to_cypher(graph): + translator = NxTranslator() + for query in translator.to_cypher_queries(graph): memgraph.execute(query) actual_nodes = list(memgraph.execute_and_fetch("MATCH (n) RETURN n ORDER BY n.id")) @@ -81,7 +82,8 @@ def test_simple_index_nx_to_memgraph(memgraph: Memgraph): MemgraphIndex("L3", "id"), } - for query in nx_to_cypher(graph, NetworkXCypherConfig(create_index=True)): + translator = NxTranslator() + for query in translator.to_cypher_queries(graph, NetworkXCypherConfig(create_index=True)): memgraph.execute(query) actual_indexes = set(memgraph.get_indexes()) @@ -99,7 +101,8 @@ def test_nx_to_memgraph(memgraph: Memgraph): graph.add_nodes_from(expected_nodes) graph.add_edges_from(expected_edges) - for query in nx_to_cypher(graph): + translator = NxTranslator() + for query in translator.to_cypher_queries(graph): memgraph.execute(query) actual_nodes = list(memgraph.execute_and_fetch("MATCH (n) RETURN n ORDER BY n.id")) @@ -124,14 +127,16 @@ def test_nx_to_memgraph(memgraph: Memgraph): def test_big_nx_to_memgraph_with_manual_index(memgraph: Memgraph, random_nx_graph: nx.Graph): memgraph.create_index(MemgraphIndex("Label", "id")) - for query in nx_to_cypher(random_nx_graph): + translator = NxTranslator() + for query in translator.to_cypher_queries(random_nx_graph): memgraph.execute(query) @pytest.mark.timeout(60) @pytest.mark.slow def test_big_nx_to_memgraph(memgraph: Memgraph, random_nx_graph: nx.Graph): - for query in nx_to_cypher(random_nx_graph, NetworkXCypherConfig(create_index=True)): + translator = NxTranslator() + for query in translator.to_cypher_queries(random_nx_graph, NetworkXCypherConfig(create_index=True)): memgraph.execute(query) @@ -139,5 +144,5 @@ def test_big_nx_to_memgraph(memgraph: Memgraph, random_nx_graph: nx.Graph): @pytest.mark.slow def test_huge_nx_to_memgraph_parallel_with_index(memgraph: Memgraph, big_random_nx_graph: nx.Graph): memgraph.create_index(MemgraphIndex("Label", "id")) - - nx_graph_to_memgraph_parallel(big_random_nx_graph) + translator = NxTranslator() + translator.nx_graph_to_memgraph_parallel(big_random_nx_graph) diff --git a/tests/test_transformations.py b/tests/test_transformations.py deleted file mode 100644 index 0657557d..00000000 --- a/tests/test_transformations.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pytest - -import networkx as nx - -from gqlalchemy.transformations import nx_to_cypher, NoNetworkXConfigException, NetworkXCypherBuilder -from gqlalchemy.utilities import NetworkXCypherConfig - - -def test_nx_create_nodes(): - graph = nx.Graph() - graph.add_nodes_from([1, 2]) - expected_cypher_queries = [ - "CREATE ( {id: 1});", - "CREATE ( {id: 2});", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_nodes_with_string(): - graph = nx.Graph() - graph.add_nodes_from( - [ - (1, {"id": "id1"}), - (2, {"id": "id2"}), - ] - ) - expected_cypher_queries = [ - "CREATE ( {id: 'id1'});", - "CREATE ( {id: 'id2'});", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_nodes_with_properties(): - graph = nx.Graph() - graph.add_nodes_from( - [ - (1, {"color": "blue", "labels": "L1"}), - (2, {"age": 32}), - (3, {"data": [1, 2, 3], "labels": ["L1", "L2", "L3"]}), - ] - ) - expected_cypher_queries = [ - "CREATE (:L1 {color: 'blue', id: 1});", - "CREATE ( {age: 32, id: 2});", - "CREATE (:L1:L2:L3 {data: [1, 2, 3], id: 3});", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_edges(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.add_edges_from([(1, 2), (2, 3)]) - expected_cypher_queries = [ - "CREATE ( {id: 1});", - "CREATE ( {id: 2});", - "CREATE ( {id: 3});", - "MATCH (n {id: 1}), (m {id: 2}) CREATE (n)-[:TO ]->(m);", - "MATCH (n {id: 2}), (m {id: 3}) CREATE (n)-[:TO ]->(m);", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_edges_with_string_ids(): - graph = nx.Graph() - graph.add_nodes_from( - [ - (1, {"id": "id1"}), - (2, {"id": "id2"}), - (3, {"id": "id3"}), - ] - ) - graph.add_edges_from([(1, 2), (2, 3)]) - expected_cypher_queries = [ - "CREATE ( {id: 'id1'});", - "CREATE ( {id: 'id2'});", - "CREATE ( {id: 'id3'});", - "MATCH (n {id: 'id1'}), (m {id: 'id2'}) CREATE (n)-[:TO ]->(m);", - "MATCH (n {id: 'id2'}), (m {id: 'id3'}) CREATE (n)-[:TO ]->(m);", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_edges_with_properties(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) - expected_cypher_queries = [ - "CREATE ( {id: 1});", - "CREATE ( {id: 2});", - "CREATE ( {id: 3});", - "MATCH (n {id: 1}), (m {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", - "MATCH (n {id: 2}), (m {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_edge_and_node_with_properties(): - graph = nx.Graph() - graph.add_nodes_from( - [(1, {"labels": "Label1"}), (2, {"labels": ["Label1", "Label2"], "name": "name1"}), (3, {"labels": "Label1"})] - ) - graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) - expected_cypher_queries = [ - "CREATE (:Label1 {id: 1});", - "CREATE (:Label1:Label2 {name: 'name1', id: 2});", - "CREATE (:Label1 {id: 3});", - "MATCH (n:Label1 {id: 1}), (m:Label1:Label2 {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", - "MATCH (n:Label1:Label2 {id: 2}), (m:Label1 {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", - ] - - actual_cypher_queries = list(nx_to_cypher(graph)) - - assert actual_cypher_queries == expected_cypher_queries - - -def test_nx_create_edge_and_node_with_index(): - graph = nx.Graph() - graph.add_nodes_from( - [(1, {"labels": "Label1"}), (2, {"labels": ["Label1", "Label2"], "name": "name1"}), (3, {"labels": "Label1"})] - ) - graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) - expected_cypher_queries = [ - "CREATE (:Label1 {id: 1});", - "CREATE (:Label1:Label2 {name: 'name1', id: 2});", - "CREATE (:Label1 {id: 3});", - "CREATE INDEX ON :Label2(id);", - "CREATE INDEX ON :Label1(id);", - "MATCH (n:Label1 {id: 1}), (m:Label1:Label2 {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", - "MATCH (n:Label1:Label2 {id: 2}), (m:Label1 {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", - ] - - actual_cypher_queries = list(nx_to_cypher(graph, NetworkXCypherConfig(create_index=True))) - - assert actual_cypher_queries[0:3] == expected_cypher_queries[0:3] - assert set(actual_cypher_queries[3:5]) == set(expected_cypher_queries[3:5]) - assert actual_cypher_queries[5:7] == expected_cypher_queries[5:7] - - -def test_creating_builder_with_no_config_throws_exception(): - with pytest.raises(NoNetworkXConfigException): - NetworkXCypherBuilder(None) diff --git a/tests/transformations/common.py b/tests/transformations/common.py new file mode 100644 index 00000000..080ff935 --- /dev/null +++ b/tests/transformations/common.py @@ -0,0 +1,16 @@ +import pytest + +from gqlalchemy import Memgraph + + +@pytest.fixture +def memgraph() -> Memgraph: + memgraph = Memgraph() + memgraph.drop_database() + yield memgraph + memgraph.drop_database() + + +def execute_queries(memgraph, queries): + for query in queries: + memgraph.execute(query) diff --git a/tests/transformations/export/test_export.py b/tests/transformations/export/test_export.py new file mode 100644 index 00000000..97f1b3ee --- /dev/null +++ b/tests/transformations/export/test_export.py @@ -0,0 +1,15 @@ +import pytest + +from gqlalchemy.transformations.export.graph_transporter import GraphTransporter +from gqlalchemy.transformations.translators.dgl_translator import DGLTranslator +from gqlalchemy.transformations.translators.pyg_translator import PyGTranslator +from gqlalchemy.transformations.translators.nx_translator import NxTranslator + + +@pytest.mark.parametrize( + "graph_type, translator_type", [("DGL", DGLTranslator), ("pyG", PyGTranslator), ("Nx", NxTranslator)] +) +def test_export_selection_strategy(graph_type, translator_type): + transporter = GraphTransporter(graph_type) + assert isinstance(transporter.translator, translator_type) + transporter.export() # even with empty graph we should check that something doesn't fail diff --git a/tests/transformations/importing/__init__.py b/tests/transformations/importing/__init__.py new file mode 100644 index 00000000..34ce70e6 --- /dev/null +++ b/tests/transformations/importing/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/transformations/importing/test_import.py b/tests/transformations/importing/test_import.py new file mode 100644 index 00000000..d717d7bb --- /dev/null +++ b/tests/transformations/importing/test_import.py @@ -0,0 +1,29 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from gqlalchemy.transformations.importing.graph_importer import GraphImporter +from gqlalchemy.transformations.translators.dgl_translator import DGLTranslator +from gqlalchemy.transformations.translators.pyg_translator import PyGTranslator +from gqlalchemy.transformations.translators.nx_translator import NxTranslator + + +@pytest.mark.parametrize( + "graph_type, translator_type", [("DGL", DGLTranslator), ("pyG", PyGTranslator), ("Nx", NxTranslator)] +) +def test_import_selection_strategy(graph_type, translator_type): + importer = GraphImporter(graph_type) + assert isinstance(importer.translator, translator_type) + importer.translate(None) # it should fail safely no matter what diff --git a/tests/transformations/loaders/__init__.py b/tests/transformations/loaders/__init__.py new file mode 100644 index 00000000..34ce70e6 --- /dev/null +++ b/tests/transformations/loaders/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/loaders/data/example.csv b/tests/transformations/loaders/data/example.csv similarity index 100% rename from tests/loaders/data/example.csv rename to tests/transformations/loaders/data/example.csv diff --git a/tests/loaders/data/example.feather b/tests/transformations/loaders/data/example.feather similarity index 100% rename from tests/loaders/data/example.feather rename to tests/transformations/loaders/data/example.feather diff --git a/tests/loaders/data/example.orc b/tests/transformations/loaders/data/example.orc similarity index 100% rename from tests/loaders/data/example.orc rename to tests/transformations/loaders/data/example.orc diff --git a/tests/loaders/data/example.parquet b/tests/transformations/loaders/data/example.parquet similarity index 100% rename from tests/loaders/data/example.parquet rename to tests/transformations/loaders/data/example.parquet diff --git a/tests/loaders/test_loaders.py b/tests/transformations/loaders/test_loaders.py similarity index 86% rename from tests/loaders/test_loaders.py rename to tests/transformations/loaders/test_loaders.py index eeb28674..873a42bf 100644 --- a/tests/loaders/test_loaders.py +++ b/tests/transformations/loaders/test_loaders.py @@ -14,8 +14,9 @@ import platform import pytest +import os -from gqlalchemy.loaders import ( +from gqlalchemy.transformations.importing.loaders import ( CSVLocalFileSystemImporter, DataLoader, FeatherLocalFileSystemImporter, @@ -26,6 +27,9 @@ ) +path = os.path.join(os.path.dirname(__file__), "data") + + class TestFileSystemHandler(FileSystemHandler): def __init__(self) -> None: super().__init__(fs=None) @@ -78,10 +82,7 @@ def test_local_table_to_graph_importer_parquet(memgraph): "name_mappings": {"example": {"label": "PERSON"}}, "one_to_many_relations": {"example": []}, } - importer = ParquetLocalFileSystemImporter( - path="./tests/loaders/data", data_configuration=my_configuration, memgraph=memgraph - ) - + importer = ParquetLocalFileSystemImporter(path=path, data_configuration=my_configuration, memgraph=memgraph) importer.translate(drop_database_on_start=True) @@ -92,10 +93,7 @@ def test_local_table_to_graph_importer_csv(memgraph): "name_mappings": {"example": {"label": "PERSON"}}, "one_to_many_relations": {"example": []}, } - importer = CSVLocalFileSystemImporter( - path="./tests/loaders/data", data_configuration=my_configuration, memgraph=memgraph - ) - + importer = CSVLocalFileSystemImporter(path=path, data_configuration=my_configuration, memgraph=memgraph) importer.translate(drop_database_on_start=True) @@ -110,10 +108,7 @@ def test_local_table_to_graph_importer_orc(memgraph): "name_mappings": {"example": {"label": "PERSON"}}, "one_to_many_relations": {"example": []}, } - importer = ORCLocalFileSystemImporter( - path="./tests/loaders/data", data_configuration=my_configuration, memgraph=memgraph - ) - + importer = ORCLocalFileSystemImporter(path=path, data_configuration=my_configuration, memgraph=memgraph) importer.translate(drop_database_on_start=True) @@ -124,8 +119,5 @@ def test_local_table_to_graph_importer_feather(memgraph): "name_mappings": {"example": {"label": "PERSON"}}, "one_to_many_relations": {"example": []}, } - importer = FeatherLocalFileSystemImporter( - path="./tests/loaders/data", data_configuration=my_configuration, memgraph=memgraph - ) - + importer = FeatherLocalFileSystemImporter(path=path, data_configuration=my_configuration, memgraph=memgraph) importer.translate(drop_database_on_start=True) diff --git a/tests/transformations/translators/__init__.py b/tests/transformations/translators/__init__.py new file mode 100644 index 00000000..34ce70e6 --- /dev/null +++ b/tests/transformations/translators/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/transformations/translators/test_dgl_transformations.py b/tests/transformations/translators/test_dgl_transformations.py new file mode 100644 index 00000000..d9367946 --- /dev/null +++ b/tests/transformations/translators/test_dgl_transformations.py @@ -0,0 +1,907 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict, Any, Set +from numbers import Number + +import numpy as np +import dgl +from dgl.data import TUDataset +import torch + +from gqlalchemy import Match +from gqlalchemy.models import Node, Relationship +from gqlalchemy.transformations.translators.dgl_translator import DGLTranslator +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.transformations.constants import DGL_ID, DEFAULT_NODE_LABEL, DEFAULT_EDGE_TYPE +from gqlalchemy.utilities import to_cypher_value +from tests.transformations.common import execute_queries + +########## +# UTILS +########## + + +def _check_entity_exists_in_dgl(entity_data, properties: Dict[str, Any], translated_properties: Set[str] = {}): + """Checks whether the node with `node label` and `node_properties` exists in the DGL. + Args: + entity_data: `graph.nodes[node_label]` or `graph.edges[etype]` + properties: Entity's properties from the Memgraph. + translated_properties: Properties that are translated from Memgraph to DGL. + Returns: + True if node with node_label and node_properties exists in the DGL, False otherwise. + """ + for property_key, property_value in properties.items(): + if not isinstance(property_value, Number) or property_key not in translated_properties: + continue + for entity_property_value in entity_data[property_key]: + # Check which conditions are OK + if (isinstance(property_value, list) and entity_property_value.tolist() == property_value) or ( + not isinstance(property_value, list) and entity_property_value.item() == property_value + ): + return True + return False + + +def _check_entity_exists_dgl_to_memgraph(entity_data, entity_id: int, properties: Dict[str, Any]): + """Checks that all properties that are in DGL, exist in Memgraph too. + Args: + entity_data: `graph.nodes[node_label]` or `graph.edges[etype]` + entity_id: Edge id or dgl id + properties: Entity's properties from the Memgraph. + """ + for dgl_property_key, dgl_property_value in entity_data.items(): + if not dgl_property_key.startswith("_"): + assert to_cypher_value(dgl_property_value[entity_id]) == properties[dgl_property_key] + + +def _check_all_edges_exist_memgraph_dgl( + graph, + translator: DGLTranslator, + translated_node_properties: Set[str] = {}, + translated_edge_properties: Set[str] = {}, + total_num_edges: int = None, + direction="EXP", +): + """Check whether all edges that exist in Memgraph, exist in the DGLGraph too. + Args: + graph: Reference to the DGLGraph + translator: Reference to the used DGLTranslator. + total_num_edges: Total number of edges in the DGL graph, checked only when importing from DGL. + direction: EXP for exporting Memgraph to DGL, IMP for DGL to Memgraph. + """ + query_results = list(Match().node(variable="n").to(variable="r").node(variable="m").return_().execute()) + assert total_num_edges is None or len(query_results) == total_num_edges + for row in query_results: + row_values = row.values() + for entity in row_values: + if isinstance(entity, Node): + if direction == "EXP": + # If properties don't exist,just check that nodes with such label exist + if not entity._properties: + assert Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL) in graph.ntypes + else: + assert _check_entity_exists_in_dgl( + graph.nodes[Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL)].data, + entity._properties, + translated_node_properties, + ) + else: + _check_entity_exists_dgl_to_memgraph( + graph.nodes[Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL)].data, + entity._properties[DGL_ID], + entity._properties, + ) + + elif isinstance(entity, Relationship): + source_node_label, dest_node_label = None, None + for new_entity in row_values: + if new_entity._id == entity._start_node_id and isinstance(new_entity, Node): + source_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + elif new_entity._id == entity._end_node_id and isinstance(new_entity, Node): + dest_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + if direction == "EXP": + # If properties don't exist,just check that edges with such label exist + if not entity._properties: + assert ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ) in graph.canonical_etypes + else: + assert _check_entity_exists_in_dgl( + graph.edges[ + ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ) + ].data, + entity._properties, + translated_edge_properties, + ) + else: + _check_entity_exists_dgl_to_memgraph( + graph.edges[ + ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ) + ].data, + entity._properties[DGL_ID], + entity._properties, + ) + + +########## +# DGL EXPORT +########## + + +def test_dgl_export_multigraph(memgraph): + """Test graph with no isolated nodes and only one numerical feature and bidirected edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 1 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)]) == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_multiple_nodes_same_features(memgraph): + """Test graph with no isolated nodes and only one numerical feature and bidirected edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 7 + assert len(graph.nodes[source_node_label].data.keys()) == 1 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)]) == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_graph_no_features(memgraph): + """Export graph which has all nodes and edges without properties.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node) REMOVE n.id") + memgraph = execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 0 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 0 + _check_all_edges_exist_memgraph_dgl(graph, translator) + + +def test_dgl_export_graph_no_features_no_labels(memgraph): + """Export graph which has all nodes and edges without properties.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m {{id: 1}})") + queries.append(f"CREATE (m {{id: 2}})") + queries.append(f"CREATE (m {{id: 3}})") + queries.append(f"CREATE (m {{id: 4}})") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n) REMOVE n.id") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ( + DEFAULT_NODE_LABEL, + "CONNECTION", + DEFAULT_NODE_LABEL, + ) # default node label and default edge type + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + _check_all_edges_exist_memgraph_dgl(graph, translator) + + +def test_dgl_export_multiple_labels(memgraph): + """Tests exporting to DGL when using multiple labels for nodes.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node:Mode {{id: 1}})") + queries.append(f"CREATE (m:Node:Mode {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append( + f"MATCH (n:Node:Mode {{id: 1}}), (m:Node:Mode {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)" + ) + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node:Mode {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Check metadata + assert len(graph.ntypes) == 2 # Node and Node:Mode + assert len(graph.canonical_etypes) == 4 + can_type_1 = ("Node", "CONNECTION", "Mode:Node") + can_type_2 = ("Mode:Node", "CONNECTION", "Node") + can_type_3 = ("Mode:Node", "CONNECTION", "Mode:Node") + can_type_4 = ("Node", "CONNECTION", "Node") + assert can_type_1 in graph.canonical_etypes + assert can_type_2 in graph.canonical_etypes + assert can_type_3 in graph.canonical_etypes + assert can_type_4 in graph.canonical_etypes + assert graph.num_nodes("Node") == 2 + assert graph.num_nodes("Mode:Node") == 2 + assert graph.num_edges(etype=can_type_1) == 1 + assert graph.num_edges(etype=can_type_2) == 3 + assert graph.num_edges(etype=can_type_3) == 1 + assert graph.num_edges(etype=can_type_4) == 1 + for ntype in graph.ntypes: + assert len(graph.nodes[ntype].data.keys()) == 1 + for etype in graph.canonical_etypes: + assert len(graph.edges[etype].data.keys()) == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_many_numerical_properties(memgraph): + """Test graph that has several numerical features on nodes and edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 3 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "edem"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_list_properties(memgraph): + """Test graph that has several numerical features on all nodes and edges together with lists that could represent feature vectors.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 4 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 4 + translated_node_properties = {"id", "num", "edem", "lst"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem", "edge_lst"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_various_dimensionality_list_properties(memgraph): + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3, 4, 4]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3, 5, 5]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0, 1, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 3 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "edem"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_non_numeric_properties(memgraph): + """Test graph which has some non-numeric properties. Non-numeric properties will be discarded.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 'one', lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 'two', lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 'three', lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 'fourth', lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 'hi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 'hu', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 'ho', edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 'la', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 'le', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 'do', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 're', edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 'mi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 3 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "lst"} + translated_edge_properties = {"edge_id", "edge_num", "edge_lst"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_partially_existing_numeric_properties(memgraph): + """Test graph for which some numeric feature is not set on all nodes. Then such a feature is ignored.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 212, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 211, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 'hi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 'hu', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 'ho', edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_edem: 'la', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_edem: 'le', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_edem: 'do', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 're', edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 'mi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 2 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 2 + translated_node_properties = {"id", "lst"} + translated_edge_properties = {"edge_id", "edge_lst"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_dgl_export_same_property_multiple_types(memgraph): + """Test graph for which some feature has multiple data types, e.g str and Number. Such feature won't be parsed for every node -> the policy is don't insert features on nodes + and edges that cannot be set on all of them.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 'not num', edem: 34, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: '12', edem: 34, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: '99', edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 'rnd id', edge_num: 'unknown', edge_edem: 12, edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = DGLTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.canonical_etypes) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.ntypes) == 1 + assert graph.ntypes[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.canonical_etypes[0] == can_etype + assert graph[can_etype].number_of_nodes() == 4 + assert graph[can_etype].number_of_edges() == 8 + assert len(graph.nodes[source_node_label].data.keys()) == 3 + assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 2 + translated_node_properties = {"id", "edem", "lst"} + translated_edge_properties = {"edge_edem", "edge_lst"} + _check_all_edges_exist_memgraph_dgl(graph, translator, translated_node_properties, translated_edge_properties) + + +########## +# DGL IMPORT +########## + + +def get_dgl_translator_run_queries(graph, memgraph_): + translator = DGLTranslator() + queries = translator.to_cypher_queries(graph) + execute_queries(memgraph_, queries) + return translator + + +def test_dgl_import_homogeneous(memgraph): + """Test homogenous graph conversion.""" + # Init graph + src = np.array( + [ + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 5, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 9, + 10, + 10, + 10, + 11, + 12, + 12, + 13, + 13, + 13, + 13, + 16, + 16, + 17, + 17, + 19, + 19, + 21, + 21, + 25, + 25, + 27, + 27, + 27, + 28, + 29, + 29, + 30, + 30, + 31, + 31, + 31, + 31, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + ] + ) + dst = np.array( + [ + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 4, + 5, + 0, + 1, + 2, + 3, + 0, + 2, + 2, + 0, + 4, + 5, + 0, + 0, + 3, + 0, + 1, + 2, + 3, + 5, + 6, + 0, + 1, + 0, + 1, + 0, + 1, + 23, + 24, + 2, + 23, + 24, + 2, + 23, + 26, + 1, + 8, + 0, + 24, + 25, + 28, + 2, + 8, + 14, + 15, + 18, + 20, + 22, + 23, + 29, + 30, + 31, + 8, + 9, + 13, + 14, + 15, + 18, + 19, + 20, + 22, + 23, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + ] + ) + graph = dgl.DGLGraph((src, dst)) + # Initialize translator and insert into the MemgrapA + # Let's test + # Check all that are in Memgraph are in DGL too + _check_all_edges_exist_memgraph_dgl( + graph, get_dgl_translator_run_queries(graph, memgraph), total_num_edges=78, direction="IMP" + ) + + +def test_dgl_import_simple_heterogeneous(memgraph): + """Test heterogeneous graph conversion.""" + graph = dgl.heterograph( + { + ("user", "PLUS", "movie"): (np.array([0, 0, 1]), np.array([0, 1, 0])), + ("user", "MINUS", "movie"): (np.array([2]), np.array([1])), + } + ) + _check_all_edges_exist_memgraph_dgl( + graph, get_dgl_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_dgl_import_simple_heterogeneous_with_features(memgraph): + """Simple heterogeneous graph for which also node and edge features are set.""" + graph = dgl.heterograph( + { + ("user", "PLUS", "movie"): (np.array([0, 0, 1]), np.array([0, 1, 0])), + ("user", "MINUS", "movie"): (np.array([2]), np.array([1])), + } + ) + # Set node features + graph.nodes["user"].data["prop1"] = torch.randn(size=(3, 1)) + graph.nodes["user"].data["prop2"] = torch.randn(size=(3, 1)) + graph.nodes["movie"].data["prop1"] = torch.randn(size=(2, 1)) + graph.nodes["movie"].data["prop2"] = torch.randn(size=(2, 1)) + graph.nodes["movie"].data["prop3"] = torch.randn(size=(2, 1)) + # Set edge features + graph.edges[("user", "PLUS", "movie")].data["edge_prop1"] = torch.randn(size=(3, 1)) + graph.edges[("user", "PLUS", "movie")].data["edge_prop2"] = torch.randn(size=(3, 1)) + graph.edges[("user", "MINUS", "movie")].data["edge_prop1"] = torch.randn(size=(1, 1)) + + _check_all_edges_exist_memgraph_dgl( + graph, get_dgl_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_dgl_import_multidimensional_features(memgraph): + """Tests how conversion works when having multidimensional features.""" + graph = dgl.heterograph( + { + ("user", "PLUS", "movie"): (np.array([0, 0, 1]), np.array([0, 1, 0])), + ("user", "MINUS", "movie"): (np.array([2]), np.array([1])), + } + ) + # Set node features + graph.nodes["user"].data["prop1"] = torch.randn(size=(3, 2, 2)) + graph.nodes["user"].data["prop2"] = torch.randn(size=(3, 2, 3)) + graph.nodes["movie"].data["prop1"] = torch.randn(size=(2, 3)) + graph.nodes["movie"].data["prop2"] = torch.randn(size=(2, 3)) + graph.nodes["movie"].data["prop3"] = torch.randn(size=(2, 2)) + # Set edge features + graph.edges[("user", "PLUS", "movie")].data["edge_prop1"] = torch.randn(size=(3, 2)) + graph.edges[("user", "PLUS", "movie")].data["edge_prop2"] = torch.randn(size=(3, 3, 10)) + graph.edges[("user", "MINUS", "movie")].data["edge_prop1"] = torch.randn(size=(1, 4)) + + _check_all_edges_exist_memgraph_dgl( + graph, get_dgl_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_dgl_import_custom_dataset(memgraph): + """Tests how conversion from some custom DGL's dataset works.""" + dataset = TUDataset("ENZYMES") + graph = dataset[0][0] + # Get queries + _check_all_edges_exist_memgraph_dgl( + graph, get_dgl_translator_run_queries(graph, memgraph), total_num_edges=168, direction="IMP" + ) diff --git a/tests/transformations/translators/test_nx_transformations.py b/tests/transformations/translators/test_nx_transformations.py new file mode 100644 index 00000000..3f81a105 --- /dev/null +++ b/tests/transformations/translators/test_nx_transformations.py @@ -0,0 +1,493 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import networkx as nx +import pytest + +from gqlalchemy.transformations.translators.nx_translator import ( + NxTranslator, + NoNetworkXConfigException, + NetworkXCypherBuilder, +) +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.models import Node, Relationship +from gqlalchemy.transformations.constants import LABEL, EDGE_TYPE, DEFAULT_NODE_LABEL, DEFAULT_EDGE_TYPE +from gqlalchemy.utilities import NetworkXCypherConfig +from tests.transformations.common import execute_queries + + +def _check_entity_exists_in_nx(graph_data, entity_properties, expected_num_features): + """Checks that entity with `entity_properties` exists in the Nx graph. + Args: + graph_data: NX node info or edge info. + entity_properties: Entity's Memgraph properties. + expected_num_features: Expected number of properties. + """ + # print(f"Entity properties: {entity_properties}") + for *_, properties in graph_data: + # print(f"Graph properties: {properties}") + if properties == entity_properties and len(properties.keys()) == expected_num_features: + return True + return False + + +def _check_nx_graph_structure( + graph: nx.Graph, translator: NxTranslator, node_expected_num_features, edge_expected_num_features +): + # Test all edges + query_results = translator.get_all_edges_from_db() + for row in query_results: + row_values = row.values() + for entity in row_values: + entity_properties = entity._properties + if isinstance(entity, Node): + entity_properties[LABEL] = Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL) + assert _check_entity_exists_in_nx(graph.nodes(data=True), entity_properties, node_expected_num_features) + elif isinstance(entity, Relationship): + entity_properties[EDGE_TYPE] = entity._type if entity._type else DEFAULT_EDGE_TYPE + assert _check_entity_exists_in_nx(graph.edges(data=True), entity_properties, edge_expected_num_features) + + # Test isolated nodes if any + isolated_nodes_results = translator.get_all_isolated_nodes_from_db() + for isolated_node in isolated_nodes_results: + isolated_node = isolated_node["n"] # + entity_properties = isolated_node._properties + entity_properties[LABEL] = Translator.merge_labels(isolated_node._labels, DEFAULT_NODE_LABEL) + assert _check_entity_exists_in_nx(graph.nodes(data=True), entity_properties, node_expected_num_features) + + +def test_export_simple_graph(memgraph): + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 2, 2) + memgraph.drop_database() + + +def test_export_simple_graph_isolated_nodes(memgraph): + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"CREATE (m:Node {{id: 5}})") # isolated node + queries.append(f"CREATE (m:Node {{id: 6}})") # isolated node + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to DGL graph + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 6 + _check_nx_graph_structure(graph, translator, 2, 2) + + +def test_nx_export_graph_no_features_no_labels(memgraph): + """Export graph which has all nodes and edges without properties.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m {{id: 1}})") + queries.append(f"CREATE (m {{id: 2}})") + queries.append(f"CREATE (m {{id: 3}})") + queries.append(f"CREATE (m {{id: 4}})") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n) REMOVE n.id") + execute_queries(memgraph, queries) + # Translate to nx graph + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 1, 1) + # Test some simple metadata properties + + +def test_nx_export_multiple_labels(memgraph): + """Tests exporting to nx when using multiple labels for nodes.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node:Mode {{id: 1}})") + queries.append(f"CREATE (m:Node:Mode {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append( + f"MATCH (n:Node:Mode {{id: 1}}), (m:Node:Mode {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)" + ) + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node:Mode {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + execute_queries(memgraph, queries) + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 6 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 2, 2) + + +def test_nx_export_many_numerical_properties(memgraph): + """Test graph that has several numerical features on nodes and edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12}}]->(m)" + ) + execute_queries(memgraph, queries) + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 4, 4) + + +def test_nx_export_list_properties(memgraph): + """Test graph that has several numerical features on all nodes and edges together with lists that could represent feature vectors.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 5, 5) + + +def test_nx_export_various_dimensionality_list_properties(memgraph): + """When lists have various dimensions, they should get translated in the same way as when for all nodes are of the same dimension.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3, 4, 4]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3, 5, 5]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0, 1, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 5, 5) + + +def test_nx_export_non_numeric_properties(memgraph): + """Test graph which has some non-numeric properties. Non-numeric properties should be translated in the same way as those numeric.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 'one', lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 'two', lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 'three', lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 'fourth', lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 'hi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 'hu', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 'ho', edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 'la', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 'le', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 'do', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 're', edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 'mi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + translator = NxTranslator() + graph = translator.get_instance() + assert graph.number_of_edges() == 8 + assert graph.number_of_nodes() == 4 + _check_nx_graph_structure(graph, translator, 5, 5) + + +def test_nx_create_nodes(): + graph = nx.Graph() + graph.add_nodes_from([1, 2]) + expected_cypher_queries = [ + "CREATE ( {id: 1});", + "CREATE ( {id: 2});", + ] + translator = NxTranslator() + + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_nodes_with_string(): + graph = nx.Graph() + graph.add_nodes_from( + [ + (1, {"id": "id1"}), + (2, {"id": "id2"}), + ] + ) + expected_cypher_queries = [ + "CREATE ( {id: 'id1'});", + "CREATE ( {id: 'id2'});", + ] + + translator = NxTranslator() + + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_nodes_with_properties(): + graph = nx.Graph() + graph.add_nodes_from( + [ + (1, {"color": "blue", "labels": "L1"}), + (2, {"age": 32}), + (3, {"data": [1, 2, 3], "labels": ["L1", "L2", "L3"]}), + ] + ) + expected_cypher_queries = [ + "CREATE (:L1 {color: 'blue', id: 1});", + "CREATE ( {age: 32, id: 2});", + "CREATE (:L1:L2:L3 {data: [1, 2, 3], id: 3});", + ] + + translator = NxTranslator() + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_edges(): + graph = nx.Graph() + graph.add_nodes_from([1, 2, 3]) + graph.add_edges_from([(1, 2), (2, 3)]) + expected_cypher_queries = [ + "CREATE ( {id: 1});", + "CREATE ( {id: 2});", + "CREATE ( {id: 3});", + "MATCH (n {id: 1}), (m {id: 2}) CREATE (n)-[:TO ]->(m);", + "MATCH (n {id: 2}), (m {id: 3}) CREATE (n)-[:TO ]->(m);", + ] + + translator = NxTranslator() + + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_edges_with_string_ids(): + graph = nx.Graph() + graph.add_nodes_from( + [ + (1, {"id": "id1"}), + (2, {"id": "id2"}), + (3, {"id": "id3"}), + ] + ) + graph.add_edges_from([(1, 2), (2, 3)]) + expected_cypher_queries = [ + "CREATE ( {id: 'id1'});", + "CREATE ( {id: 'id2'});", + "CREATE ( {id: 'id3'});", + "MATCH (n {id: 'id1'}), (m {id: 'id2'}) CREATE (n)-[:TO ]->(m);", + "MATCH (n {id: 'id2'}), (m {id: 'id3'}) CREATE (n)-[:TO ]->(m);", + ] + + translator = NxTranslator() + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_edges_with_properties(): + graph = nx.Graph() + graph.add_nodes_from([1, 2, 3]) + graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) + expected_cypher_queries = [ + "CREATE ( {id: 1});", + "CREATE ( {id: 2});", + "CREATE ( {id: 3});", + "MATCH (n {id: 1}), (m {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", + "MATCH (n {id: 2}), (m {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", + ] + + translator = NxTranslator() + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_edge_and_node_with_properties(): + graph = nx.Graph() + graph.add_nodes_from( + [(1, {"labels": "Label1"}), (2, {"labels": ["Label1", "Label2"], "name": "name1"}), (3, {"labels": "Label1"})] + ) + graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) + expected_cypher_queries = [ + "CREATE (:Label1 {id: 1});", + "CREATE (:Label1:Label2 {name: 'name1', id: 2});", + "CREATE (:Label1 {id: 3});", + "MATCH (n:Label1 {id: 1}), (m:Label1:Label2 {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", + "MATCH (n:Label1:Label2 {id: 2}), (m:Label1 {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", + ] + + translator = NxTranslator() + + actual_cypher_queries = list(translator.to_cypher_queries(graph)) + + assert actual_cypher_queries == expected_cypher_queries + + +def test_nx_create_edge_and_node_with_index(): + graph = nx.Graph() + graph.add_nodes_from( + [(1, {"labels": "Label1"}), (2, {"labels": ["Label1", "Label2"], "name": "name1"}), (3, {"labels": "Label1"})] + ) + graph.add_edges_from([(1, 2, {"type": "TYPE1"}), (2, 3, {"type": "TYPE2", "data": "abc"})]) + expected_cypher_queries = [ + "CREATE (:Label1 {id: 1});", + "CREATE (:Label1:Label2 {name: 'name1', id: 2});", + "CREATE (:Label1 {id: 3});", + "CREATE INDEX ON :Label2(id);", + "CREATE INDEX ON :Label1(id);", + "MATCH (n:Label1 {id: 1}), (m:Label1:Label2 {id: 2}) CREATE (n)-[:TYPE1 ]->(m);", + "MATCH (n:Label1:Label2 {id: 2}), (m:Label1 {id: 3}) CREATE (n)-[:TYPE2 {data: 'abc'}]->(m);", + ] + + translator = NxTranslator() + actual_cypher_queries = list(translator.to_cypher_queries(graph, NetworkXCypherConfig(create_index=True))) + + assert actual_cypher_queries[0:3] == expected_cypher_queries[0:3] + assert set(actual_cypher_queries[3:5]) == set(expected_cypher_queries[3:5]) + assert actual_cypher_queries[5:7] == expected_cypher_queries[5:7] + + +def test_creating_builder_with_no_config_throws_exception(): + with pytest.raises(NoNetworkXConfigException): + NetworkXCypherBuilder(None) diff --git a/tests/transformations/translators/test_pyg_transformations.py b/tests/transformations/translators/test_pyg_transformations.py new file mode 100644 index 00000000..eb81e9a5 --- /dev/null +++ b/tests/transformations/translators/test_pyg_transformations.py @@ -0,0 +1,1003 @@ +# Copyright (c) 2016-2022 Memgraph Ltd. [https://memgraph.com] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict, Any, Set +from numbers import Number + +from torch_geometric.data import Data, HeteroData +from torch_geometric.datasets import FakeDataset, FakeHeteroDataset +import torch + +from gqlalchemy import Match +from gqlalchemy.models import Node, Relationship +from gqlalchemy.transformations.translators.pyg_translator import PyGTranslator +from gqlalchemy.transformations.translators.translator import Translator +from gqlalchemy.transformations.constants import PYG_ID, DEFAULT_NODE_LABEL, DEFAULT_EDGE_TYPE +from gqlalchemy.utilities import to_cypher_value +from tests.transformations.common import execute_queries + +# TODO: test number of properties that were converted + +########## +# UTILS +########## + + +def _check_entity_exists_in_pyg( + entity_data, entity_mark: str, properties: Dict[str, Any], translated_properties: Set[str] = {} +): + """Checks whether the node with `node label` and `node_properties` exists in the pyg. + Args: + entity_data: `graph.node_items()` or `graph.edge_items()`. + entity_mark: Node's label or edge type. + properties: Entity's properties from the Memgraph. + translated_properties: Properties that are translated from Memgraph to pyg. + Returns: + True if node with node_label and node_properties exists in the pyg, False otherwise. + """ + for property_key, property_value in properties.items(): + if not isinstance(property_value, Number) or property_key not in translated_properties: + continue + for pyg_label, pyg_properties in entity_data: + if pyg_label == entity_mark: # because it is stored in tuples + for entity_property_value in pyg_properties[property_key]: + # Check which conditions are OK + if (isinstance(property_value, list) and entity_property_value.tolist() == property_value) or ( + not isinstance(property_value, list) and entity_property_value.item() == property_value + ): + return True + return False + + +def _check_entity_exists_in_pyg_homogeneous(entity_data, properties: Dict[str, Any], entity_id): + """Checks whether the node with `node label` and `node_properties` exists in the pyg. + Args: + entity_data: `graph.node_items()`, `graph.edge_items()' or node_properties and etype_properties when dealing with homogeneous graph. + entity_id: Edge id or pyg id + properties: Entity's properties from the Memgraph. + Returns: + True if node with node_label and node_properties exists in the pyg, False otherwise. + """ + for property_key, property_value in entity_data.items(): + if not property_key.startswith("_"): + assert to_cypher_value(property_value[entity_id]) == properties[property_key] + return False + + +def _check_entity_exists_pyg_to_memgraph(entity_data, entity_mark, entity_id, properties: Dict[str, Any]): + """Checks that all properties that are in pyg, exist in Memgraph too. + Args: + entity_data: `graph.node_items()` or `graph.edge_items()`. + entity_mark: Node's label or edge type. + entity_id: Edge id or pyg id + properties: Entity's properties from the Memgraph. + """ + for pyg_label, pyg_properties in entity_data: + if pyg_label == entity_mark: + for pyg_property_key, pyg_property_value in pyg_properties.items(): + if pyg_property_key.startswith("_"): + continue + assert to_cypher_value(pyg_property_value[entity_id]) == properties[pyg_property_key] + + +def _check_all_edges_exist_memgraph_pyg( + graph, + translator: PyGTranslator, + translated_node_properties: Set[str] = {}, + translated_edge_properties: Set[str] = {}, + total_num_edges: int = None, + direction="EXP", +): + """Check whether all edges that exist in Memgraph, exist in the pygGraph too. + Args: + graph: Reference to the pygGraph + translator: Reference to the used PyGTranslator. + total_num_edges: Total number of edges in the pyg graph, checked only when importing from pyg. + direction: EXP for exporting Memgraph to pyg, IMP for pyg to Memgraph. + TODO: maybe it would be better to use static variables for default node labels if this is the only dependency + """ + query_results = list(Match().node(variable="n").to(variable="r").node(variable="m").return_().execute()) + assert total_num_edges is None or len(query_results) == total_num_edges + if isinstance(graph, Data): + node_properties, etype_properties = PyGTranslator.extract_node_edge_properties_from_homogeneous_graph(graph) + for row in query_results: + row_values = row.values() + for entity in row_values: + if isinstance(entity, Node): + node_label = Translator.merge_labels(entity._labels, DEFAULT_NODE_LABEL) + if not entity._properties: + assert node_label in graph.node_types + continue + + if direction == "EXP": + # If properties don't exist,just check that nodes with such label exist + assert _check_entity_exists_in_pyg( + graph.node_items(), + node_label, + entity._properties, + translated_node_properties, + ) + else: + if isinstance(graph, Data): + _check_entity_exists_in_pyg_homogeneous( + node_properties, + entity._properties, + entity._properties[PYG_ID], + ) + elif isinstance(graph, HeteroData): + _check_entity_exists_pyg_to_memgraph( + graph.node_items(), + node_label, + entity._properties[PYG_ID], + entity._properties, + ) + + elif isinstance(entity, Relationship): + source_node_label, dest_node_label = None, None + for new_entity in row_values: + if new_entity._id == entity._start_node_id and isinstance(new_entity, Node): + source_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + elif new_entity._id == entity._end_node_id and isinstance(new_entity, Node): + dest_node_label = Translator.merge_labels(new_entity._labels, DEFAULT_NODE_LABEL) + if not entity._properties: + assert ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ) in graph.edge_types + continue + if direction == "EXP": + # If properties don't exist,just check that edges with such label exist + assert _check_entity_exists_in_pyg( + graph.edge_items(), + ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ), + entity._properties, + translated_edge_properties, + ) + else: + if isinstance(graph, Data): + _check_entity_exists_in_pyg_homogeneous( + etype_properties, entity._properties, translated_edge_properties + ) + elif isinstance(graph, HeteroData): + _check_entity_exists_pyg_to_memgraph( + graph.edge_items(), + ( + source_node_label, + entity._type if entity._type else DEFAULT_EDGE_TYPE, + dest_node_label, + ), + entity._properties[PYG_ID], + entity._properties, + ) + + +########## +# pyg EXPORT +########## + + +def test_pyg_export_multigraph(memgraph): + """Test graph with no isolated nodes and only one numerical feature and bidirected edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # print(f"Graph: {graph.num_node_features}|") + # print(f"Graph: {graph.num_edge_features}|") + # assert graph.num_node_features[source_node_label] == 1 + # assert graph.num_edge_features[(source_node_label, edge_type, dest_node_label)] == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_multiple_nodes_same_features(memgraph): + """Test graph with no isolated nodes and only one numerical feature and bidirected edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8}}]->(m)") + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 7 + # Property stuff + # assert len(graph.nodes[source_node_label].data.keys()) == 1 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)]) == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_graph_no_features(memgraph): + """Export graph which has all nodes and edges without properties.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1}})") + queries.append(f"CREATE (m:Node {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n:Node) REMOVE n.id") + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 0 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 0 + _check_all_edges_exist_memgraph_pyg(graph, translator) + + +def test_pyg_export_graph_no_features_no_labels(memgraph): + """Export graph which has all nodes and edges without properties.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m {{id: 1}})") + queries.append(f"CREATE (m {{id: 2}})") + queries.append(f"CREATE (m {{id: 3}})") + queries.append(f"CREATE (m {{id: 4}})") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 1}}), (m {{id: 3}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 2}}), (m {{id: 4}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 4}}), (m {{id: 2}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n {{id: 3}}), (m {{id: 1}}) CREATE (n)-[r:CONNECTION]->(m)") + queries.append(f"MATCH (n) REMOVE n.id") + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ( + DEFAULT_NODE_LABEL, + "CONNECTION", + DEFAULT_NODE_LABEL, + ) # default node label and default edge type + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + _check_all_edges_exist_memgraph_pyg(graph, translator) + + +def test_pyg_export_multiple_labels(memgraph): + """Tests exporting to pyg when using multiple labels for nodes.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node:Mode {{id: 1}})") + queries.append(f"CREATE (m:Node:Mode {{id: 2}})") + queries.append(f"CREATE (m:Node {{id: 3}})") + queries.append(f"CREATE (m:Node {{id: 4}})") + queries.append( + f"MATCH (n:Node:Mode {{id: 1}}), (m:Node:Mode {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1}}]->(m)" + ) + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3}}]->(m)") + queries.append(f"MATCH (n:Node {{id: 4}}), (m:Node:Mode {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5}}]->(m)") + queries.append(f"MATCH (n:Node:Mode {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6}}]->(m)") + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Check metadata + assert len(graph.node_types) == 2 # Node and Node:Mode + assert len(graph.edge_types) == 4 + can_type_1 = ("Node", "CONNECTION", "Mode:Node") + can_type_2 = ("Mode:Node", "CONNECTION", "Node") + can_type_3 = ("Mode:Node", "CONNECTION", "Mode:Node") + can_type_4 = ("Node", "CONNECTION", "Node") + assert can_type_1 in graph.edge_types + assert can_type_2 in graph.edge_types + assert can_type_3 in graph.edge_types + assert can_type_4 in graph.edge_types + assert graph["Node"].num_nodes == 2 + assert graph["Mode:Node"].num_nodes == 2 + assert graph[can_type_1].num_edges == 1 + assert graph[can_type_2].num_edges == 3 + assert graph[can_type_3].num_edges == 1 + assert graph[can_type_4].num_edges == 1 + # for ntype in graph.node_types: + # assert len(graph.nodes[ntype].data.keys()) == 1 + # for etype in graph.edge_types: + # assert len(graph.edges[etype].data.keys()) == 1 + translated_node_properties = {"id"} + translated_edge_properties = {"edge_id"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_many_numerical_properties(memgraph): + """Test graph that has several numerical features on nodes and edges.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 3 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "edem"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_list_properties(memgraph): + """Test graph that has several numerical features on all nodes and edges together with lists that could represent feature vectors.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 4 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 4 + translated_node_properties = {"id", "num", "edem", "lst"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem", "edge_lst"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_list_properties_x_y(memgraph): + """Test graph that has several numerical features on all nodes and edges together with lists that could represent feature vectors.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, y: 82, edem: 21, x: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, y: 91, edem: 32, x: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, y: 100, edem: 34, x: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, y: 12, edem: 34, x: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, x: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, x: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, x: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 4 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 4 + translated_node_properties = {"id", "num", "edem", "lst"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem", "edge_lst"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_various_dimensionality_list_properties(memgraph): + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 34, lst: [3, 2, 2, 3, 4, 4]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 34, lst: [2, 2, 2, 3, 5, 5]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 12, edge_lst: [1, 1, 0, 0, 1, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 3 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "edem"} + translated_edge_properties = {"edge_id", "edge_num", "edge_edem"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_non_numeric_properties(memgraph): + """Test graph which has some non-numeric properties. Non-numeric properties will be discarded.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 'one', lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 'two', lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 100, edem: 'three', lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: 12, edem: 'fourth', lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 'hi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 'hu', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 'ho', edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 'la', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: 99, edge_edem: 'le', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 'do', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 're', edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 'mi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 3 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 3 + translated_node_properties = {"id", "num", "lst"} + translated_edge_properties = {"edge_id", "edge_num", "edge_lst"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_partially_existing_numeric_properties(memgraph): + """Test graph for which some numeric feature is not set on all nodes. Then such a feature is ignored.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 212, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 211, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 'hi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 'hu', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 'ho', edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_edem: 'la', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_edem: 'le', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_edem: 'do', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 7, edge_num: 99, edge_edem: 're', edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 'mi', edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 2 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 2 + translated_node_properties = {"id", "lst"} + translated_edge_properties = {"edge_id", "edge_lst"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +def test_pyg_export_same_property_multiple_types(memgraph): + """Test graph for which some feature has multiple data types, e.g str and Number. Such feature won't be parsed for every node -> the policy is don't insert features on nodes + and edges that cannot be set on all of them.""" + # Prepare queries + queries = [] + queries.append(f"CREATE (m:Node {{id: 1, num: 80, edem: 30, lst: [2, 3, 3, 2]}})") + queries.append(f"CREATE (m:Node {{id: 2, num: 91, edem: 32, lst: [2, 2, 3, 3]}})") + queries.append(f"CREATE (m:Node {{id: 3, num: 'not num', edem: 34, lst: [3, 2, 2, 3]}})") + queries.append(f"CREATE (m:Node {{id: 4, num: '12', edem: 34, lst: [2, 2, 2, 3]}})") + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 1, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 2, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 3, edge_num: 99, edge_edem: 12, edge_lst: [1, 0, 1, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 4, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 1}}), (m:Node {{id: 3}}) CREATE (n)-[r:CONNECTION {{edge_id: 5, edge_num: '99', edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 2}}), (m:Node {{id: 4}}) CREATE (n)-[r:CONNECTION {{edge_id: 6, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 4}}), (m:Node {{id: 2}}) CREATE (n)-[r:CONNECTION {{edge_id: 'rnd id', edge_num: 'unknown', edge_edem: 12, edge_lst: [1, 1, 0, 0]}}]->(m)" + ) + queries.append( + f"MATCH (n:Node {{id: 3}}), (m:Node {{id: 1}}) CREATE (n)-[r:CONNECTION {{edge_id: 8, edge_num: 99, edge_edem: 12, edge_lst: [0, 1, 0, 1]}}]->(m)" + ) + execute_queries(memgraph, queries) + # Translate to pyg graph + translator = PyGTranslator() + graph = translator.get_instance() + # Test some simple metadata properties + assert len(graph.edge_types) == 1 + source_node_label, edge_type, dest_node_label = ("Node", "CONNECTION", "Node") + assert len(graph.node_types) == 1 + assert graph.node_types[0] == source_node_label + can_etype = (source_node_label, edge_type, dest_node_label) + assert graph.edge_types[0] == can_etype + assert graph[source_node_label].num_nodes == 4 + assert graph[can_etype].num_edges == 8 + # assert len(graph.nodes[source_node_label].data.keys()) == 3 + # assert len(graph.edges[(source_node_label, edge_type, dest_node_label)].data.keys()) == 2 + translated_node_properties = {"id", "edem", "lst"} + translated_edge_properties = {"edge_edem", "edge_lst"} + _check_all_edges_exist_memgraph_pyg(graph, translator, translated_node_properties, translated_edge_properties) + + +########## +# pyg IMPORT +########## + + +def get_pyg_translator_run_queries(graph, memgraph_): + translator = PyGTranslator() + queries = translator.to_cypher_queries(graph) + execute_queries(memgraph_, queries) + return translator + + +def test_pyg_import_homogeneous(memgraph): + """Test homogenous graph conversion.""" + # Init graph + src = [ + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 5, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 9, + 10, + 10, + 10, + 11, + 12, + 12, + 13, + 13, + 13, + 13, + 16, + 16, + 17, + 17, + 19, + 19, + 21, + 21, + 25, + 25, + 27, + 27, + 27, + 28, + 29, + 29, + 30, + 30, + 31, + 31, + 31, + 31, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + ] + dst = [ + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 4, + 5, + 0, + 1, + 2, + 3, + 0, + 2, + 2, + 0, + 4, + 5, + 0, + 0, + 3, + 0, + 1, + 2, + 3, + 5, + 6, + 0, + 1, + 0, + 1, + 0, + 1, + 23, + 24, + 2, + 23, + 24, + 2, + 23, + 26, + 1, + 8, + 0, + 24, + 25, + 28, + 2, + 8, + 14, + 15, + 18, + 20, + 22, + 23, + 29, + 30, + 31, + 8, + 9, + 13, + 14, + 15, + 18, + 19, + 20, + 22, + 23, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + ] + graph = Data(edge_index=torch.tensor([src, dst], dtype=torch.int32)) + # Initialize translator and insert into the MemgrapA + # Let's test + # Check all that are in Memgraph are in pyg too + _check_all_edges_exist_memgraph_pyg( + graph, + get_pyg_translator_run_queries(graph, memgraph), + total_num_edges=78, + direction="IMP", + ) + + +def test_pyg_import_simple_heterogeneous(memgraph): + """Test heterogeneous graph conversion.""" + graph = HeteroData() + graph[("user", "PLUS", "movie")].edge_index = torch.tensor([[0, 0, 1], [0, 1, 0]], dtype=torch.int32) + graph[("user", "MINUS", "movie")].edge_index = torch.tensor([[2], [1]], dtype=torch.int32) + _check_all_edges_exist_memgraph_pyg( + graph, get_pyg_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_pyg_import_simple_heterogeneous_with_features(memgraph): + """Simple heterogeneous graph for which also node and edge features are set.""" + graph = HeteroData() + graph[("user", "PLUS", "movie")].edge_index = torch.tensor([[0, 0, 1], [0, 1, 0]], dtype=torch.int32) + graph[("user", "MINUS", "movie")].edge_index = torch.tensor([[2], [1]], dtype=torch.int32) + # Set node features + graph["user"].prop1 = torch.randn(size=(3, 1)) + graph["user"].prop2 = torch.randn(size=(3, 1)) + graph["movie"].prop1 = torch.randn(size=(2, 1)) + graph["movie"].prop2 = torch.randn(size=(2, 1)) + graph["movie"].prop3 = torch.randn(size=(2, 1)) + graph["movie"].x = torch.randn(size=(2, 1)) + graph["movie"].y = torch.randn(size=(2, 1)) + # Set edge features + graph[("user", "PLUS", "movie")].edge_prop1 = torch.randn(size=(3, 1)) + graph[("user", "PLUS", "movie")].edge_prop2 = torch.randn(size=(3, 1)) + graph[("user", "MINUS", "movie")].edge_prop1 = torch.randn(size=(1, 1)) + + _check_all_edges_exist_memgraph_pyg( + graph, get_pyg_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_pyg_import_multidimensional_features(memgraph): + """Tests how conversion works when having multidimensional features.""" + # Set node features + graph = HeteroData() + graph[("user", "PLUS", "movie")].edge_index = torch.tensor([[0, 0, 1], [0, 1, 0]], dtype=torch.int32) + graph[("user", "MINUS", "movie")].edge_index = torch.tensor([[2], [1]], dtype=torch.int32) + # Set node features + graph["user"].prop1 = torch.randn(size=(3, 2, 2)) + graph["user"].prop2 = torch.randn(size=(3, 2, 3)) + graph["movie"].prop1 = torch.randn(size=(2, 3)) + graph["movie"].prop2 = torch.randn(size=(2, 3)) + graph["movie"].prop3 = torch.randn(size=(2, 2)) + # Set edge features + graph[("user", "PLUS", "movie")].edge_prop1 = torch.randn(size=(3, 2)) + graph[("user", "PLUS", "movie")].edge_prop2 = torch.randn(size=(3, 3, 10)) + graph[("user", "MINUS", "movie")].edge_prop1 = torch.randn(size=(1, 4)) + graph["movie"].x = torch.randn(size=(2, 4, 6)) + graph["movie"].y = torch.randn(size=(2, 8, 4)) + + _check_all_edges_exist_memgraph_pyg( + graph, get_pyg_translator_run_queries(graph, memgraph), total_num_edges=4, direction="IMP" + ) + + +def test_pyg_import_custom_dataset(memgraph): + """Tests how conversion from some custom pyg's dataset works.""" + graph = FakeDataset(avg_num_nodes=100, avg_degree=4, num_channels=10)[0] + # Get queries + _check_all_edges_exist_memgraph_pyg(graph, get_pyg_translator_run_queries(graph, memgraph), direction="IMP") + + +def test_pyg_import_custom_hetero_dataset(memgraph): + """Tests how conversion from some custom pyg's dataset works.""" + graph = FakeHeteroDataset(avg_num_nodes=100, avg_degree=4, num_channels=10)[0] + # Get queries + _check_all_edges_exist_memgraph_pyg(graph, get_pyg_translator_run_queries(graph, memgraph), direction="IMP") From 4833ca007b88164373e52286cb4d8caa472a19ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Sa=C4=8Dari=C4=87?= Date: Thu, 9 Mar 2023 15:58:31 +0100 Subject: [PATCH 8/8] Bump version to 1.4 for release (#222) --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6c9f48ba..1a0b8aad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,13 @@ [tool.poetry] name = "GQLAlchemy" -version = "1.3.3" +version = "1.4.0" description = "GQLAlchemy is library developed with purpose of assisting writing and running queries on Memgraph." repository = "https://github.com/memgraph/gqlalchemy" authors = [ - "Boris Tasevski ", "Bruno Sacaric ", "Josip Mrden ", "Katarina Supe ", - "Niko Krvavica ", + "Andi Skrgat ", ] license = "Apache-2.0" readme = "README.md"