Add class argument support for identity

This commit is contained in:
Konsta Vesterinen
2014-02-21 12:32:06 +02:00
parent ff4e11a16c
commit 218c6682af
5 changed files with 30 additions and 20 deletions

View File

@@ -4,6 +4,14 @@ 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.24.1 (2014-02-21)
^^^^^^^^^^^^^^^^^^^
- Made identity return a tuple in all cases
- Added support for declarative model classes as identity function's first argument
0.24.0 (2014-02-18) 0.24.0 (2014-02-18)
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^

View File

@@ -42,7 +42,7 @@ for name, requirements in extras_require.items():
setup( setup(
name='SQLAlchemy-Utils', name='SQLAlchemy-Utils',
version='0.24.0', version='0.24.1',
url='https://github.com/kvesteri/sqlalchemy-utils', url='https://github.com/kvesteri/sqlalchemy-utils',
license='BSD', license='BSD',
author='Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen', author='Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen',

View File

@@ -56,7 +56,7 @@ from .types import (
) )
__version__ = '0.24.0' __version__ = '0.24.1'
__all__ = ( __all__ = (

View File

@@ -1,4 +1,5 @@
from functools import partial from functools import partial
from operator import attrgetter
from toolz import curry, first from toolz import curry, first
import six import six
import sqlalchemy as sa import sqlalchemy as sa
@@ -220,9 +221,6 @@ def declarative_base(model):
return model return model
from operator import attrgetter
def getdotattr(obj_or_class, dot_path): def getdotattr(obj_or_class, dot_path):
""" """
Allow dot-notated strings to be passed to `getattr`. Allow dot-notated strings to be passed to `getattr`.
@@ -293,12 +291,13 @@ def has_changes(obj, attr):
) )
def identity(obj): def identity(obj_or_class):
""" """
Return the identity of given sqlalchemy declarative model instance as a Return the identity of given sqlalchemy declarative model class or instance
tuple. This differs from obj._sa_instance_state.identity in a way that it as a tuple. This differs from obj._sa_instance_state.identity in a way that
always returns the identity even if object is still in transient state ( it always returns the identity even if object is still in transient state (
new object that is not yet persisted into database). new object that is not yet persisted into database). Also for classes it
returns the identity attributes.
:: ::
@@ -322,19 +321,19 @@ def identity(obj):
inspect(user).identity # (1, ) inspect(user).identity # (1, )
You can also use identity for classes::
identity(User) # (User.id, )
.. versionadded: 0.21.0 .. versionadded: 0.21.0
:param obj: SQLAlchemy declarative model object :param obj: SQLAlchemy declarative model object
""" """
id_ = [] return tuple(
for column in sa.inspect(obj.__class__).columns: getattr(obj_or_class, column.name)
if column.primary_key: for column in primary_keys(obj_or_class)
id_.append(getattr(obj, column.name)) )
if all(value is None for value in id_):
return None
else:
return tuple(id_)
def naturally_equivalent(obj, obj2): def naturally_equivalent(obj, obj2):

View File

@@ -13,7 +13,7 @@ class TestIdentity(TestCase):
self.Building = Building self.Building = Building
def test_for_transient_class_without_id(self): def test_for_transient_class_without_id(self):
assert identity(self.Building()) is None assert identity(self.Building()) == (None, )
def test_for_transient_class_with_id(self): def test_for_transient_class_with_id(self):
building = self.Building(name=u'Some building') building = self.Building(name=u'Some building')
@@ -21,3 +21,6 @@ class TestIdentity(TestCase):
self.session.flush() self.session.flush()
assert identity(building) == (building.id, ) assert identity(building) == (building.id, )
def test_identity_for_class(self):
assert identity(self.Building) == (self.Building.id, )