diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-07-20 20:35:04 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-07-20 20:35:04 -0400 |
commit | 575f080850a0a061ccb7ac40e3ea1fbf6b0fedf4 (patch) | |
tree | 4c3f6020e3d1a6bd4d761d31f996665fde826dce | |
parent | a4b8aa320d63f7c0dc7c70dfce56f0af593d95f0 (diff) | |
download | sqlalchemy-575f080850a0a061ccb7ac40e3ea1fbf6b0fedf4.tar.gz |
- Fixed an issue where a particular base class within utils
didn't implement ``__slots__``, and therefore meant all subclasses
of that class didn't either, negating the rationale for ``__slots__``
to be in use. Didn't cause any issue except on IronPython
which apparently does not implement ``__slots__`` behavior compatibly
with cPython.
Fixes #3494
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 15 | ||||
-rw-r--r-- | lib/sqlalchemy/__init__.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/event/attr.py | 14 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/properties.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/util/langhelpers.py | 2 | ||||
-rw-r--r-- | test/base/test_utils.py | 30 |
7 files changed, 57 insertions, 11 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 4fdb50945..64bce97ae 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -16,6 +16,21 @@ :start-line: 5 .. changelog:: + :version: 1.0.8 + + .. change:: + :tags: bug, misc + :tickets: 3494 + + Fixed an issue where a particular base class within utils + didn't implement ``__slots__``, and therefore meant all subclasses + of that class didn't either, negating the rationale for ``__slots__`` + to be in use. Didn't cause any issue except on IronPython + which apparently does not implement ``__slots__`` behavior compatibly + with cPython. + + +.. changelog:: :version: 1.0.7 :released: July 20, 2015 diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py index 093e90bbf..9b8d06167 100644 --- a/lib/sqlalchemy/__init__.py +++ b/lib/sqlalchemy/__init__.py @@ -120,7 +120,7 @@ from .schema import ( from .inspection import inspect from .engine import create_engine, engine_from_config -__version__ = '1.0.7' +__version__ = '1.0.8' def __go(lcls): diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py index a64c7d08d..8a88e40ef 100644 --- a/lib/sqlalchemy/event/attr.py +++ b/lib/sqlalchemy/event/attr.py @@ -51,7 +51,7 @@ class _ClsLevelDispatch(RefCollection): """Class-level events on :class:`._Dispatch` classes.""" __slots__ = ('name', 'arg_names', 'has_kw', - 'legacy_signatures', '_clslevel') + 'legacy_signatures', '_clslevel', '__weakref__') def __init__(self, parent_dispatch_cls, fn): self.name = fn.__name__ @@ -230,9 +230,7 @@ class _EmptyListener(_InstanceLevelDispatch): class _CompoundListener(_InstanceLevelDispatch): - _exec_once = False - - __slots__ = '_exec_once_mutex', + __slots__ = '_exec_once_mutex', '_exec_once' def _memoized_attr__exec_once_mutex(self): return threading.Lock() @@ -279,11 +277,14 @@ class _ListenerCollection(_CompoundListener): """ - __slots__ = 'parent_listeners', 'parent', 'name', 'listeners', 'propagate' + __slots__ = ( + 'parent_listeners', 'parent', 'name', 'listeners', + 'propagate', '__weakref__') def __init__(self, parent, target_cls): if target_cls not in parent._clslevel: parent.update_subclass(target_cls) + self._exec_once = False self.parent_listeners = parent._clslevel[target_cls] self.parent = parent self.name = parent.name @@ -339,11 +340,10 @@ class _ListenerCollection(_CompoundListener): class _JoinedListener(_CompoundListener): - _exec_once = False - __slots__ = 'parent', 'name', 'local', 'parent_listeners' def __init__(self, parent, name, local): + self._exec_once = False self.parent = parent self.name = name self.local = local diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 55e02984b..b1f1c61c4 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -39,7 +39,7 @@ class ColumnProperty(StrategizedProperty): 'instrument', 'comparator_factory', 'descriptor', 'extension', 'active_history', 'expire_on_flush', 'info', 'doc', 'strategy_class', '_creation_order', '_is_polymorphic_discriminator', - '_mapped_by_synonym', '_deferred_loader') + '_mapped_by_synonym', '_deferred_column_loader') def __init__(self, *columns, **kwargs): """Provide a column-level property for use with a Mapper. diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 78e929345..b9ef5808b 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -361,7 +361,8 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): __slots__ = ( '_lazywhere', '_rev_lazywhere', 'use_get', '_bind_to_col', - '_equated_columns', '_rev_bind_to_col', '_rev_equated_columns') + '_equated_columns', '_rev_bind_to_col', '_rev_equated_columns', + '_simple_lazy_clause') def __init__(self, parent): super(LazyLoader, self).__init__(parent) diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 499515142..dd2589243 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -805,6 +805,8 @@ class MemoizedSlots(object): """ + __slots__ = () + def _fallback_getattr(self, key): raise AttributeError(key) diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 256f52850..8074de53e 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -2,13 +2,14 @@ import copy from sqlalchemy import util, sql, exc, testing from sqlalchemy.testing import assert_raises, assert_raises_message, fixtures -from sqlalchemy.testing import eq_, is_, ne_, fails_if +from sqlalchemy.testing import eq_, is_, ne_, fails_if, mock from sqlalchemy.testing.util import picklers, gc_collect from sqlalchemy.util import classproperty, WeakSequence, get_callable_argspec from sqlalchemy.sql import column from sqlalchemy.util import langhelpers import inspect + class _KeyedTupleTest(object): def _fixture(self, values, labels): @@ -284,6 +285,33 @@ class MemoizedAttrTest(fixtures.TestBase): eq_(f1.bar(), 20) eq_(val[0], 21) + def test_memoized_slots(self): + canary = mock.Mock() + + class Foob(util.MemoizedSlots): + __slots__ = ('foo_bar', 'gogo') + + def _memoized_method_gogo(self): + canary.method() + return "gogo" + + def _memoized_attr_foo_bar(self): + canary.attr() + return "foobar" + + f1 = Foob() + assert_raises(AttributeError, setattr, f1, "bar", "bat") + + eq_(f1.foo_bar, "foobar") + + eq_(f1.foo_bar, "foobar") + + eq_(f1.gogo(), "gogo") + + eq_(f1.gogo(), "gogo") + + eq_(canary.mock_calls, [mock.call.attr(), mock.call.method()]) + class ToListTest(fixtures.TestBase): def test_from_string(self): |