python driver psycopg3 (#1793)

* update for psycopg3

* set a default argparse namespace  in case tests are run in such a way that argparse is bypassed.
diff --git a/.gitignore b/.gitignore
index e03dd04..a8e809d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,7 @@
 *.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 5d0e31e..6382690 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 @@
     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 40ad0c2..2d98e3f 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 @@
             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 @@
     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 @@
         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 @@
     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 @@
         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 @@
     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 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 0f4d711..a3815b8 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

@@ -42,7 +42,7 @@
     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 8c46e8e..3aa94f4 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 3a16aa3..4e27a54 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 @@
     """
     @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 a4df088..3086586 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 @@
             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 @@
         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 @@
     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 @@
         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 @@
     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 @@
     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 @@
 
         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 @@
 
         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 @@
         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 90cee97..053193c 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 81d1ef7..b0593b7 100644
--- a/drivers/python/requirements.txt
+++ b/drivers/python/requirements.txt
Binary files differ
diff --git a/drivers/python/samples/apache-age-agtypes.ipynb b/drivers/python/samples/apache-age-agtypes.ipynb
index 141ff3f..7055db9 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": [
+      "<class 'dict'> | {\"name\": \"Smith\", \"num\":123, \"yn\":true, \"bigInt\":123456789123456789123456789123456789::numeric}  -->  {'name': 'Smith', 'num': 123, 'yn': True, 'bigInt': Decimal('123456789123456789123456789123456789')}\n",
+      "<class 'list'> | [\"name\", \"Smith\", \"num\", 123, \"yn\", true, 123456789123456789123456789123456789.8888::numeric]  -->  ['name', 'Smith', 'num', 123, 'yn', True, Decimal('123456789123456789123456789123456789.8888')]\n",
+      "<class 'str'> | \"abcd\"  -->  abcd\n",
+      "<class 'int'> | 1234  -->  1234\n",
+      "<class 'float'> | 1234.56789  -->  1234.56789\n",
+      "<class 'decimal.Decimal'> | 12345678901234567890123456789123456789.789::numeric  -->  12345678901234567890123456789123456789.789\n",
+      "<class 'decimal.Decimal'> | 12345678901234567890123456789123456789::numeric  -->  12345678901234567890123456789123456789\n",
+      "<class 'bool'> | true  -->  True\n",
+      "<class 'float'> | -6.45161290322581e+46  -->  -6.45161290322581e+46\n",
+      "<class 'decimal.Decimal'> | -123456789.99::numeric  -->  -123456789.99\n",
+      "<class 'decimal.Decimal'> | -6.45161290322581e+46::numeric  -->  -6.45161290322581E+46\n",
+      "<class 'int'> | 1234  -->  1234\n",
+      "<class 'float'> | NaN  -->  nan\n",
+      "<class 'float'> | -Infinity  -->  -inf\n",
+      "<class 'float'> | 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": [
+      "<class 'int'> 2251799813685425\n",
+      "<class 'str'> Person\n",
+      "<class 'str'> Smith\n",
+      "<class 'int'> 123\n",
+      "<class 'float'> 384.23424\n",
+      "<class 'decimal.Decimal'> 123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789\n",
+      "<class 'decimal.Decimal'> 123456789123456789123456789123456789.12345\n",
+      "<class 'bool'> True\n",
+      "<class 'NoneType'> 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": [
+      "<class 'int'> 2251799813685425\n",
+      "<class 'str'> Person\n",
+      "<class 'str'> Smith\n",
+      "<class 'int'> 2533274790396576\n",
+      "<class 'str'> workWith\n",
+      "<class 'int'> 3\n",
+      "<class 'decimal.Decimal'> 123456789123456789123456789.12345\n",
+      "<class 'int'> 2251799813685424\n",
+      "<class 'str'> Person\n",
+      "<class 'str'> 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 f174963..59de8e4 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",
+      "<class 'psycopg.ClientCursor'>\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 59c25bc..d6bcf69 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 20fc566..759dee2 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 15be9e7..1da49d9 100644
--- a/drivers/python/setup.py
+++ b/drivers/python/setup.py
@@ -30,7 +30,7 @@
     url              = 'https://github.com/apache/age/tree/master/drivers/python',

     download_url     = 'https://github.com/apache/age/releases' ,

     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 8048844..f904fb9 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 @@
         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 @@
             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 @@
         # 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 @@
 
         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 @@
         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 @@
                 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 @@
                 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 @@
 
         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 @@
                 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 @@
                 ag.rollback()
                 raise ex
 
-
         cursor = ag.execCypher("""MATCH p=(:Country {name:"USA"})-[:distance]-(:Country)-[:distance]-(:Country)
                 RETURN p""")
 
@@ -263,7 +324,9 @@
                 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 @@
 
         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 @@
         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 @@
                 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 @@
 
         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 @@
 
         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 @@
         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 290d4c4..310d2cf 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 @@
     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 @@
     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()