diff --git a/CHANGES.rst b/CHANGES.rst index 52a1924..a4e0122 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,18 @@ Changelog Here you can see the full list of changes between each SQLAlchemy-Utils release. +0.31.2 (2015-10-30) +^^^^^^^^^^^^^^^^^^^ + +- Fixed observes crashing when observable root_obj is ``None`` (#168) + + +0.31.1 (2015-10-26) +^^^^^^^^^^^^^^^^^^^ + +- Column observers only notified when actual changes have been made to underlying columns (#138) + + 0.31.0 (2015-09-17) ^^^^^^^^^^^^^^^^^^^ diff --git a/sqlalchemy_utils/__init__.py b/sqlalchemy_utils/__init__.py index 9e2c582..cab47cc 100644 --- a/sqlalchemy_utils/__init__.py +++ b/sqlalchemy_utils/__init__.py @@ -93,4 +93,4 @@ from .types import ( # noqa WeekDaysType ) -__version__ = '0.31.1' +__version__ = '0.31.2' diff --git a/sqlalchemy_utils/observer.py b/sqlalchemy_utils/observer.py index bd7c1de..0e0db69 100644 --- a/sqlalchemy_utils/observer.py +++ b/sqlalchemy_utils/observer.py @@ -245,9 +245,10 @@ class PropertyObserver(object): root_objs = [root_objs] for root_obj in root_objs: - args = self.get_callback_args(root_obj, callback) - if args: - yield args + if root_obj: + args = self.get_callback_args(root_obj, callback) + if args: + yield args def get_callback_args(self, root_obj, callback): session = sa.orm.object_session(root_obj) diff --git a/tests/observes/test_o2o_o2o.py b/tests/observes/test_o2o_o2o.py new file mode 100644 index 0000000..a923295 --- /dev/null +++ b/tests/observes/test_o2o_o2o.py @@ -0,0 +1,53 @@ +import sqlalchemy as sa + +from sqlalchemy_utils.observer import observes +from tests import TestCase + + +class TestObservesForOneToManyToOneToMany(TestCase): + dns = 'postgres://postgres@localhost/sqlalchemy_utils_test' + + def create_models(self): + class Device(self.Base): + __tablename__ = 'device' + id = sa.Column(sa.Integer, primary_key=True) + name = sa.Column(sa.String) + + class Order(self.Base): + __tablename__ = 'order' + id = sa.Column(sa.Integer, primary_key=True) + + device_id = sa.Column( + 'device', sa.ForeignKey('device.id'), nullable=False + ) + device = sa.orm.relationship('Device', backref='orders') + + class SalesInvoice(self.Base): + __tablename__ = 'sales_invoice' + id = sa.Column(sa.Integer, primary_key=True) + order_id = sa.Column( + 'order', + sa.ForeignKey('order.id'), + nullable=False + ) + order = sa.orm.relationship( + 'Order', + backref=sa.orm.backref( + 'invoice', + uselist=False + ) + ) + device_name = sa.Column(sa.String) + + @observes('order.device') + def process_device(self, device): + self.device_name = device.name + + self.Device = Device + self.Order = Order + self.SalesInvoice = SalesInvoice + + def test_observable_root_obj_is_none(self): + order = self.Order(device=self.Device(name='Something')) + self.session.add(order) + self.session.flush()