From 9769628ac1c080dc69b3812bc546ff6df3318cbb Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 18 Aug 2013 16:05:38 -0400 Subject: - add WeakSequence.append() - fix and test weakref cleanout for WeakSequence, [ticket:2794] --- test/base/test_utils.py | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'test/base/test_utils.py') diff --git a/test/base/test_utils.py b/test/base/test_utils.py index aefc6d421..2fd1edbb5 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -1,10 +1,10 @@ import copy -from sqlalchemy import util, sql, exc +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.util import picklers -from sqlalchemy.util import classproperty +from sqlalchemy.testing.util import picklers, gc_collect +from sqlalchemy.util import classproperty, WeakSequence class KeyedTupleTest(): @@ -115,6 +115,36 @@ class KeyedTupleTest(): keyed_tuple[0] = 100 assert_raises(TypeError, should_raise) +class WeakSequenceTest(fixtures.TestBase): + @testing.requires.predictable_gc + def test_cleanout_elements(self): + class Foo(object): + pass + f1, f2, f3 = Foo(), Foo(), Foo() + w = WeakSequence([f1, f2, f3]) + eq_(len(w), 3) + eq_(len(w._storage), 3) + del f2 + gc_collect() + eq_(len(w), 2) + eq_(len(w._storage), 2) + + @testing.requires.predictable_gc + def test_cleanout_appended(self): + class Foo(object): + pass + f1, f2, f3 = Foo(), Foo(), Foo() + w = WeakSequence() + w.append(f1) + w.append(f2) + w.append(f3) + eq_(len(w), 3) + eq_(len(w._storage), 3) + del f2 + gc_collect() + eq_(len(w), 2) + eq_(len(w._storage), 2) + class OrderedDictTest(fixtures.TestBase): -- cgit v1.2.1 From 2692238f45ae4d2f46949dfa52b16132bd266e0e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 18 Dec 2013 18:26:15 -0500 Subject: - Improvements to the system by which SQL types generate within ``__repr__()``, particularly with regards to the MySQL integer/numeric/ character types which feature a wide variety of keyword arguments. The ``__repr__()`` is important for use with Alembic autogenerate for when Python code is rendered in a migration script. [ticket:2893] --- test/base/test_utils.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'test/base/test_utils.py') diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 2fd1edbb5..1946bd704 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -1419,6 +1419,55 @@ class GenericReprTest(fixtures.TestBase): "Foo(b=5, d=7)" ) + def test_multi_kw(self): + class Foo(object): + def __init__(self, a, b, c=3, d=4): + self.a = a + self.b = b + self.c = c + self.d = d + class Bar(Foo): + def __init__(self, e, f, g=5, **kw): + self.e = e + self.f = f + self.g = g + super(Bar, self).__init__(**kw) + + eq_( + util.generic_repr( + Bar('e', 'f', g=7, a=6, b=5, d=9), + to_inspect=[Bar, Foo] + ), + "Bar('e', 'f', g=7, a=6, b=5, d=9)" + ) + + eq_( + util.generic_repr( + Bar('e', 'f', a=6, b=5), + to_inspect=[Bar, Foo] + ), + "Bar('e', 'f', a=6, b=5)" + ) + + def test_multi_kw_repeated(self): + class Foo(object): + def __init__(self, a=1, b=2): + self.a = a + self.b = b + class Bar(Foo): + def __init__(self, b=3, c=4, **kw): + self.c = c + super(Bar, self).__init__(b=b, **kw) + + eq_( + util.generic_repr( + Bar(a='a', b='b', c='c'), + to_inspect=[Bar, Foo] + ), + "Bar(b='b', c='c', a='a')" + ) + + def test_discard_vargs(self): class Foo(object): def __init__(self, a, b, *args): -- cgit v1.2.1 From c450cd6cb6d0c8fed110abcec5bc17ec4e0e8c5e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 4 Jan 2014 00:35:48 -0500 Subject: - Fixed regression where using a ``functools.partial()`` with the event system would cause a recursion overflow due to usage of inspect.getargspec() on it in order to detect a legacy calling signature for certain events, and apparently there's no way to do this with a partial object. Instead we skip the legacy check and assume the modern style; the check itself now only occurs for the SessionEvents.after_bulk_update and SessionEvents.after_bulk_delete events. Those two events will require the new signature style if assigned to a "partial" event listener. [ticket:2905] --- test/base/test_utils.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'test/base/test_utils.py') diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 1946bd704..86e4b190a 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -4,7 +4,7 @@ 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.util import picklers, gc_collect -from sqlalchemy.util import classproperty, WeakSequence +from sqlalchemy.util import classproperty, WeakSequence, get_callable_argspec class KeyedTupleTest(): @@ -1184,6 +1184,33 @@ class ArgInspectionTest(fixtures.TestBase): test(f3) test(f4) + def test_callable_argspec_fn(self): + def foo(x, y, **kw): + pass + eq_( + get_callable_argspec(foo), + (['x', 'y'], None, 'kw', None) + ) + + def test_callable_argspec_method(self): + class Foo(object): + def foo(self, x, y, **kw): + pass + eq_( + get_callable_argspec(Foo.foo), + (['self', 'x', 'y'], None, 'kw', None) + ) + + def test_callable_argspec_partial(self): + from functools import partial + def foo(x, y, z, **kw): + pass + bar = partial(foo, 5) + + assert_raises( + ValueError, + get_callable_argspec, bar + ) class SymbolTest(fixtures.TestBase): @@ -1665,3 +1692,5 @@ class TestClassProperty(fixtures.TestBase): return d eq_(B.something, {'foo': 1, 'bazz': 2}) + + -- cgit v1.2.1