Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator for Sqlite3

Tags:

python

sql

sqlite

I have a simple sqlite3 function

from sqlite3 import connect


def foo(name):
    conn = connect("data.db")
    curs = conn.cursor()
    curs.execute(f"CREATE TABLE IF NOT EXISTS {name}(test TEXT PRIMARY KEY);")
    conn.commit()
    conn.close()

I want to have a decorator, so that I can write

from sqlite3 import connect

@db_connect
def foo(name):  # Don't know how to pass the args
    curs.execute(f"CREATE TABLE IF NOT EXISTS {name}(test TEXT PRIMARY KEY);")

The goal is, that I don't have to get a connection, close it, etc.

What I've tried:

def db_connect(func):
    def _db_connect(*args, **kwargs):
        conn = connect("data.db")
        curs = conn.cursor()
        result = func(*args, **kwargs)
        conn.commit()
        conn.close()
        return result
    return _db_connect

But now I am a bit stuck, because how to pass the cursor, to the function and would my decorator work?


1 Answers

What you actually need is a context manager, not a decorator.

import sqlite3
from contextlib import contextmanager

@contextmanager
def db_ops(db_name):
    conn = sqlite3.connect(db_name)
    try:
        cur = conn.cursor()
        yield cur
    except Exception as e:
        # do something with exception
        conn.rollback()
        raise e
    else:
        conn.commit()
    finally:
        conn.close()



with db_ops('db_path') as cur:
    cur.execute('create table if not exists temp (id int, name text)')

with db_ops('db_path') as cur:
    rows = [(1, 'a'), (2, 'b'), (3, 'c')]
    cur.executemany('insert into temp values (?, ?)', rows)

with db_ops('db_path') as cur:
    print(list(cur.execute('select * from temp')))

Output

[(1, 'a'), (2, 'b'), (3, 'c')]

As you can see you dont have to commit or create connection anymore.

It is worth noting that the the connection object supports the context manager protocol by default, meaning you can do this

conn = sqlite3.connect(...)
with conn:
    ...

But this only commits, it does not close the connection, you still have to use conn.close().

like image 122
python_user Avatar answered Sep 05 '25 04:09

python_user



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!