0.4 release

This commit is contained in:
Konsta Vesterinen
2013-03-15 10:02:28 +02:00
parent a1955c3a00
commit 37e1072787
4 changed files with 29 additions and 39 deletions

View File

@@ -5,6 +5,13 @@ Here you can see the full list of changes between each SQLAlchemy-Utils release.
0.4.0 (2013-03-01)
^^^^^^^^^^^^^^^^^^
- Renamed SmartList to InstrumentedList
- Added instrumented_list decorator
0.3.0 (2013-03-01) 0.3.0 (2013-03-01)
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^

View File

@@ -24,7 +24,7 @@ class PyTest(Command):
setup( setup(
name='SQLAlchemy-Utils', name='SQLAlchemy-Utils',
version='0.3', version='0.4',
url='https://github.com/kvesteri/sqlalchemy-utils', url='https://github.com/kvesteri/sqlalchemy-utils',
license='BSD', license='BSD',
author='Konsta Vesterinen', author='Konsta Vesterinen',

View File

@@ -1,39 +1,28 @@
from functools import wraps
from sqlalchemy.orm import defer from sqlalchemy.orm import defer
from sqlalchemy.orm.collections import InstrumentedList from sqlalchemy.orm.collections import InstrumentedList as _InstrumentedList
from sqlalchemy.orm.mapper import Mapper from sqlalchemy.orm.mapper import Mapper
from sqlalchemy.orm.query import _ColumnEntity from sqlalchemy.orm.query import _ColumnEntity
from sqlalchemy.orm.properties import ColumnProperty from sqlalchemy.orm.properties import ColumnProperty
from sqlalchemy.sql.expression import desc, asc from sqlalchemy.sql.expression import desc, asc
class SmartList(InstrumentedList): class InstrumentedList(_InstrumentedList):
def has(self, attr): """Enhanced version of SQLAlchemy InstrumentedList. Provides some
""" additional functionality."""
Returns True if any member of this collection has given attribute
defined.
Example syntax: def any(self, attr):
return any(getattr(item, attr) for item in self)
>>> Category.articles.has('name') def all(self, attr):
return all(getattr(item, attr) for item in self)
:param attr: collection member attribute name
"""
adapter = self._sa_adapter
owner_class = adapter.owner_state.class_
relation = getattr(owner_class, adapter._key).property
relation_class = relation.mapper.class_
if not hasattr(relation_class, attr): def instrumented_list(f):
raise AttributeError( @wraps(f)
'Class %s does not have attribute named %s' % def wrapper(*args, **kwargs):
(relation_class.__name__, attr) return InstrumentedList([item for item in f(*args, **kwargs)])
) return wrapper
for record in self:
if getattr(record, attr):
return True
return False
def sort_query(query, sort): def sort_query(query, sort):

View File

@@ -1,11 +1,10 @@
from pytest import raises
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utils import escape_like, sort_query, SmartList from sqlalchemy_utils import escape_like, sort_query, InstrumentedList
engine = create_engine( engine = create_engine(
@@ -34,27 +33,22 @@ class Article(Base):
primaryjoin=category_id == Category.id, primaryjoin=category_id == Category.id,
backref=sa.orm.backref( backref=sa.orm.backref(
'articles', 'articles',
collection_class=SmartList collection_class=InstrumentedList
) )
) )
class TestSmartList(object): class TestInstrumentedList(object):
def test_has_raises_error_for_unknown_attribute(self): def test_any_returns_true_if_member_has_attr_defined(self):
category = Category()
with raises(AttributeError):
category.articles.has('unknown_column')
def test_has_returns_true_if_member_has_attr_defined(self):
category = Category() category = Category()
category.articles.append(Article()) category.articles.append(Article())
category.articles.append(Article(name=u'some name')) category.articles.append(Article(name=u'some name'))
assert category.articles.has('name') assert category.articles.any('name')
def test_has_returns_false_if_no_member_has_attr_defined(self): def test_any_returns_false_if_no_member_has_attr_defined(self):
category = Category() category = Category()
category.articles.append(Article()) category.articles.append(Article())
assert not category.articles.has('name') assert not category.articles.any('name')
class TestEscapeLike(object): class TestEscapeLike(object):