Added automatic expiration of proxy dicts, updated sqlalchemy in requirements
This commit is contained in:
@@ -4,6 +4,13 @@ Changelog
|
|||||||
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
||||||
|
|
||||||
|
|
||||||
|
0.12.2 (2013-05-29)
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Added automatic expiration of proxy dicts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
0.12.1 (2013-05-18)
|
0.12.1 (2013-05-18)
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
4
setup.py
4
setup.py
@@ -24,7 +24,7 @@ class PyTest(Command):
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='SQLAlchemy-Utils',
|
name='SQLAlchemy-Utils',
|
||||||
version='0.12.1',
|
version='0.12.2',
|
||||||
url='https://github.com/kvesteri/sqlalchemy-utils',
|
url='https://github.com/kvesteri/sqlalchemy-utils',
|
||||||
license='BSD',
|
license='BSD',
|
||||||
author='Konsta Vesterinen',
|
author='Konsta Vesterinen',
|
||||||
@@ -38,7 +38,7 @@ setup(
|
|||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
platforms='any',
|
platforms='any',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'SQLAlchemy>=0.7.8',
|
'SQLAlchemy>=0.8.0',
|
||||||
'phonenumbers>=5.4b1',
|
'phonenumbers>=5.4b1',
|
||||||
'colour==0.0.2'
|
'colour==0.0.2'
|
||||||
],
|
],
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
from .functions import sort_query, defer_except, escape_like
|
from .functions import sort_query, defer_except, escape_like, primary_keys
|
||||||
from .listeners import coercion_listener
|
from .listeners import coercion_listener
|
||||||
from .merge import merge, Merger
|
from .merge import merge, Merger
|
||||||
from .proxy_dict import ProxyDict
|
from .proxy_dict import ProxyDict, proxy_dict
|
||||||
from .types import (
|
from .types import (
|
||||||
ColorType,
|
ColorType,
|
||||||
EmailType,
|
EmailType,
|
||||||
@@ -25,6 +25,8 @@ __all__ = (
|
|||||||
escape_like,
|
escape_like,
|
||||||
instrumented_list,
|
instrumented_list,
|
||||||
merge,
|
merge,
|
||||||
|
primary_keys,
|
||||||
|
proxy_dict,
|
||||||
ColorType,
|
ColorType,
|
||||||
EmailType,
|
EmailType,
|
||||||
InstrumentedList,
|
InstrumentedList,
|
||||||
|
@@ -2,11 +2,11 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
class ProxyDict(object):
|
class ProxyDict(object):
|
||||||
def __init__(self, parent, collection_name, child_class, key_name):
|
def __init__(self, parent, collection_name, mapping_attr):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.collection_name = collection_name
|
self.collection_name = collection_name
|
||||||
self.child_class = child_class
|
self.child_class = mapping_attr.class_
|
||||||
self.key_name = key_name
|
self.key_name = mapping_attr.key
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -26,20 +26,22 @@ class ProxyDict(object):
|
|||||||
def fetch(self, key):
|
def fetch(self, key):
|
||||||
return self.collection.filter_by(**{self.key_name: key}).first()
|
return self.collection.filter_by(**{self.key_name: key}).first()
|
||||||
|
|
||||||
|
def create_new_instance(self, key):
|
||||||
|
value = self.child_class(**{self.key_name: key})
|
||||||
|
self.collection.append(value)
|
||||||
|
return value
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if key in self.cache:
|
if key in self.cache:
|
||||||
return self.cache[key]
|
return self.cache[key]
|
||||||
|
|
||||||
session = sa.orm.object_session(self.parent)
|
session = sa.orm.object_session(self.parent)
|
||||||
if not session or not sa.orm.util.has_identity(self.parent):
|
if not session or not sa.orm.util.has_identity(self.parent):
|
||||||
value = self.child_class(**{self.key_name: key})
|
value = self.create_new_instance(key)
|
||||||
self.collection.append(value)
|
|
||||||
else:
|
else:
|
||||||
value = self.fetch(key)
|
value = self.fetch(key)
|
||||||
if not value:
|
if not value:
|
||||||
value = self.child_class(**{self.key_name: key})
|
value = self.create_new_instance(key)
|
||||||
self.collection.append(value)
|
|
||||||
|
|
||||||
self.cache[key] = value
|
self.cache[key] = value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -51,3 +53,24 @@ class ProxyDict(object):
|
|||||||
pass
|
pass
|
||||||
self.collection.append(value)
|
self.collection.append(value)
|
||||||
self.cache[key] = value
|
self.cache[key] = value
|
||||||
|
|
||||||
|
|
||||||
|
def proxy_dict(parent, collection_name, mapping_attr):
|
||||||
|
try:
|
||||||
|
parent._proxy_dicts
|
||||||
|
except AttributeError:
|
||||||
|
def expire_proxy_dicts(target, context):
|
||||||
|
target._proxy_dicts = {}
|
||||||
|
|
||||||
|
sa.event.listen(parent.__class__, 'expire', expire_proxy_dicts)
|
||||||
|
parent._proxy_dicts = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
return parent._proxy_dicts[collection_name]
|
||||||
|
except KeyError:
|
||||||
|
parent._proxy_dicts[collection_name] = ProxyDict(
|
||||||
|
parent,
|
||||||
|
collection_name,
|
||||||
|
mapping_attr
|
||||||
|
)
|
||||||
|
return parent._proxy_dicts[collection_name]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from flexmock import flexmock
|
from flexmock import flexmock
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy_utils import ProxyDict
|
from sqlalchemy_utils import ProxyDict, proxy_dict
|
||||||
from tests import TestCase
|
from tests import TestCase
|
||||||
|
|
||||||
|
|
||||||
@@ -21,16 +21,11 @@ class TestProxyDict(TestCase):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def translations(self):
|
def translations(self):
|
||||||
try:
|
return proxy_dict(
|
||||||
return self.proxied_translations
|
self,
|
||||||
except AttributeError:
|
'_translations',
|
||||||
self.proxied_translations = ProxyDict(
|
ArticleTranslation.locale
|
||||||
self,
|
)
|
||||||
'_translations',
|
|
||||||
ArticleTranslation,
|
|
||||||
'locale'
|
|
||||||
)
|
|
||||||
return self.proxied_translations
|
|
||||||
|
|
||||||
class ArticleTranslation(self.Base):
|
class ArticleTranslation(self.Base):
|
||||||
__tablename__ = 'article_translation'
|
__tablename__ = 'article_translation'
|
||||||
@@ -83,3 +78,16 @@ class TestProxyDict(TestCase):
|
|||||||
name=u'something'
|
name=u'something'
|
||||||
)
|
)
|
||||||
article.translations['en']
|
article.translations['en']
|
||||||
|
|
||||||
|
def test_committing_session_empties_proxy_dict_cache(self):
|
||||||
|
article = self.Article()
|
||||||
|
(
|
||||||
|
flexmock(ProxyDict)
|
||||||
|
.should_receive('fetch')
|
||||||
|
.twice()
|
||||||
|
)
|
||||||
|
self.session.add(article)
|
||||||
|
self.session.commit()
|
||||||
|
article.translations['en']
|
||||||
|
self.session.commit()
|
||||||
|
article.translations['en']
|
||||||
|
Reference in New Issue
Block a user