diff --git a/.gitignore b/.gitignore index e03dd04ab..a8e809dda 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ build.sh *.dylib age--*.*.*.sql !age--*--*sql +__pycache__ +**/__pycache__ + +drivers/python/build diff --git a/drivers/python/age/__init__.py b/drivers/python/age/__init__.py index 5d0e31ef8..638269090 100644 --- a/drivers/python/age/__init__.py +++ b/drivers/python/age/__init__.py @@ -13,6 +13,7 @@ # specific language governing permissions and limitations # under the License. +import psycopg.conninfo as conninfo from . import age from .age import * from .models import * @@ -23,10 +24,13 @@ def version(): return VERSION.VERSION -def connect(dsn=None, graph=None, connection_factory=None, cursor_factory=None, **kwargs): - ag = Age() - ag.connect(dsn=dsn, graph=graph, connection_factory=connection_factory, cursor_factory=cursor_factory, **kwargs) - return ag +def connect(dsn=None, graph=None, connection_factory=None, cursor_factory=ClientCursor, **kwargs): + + dsn = conninfo.make_conninfo('' if dsn is None else dsn, **kwargs) + + ag = Age() + ag.connect(dsn=dsn, graph=graph, connection_factory=connection_factory, cursor_factory=cursor_factory, **kwargs) + return ag # Dummy ResultHandler rawPrinter = DummyResultHandler() diff --git a/drivers/python/age/age.py b/drivers/python/age/age.py index 40ad0c21e..2d98e3ff2 100644 --- a/drivers/python/age/age.py +++ b/drivers/python/age/age.py @@ -13,13 +13,14 @@ # specific language governing permissions and limitations # under the License. -import re -import psycopg2 -from psycopg2 import errors -from psycopg2 import extensions as ext -from psycopg2 import sql +import re +import psycopg +from psycopg.types import TypeInfo +from psycopg.adapt import Loader +from psycopg import sql +from psycopg.client_cursor import ClientCursor from .exceptions import * -from .builder import ResultHandler , parseAgeValue, newResultHandler +from .builder import parseAgeValue _EXCEPTION_NoConnection = NoConnection() @@ -27,26 +28,36 @@ WHITESPACE = re.compile('\s') -def setUpAge(conn:ext.connection, graphName:str): + +class AgeDumper(psycopg.adapt.Dumper): + def dump(self, obj: Any) -> bytes | bytearray | memoryview: + pass + + +class AgeLoader(psycopg.adapt.Loader): + def load(self, data: bytes | bytearray | memoryview) -> Any | None: + return parseAgeValue(data.decode('utf-8')) + + +def setUpAge(conn:psycopg.connection, graphName:str): with conn.cursor() as cursor: cursor.execute("LOAD 'age';") cursor.execute("SET search_path = ag_catalog, '$user', public;") - cursor.execute("SELECT typelem FROM pg_type WHERE typname='_agtype'") - oid = cursor.fetchone()[0] - if oid == None : - raise AgeNotSet() + ag_info = TypeInfo.fetch(conn, 'agtype') - AGETYPE = ext.new_type((oid,), 'AGETYPE', parseAgeValue) - ext.register_type(AGETYPE) - # ext.register_adapter(Path, marshalAgtValue) + if not ag_info: + raise AgeNotSet() + + conn.adapters.register_loader(ag_info.oid, AgeLoader) + conn.adapters.register_loader(ag_info.array_oid, AgeLoader) # Check graph exists if graphName != None: checkGraphCreated(conn, graphName) # Create the graph, if it does not exist -def checkGraphCreated(conn:ext.connection, graphName:str): +def checkGraphCreated(conn:psycopg.connection, graphName:str): with conn.cursor() as cursor: cursor.execute(sql.SQL("SELECT count(*) FROM ag_graph WHERE name={graphName}").format(graphName=sql.Literal(graphName))) if cursor.fetchone()[0] == 0: @@ -54,7 +65,7 @@ def checkGraphCreated(conn:ext.connection, graphName:str): conn.commit() -def deleteGraph(conn:ext.connection, graphName:str): +def deleteGraph(conn:psycopg.connection, graphName:str): with conn.cursor() as cursor: cursor.execute(sql.SQL("SELECT drop_graph({graphName}, true);").format(graphName=sql.Literal(graphName))) conn.commit() @@ -82,7 +93,7 @@ def buildCypher(graphName:str, cypherStmt:str, columns:list) ->str: stmtArr.append(");") return "".join(stmtArr) -def execSql(conn:ext.connection, stmt:str, commit:bool=False, params:tuple=None) -> ext.cursor : +def execSql(conn:psycopg.connection, stmt:str, commit:bool=False, params:tuple=None) -> psycopg.cursor : if conn == None or conn.closed: raise _EXCEPTION_NoConnection @@ -101,14 +112,14 @@ def execSql(conn:ext.connection, stmt:str, commit:bool=False, params:tuple=None) raise SqlExecutionError("Execution ERR[" + str(cause) +"](" + stmt +")", cause) -def querySql(conn:ext.connection, stmt:str, params:tuple=None) -> ext.cursor : +def querySql(conn:psycopg.connection, stmt:str, params:tuple=None) -> psycopg.cursor : return execSql(conn, stmt, False, params) # Execute cypher statement and return cursor. # If cypher statement changes data (create, set, remove), # You must commit session(ag.commit()) # (Otherwise the execution cannot make any effect.) -def execCypher(conn:ext.connection, graphName:str, cypherStmt:str, cols:list=None, params:tuple=None) -> ext.cursor : +def execCypher(conn:psycopg.connection, graphName:str, cypherStmt:str, cols:list=None, params:tuple=None) -> psycopg.cursor : if conn == None or conn.closed: raise _EXCEPTION_NoConnection @@ -117,7 +128,7 @@ def execCypher(conn:ext.connection, graphName:str, cypherStmt:str, cols:list=Non cypherStmt = cypherStmt.replace("\n", "") cypherStmt = cypherStmt.replace("\t", "") cypher = str(cursor.mogrify(cypherStmt, params)) - cypher = cypher[2:len(cypher)-1] + cypher = cypher.strip() preparedStmt = "SELECT * FROM age_prepare_cypher({graphName},{cypherStmt})" @@ -145,12 +156,12 @@ def execCypher(conn:ext.connection, graphName:str, cypherStmt:str, cols:list=Non raise SqlExecutionError("Execution ERR[" + str(cause) +"](" + stmt +")", cause) -def cypher(cursor:ext.cursor, graphName:str, cypherStmt:str, cols:list=None, params:tuple=None) -> ext.cursor : +def cypher(cursor:psycopg.cursor, graphName:str, cypherStmt:str, cols:list=None, params:tuple=None) -> psycopg.cursor : #clean up the string for mogrification cypherStmt = cypherStmt.replace("\n", "") cypherStmt = cypherStmt.replace("\t", "") cypher = str(cursor.mogrify(cypherStmt, params)) - cypher = cypher[2:len(cypher)-1] + cypher = cypher.strip() preparedStmt = "SELECT * FROM age_prepare_cypher({graphName},{cypherStmt})" cursor.execute(sql.SQL(preparedStmt).format(graphName=sql.Literal(graphName),cypherStmt=sql.Literal(cypher))) @@ -159,22 +170,22 @@ def cypher(cursor:ext.cursor, graphName:str, cypherStmt:str, cols:list=None, par cursor.execute(stmt) -# def execCypherWithReturn(conn:ext.connection, graphName:str, cypherStmt:str, columns:list=None , params:tuple=None) -> ext.cursor : +# def execCypherWithReturn(conn:psycopg.connection, graphName:str, cypherStmt:str, columns:list=None , params:tuple=None) -> psycopg.cursor : # stmt = buildCypher(graphName, cypherStmt, columns) # return execSql(conn, stmt, False, params) -# def queryCypher(conn:ext.connection, graphName:str, cypherStmt:str, columns:list=None , params:tuple=None) -> ext.cursor : +# def queryCypher(conn:psycopg.connection, graphName:str, cypherStmt:str, columns:list=None , params:tuple=None) -> psycopg.cursor : # return execCypherWithReturn(conn, graphName, cypherStmt, columns, params) class Age: def __init__(self): - self.connection = None # psycopg2 connection] + self.connection = None # psycopg connection] self.graphName = None # Connect to PostgreSQL Server and establish session and type extension environment. - def connect(self, graph:str=None, dsn:str=None, connection_factory=None, cursor_factory=None, **kwargs): - conn = psycopg2.connect(dsn, connection_factory, cursor_factory, **kwargs) + def connect(self, graph:str=None, dsn:str=None, connection_factory=None, cursor_factory=ClientCursor, **kwargs): + conn = psycopg.connect(dsn, cursor_factory=cursor_factory, **kwargs) setUpAge(conn, graph) self.connection = conn self.graphName = graph @@ -194,21 +205,21 @@ def commit(self): def rollback(self): self.connection.rollback() - def execCypher(self, cypherStmt:str, cols:list=None, params:tuple=None) -> ext.cursor : + def execCypher(self, cypherStmt:str, cols:list=None, params:tuple=None) -> psycopg.cursor : return execCypher(self.connection, self.graphName, cypherStmt, cols=cols, params=params) - def cypher(self, cursor:ext.cursor, cypherStmt:str, cols:list=None, params:tuple=None) -> ext.cursor : + def cypher(self, cursor:psycopg.cursor, cypherStmt:str, cols:list=None, params:tuple=None) -> psycopg.cursor : return cypher(cursor, self.graphName, cypherStmt, cols=cols, params=params) - # def execSql(self, stmt:str, commit:bool=False, params:tuple=None) -> ext.cursor : + # def execSql(self, stmt:str, commit:bool=False, params:tuple=None) -> psycopg.cursor : # return execSql(self.connection, stmt, commit, params) - # def execCypher(self, cypherStmt:str, commit:bool=False, params:tuple=None) -> ext.cursor : + # def execCypher(self, cypherStmt:str, commit:bool=False, params:tuple=None) -> psycopg.cursor : # return execCypher(self.connection, self.graphName, cypherStmt, commit, params) - # def execCypherWithReturn(self, cypherStmt:str, columns:list=None , params:tuple=None) -> ext.cursor : + # def execCypherWithReturn(self, cypherStmt:str, columns:list=None , params:tuple=None) -> psycopg.cursor : # return execCypherWithReturn(self.connection, self.graphName, cypherStmt, columns, params) - # def queryCypher(self, cypherStmt:str, columns:list=None , params:tuple=None) -> ext.cursor : - # return queryCypher(self.connection, self.graphName, cypherStmt, columns, params) + # def queryCypher(self, cypherStmt:str, columns:list=None , params:tuple=None) -> psycopg.cursor : + # return queryCypher(self.connection, self.graphName, cypherStmt, columns, params) diff --git a/drivers/python/age/builder.py b/drivers/python/age/builder.py index 44bcee9df..fec8a4ade 100644 --- a/drivers/python/age/builder.py +++ b/drivers/python/age/builder.py @@ -18,8 +18,8 @@ from .gen.AgtypeVisitor import AgtypeVisitor from .models import * from .exceptions import * -from antlr4 import * -from antlr4.tree.Tree import * +from antlr4 import InputStream, CommonTokenStream, ParserRuleContext +from antlr4.tree.Tree import TerminalNode from decimal import Decimal resultHandler = None @@ -43,7 +43,7 @@ def parseAgeValue(value, cursor=None): try: return resultHandler.parse(value) except Exception as ex: - raise AGTypeError(value) + raise AGTypeError(value, ex) class Antlr4ResultHandler(ResultHandler): diff --git a/drivers/python/age/exceptions.py b/drivers/python/age/exceptions.py index 8c46e8e99..3aa94f4b8 100644 --- a/drivers/python/age/exceptions.py +++ b/drivers/python/age/exceptions.py @@ -13,7 +13,7 @@ # specific language governing permissions and limitations # under the License. -from psycopg2.errors import * +from psycopg.errors import * class AgeNotSet(Exception): def __init__(self, name): diff --git a/drivers/python/age/networkx/age_to_networkx.py b/drivers/python/age/networkx/age_to_networkx.py index 3a16aa3a2..4e27a547c 100644 --- a/drivers/python/age/networkx/age_to_networkx.py +++ b/drivers/python/age/networkx/age_to_networkx.py @@ -14,13 +14,13 @@ # under the License. from age import * -import psycopg2 +import psycopg import networkx as nx from age.models import Vertex, Edge, Path from .lib import * -def age_to_networkx(connection: psycopg2.connect, +def age_to_networkx(connection: psycopg.connect, graphName: str, G: None | nx.DiGraph = None, query: str | None = None @@ -28,7 +28,7 @@ def age_to_networkx(connection: psycopg2.connect, """ @params --------------------- - connection - (psycopg2.connect) Connection object + connection - (psycopg.connect) Connection object graphName - (str) Name of the graph G - (networkx.DiGraph) Networkx directed Graph [optional] query - (str) Cypher query [optional] diff --git a/drivers/python/age/networkx/lib.py b/drivers/python/age/networkx/lib.py index a4df08863..308658620 100644 --- a/drivers/python/age/networkx/lib.py +++ b/drivers/python/age/networkx/lib.py @@ -14,15 +14,15 @@ # under the License. from age import * -import psycopg2 +import json +import psycopg import networkx as nx -from psycopg2 import sql -from psycopg2.extras import execute_values +from psycopg import sql from typing import Dict, Any, List, Set from age.models import Vertex, Edge, Path -def checkIfGraphNameExistInAGE(connection: psycopg2.connect, +def checkIfGraphNameExistInAGE(connection: psycopg.connect, graphName: str): """Check if the age graph exists""" with connection.cursor() as cursor: @@ -35,7 +35,7 @@ def checkIfGraphNameExistInAGE(connection: psycopg2.connect, raise GraphNotFound(graphName) -def getOidOfGraph(connection: psycopg2.connect, +def getOidOfGraph(connection: psycopg.connect, graphName: str) -> int: """Returns oid of a graph""" try: @@ -49,7 +49,7 @@ def getOidOfGraph(connection: psycopg2.connect, print(e) -def get_vlabel(connection: psycopg2.connect, +def get_vlabel(connection: psycopg.connect, graphName: str): node_label_list = [] oid = getOidOfGraph(connection, graphName) @@ -65,7 +65,7 @@ def get_vlabel(connection: psycopg2.connect, return node_label_list -def create_vlabel(connection: psycopg2.connect, +def create_vlabel(connection: psycopg.connect, graphName: str, node_label_list: List): """create_vlabels from list if not exist""" @@ -85,7 +85,7 @@ def create_vlabel(connection: psycopg2.connect, raise Exception(e) -def get_elabel(connection: psycopg2.connect, +def get_elabel(connection: psycopg.connect, graphName: str): edge_label_list = [] oid = getOidOfGraph(connection, graphName) @@ -100,7 +100,7 @@ def get_elabel(connection: psycopg2.connect, return edge_label_list -def create_elabel(connection: psycopg2.connect, +def create_elabel(connection: psycopg.connect, graphName: str, edge_label_list: List): """create_vlabels from list if not exist""" @@ -169,7 +169,7 @@ def getEdgeLabelListAfterPreprocessing(G: nx.DiGraph): return edge_label_list -def addAllNodesIntoAGE(connection: psycopg2.connect, graphName: str, G: nx.DiGraph, node_label_list: Set): +def addAllNodesIntoAGE(connection: psycopg.connect, graphName: str, G: nx.DiGraph, node_label_list: Set): """Add all node to AGE""" try: queue_data = {label: [] for label in node_label_list} @@ -181,23 +181,29 @@ def addAllNodesIntoAGE(connection: psycopg2.connect, graphName: str, G: nx.DiGra for label, rows in queue_data.items(): table_name = """%s."%s" """ % (graphName, label) - insert_query = f"INSERT INTO {table_name} (properties) VALUES %s RETURNING id" + insert_query = f"INSERT INTO {table_name} (properties) VALUES (%s) RETURNING id" cursor = connection.cursor() - id_data[label] = execute_values( - cursor, insert_query, rows, fetch=True) + cursor.executemany(insert_query, rows, returning=True) + ids = [] + while True: + ids.append(cursor.fetchone()[0]) + if not cursor.nextset(): + break + + id_data[label] = ids connection.commit() cursor.close() id_data[label].reverse() for node, data in G.nodes(data=True): - data['properties']['__gid__'] = id_data[data['label']][-1][0] + data['properties']['__gid__'] = id_data[data['label']][-1] id_data[data['label']].pop() except Exception as e: raise Exception(e) -def addAllEdgesIntoAGE(connection: psycopg2.connect, graphName: str, G: nx.DiGraph, edge_label_list: Set): +def addAllEdgesIntoAGE(connection: psycopg.connect, graphName: str, G: nx.DiGraph, edge_label_list: Set): """Add all edge to AGE""" try: queue_data = {label: [] for label in edge_label_list} @@ -208,16 +214,16 @@ def addAllEdgesIntoAGE(connection: psycopg2.connect, graphName: str, G: nx.DiGra for label, rows in queue_data.items(): table_name = """%s."%s" """ % (graphName, label) - insert_query = f"INSERT INTO {table_name} (start_id,end_id,properties) VALUES %s" + insert_query = f"INSERT INTO {table_name} (start_id,end_id,properties) VALUES (%s, %s, %s)" cursor = connection.cursor() - execute_values(cursor, insert_query, rows) + cursor.executemany(insert_query, rows) connection.commit() cursor.close() except Exception as e: raise Exception(e) -def addAllNodesIntoNetworkx(connection: psycopg2.connect, graphName: str, G: nx.DiGraph): +def addAllNodesIntoNetworkx(connection: psycopg.connect, graphName: str, G: nx.DiGraph): """Add all nodes to Networkx""" node_label_list = get_vlabel(connection, graphName) try: @@ -235,7 +241,7 @@ def addAllNodesIntoNetworkx(connection: psycopg2.connect, graphName: str, G: nx. print(e) -def addAllEdgesIntoNetworkx(connection: psycopg2.connect, graphName: str, G: nx.DiGraph): +def addAllEdgesIntoNetworkx(connection: psycopg.connect, graphName: str, G: nx.DiGraph): """Add All edges to Networkx""" try: edge_label_list = get_elabel(connection, graphName) diff --git a/drivers/python/age/networkx/networkx_to_age.py b/drivers/python/age/networkx/networkx_to_age.py index 90cee97b3..053193c87 100644 --- a/drivers/python/age/networkx/networkx_to_age.py +++ b/drivers/python/age/networkx/networkx_to_age.py @@ -14,18 +14,18 @@ # under the License. from age import * -import psycopg2 +import psycopg import networkx as nx from .lib import * -def networkx_to_age(connection: psycopg2.connect, +def networkx_to_age(connection: psycopg.connect, G: nx.DiGraph, graphName: str): """ @params ----------- - connection - (psycopg2.connect) Connection object + connection - (psycopg.connect) Connection object G - (networkx.DiGraph) Networkx directed Graph diff --git a/drivers/python/requirements.txt b/drivers/python/requirements.txt index 45af26158..92c42e422 100644 Binary files a/drivers/python/requirements.txt and b/drivers/python/requirements.txt differ diff --git a/drivers/python/samples/apache-age-agtypes.ipynb b/drivers/python/samples/apache-age-agtypes.ipynb index 141ff3f4b..7055db98b 100644 --- a/drivers/python/samples/apache-age-agtypes.ipynb +++ b/drivers/python/samples/apache-age-agtypes.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "6301516b-a3fa-48e2-a95f-0f79903a6cdd", "metadata": {}, "outputs": [], @@ -22,10 +22,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "adf14fe9-692c-4701-86d4-8c84fd53d966", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " | {\"name\": \"Smith\", \"num\":123, \"yn\":true, \"bigInt\":123456789123456789123456789123456789::numeric} --> {'name': 'Smith', 'num': 123, 'yn': True, 'bigInt': Decimal('123456789123456789123456789123456789')}\n", + " | [\"name\", \"Smith\", \"num\", 123, \"yn\", true, 123456789123456789123456789123456789.8888::numeric] --> ['name', 'Smith', 'num', 123, 'yn', True, Decimal('123456789123456789123456789123456789.8888')]\n", + " | \"abcd\" --> abcd\n", + " | 1234 --> 1234\n", + " | 1234.56789 --> 1234.56789\n", + " | 12345678901234567890123456789123456789.789::numeric --> 12345678901234567890123456789123456789.789\n", + " | 12345678901234567890123456789123456789::numeric --> 12345678901234567890123456789123456789\n", + " | true --> True\n", + " | -6.45161290322581e+46 --> -6.45161290322581e+46\n", + " | -123456789.99::numeric --> -123456789.99\n", + " | -6.45161290322581e+46::numeric --> -6.45161290322581E+46\n", + " | 1234 --> 1234\n", + " | NaN --> nan\n", + " | -Infinity --> -inf\n", + " | Infinity --> inf\n" + ] + } + ], "source": [ "\n", "mapStr = '{\"name\": \"Smith\", \"num\":123, \"yn\":true, \"bigInt\":123456789123456789123456789123456789::numeric}' \n", @@ -57,10 +79,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "8881804e-d71d-4704-b74c-376ed55be808", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 2251799813685425\n", + " Person\n", + " Smith\n", + " 123\n", + " 384.23424\n", + " 123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789\n", + " 123456789123456789123456789123456789.12345\n", + " True\n", + " None\n" + ] + } + ], "source": [ "vertexExp = '''{\"id\": 2251799813685425, \"label\": \"Person\", \n", " \"properties\": {\"name\": \"Smith\", \"numInt\":123, \"numFloat\": 384.23424, \n", @@ -82,10 +120,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "0a70e467-9587-4eb7-b97d-895223009bcc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 2251799813685425\n", + " Person\n", + " Smith\n", + " 2533274790396576\n", + " workWith\n", + " 3\n", + " 123456789123456789123456789.12345\n", + " 2251799813685424\n", + " Person\n", + " Joe\n" + ] + } + ], "source": [ "\n", "pathExp = '''[{\"id\": 2251799813685425, \"label\": \"Person\", \"properties\": {\"name\": \"Smith\"}}::vertex, \n", @@ -138,7 +193,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.11.1" } }, "nbformat": 4, diff --git a/drivers/python/samples/apache-age-basic.ipynb b/drivers/python/samples/apache-age-basic.ipynb index f1749630b..59de8e429 100644 --- a/drivers/python/samples/apache-age-basic.ipynb +++ b/drivers/python/samples/apache-age-basic.ipynb @@ -5,9 +5,9 @@ "id": "2e236ac7-6f78-4a59-bed7-45f593d060c2", "metadata": {}, "source": [ - "# Basic Samples : Agtype mapper for Psycopg2 driver\n", + "# Basic Samples : Agtype mapper for psycopg driver\n", "\n", - "You can make transactions and queries for PostgreSQL with Psycopg2.\n", + "You can make transactions and queries for PostgreSQL with Psycopg.\n", "\n", "This module enable to mapping agtype to python class(Path, Vertex, Edge)\n", "\n", @@ -16,26 +16,46 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "98a5863c-1e79-438e-81d4-d1f5354a1bdb", "metadata": {}, "outputs": [], "source": [ - "import psycopg2 \n", + "import psycopg \n", "import age\n", "\n", "GRAPH_NAME = \"test_graph\"\n", - "conn = psycopg2.connect(host=\"172.17.0.2\", port=\"5432\", dbname=\"postgres\", user=\"postgres\", password=\"agens\")\n", - "\n", - "age.setUpAge(conn, GRAPH_NAME)\n" + "ag = age.connect(host=\"172.17.0.2\", port=\"5432\", dbname=\"postgre\", user=\"postgres\", password=\"agens\", graph=GRAPH_NAME)\n", + "conn = ag.connection\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "ebcf65a5-de7c-4224-aacc-2695c9e5f8d5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CREATED:: {label:Person, id:844424930131971, properties:{name: Tom, title: Manager}}::VERTEX\n", + "------- [Select Vertices] --------\n", + "844424930131969 Person Joe Developer\n", + "--> {label:Person, id:844424930131969, properties:{name: Joe, title: Developer}}::VERTEX\n", + "844424930131970 Person Smith Developer\n", + "--> {label:Person, id:844424930131970, properties:{name: Smith, title: Developer}}::VERTEX\n", + "844424930131971 Person Tom Manager\n", + "--> {label:Person, id:844424930131971, properties:{name: Tom, title: Manager}}::VERTEX\n", + "\n", + "------- [Select Paths] --------\n", + "1 Joe 2 workWith 5 1 Smith\n", + "--> [{label:Person, id:844424930131969, properties:{name: Joe, title: Developer}}::VERTEX,{label:workWith, id:1125899906842625, properties:{weight: 5}, start_id:844424930131969, end_id:844424930131970}::EDGE,{label:Person, id:844424930131970, properties:{name: Smith, title: Developer}}::VERTEX]::PATH\n", + "1 Smith 2 workWith 3 1 Tom\n", + "--> [{label:Person, id:844424930131970, properties:{name: Smith, title: Developer}}::VERTEX,{label:workWith, id:1125899906842626, properties:{weight: 3}, start_id:844424930131970, end_id:844424930131971}::EDGE,{label:Person, id:844424930131971, properties:{name: Tom, title: Manager}}::VERTEX]::PATH\n" + ] + } + ], "source": [ "with conn.cursor() as cursor:\n", " try :\n", @@ -91,10 +111,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "id": "f45f7c7d-2256-4aea-92f6-e0ad71017feb", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Joe workWith Smith\n", + "--> ('Joe', 'workWith', 'Smith')\n", + "Smith workWith Tom\n", + "--> ('Smith', 'workWith', 'Tom')\n" + ] + } + ], "source": [ "with conn.cursor() as cursor:\n", " try:\n", @@ -111,10 +142,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "c40b9076-d45e-43e6-85ae-296ba68a3031", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Joe {'weight': 5} Smith\n", + "Smith {'weight': 3} Tom\n", + "Jack {'weight': 2} John\n" + ] + } + ], "source": [ "with conn.cursor() as cursor:\n", " try :\n", @@ -152,10 +193,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "29ffe1b7-86df-446a-9df0-635be25a9eea", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Joe 1125899906842625 {'weight': 5} Smith\n", + "Smith 1125899906842626 {'weight': 3} Tom\n", + "Jack 1125899906842627 {'weight': 2} John\n" + ] + } + ], "source": [ "with conn.cursor() as cursor:\n", " try:\n", @@ -172,7 +223,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "428e6ddf-3958-49ff-af73-809b9a1ce42b", "metadata": {}, "outputs": [], @@ -180,25 +231,6 @@ "age.deleteGraph(conn, GRAPH_NAME)\n", "conn.close()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a4819e39-9f37-4dd5-bdbd-337b6d289158", - "metadata": {}, - "outputs": [], - "source": [ - "\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "02041ef2-9761-4eb3-b270-ded23e1caa6d", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -217,7 +249,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.11.1" } }, "nbformat": 4, diff --git a/drivers/python/samples/apache-age-note.ipynb b/drivers/python/samples/apache-age-note.ipynb index 59c25bc5b..d6bcf69ba 100644 --- a/drivers/python/samples/apache-age-note.ipynb +++ b/drivers/python/samples/apache-age-note.ipynb @@ -131,12 +131,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "CREATED: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "CREATED: 844424930131976\n", + "CREATED: {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", + "CREATED: 844424930131972\n", "SET: \"Manager\"\n", - "SET: \"Manager\"\n", - "REMOVE Prop: 844424930131970\n", - "REMOVE Prop: 844424930131974\n" + "REMOVE Prop: 844424930131970\n" ] } ], @@ -221,29 +219,17 @@ "text": [ "-- Query Vertices --------------------\n", "844424930131969 Person Joe\n", - "--> {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", + "--> {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX\n", "844424930131971 Person Jack\n", - "--> {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", + "--> {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", "844424930131972 Person Andy\n", - "--> {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "844424930131973 Person Joe\n", - "--> {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "844424930131975 Person Jack\n", - "--> {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "844424930131976 Person Andy\n", - "--> {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", + "--> {label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX\n", "844424930131970 Person Smith\n", - "--> {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "844424930131974 Person Smith\n", - "--> {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", + "--> {label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX\n", "-- Query Vertices with with multi columns. --------------------\n", "\"Person\" Joe\n", "\"Person\" Jack\n", "\"Person\" Andy\n", - "\"Person\" Joe\n", - "\"Person\" Jack\n", - "\"Person\" Andy\n", - "\"Person\" Smith\n", "\"Person\" Smith\n" ] } @@ -305,14 +291,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "[{label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX,{label:workWith, id:1125899906842637, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE,{label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX]::PATH\n", - "[{label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX,{label:workWith, id:1125899906842638, properties:{}, start_id:844424930131972, end_id:844424930131974}::EDGE,{label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX]::PATH\n", - "[{label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX,{label:workWith, id:1125899906842639, properties:{}, start_id:844424930131976, end_id:844424930131970}::EDGE,{label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX]::PATH\n", - "[{label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX,{label:workWith, id:1125899906842640, properties:{}, start_id:844424930131976, end_id:844424930131974}::EDGE,{label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX]::PATH\n", - "(a) {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX : (r) {label:workWith, id:1125899906842641, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131971}::EDGE : (b) {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "(a) {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX : (r) {label:workWith, id:1125899906842642, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131975}::EDGE : (b) {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "(a) {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX : (r) {label:workWith, id:1125899906842643, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131971}::EDGE : (b) {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "(a) {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX : (r) {label:workWith, id:1125899906842644, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131975}::EDGE : (b) {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n" + "[{label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX,{label:workWith, id:1125899906842627, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE,{label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX]::PATH\n", + "(a) {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX : (r) {label:workWith, id:1125899906842628, properties:{weight: 5}, start_id:844424930131969, end_id:844424930131971}::EDGE : (b) {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n" ] } ], @@ -393,7 +373,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "7673e270-4ea3-4878-961c-8fc97106e1bd", "metadata": {}, "outputs": [ @@ -401,156 +381,36 @@ "name": "stdout", "output_type": "stream", "text": [ - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842628, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842641, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842642, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131975}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842625, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842629, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842630, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842628, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842641, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842626, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842633, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842643, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842634, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131976}::EDGE\n", - "END: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842626, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842633, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842635, properties:{weight: 5, }, start_id:844424930131975, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", + "START: {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842628, properties:{weight: 5}, start_id:844424930131969, end_id:844424930131971}::EDGE\n", + "END: {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX\n", + "START: {label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842625, properties:{weight: 3}, start_id:844424930131969, end_id:844424930131970}::EDGE\n", + "END: {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX\n", + "START: {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842628, properties:{weight: 5}, start_id:844424930131969, end_id:844424930131971}::EDGE\n", + "END: {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", + "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842626, properties:{weight: 5}, start_id:844424930131971, end_id:844424930131972}::EDGE\n", + "END: {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", + "START: {label:Person, id:844424930131971, properties:{name: Jack}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842626, properties:{weight: 5}, start_id:844424930131971, end_id:844424930131972}::EDGE\n", + "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX\n", + "START: {label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX\n", "EDGE: {label:workWith, id:1125899906842627, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842637, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842638, properties:{}, start_id:844424930131972, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842643, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131971}::EDGE\n", - "END: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842644, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131975}::EDGE\n", - "END: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842631, properties:{weight: 3, }, start_id:844424930131973, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842632, properties:{weight: 3, }, start_id:844424930131973, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842642, properties:{weight: 5, }, start_id:844424930131969, end_id:844424930131975}::EDGE\n", - "END: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842635, properties:{weight: 5, }, start_id:844424930131975, end_id:844424930131972}::EDGE\n", - "END: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842644, properties:{weight: 5, }, start_id:844424930131973, end_id:844424930131975}::EDGE\n", - "END: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842636, properties:{weight: 5, }, start_id:844424930131975, end_id:844424930131976}::EDGE\n", - "END: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "START: {label:Person, id:844424930131971, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842634, properties:{weight: 5, }, start_id:844424930131971, end_id:844424930131976}::EDGE\n", - "END: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131975, properties:{name: Jack, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842636, properties:{weight: 5, }, start_id:844424930131975, end_id:844424930131976}::EDGE\n", - "END: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842639, properties:{}, start_id:844424930131976, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842640, properties:{}, start_id:844424930131976, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842625, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842629, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", + "END: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX\n", + "START: {label:Person, id:844424930131969, properties:{name: Joe}}::VERTEX\n", + "EDGE: {label:workWith, id:1125899906842625, properties:{weight: 3}, start_id:844424930131969, end_id:844424930131970}::EDGE\n", + "END: {label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX\n", + "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer}}::VERTEX\n", "EDGE: {label:workWith, id:1125899906842627, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842637, properties:{}, start_id:844424930131972, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842631, properties:{weight: 3, }, start_id:844424930131973, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842639, properties:{}, start_id:844424930131976, end_id:844424930131970}::EDGE\n", - "END: {label:Person, id:844424930131970, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131969, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842630, properties:{weight: 3, }, start_id:844424930131969, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131972, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842638, properties:{}, start_id:844424930131972, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131973, properties:{name: Joe, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842632, properties:{weight: 3, }, start_id:844424930131973, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", - "START: {label:Person, id:844424930131976, properties:{name: Andy, title: Developer, }}::VERTEX\n", - "EDGE: {label:workWith, id:1125899906842640, properties:{}, start_id:844424930131976, end_id:844424930131974}::EDGE\n", - "END: {label:Person, id:844424930131974, properties:{name: Smith, }}::VERTEX\n", + "END: {label:Person, id:844424930131970, properties:{name: Smith}}::VERTEX\n", "-- [Query path with multi columns --------\n", "Jack workWith 5 Joe\n", - "Jack workWith 5 Joe\n", - "Jack workWith 5 Joe\n", - "Smith workWith 3 Joe\n", - "Smith workWith 3 Joe\n", - "Smith workWith 3 Joe\n", - "Joe workWith 5 Jack\n", - "Joe workWith 5 Jack\n", - "Andy workWith 5 Jack\n", - "Andy workWith 5 Jack\n", - "Joe workWith 5 Jack\n", - "Andy workWith 5 Jack\n", - "Jack workWith 5 Andy\n", - "Jack workWith 5 Andy\n", - "Jack workWith 5 Andy\n", - "Jack workWith 5 Joe\n", - "Jack workWith 5 Joe\n", - "Smith workWith 3 Joe\n", "Smith workWith 3 Joe\n", "Joe workWith 5 Jack\n", "Andy workWith 5 Jack\n", - "Joe workWith 5 Jack\n", - "Andy workWith 5 Jack\n", "Jack workWith 5 Andy\n", - "Jack workWith 5 Andy\n", - "Joe workWith 3 Smith\n", - "Joe workWith 3 Smith\n", - "Joe workWith 3 Smith\n", - "Joe workWith 3 Smith\n", "Joe workWith 3 Smith\n" ] } @@ -564,7 +424,7 @@ " print(\"END:\", path[2]) \n", "\n", "print(\"-- [Query path with multi columns --------\")\n", - "cursor = ag.execCypher(\"MATCH p=(a)-[b]-(c) WHERE b.weight>2 RETURN a,label(b), b.weight, c\", cols=[\"a\",\"bl\",\"bw\", \"c\"], params=(2,))\n", + "cursor = ag.execCypher(\"MATCH p=(a)-[b]-(c) WHERE b.weight>%s RETURN a,label(b), b.weight, c\", cols=[\"a\",\"bl\",\"bw\", \"c\"], params=(2,))\n", "for row in cursor:\n", " start = row[0]\n", " edgel = row[1]\n", @@ -588,7 +448,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "id": "5771219a", "metadata": {}, "outputs": [ @@ -596,22 +456,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Joe workWith ['Smith', 'Smith', 'Jack', 'Jack', 'Smith', 'Jack']\n", - "Smith workWith ['Joe', 'Joe', 'Andy', 'Andy', 'Joe', 'Andy']\n", - "Jack workWith ['Joe', 'Joe', 'Andy', 'Andy', 'Joe', 'Andy']\n", - "Andy workWith ['Smith', 'Smith', 'Jack', 'Jack', 'Smith', 'Jack']\n", - "Joe workWith ['Jack', 'Smith', 'Jack', 'Smith']\n", - "Smith workWith ['Andy', 'Joe', 'Andy', 'Joe']\n", - "Jack workWith ['Joe', 'Joe', 'Andy', 'Andy']\n", - "Andy workWith ['Jack', 'Smith', 'Jack', 'Smith']\n", - "Joe workWith ['Smith', 'Smith', 'Jack', 'Jack', 'Smith', 'Jack']\n", - "Smith workWith ['Joe', 'Joe', 'Andy', 'Andy', 'Joe', 'Andy']\n", - "Jack workWith ['Joe', 'Joe', 'Andy', 'Andy', 'Joe', 'Andy']\n", - "Andy workWith ['Smith', 'Smith', 'Jack', 'Jack', 'Smith', 'Jack']\n", - "Joe workWith ['Jack', 'Smith', 'Jack', 'Smith']\n", - "Smith workWith ['Andy', 'Joe', 'Andy', 'Joe']\n", - "Jack workWith ['Joe', 'Joe', 'Andy', 'Andy']\n", - "Andy workWith ['Jack', 'Smith', 'Jack', 'Smith']\n" + "Joe workWith ['Jack', 'Smith']\n", + "Smith workWith ['Joe', 'Andy']\n", + "Jack workWith ['Joe', 'Andy']\n", + "Andy workWith ['Jack', 'Smith']\n", + "Joe workWith ['Jack', 'Smith']\n", + "Smith workWith ['Joe', 'Andy']\n", + "Jack workWith ['Joe', 'Andy']\n", + "Andy workWith ['Jack', 'Smith']\n" ] } ], @@ -642,7 +494,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "c8b36687-c842-4663-a7aa-084ae618301e", "metadata": {}, "outputs": [ @@ -714,7 +566,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "7f93e698-888a-4dde-b327-e591659e051f", "metadata": {}, "outputs": [ @@ -726,22 +578,13 @@ "844424930131969\n", "844424930131971\n", "844424930131972\n", - "844424930131973\n", - "844424930131975\n", - "844424930131976\n", "844424930131970\n", - "844424930131974\n", "-- Query properties --------------------\n", "{'name': 'Joe'}\n", "{'name': 'Jack'}\n", "{'name': 'Andy', 'title': 'Developer'}\n", - "{'name': 'Joe'}\n", - "{'name': 'Jack'}\n", - "{'name': 'Andy', 'title': 'Developer'}\n", - "{'name': 'Smith'}\n", "{'name': 'Smith'}\n", "-- Query property value --------------------\n", - "Developer\n", "Developer\n" ] } @@ -777,7 +620,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "e15b0654-66d2-4da4-af66-6f776e6729ac", "metadata": {}, "outputs": [], diff --git a/drivers/python/samples/networkx.ipynb b/drivers/python/samples/networkx.ipynb index 20fc566d5..759dee289 100644 --- a/drivers/python/samples/networkx.ipynb +++ b/drivers/python/samples/networkx.ipynb @@ -6,12 +6,12 @@ "metadata": {}, "outputs": [], "source": [ - "import psycopg2\n", + "import psycopg\n", "from age.networkx import *\n", "from age import *\n", "import networkx as nx\n", "\n", - "conn = psycopg2.connect(\n", + "conn = psycopg.connect(\n", " host=\"localhost\",\n", " port=\"5432\",\n", " dbname=\"postgres\",\n", diff --git a/drivers/python/setup.py b/drivers/python/setup.py index ab4c899cc..17a226415 100644 --- a/drivers/python/setup.py +++ b/drivers/python/setup.py @@ -29,7 +29,7 @@ author_email = 'dev-subscribe@age.apache.org', url = 'https://github.com/apache/age', license = 'Apache2.0', - install_requires = [ 'psycopg2', 'antlr4-python3-runtime==4.11.1'], + install_requires = [ 'psycopg', 'antlr4-python3-runtime==4.11.1'], packages = ['age', 'age.gen','age.networkx'], keywords = ['Graph Database', 'Apache AGE', 'PostgreSQL'], python_requires = '>=3.9', diff --git a/drivers/python/test_age_py.py b/drivers/python/test_age_py.py index 8048844f6..f904fb9e3 100644 --- a/drivers/python/test_age_py.py +++ b/drivers/python/test_age_py.py @@ -20,7 +20,6 @@ import age import argparse -DSN = "host=localhost port=5432 dbname=postgres user=postgres password=agens" TEST_HOST = "localhost" TEST_PORT = 5432 TEST_DB = "postgres" @@ -28,12 +27,32 @@ TEST_PASSWORD = "agens" TEST_GRAPH_NAME = "test_graph" + class TestAgeBasic(unittest.TestCase): ag = None + args: argparse.Namespace = argparse.Namespace( + host=TEST_HOST, + port=TEST_PORT, + database=TEST_DB, + user=TEST_USER, + password=TEST_PASSWORD, + graphName=TEST_GRAPH_NAME + ) + def setUp(self): print("Connecting to Test Graph.....") - self.ag = age.connect(graph=TEST_GRAPH_NAME, host=TEST_HOST, port=TEST_PORT, dbname=TEST_DB, user=TEST_USER, password=TEST_PASSWORD) - + args = dict( + host=self.args.host, + port=self.args.port, + dbname=self.args.database, + user=self.args.user, + password=self.args.password, + ) + + dsn = "host={host} port={port} dbname={dbname} user={user} password={password}".format( + **args + ) + self.ag = age.connect(dsn, graph=self.args.graphName, **args) def tearDown(self): # Clear test data @@ -42,43 +61,52 @@ def tearDown(self): self.ag.close() def testExec(self): - print("\n---------------------------------------------------") print("Test 1: Checking single and multi column Returns.....") print("---------------------------------------------------\n") ag = self.ag # Create and Return single column - cursor = ag.execCypher("CREATE (n:Person {name: %s, title: 'Developer'}) RETURN n", params=('Andy',)) + cursor = ag.execCypher( + "CREATE (n:Person {name: %s, title: 'Developer'}) RETURN n", + params=("Andy",), + ) for row in cursor: print("Vertex: %s , Type: %s " % (Vertex, type(row[0]))) - # Create and Return multi columns - cursor = ag.execCypher("CREATE (n:Person {name: %s, title: %s}) RETURN id(n), n.name", cols=['id','name'], params=('Jack','Manager')) + cursor = ag.execCypher( + "CREATE (n:Person {name: %s, title: %s}) RETURN id(n), n.name", + cols=["id", "name"], + params=("Jack", "Manager"), + ) row = cursor.fetchone() print("Id: %s , Name: %s" % (row[0], row[1])) self.assertEqual(int, type(row[0])) ag.commit() print("\nTest 1 Successful....") - - - def testQuery(self): - print("\n--------------------------------------------------") - print("Test 2: Testing CREATE and query relationships....." ) + print("Test 2: Testing CREATE and query relationships.....") print("--------------------------------------------------\n") ag = self.ag - ag.execCypher("CREATE (n:Person {name: %s}) ", params=('Jack',)) - ag.execCypher("CREATE (n:Person {name: %s}) ", params=('Andy',)) - ag.execCypher("CREATE (n:Person {name: %s}) ", params=('Smith',)) - ag.execCypher("MATCH (a:Person), (b:Person) WHERE a.name = 'Andy' AND b.name = 'Jack' CREATE (a)-[r:worksWith {weight: 3}]->(b)") - ag.execCypher("""MATCH (a:Person), (b:Person) + ag.execCypher("CREATE (n:Person {name: %s}) ", params=("Jack",)) + ag.execCypher("CREATE (n:Person {name: %s}) ", params=("Andy",)) + ag.execCypher("CREATE (n:Person {name: %s}) ", params=("Smith",)) + ag.execCypher( + "MATCH (a:Person), (b:Person) WHERE a.name = 'Andy' AND b.name = 'Jack' CREATE (a)-[r:worksWith {weight: 3}]->(b)" + ) + ag.execCypher( + """MATCH (a:Person), (b:Person) WHERE a.name = %s AND b.name = %s - CREATE p=((a)-[r:worksWith]->(b)) """, params=('Jack', 'Smith',)) + CREATE p=((a)-[r:worksWith]->(b)) """, + params=( + "Jack", + "Smith", + ), + ) ag.commit() @@ -89,20 +117,25 @@ def testQuery(self): print("EDGE:", path[1]) print("END:", path[2]) - cursor = ag.execCypher("MATCH p=(a)-[b]-(c) WHERE b.weight>2 RETURN a,label(b), b.weight, c", cols=["a","bl","bw", "c"], params=(2,)) + cursor = ag.execCypher( + "MATCH p=(a)-[b]-(c) WHERE b.weight>%s RETURN a,label(b), b.weight, c", + cols=["a", "bl", "bw", "c"], + params=(2,), + ) for row in cursor: start = row[0] edgel = row[1] edgew = row[2] end = row[3] - print("Relationship: %s %s %s. Edge weight: %s" % (start["name"] , edgel,end["name"], edgew)) - #Assert that the weight of the edge is greater than 2 + print( + "Relationship: %s %s %s. Edge weight: %s" + % (start["name"], edgel, end["name"], edgew) + ) + # Assert that the weight of the edge is greater than 2 self.assertEqual(edgew > 2, True) print("\nTest 2 Successful...") - def testChangeData(self): - print("\n-------------------------------------------------------") print("Test 3: Testing changes in data using SET and REMOVE.....") print("-------------------------------------------------------\n") @@ -112,14 +145,23 @@ def testChangeData(self): # Commit automatically ag.execCypher("CREATE (n:Person {name: 'Joe'})") - cursor = ag.execCypher("CREATE (n:Person {name: %s, title: 'Developer'}) RETURN n", params=('Smith',)) + cursor = ag.execCypher( + "CREATE (n:Person {name: %s, title: 'Developer'}) RETURN n", + params=("Smith",), + ) row = cursor.fetchone() print("CREATED: ", row[0]) # You must commit explicitly ag.commit() - cursor = ag.execCypher("MATCH (n:Person {name: %s}) SET n.title=%s RETURN n", params=('Smith','Manager',)) + cursor = ag.execCypher( + "MATCH (n:Person {name: %s}) SET n.title=%s RETURN n", + params=( + "Smith", + "Manager", + ), + ) row = cursor.fetchone() vertex = row[0] title1 = vertex["title"] @@ -133,38 +175,39 @@ def testChangeData(self): self.assertEqual(title1, title2) - cursor = ag.execCypher("MATCH (n:Person {name: %s}) SET n.bigNum=-6.45161e+46::numeric RETURN n", params=('Smith',)) + cursor = ag.execCypher( + "MATCH (n:Person {name: %s}) SET n.bigNum=-6.45161e+46::numeric RETURN n", + params=("Smith",), + ) row = cursor.fetchone() vertex = row[0] for row in cursor: - print("SET bigNum: ", vertex['bigNum']) + print("SET bigNum: ", vertex["bigNum"]) bigNum1 = vertex["bigNum"] self.assertEqual(decimal.Decimal("-6.45161e+46"), bigNum1) ag.commit() - cursor = ag.execCypher("MATCH (p:Person {name: 'Smith'}) RETURN p.bigNum") row = cursor.fetchone() bigNum2 = row[0] self.assertEqual(bigNum1, bigNum2) - - cursor = ag.execCypher("MATCH (n:Person {name: %s}) REMOVE n.title RETURN n", params=('Smith',)) + cursor = ag.execCypher( + "MATCH (n:Person {name: %s}) REMOVE n.title RETURN n", params=("Smith",) + ) for row in cursor: print("REMOVE Prop title: ", row[0]) - #Assert that the title property is removed - self.assertIsNone(row[0].properties.get('title')) + # Assert that the title property is removed + self.assertIsNone(row[0].properties.get("title")) print("\nTest 3 Successful....") # You must commit explicitly ag.commit() - def testCypher(self): - print("\n--------------------------") print("Test 4: Testing Cypher.....") print("--------------------------\n") @@ -172,12 +215,12 @@ def testCypher(self): ag = self.ag with ag.connection.cursor() as cursor: - try : - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Joe',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Jack',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Andy',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Smith',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Tom',)) + try: + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Joe",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Jack",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Andy",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Smith",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Tom",)) # You must commit explicitly ag.commit() @@ -186,10 +229,19 @@ def testCypher(self): ag.rollback() with ag.connection.cursor() as cursor: - try :# Create Edges - ag.cypher(cursor,"MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Smith' CREATE (a)-[r:worksWith {weight: 3}]->(b)") - ag.cypher(cursor,"MATCH (a:Person), (b:Person) WHERE a.name = 'Andy' AND b.name = 'Tom' CREATE (a)-[r:worksWith {weight: 1}]->(b)") - ag.cypher(cursor,"MATCH (a:Person {name: 'Jack'}), (b:Person {name: 'Andy'}) CREATE (a)-[r:worksWith {weight: 5}]->(b)") + try: # Create Edges + ag.cypher( + cursor, + "MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Smith' CREATE (a)-[r:worksWith {weight: 3}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Person), (b:Person) WHERE a.name = 'Andy' AND b.name = 'Tom' CREATE (a)-[r:worksWith {weight: 1}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Person {name: 'Jack'}), (b:Person {name: 'Andy'}) CREATE (a)-[r:worksWith {weight: 5}]->(b)", + ) # You must commit explicitly ag.commit() @@ -197,12 +249,16 @@ def testCypher(self): print(ex) ag.rollback() - # With Params - cursor = ag.execCypher("""MATCH (a:Person), (b:Person) + cursor = ag.execCypher( + """MATCH (a:Person), (b:Person) WHERE a.name = %s AND b.name = %s CREATE p=((a)-[r:worksWith]->(b)) RETURN p""", - params=('Andy', 'Smith',)) + params=( + "Andy", + "Smith", + ), + ) for row in cursor: print("CREATED EDGE: %s" % row[0]) @@ -213,25 +269,22 @@ def testCypher(self): for row in cursor: print("CREATED EDGE WITH PROPERTIES: %s" % row[0]) - self.assertEqual(row[0][1].properties['weight'], 5) + self.assertEqual(row[0][1].properties["weight"], 5) print("\nTest 4 Successful...") - - def testMultipleEdges(self): - print("\n------------------------------------") print("Test 5: Testing Multiple Edges.....") print("------------------------------------\n") ag = self.ag with ag.connection.cursor() as cursor: - try : - ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=('USA',)) - ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=('France',)) - ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=('Korea',)) - ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=('Russia',)) + try: + ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=("USA",)) + ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=("France",)) + ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=("Korea",)) + ag.cypher(cursor, "CREATE (n:Country {name: %s}) ", params=("Russia",)) # You must commit explicitly after all executions. ag.connection.commit() @@ -240,10 +293,19 @@ def testMultipleEdges(self): raise ex with ag.connection.cursor() as cursor: - try :# Create Edges - ag.cypher(cursor,"MATCH (a:Country), (b:Country) WHERE a.name = 'USA' AND b.name = 'France' CREATE (a)-[r:distance {unit:'miles', value: 4760}]->(b)") - ag.cypher(cursor,"MATCH (a:Country), (b:Country) WHERE a.name = 'France' AND b.name = 'Korea' CREATE (a)-[r:distance {unit: 'km', value: 9228}]->(b)") - ag.cypher(cursor,"MATCH (a:Country {name: 'Korea'}), (b:Country {name: 'Russia'}) CREATE (a)-[r:distance {unit:'km', value: 3078}]->(b)") + try: # Create Edges + ag.cypher( + cursor, + "MATCH (a:Country), (b:Country) WHERE a.name = 'USA' AND b.name = 'France' CREATE (a)-[r:distance {unit:'miles', value: 4760}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Country), (b:Country) WHERE a.name = 'France' AND b.name = 'Korea' CREATE (a)-[r:distance {unit: 'km', value: 9228}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Country {name: 'Korea'}), (b:Country {name: 'Russia'}) CREATE (a)-[r:distance {unit:'km', value: 3078}]->(b)", + ) # You must commit explicitly ag.connection.commit() @@ -251,7 +313,6 @@ def testMultipleEdges(self): ag.rollback() raise ex - cursor = ag.execCypher("""MATCH p=(:Country {name:"USA"})-[:distance]-(:Country)-[:distance]-(:Country) RETURN p""") @@ -263,7 +324,9 @@ def testMultipleEdges(self): if e.gtype == age.TP_VERTEX: output.append(e.label + " " + e["name"]) elif e.gtype == age.TP_EDGE: - output.append("---- (distance " + str(e["value"]) + " " + e["unit"] + ") --->") + output.append( + "---- (distance " + str(e["value"]) + " " + e["unit"] + ") --->" + ) else: output.append("Unknown element. " + str(e)) @@ -271,14 +334,11 @@ def testMultipleEdges(self): formatted_output = " ".join(output) print("PATH WITH MULTIPLE EDGES: %s" % formatted_output) - self.assertEqual(5,count) + self.assertEqual(5, count) print("\nTest 5 Successful...") - - def testCollect(self): - print("\n--------------------------") print("Test 6: Testing COLLECT.....") print("--------------------------\n") @@ -286,12 +346,12 @@ def testCollect(self): ag = self.ag with ag.connection.cursor() as cursor: - try : - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Joe',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Jack',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Andy',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Smith',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Tom',)) + try: + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Joe",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Jack",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Andy",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Smith",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Tom",)) # You must commit explicitly ag.commit() @@ -300,10 +360,19 @@ def testCollect(self): ag.rollback() with ag.connection.cursor() as cursor: - try :# Create Edges - ag.cypher(cursor,"MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Smith' CREATE (a)-[r:worksWith {weight: 3}]->(b)") - ag.cypher(cursor,"MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Tom' CREATE (a)-[r:worksWith {weight: 1}]->(b)") - ag.cypher(cursor,"MATCH (a:Person {name: 'Joe'}), (b:Person {name: 'Andy'}) CREATE (a)-[r:worksWith {weight: 5}]->(b)") + try: # Create Edges + ag.cypher( + cursor, + "MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Smith' CREATE (a)-[r:worksWith {weight: 3}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Person), (b:Person) WHERE a.name = 'Joe' AND b.name = 'Tom' CREATE (a)-[r:worksWith {weight: 1}]->(b)", + ) + ag.cypher( + cursor, + "MATCH (a:Person {name: 'Joe'}), (b:Person {name: 'Andy'}) CREATE (a)-[r:worksWith {weight: 5}]->(b)", + ) # You must commit explicitly ag.commit() @@ -313,24 +382,29 @@ def testCollect(self): print(" -------- TESTING COLLECT #1 --------") with ag.connection.cursor() as cursor: - ag.cypher(cursor, "MATCH (a)-[:worksWith]->(c) WITH a as V, COLLECT(c) as CV RETURN V.name, CV", cols=["V","CV"]) + ag.cypher( + cursor, + "MATCH (a)-[:worksWith]->(c) WITH a as V, COLLECT(c) as CV RETURN V.name, CV", + cols=["V", "CV"], + ) for row in cursor: nm = row[0] collected = row[1] print(nm, "worksWith", [i["name"] for i in collected]) - self.assertEqual(3,len(collected)) - + self.assertEqual(3, len(collected)) print(" -------- TESTING COLLECT #2 --------") - for row in ag.execCypher("MATCH (a)-[:worksWith]->(c) WITH a as V, COLLECT(c) as CV RETURN V.name, CV", cols=["V1","CV"]): + for row in ag.execCypher( + "MATCH (a)-[:worksWith]->(c) WITH a as V, COLLECT(c) as CV RETURN V.name, CV", + cols=["V1", "CV"], + ): nm = row[0] collected = row[1] print(nm, "worksWith", [i["name"] for i in collected]) - self.assertEqual(3,len(collected)) + self.assertEqual(3, len(collected)) print("\nTest 6 Successful...") def testSerialization(self): - print("\n---------------------------------------") print("Test 6: Testing Vertex Serialization.....") print("-----------------------------------------\n") @@ -339,11 +413,11 @@ def testSerialization(self): with ag.connection.cursor() as cursor: try: - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Joe',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Jack',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Andy',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Smith',)) - ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=('Tom',)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Joe",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Jack",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Andy",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Smith",)) + ag.cypher(cursor, "CREATE (n:Person {name: %s}) ", params=("Tom",)) # You must commit explicitly ag.commit() @@ -375,42 +449,48 @@ def testSerialization(self): print("Vertex.toString() 'properties' field is formatted properly.") -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-host', - '--host', - help='Optional Host Name. Default Host is "127.0.0.1" ', - default="127.0.0.1") - parser.add_argument('-port', - '--port', - help='Optional Port Number. Default port no is 5432', - default=5432) - parser.add_argument('-db', - '--database', - help='Required Database Name', - required=True) - parser.add_argument('-u', - '--user', - help='Required Username Name', - required=True) - parser.add_argument('-pass', - '--password', - help='Required Password for authentication', - required=True) - parser.add_argument('-gn', - '--graphName', - help='Optional Graph Name to be created. Default graphName is "test_graph"', - default="test_graph") + parser.add_argument( + "-host", + "--host", + help='Optional Host Name. Default Host is "127.0.0.1" ', + default=TEST_HOST, + ) + parser.add_argument( + "-port", + "--port", + help="Optional Port Number. Default port no is 5432", + default=TEST_PORT, + ) + parser.add_argument( + "-db", "--database", help="Required Database Name", default=TEST_DB + ) + parser.add_argument( + "-u", "--user", help="Required Username Name", default=TEST_USER + ) + parser.add_argument( + "-pass", + "--password", + help="Required Password for authentication", + default=TEST_PASSWORD, + ) + parser.add_argument( + "-gn", + "--graphName", + help='Optional Graph Name to be created. Default graphName is "test_graph"', + default=TEST_GRAPH_NAME, + ) args = parser.parse_args() suite = unittest.TestSuite() - suite.addTest(TestAgeBasic('testExec')) - suite.addTest(TestAgeBasic('testQuery')) - suite.addTest(TestAgeBasic('testChangeData')) - suite.addTest(TestAgeBasic('testCypher')) - suite.addTest(TestAgeBasic('testMultipleEdges')) - suite.addTest(TestAgeBasic('testCollect')) - suite.addTest(TestAgeBasic('testSerialization')) + suite.addTest(TestAgeBasic("testExec")) + suite.addTest(TestAgeBasic("testQuery")) + suite.addTest(TestAgeBasic("testChangeData")) + suite.addTest(TestAgeBasic("testCypher")) + suite.addTest(TestAgeBasic("testMultipleEdges")) + suite.addTest(TestAgeBasic("testCollect")) + suite.addTest(TestAgeBasic("testSerialization")) TestAgeBasic.args = args unittest.TextTestRunner().run(suite) diff --git a/drivers/python/test_networkx.py b/drivers/python/test_networkx.py index 290d4c470..310d2cf5e 100644 --- a/drivers/python/test_networkx.py +++ b/drivers/python/test_networkx.py @@ -26,22 +26,38 @@ ORIGINAL_GRAPH = "original_graph" EXPECTED_GRAPH = "expected_graph" +TEST_HOST = "localhost" +TEST_PORT = 5432 +TEST_DB = "postgres" +TEST_USER = "postgres" +TEST_PASSWORD = "agens" + class TestAgeToNetworkx(unittest.TestCase): ag = None + args: argparse.Namespace = argparse.Namespace( + host=TEST_HOST, + port=TEST_PORT, + database=TEST_DB, + user=TEST_USER, + password=TEST_PASSWORD, + graphName=TEST_GRAPH_NAME + ) def setUp(self): + args = dict( + host=self.args.host, + port=self.args.port, + dbname=self.args.database, + user=self.args.user, + password=self.args.password + ) - TEST_DB = self.args.database - TEST_USER = self.args.user - TEST_PASSWORD = self.args.password - TEST_PORT = self.args.port - TEST_HOST = self.args.host - self.ag = age.connect(graph=TEST_GRAPH_NAME, host=TEST_HOST, port=TEST_PORT, - dbname=TEST_DB, user=TEST_USER, password=TEST_PASSWORD) + dsn = "host={host} port={port} dbname={dbname} user={user} password={password}".format(**args) + self.ag = age.connect(dsn, graph=TEST_GRAPH_NAME, **args) def tearDown(self): - age.deleteGraph(self.ag.connection, self.ag.graphName) + age.deleteGraph(self.ag.connection, TEST_GRAPH_NAME) self.ag.close() def compare_networkX(self, G, H): @@ -215,19 +231,28 @@ class TestNetworkxToAGE(unittest.TestCase): ag = None ag1 = None ag2 = None + args: argparse.Namespace = argparse.Namespace( + host=TEST_HOST, + port=TEST_PORT, + database=TEST_DB, + user=TEST_USER, + password=TEST_PASSWORD, + graphName=TEST_GRAPH_NAME + ) def setUp(self): - TEST_DB = self.args.database - TEST_USER = self.args.user - TEST_PASSWORD = self.args.password - TEST_PORT = self.args.port - TEST_HOST = self.args.host - self.ag = age.connect(graph=TEST_GRAPH_NAME, host=TEST_HOST, port=TEST_PORT, - dbname=TEST_DB, user=TEST_USER, password=TEST_PASSWORD) - self.ag1 = age.connect(graph=ORIGINAL_GRAPH, host=TEST_HOST, port=TEST_PORT, - dbname=TEST_DB, user=TEST_USER, password=TEST_PASSWORD) - self.ag2 = age.connect(graph=EXPECTED_GRAPH, host=TEST_HOST, port=TEST_PORT, - dbname=TEST_DB, user=TEST_USER, password=TEST_PASSWORD) + args = dict( + host=self.args.host, + port=self.args.port, + dbname=self.args.database, + user=self.args.user, + password=self.args.password + ) + + dsn = "host={host} port={port} dbname={dbname} user={user} password={password}".format(**args) + self.ag = age.connect(dsn, graph=TEST_GRAPH_NAME, **args) + self.ag1 = age.connect(dsn, graph=ORIGINAL_GRAPH, **args) + self.ag2 = age.connect(dsn, graph=EXPECTED_GRAPH, **args) self.graph = nx.DiGraph() def tearDown(self): @@ -441,23 +466,23 @@ def test_invalid_edge_properties(self): parser.add_argument('-host', '--host', help='Optional Host Name. Default Host is "127.0.0.1" ', - default="127.0.0.1") + default=TEST_HOST) parser.add_argument('-port', '--port', help='Optional Port Number. Default port no is 5432', - default=5432) + default=TEST_PORT) parser.add_argument('-db', '--database', help='Required Database Name', - required=True) + default=TEST_DB) parser.add_argument('-u', '--user', help='Required Username Name', - required=True) + default=TEST_USER) parser.add_argument('-pass', '--password', help='Required Password for authentication', - required=True) + default=TEST_PASSWORD) args = parser.parse_args() suite = unittest.TestSuite()