Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dataset wrapper for With statement #418

Open
ohld opened this issue May 19, 2023 · 3 comments
Open

dataset wrapper for With statement #418

ohld opened this issue May 19, 2023 · 3 comments

Comments

@ohld
Copy link

ohld commented May 19, 2023

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
Copy link

rrr2rrr commented Nov 1, 2023

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
Copy link

medecau commented Nov 22, 2023

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

dataset/dataset/database.py

Lines 155 to 169 in 5c2dc8d

def __enter__(self):
"""Start a transaction."""
self.begin()
return self
def __exit__(self, error_type, error_value, traceback):
"""End a transaction by committing or rolling back."""
if error_type is None:
try:
self.commit()
except Exception:
with safe_reraise():
self.rollback()
else:
self.rollback()

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
Copy link
Contributor

mijaba commented Jan 23, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants