From: Mike Bayer Date: Fri, 14 Oct 2016 17:26:35 +0000 (-0400) Subject: Check for __module__ not present in util.wrap_callable() X-Git-Tag: rel_1_1_2~7^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=665b92d83f3a93d8df54338a35f2b3e70e7f21a0;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Check for __module__ not present in util.wrap_callable() The newly added wrap_callable() function assumes __module__ is present when this is not the case for objects such as functools.partial. Change-Id: Ia226260e9a65419e26d5c1f7187512f7fd4bb7c1 Fixes: #3823 --- diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index b879adc10b..b90b932b55 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -21,6 +21,17 @@ .. changelog:: :version: 1.1.2 + .. change:: + :tags: bug, sql + :tickets: 3823 + + Fixed a regression caused by a newly added function that performs the + "wrap callable" function of sql :class:`.DefaultGenerator` objects, + an attribute error raised for ``__module__`` when the default callable + was a ``functools.partial`` or other object that doesn't have a + ``__module__`` attribute. + + .. changelog:: :version: 1.1.1 :released: October 7, 2016 diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 4675f7cdb8..f2ca806647 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -1398,7 +1398,8 @@ def wrap_callable(wrapper, fn): else: _f = wrapper _f.__name__ = fn.__class__.__name__ - _f.__module__ = fn.__module__ + if hasattr(fn, '__module__'): + _f.__module__ = fn.__module__ if hasattr(fn.__call__, '__doc__') and fn.__call__.__doc__: _f.__doc__ = fn.__call__.__doc__ diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 7e2473deed..5199d6155d 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -382,6 +382,19 @@ class WrapCallableTest(fixtures.TestBase): eq_(c.__name__, "MyFancyDefault") eq_(c.__doc__, None) + def test_wrapping_update_wrapper_functools_parial(self): + def my_default(x): + return x + + import functools + my_functools_default = functools.partial(my_default, 5) + + c = util.wrap_callable( + lambda: my_functools_default(), my_functools_default) + eq_(c.__name__, "partial") + eq_(c.__doc__, my_functools_default.__call__.__doc__) + eq_(c(), 5) + class ToListTest(fixtures.TestBase): def test_from_string(self):