From 13b6ddc823bb9f8b80dca2ee85d673a6a77145b8 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 19 Nov 2013 19:42:21 -0500 Subject: [PATCH] break up behavioral changes into ORM and Core --- doc/build/changelog/migration_09.rst | 133 ++++++++++++++------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/doc/build/changelog/migration_09.rst b/doc/build/changelog/migration_09.rst index a63c334304..52af788249 100644 --- a/doc/build/changelog/migration_09.rst +++ b/doc/build/changelog/migration_09.rst @@ -49,8 +49,8 @@ in both Python 2 and Python 3 environments. .. _behavioral_changes_09: -Behavioral Changes -================== +Behavioral Changes - ORM +======================== .. _migration_2824: @@ -287,30 +287,6 @@ The change is illustrated as follows:: :ticket:`2833` -.. _migration_2848: - -``RowProxy`` now has tuple-sorting behavior -------------------------------------------- - -The :class:`.RowProxy` object acts much like a tuple, but up until now -would not sort as a tuple if a list of them were sorted using ``sorted()``. -The ``__eq__()`` method now compares both sides as a tuple and also -an ``__lt__()`` method has been added:: - - users.insert().execute( - dict(user_id=1, user_name='foo'), - dict(user_id=2, user_name='bar'), - dict(user_id=3, user_name='def'), - ) - - rows = users.select().order_by(users.c.user_name).execute().fetchall() - - eq_(rows, [(2, 'bar'), (3, 'def'), (1, 'foo')]) - - eq_(sorted(rows), [(1, 'foo'), (2, 'bar'), (3, 'def')]) - -:ticket:`2848` - .. _migration_2751: Association Proxy SQL Expression Improvements and Fixes @@ -445,6 +421,57 @@ proxied value. E.g.:: :ticket:`2810` + +.. _change_2787: + +attributes.get_history() will query from the DB by default if value not present +------------------------------------------------------------------------------- + +A bugfix regarding :func:`.attributes.get_history` allows a column-based attribute +to query out to the database for an unloaded value, assuming the ``passive`` +flag is left at its default of ``PASSIVE_OFF``. Previously, this flag would +not be honored. Additionally, a new method :meth:`.AttributeState.load_history` +is added to complement the :attr:`.AttributeState.history` attribute, which +will emit loader callables for an unloaded attribute. + +This is a small change demonstrated as follows:: + + from sqlalchemy import Column, Integer, String, create_engine, inspect + from sqlalchemy.orm import Session, attributes + from sqlalchemy.ext.declarative import declarative_base + + Base = declarative_base() + + class A(Base): + __tablename__ = 'a' + id = Column(Integer, primary_key=True) + data = Column(String) + + e = create_engine("sqlite://", echo=True) + Base.metadata.create_all(e) + + sess = Session(e) + + a1 = A(data='a1') + sess.add(a1) + sess.commit() # a1 is now expired + + # history doesn't emit loader callables + assert inspect(a1).attrs.data.history == (None, None, None) + + # in 0.8, this would fail to load the unloaded state. + assert attributes.get_history(a1, 'data') == ((), ['a1',], ()) + + # load_history() is now equiavlent to get_history() with + # passive=PASSIVE_OFF ^ INIT_OK + assert inspect(a1).attrs.data.load_history() == ((), ['a1',], ()) + +:ticket:`2787` + + +Behavioral Changes - Core +========================= + .. _migration_2850: A bindparam() construct with no type gets upgraded via copy when a type is available @@ -610,51 +637,29 @@ now consistent:: :ticket:`2804` -.. _change_2787: - -attributes.get_history() will query from the DB by default if value not present -------------------------------------------------------------------------------- - -A bugfix regarding :func:`.attributes.get_history` allows a column-based attribute -to query out to the database for an unloaded value, assuming the ``passive`` -flag is left at its default of ``PASSIVE_OFF``. Previously, this flag would -not be honored. Additionally, a new method :meth:`.AttributeState.load_history` -is added to complement the :attr:`.AttributeState.history` attribute, which -will emit loader callables for an unloaded attribute. - -This is a small change demonstrated as follows:: - - from sqlalchemy import Column, Integer, String, create_engine, inspect - from sqlalchemy.orm import Session, attributes - from sqlalchemy.ext.declarative import declarative_base - - Base = declarative_base() - - class A(Base): - __tablename__ = 'a' - id = Column(Integer, primary_key=True) - data = Column(String) +.. _migration_2848: - e = create_engine("sqlite://", echo=True) - Base.metadata.create_all(e) +``RowProxy`` now has tuple-sorting behavior +------------------------------------------- - sess = Session(e) +The :class:`.RowProxy` object acts much like a tuple, but up until now +would not sort as a tuple if a list of them were sorted using ``sorted()``. +The ``__eq__()`` method now compares both sides as a tuple and also +an ``__lt__()`` method has been added:: - a1 = A(data='a1') - sess.add(a1) - sess.commit() # a1 is now expired + users.insert().execute( + dict(user_id=1, user_name='foo'), + dict(user_id=2, user_name='bar'), + dict(user_id=3, user_name='def'), + ) - # history doesn't emit loader callables - assert inspect(a1).attrs.data.history == (None, None, None) + rows = users.select().order_by(users.c.user_name).execute().fetchall() - # in 0.8, this would fail to load the unloaded state. - assert attributes.get_history(a1, 'data') == ((), ['a1',], ()) + eq_(rows, [(2, 'bar'), (3, 'def'), (1, 'foo')]) - # load_history() is now equiavlent to get_history() with - # passive=PASSIVE_OFF ^ INIT_OK - assert inspect(a1).attrs.data.load_history() == ((), ['a1',], ()) + eq_(sorted(rows), [(1, 'foo'), (2, 'bar'), (3, 'def')]) -:ticket:`2787` +:ticket:`2848` New Features -- 2.47.3