I have created a decorator to handle database connections like this:
def with_connection(f):
def with_connection_(args, **kwargs):
conn = mysql.connector.Connect("my redacted credentials")
try:
result = f(conn, args, **kwargs)
except:
conn.rollback()
print("SQL failed")
raise
else:
conn.commit()
finally:
conn.close()
return result
return with_connection_
I call it like this:
@with_connection
def GetUsername(conn, args):
Cursor = conn.cursor()
query = "select user_name from users where user_id = %s"
Cursor.execute(query, (args[0],))
result = Cursor.fetchone()
return result
user_name = DBQueries.GetUsername(user_id)
This code works just fine.
However, in VS Code, I get the following error reported, and I feel I should understand why it is happening:
"message": "No value for argument 'args' in function call",
I kind of get it, because GetUsername has 2 arguments, conn & args and I call it with one, so it thinks it is missing the args argument. But it WORKS.
Can anyone clarify for me what is going on here?
Your IDE is basically confused because GetUsername
indeed expects different arguments. In some IDE's this problem can be solved by wrapping the inner function with @functools.wraps(f)
. (https://docs.python.org/3/library/functools.html#functools.wraps). This basically takes proper care of the meta information of the wrapped function so that it resembles the information of the original function.
Another approach you can take (but I would still suggest using functools.wraps
as well for this method) is taking the connection argument from the kwargs like this:
def with_connection(f):
def with_connection_(*args, **kwargs):
conn = mysql.connector.Connect("my redacted credentials")
try:
result = f(*args, connection=conn, **kwargs)
except:
conn.rollback()
print("SQL failed")
raise
else:
conn.commit()
finally:
conn.close()
return result
return with_connection_
@with_connection
def GetUsername(*args, **kwargs):
conn = kwargs.pop("connection")
Cursor = conn.cursor()
query = "select user_name from users where user_id = %s"
Cursor.execute(query, (args[0],))
result = Cursor.fetchone()
return result
There's also not really a need to do args[0], you could just do:
@with_connection
def GetUsername(user_id, *args, **kwargs):
conn = kwargs.pop("connection")
Cursor = conn.cursor()
query = "select user_name from users where user_id = %s"
Cursor.execute(query, (user_id,))
result = Cursor.fetchone()
return result