<commit_before>""":mod:`sqlalchemy_imageattach.context` --- Scoped context of image storage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Scoped context makes other modules able to vertically take an image
store object without explicit parameter for it.  It's similar to
Flask_'s design decision and Werkzeug_'s context locals.
Context locals are workaround to use dynamic scoping in
programming languages that doesn't provide it (like Python).

For example, a function can take an image store to use as its parameter::

    def func(store):
        url = store.locate(image)
        # ...

    func(fs_store)

But, what if for various reasions it can't take an image store
as parameter?  You should vertically take it using scoped context::

    def func():
        current_store.locate(image)

    with store_context(fs_store):
        func()

What if you have to pass the another store to other subroutine?::

    def func(store):
        decorated_store = DecoratedStore(store)
        func2(decorated_store)

    def func2(store):
        url = store.locate(image)
        # ...

    func(fs_store)

The above code can be rewritten using scoped context::

    def func():
        decorated_store = DecoratedStore(current_store)
        with store_context(decorated_store):
            func2()

    def func2():
        url = current_store.locate(image)
        # ...

    with store_context(fs_store):
        func()

.. _Flask: http://flask.pocoo.org/
.. _Werkzeug: http://werkzeug.pocoo.org/

"""
import contextlib
try:
    import thread
except ImportError:
    import dummy_thread as thread

try:
    import greenlet
except ImportError:
    greenlet = None
try:
    import stackless
except ImportError:
    stackless = None

from .store import Store

__all__ = ('current_store', 'current_store_stack', 'get_current_context_id',
           'get_current_store', 'store_context')


def get_current_context_id():
    """Identifis which context it is (greenlet, stackless, or thread).

    :returns: the identifier of the current context.

    """
    global get_current_context_id
    if greenlet is not None:
        if stackless is None:
            get_current_context_id = greenlet.getcurrent
            return greenlet.getcurrent()
        return greenlet.getcurrent(), stackless.getcurrent()
    elif stackless is not None:
        get_current_context_id = stackless.getcurrent
        return stackless.getcurrent()
    get_current_context_id = thread.get_ident
    return thread.get_ident()


#: (:class:`dict`) The dictionary of concurrent contexts to their stacks.
context_stacks = {}


@contextlib.contextmanager
def store_context(store):
    """Sets the new (nested) context of the current image storage::

        with store_context(store):<commit_msg>Update __all__ list in context.py<commit_after>""":mod:`sqlalchemy_imageattach.context` --- Scoped context of image storage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Scoped context makes other modules able to vertically take an image
store object without explicit parameter for it.  It's similar to
Flask_'s design decision and Werkzeug_'s context locals.
Context locals are workaround to use dynamic scoping in
programming languages that doesn't provide it (like Python).

For example, a function can take an image store to use as its parameter::

    def func(store):
        url = store.locate(image)
        # ...

    func(fs_store)

But, what if for various reasions it can't take an image store
as parameter?  You should vertically take it using scoped context::

    def func():
        current_store.locate(image)

    with store_context(fs_store):
        func()

What if you have to pass the another store to other subroutine?::

    def func(store):
        decorated_store = DecoratedStore(store)
        func2(decorated_store)

    def func2(store):
        url = store.locate(image)
        # ...

    func(fs_store)

The above code can be rewritten using scoped context::

    def func():
        decorated_store = DecoratedStore(current_store)
        with store_context(decorated_store):
            func2()

    def func2():
        url = current_store.locate(image)
        # ...

    with store_context(fs_store):
        func()

.. _Flask: http://flask.pocoo.org/
.. _Werkzeug: http://werkzeug.pocoo.org/

"""
import contextlib
try:
    import thread
except ImportError:
    import dummy_thread as thread

try:
    import greenlet
except ImportError:
    greenlet = None
try:
    import stackless
except ImportError:
    stackless = None

from .store import Store

__all__ = ('ContextError', 'LocalProxyStore', 'context_stacks',
           'current_store', 'get_current_context_id', 'get_current_store',
           'store_context')


def get_current_context_id():
    """Identifis which context it is (greenlet, stackless, or thread).

    :returns: the identifier of the current context.

    """
    global get_current_context_id
    if greenlet is not None:
        if stackless is None:
            get_current_context_id = greenlet.getcurrent
            return greenlet.getcurrent()
        return greenlet.getcurrent(), stackless.getcurrent()
    elif stackless is not None:
        get_current_context_id = stackless.getcurrent
        return stackless.getcurrent()
    get_current_context_id = thread.get_ident
    return thread.get_ident()


#: (:class:`dict`) The dictionary of concurrent contexts to their stacks.
context_stacks = {}


@contextlib.contextmanager
def store_context(store):
    """Sets the new (nested) context of the current image storage::

        with store_context(store):
{'fraction_non_alphanumeric': 0.10718700335511214, 'fraction_numerical': 0.0014126787921596327, 'mean_word_length': 3.294162244124337, 'pattern_counts': {'":': 2, '<': 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': '4420010', 'n_tokens_mistral': 1619, 'n_tokens_neox': 1565, 'n_words': 517}