I am using a decorator to open and close a neo4j database session (and allow my decorated functions to run queries within that session). At first I used a decorator function :
from neo4j.v1 import GraphDatabase, basic_auth
def session(func,url="bolt://localhost:7474", user="neo4j",pwd="neo4j", *args, **kwargs):
def operate(*args, **kwargs):
driver = GraphDatabase.driver(url, auth=basic_auth(user,pwd))
session=driver.session()
kwargs["session"]=session
result=func(*args, **kwargs)
session.close()
return result
return operate
and for example I then call this function:
@session
def RUN(command,session):
result=session.run(command)
return(result)
However, this opens and closes the session for every query which is resource consuming. Thus, I tried to create a decorator class, and store the session:
class session(object):
def __init__(self, func, url="bolt://localhost", user="neo4j", pwd="neo4j"):
try:
driver = GraphDatabase.driver(url, auth=basic_auth(user, pwd))
print("session opened")
except:
print("Exception during authentification")
self.__exit__()
else:
session=driver.session()
self.func=func
self.SESSION=session
def __call__(self, *args, **kwargs):
kwargs["session"]=self.SESSION
result=self.func(*args, **kwargs)
return result
def __del__(self):
print("del")
try:
self.SESSION.close()
print("session closed")
except:
print("could not close session")
This seems to work, as the "session opened" appears only once. But the session does not seem to close ("session close" is never printed).
So my first question is the following, how can I call the self.SESSION.close() at the destruction of the decorator ?
I'm also wondering if I understood well what my code is doing. When I call a decorated function such as RUN
, is only one session object created? And what if I were to have an other decorated function MATCH
@session
def MATCH(*args,**kwargs):
pass
would the session object be the same ?
Here is a template to create a decorator with parameters using a function:
def decorator_maker(param1, param2):
print("The parameters of my decorator are: {0} and {1}".format(param1, param2))
def my_decorator(function_to_decorate):
def wrapper(arg1, arg2):
print("before call")
result = function_to_decorate(arg1, arg2)
print("after call")
return result
return wrapper
return my_decorator
The usage is as follow:
@decorator_maker("hello", "How are you?")
def my_function(arg1, arg2):
print("The parameters of my function are: {0} and {1}".format(arg1, arg2))
return arg1 + "-" + arg2
With a class, it is more straightforward:
class decorator_maker(object):
def __init__(self, param1, param2):
print("The parameters of my decorator are: {0} and {1}".format(param1, param2))
self.param1 = param1
self.param2 = param2
def __call__(self, function_to_decorate):
def wrapper(arg1, arg2):
print("before call")
result = function_to_decorate(arg1, arg2)
print("after call")
return result
return wrapper
To open and close your session before/after the function call, you have to implement it in the wrapped function, like this:
class with_session(object):
def __init__(self, url="bolt://localhost", user="neo4j", pwd="neo4j"):
self.url = url
self.user = user
self.pwd = pwd
def __call__(self, f):
def wrapper(*args, **kwargs):
driver = GraphDatabase.driver(self.url, auth=basic_auth(self.user, self.pwd))
kwargs["session"] = session = driver.session()
try:
return f(*args, **kwargs)
finally:
session.close()
return wrapper
Notes:
__enter__
and __exit__
, this is another use case...