<commit_before>import functools
from threading import Lock

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker


def threadsafe(fn):
    """Makes the execution of `fn` thread-safe."""
    lock = Lock()
    @functools.wraps(fn)
    def wrapper(self, *args, **kwargs):
        lock.acquire()
        try:
            return fn(self, *args, **kwargs)
        finally:
            lock.release()
    return wrapper


def memoize(fn):
    """Remembers the return value of `fn` for the given `args` and `kwargs`. If
    `fn` is called again with the same combination of `args` and `kwargs` no
    computation takes place.

    """
    memo = {}
    @functools.wraps(fn)
    def wrapper(self, *args, **kwargs):
        key = fn.__name__ + str(args) + str(kwargs)
        if key not in memo:
            memo[key] = fn(self, *args, **kwargs)
        return memo[key]
    return wrapper


class SQLAlchemy(object):

    DEFAULTS = (
        ('SQLALCHEMY_DATABASE_URI', 'sqlite://'),
        ('SQLALCHEMY_ECHO', False),
        ('SQLALCHEMY_POOL_SIZE', None),
        ('SQLALCHEMY_POOL_TIMEOUT', None),
        ('SQLALCHEMY_POOL_RECYCLE', None),
        ('SQLALCHEMY_MAX_OVERFLOW', None),
        ('SQLALCHEMY_COMMIT_ON_TEARDOWN', False)
    )

    @property
    @memoize
    @threadsafe
    def engine(self):
        return self.create_engine()

    @property
    @memoize
    def session(self):
        engine = self.engine
        factory = sessionmaker(autocommit=False, autoflush=True, bind=engine)
        # Returning a `scoped_session` takes care of threading issues as each
        # thread will get a local session.
        return scoped_session(factory)

    def init_app(self, app):
        self.configure_defaults(app)

        # Assumming Flask 0.9 and later
        @app.teardown_appcontext
        def remove_session(resp_or_exc):
            should_commit = app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']
            if should_commit and resp_or_exc is None:
                self.session.commit()
            self.session.remove()
            return resp_or_exc

        self.app = app

    def configure_defaults(self, app):
        for key, value in self.DEFAULTS:
            app.config.setdefault(key, value)

    def create_engine(self):
        if not hasattr(self, 'app'):
            raise Exception('not initialized')
        dburi = self.app.config['SQLALCHEMY_DATABASE_URI']
        echo = self.app.config['SQLALCHEMY_ECHO']
        options = {
            'convert_unicode': True,
            'echo': echo
        }
        return create_engine(dburi, **options)


db = SQLAlchemy()<commit_msg>Better exception naming<commit_after>import functools
from threading import Lock

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker


def threadsafe(fn):
    """Makes the execution of `fn` thread-safe."""
    lock = Lock()
    @functools.wraps(fn)
    def wrapper(self, *args, **kwargs):
        lock.acquire()
        try:
            return fn(self, *args, **kwargs)
        finally:
            lock.release()
    return wrapper


def memoize(fn):
    """Remembers the return value of `fn` for the given `args` and `kwargs`. If
    `fn` is called again with the same combination of `args` and `kwargs` no
    computation takes place.

    """
    memo = {}
    @functools.wraps(fn)
    def wrapper(self, *args, **kwargs):
        key = fn.__name__ + str(args) + str(kwargs)
        if key not in memo:
            memo[key] = fn(self, *args, **kwargs)
        return memo[key]
    return wrapper


class NotInitialized(Exception):
    pass


class SQLAlchemy(object):

    DEFAULTS = (
        ('SQLALCHEMY_DATABASE_URI', 'sqlite://'),
        ('SQLALCHEMY_ECHO', False),
        ('SQLALCHEMY_POOL_SIZE', None),
        ('SQLALCHEMY_POOL_TIMEOUT', None),
        ('SQLALCHEMY_POOL_RECYCLE', None),
        ('SQLALCHEMY_MAX_OVERFLOW', None),
        ('SQLALCHEMY_COMMIT_ON_TEARDOWN', False)
    )

    @property
    def initialized(self):
        return hasattr(self, 'app')

    @property
    @memoize
    @threadsafe
    def engine(self):
        return self.create_engine()

    @property
    @memoize
    def session(self):
        engine = self.engine
        factory = sessionmaker(autocommit=False, autoflush=True, bind=engine)
        # Returning a `scoped_session` takes care of threading issues as each
        # thread will get a local session.
        return scoped_session(factory)

    def init_app(self, app):
        self.configure_defaults(app)

        # Assumming Flask 0.9 and later
        @app.teardown_appcontext
        def remove_session(resp_or_exc):
            should_commit = app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']
            if should_commit and resp_or_exc is None:
                self.session.commit()
            self.session.remove()
            return resp_or_exc

        self.app = app

    def configure_defaults(self, app):
        for key, value in self.DEFAULTS:
            app.config.setdefault(key, value)

    def create_engine(self):
        if not self.initialized:
            raise NotInitialized(
                'The `SQLAlchemy` wrapper is not initialized. Make sure you '
                'call init_app() before any operations take place.'
            )

        dburi = self.app.config['SQLALCHEMY_DATABASE_URI']
        echo = self.app.config['SQLALCHEMY_ECHO']
        options = {
            'convert_unicode': True,
            'echo': echo
        }

        return create_engine(dburi, **options)


db = SQLAlchemy()
{'fraction_non_alphanumeric': 0.10252733464778634, 'fraction_numerical': 0.000716974368166338, 'mean_word_length': 2.3900364520048605, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1310735', 'n_tokens_mistral': 1758, 'n_tokens_neox': 1699, 'n_words': 434}