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

thread-localized BaseImageQuery._stored_images/_deleted_images #36

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions sqlalchemy_imageattach/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class User(Base):
import io
import numbers
import shutil
import threading
import uuid

from sqlalchemy import Column
Expand All @@ -96,7 +97,7 @@ class User(Base):
from .context import current_store, get_current_store, store_context
from .file import ReusableFileProxy
from .store import Store
from .util import append_docstring_attributes
from .util import append_docstring_attributes, classproperty

__all__ = ('VECTOR_TYPES', 'BaseImageSet', 'BaseImageQuery', 'Image',
'ImageSet', 'ImageSubset', 'MultipleImageSet', 'SingleImageSet',
Expand Down Expand Up @@ -373,18 +374,32 @@ class BaseImageQuery(Query):

"""

#: (:class:`collections.abc.MutableSet`) The set of instances that their
#: image files are stored but the ongoing transaction isn't committed.
#: When the transaction might fail and rollback, image files in the
#: set are deleted back in the storage.
_stored_images = set()

#: (:class:`collections.abc.MutableSet`) The set of instanced marked
#: as deleted. If the ongoing transaction is successfully committed
#: the actual files in the storages will be deleted as well.
#: When the transaction might fail and rollback, image files won't
#: deleted and the set will be empty.
_deleted_images = set()
_local = threading.local()

@classproperty
def _stored_images(cls):
"""(:class:`collections.abc.MutableSet`) The set of instances that
their image files are stored but the ongoing transaction isn't
committed. When the transaction might fail and rollback, image files
in the set are deleted back in the storage. This set is thread-local.

"""
if not getattr(cls._local, '_stored_images', None):
cls._local._stored_images = set()
return cls._local._stored_images

@classproperty
def _deleted_images(cls):
"""(:class:`collections.abc.MutableSet`) The set of instanced marked
as deleted. If the ongoing transaction is successfully committed
the actual files in the storages will be deleted as well. When the
transaction might fail and rollback, image files won't deleted and
the set will be empty. This set is thread-local.

"""
if not getattr(cls._local, '_deleted_images', None):
cls._local._deleted_images = set()
return cls._local._deleted_images

@classmethod
def _mark_image_file_stored(cls, mapper, connection, target):
Expand Down
10 changes: 9 additions & 1 deletion sqlalchemy_imageattach/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import textwrap

__all__ = ('append_docstring', 'append_docstring_attributes',
'get_minimum_indent')
'classproperty', 'get_minimum_indent')


def get_minimum_indent(docstring, ignore_before=1):
Expand Down Expand Up @@ -102,3 +102,11 @@ class Entity(object):
*lines
)
return docstring


class classproperty(object):
def __init__(self, getter):
self.getter = getter

def __get__(self, instance, owner):
return self.getter(owner)
14 changes: 13 additions & 1 deletion tests/util_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import absolute_import

from sqlalchemy_imageattach.util import append_docstring, get_minimum_indent
from sqlalchemy_imageattach.util import (append_docstring, classproperty,
get_minimum_indent)


def test_minimum_indent():
Expand Down Expand Up @@ -52,3 +53,14 @@ def test_func():

Appended docstring!
'''.rstrip()


def test_classproperty():

class Foo(object):
@classproperty
def bar(cls):
return 'baz'

assert Foo.bar == 'baz'
assert Foo().bar == 'baz'