pudo / dataset

Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions.
https://dataset.readthedocs.org/
MIT License
4.76k stars 297 forks source link

dataset wrapper for With statement #418

Open ohld opened 1 year ago

ohld commented 1 year ago

I really love dataset library but it lacks a nice wrapper for with statement which will automatically close DB connection.

So I have to create my own wrapper and keep it as a submodule in my projects. It would be nice to have something like this built in the dataset future versions.

import dataset

class DB(object):
    """
        small wrapper around dataset which
        supports 'with' statements

        Example:
        with DB() as db:
            res = db.query("SELECT * FROM table LIMIT 10")
    """

    def __init__(self, database_url):
        self.database_url = database_url

    def __enter__(self):
        self.db = dataset.connect(self.database_url)
        return self.db

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.db.executable.close()
rrr2rrr commented 10 months ago

Can be better with schema:

class DB(object):

    def __init__(self, database_url: str = None, schema: str = None):
        if not database_url:
            database_url = os.environ.get("DATABASE_URL", "sqlite://")
        self.database_url = database_url.replace("postgres://", "postgresql://")
        self.connect_args = None
        self.schema = schema
        if schema:
            self.connect_args = {'connect_args': {'options': '-csearch_path={}'.format(schema)}}

    def __enter__(self):
        self.db = dataset.connect(self.database_url, schema=self.schema, engine_kwargs=self.connect_args)
        return self.db

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.db.commit()
        self.db.close()
medecau commented 9 months ago

Unfortunately the database object can already be used to enter a context block, but it is being used to start/end transactions.

https://github.com/pudo/dataset/blob/5c2dc8d3af1e0af0290dcd7ae2cae92589f305a1/dataset/database.py#L155-L169

In hindsight the proposed behaviour makes more sense, with a transaction context still available from Database.transaction.

But changing this would break API.

@pudo would a PR with this behaviour have any chance of being merged?

mijaba commented 7 months ago

It's possible to get the same effect using just the standard library. Specifically, contextlib.closing will work, since dataset.Database has a close method:

import contextlib
import dataset
with contextlib.closing(dataset.connect()) as db:
    print(db.tables)

The close method isn't documented on Read the Docs, admittedly, but I can't imagine it is going to change.