From 9e7248258800ef2c7072f497901172ab94988708 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 20:06:48 -0800 Subject: Catch bad `name` and raise a `ValueError` --- pyramid/tests/test_config/test_factories.py | 18 +++++++++++++++++- pyramid/util.py | 10 +++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_config/test_factories.py b/pyramid/tests/test_config/test_factories.py index 6e679397f..5ae486c4b 100644 --- a/pyramid/tests/test_config/test_factories.py +++ b/pyramid/tests/test_config/test_factories.py @@ -111,6 +111,22 @@ class TestFactoriesMixin(unittest.TestCase): config = self._makeOne(autocommit=True) self.assertRaises(AttributeError, config.add_request_method) + def test_add_request_method_with_text_type_name(self): + from pyramid.interfaces import IRequestExtensions + from pyramid.compat import text_ + from pyramid.util import InstancePropertyMixin + + config = self._makeOne(autocommit=True) + def boomshaka(r): pass + name = text_(b'La Pe\xc3\xb1a', 'utf-8') + config.add_request_method(boomshaka, name=name) + exts = config.registry.getUtility(IRequestExtensions) + inst = InstancePropertyMixin() + + def set_extensions(): + inst._set_extensions(exts) + self.assertRaises(ValueError, set_extensions) + self.assertTrue(name in exts.methods) class TestDeprecatedFactoriesMixinMethods(unittest.TestCase): def setUp(self): @@ -120,7 +136,7 @@ class TestDeprecatedFactoriesMixinMethods(unittest.TestCase): def tearDown(self): from zope.deprecation import __show__ __show__.on() - + def _makeOne(self, *arg, **kw): from pyramid.config import Configurator config = Configurator(*arg, **kw) diff --git a/pyramid/util.py b/pyramid/util.py index 6de53d559..e9f5760a6 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -111,7 +111,15 @@ class InstancePropertyMixin(object): def _set_extensions(self, extensions): for name, fn in iteritems_(extensions.methods): method = fn.__get__(self, self.__class__) - setattr(self, name, method) + try: + setattr(self, name, method) + except UnicodeEncodeError: + msg = ( + '`name="%s"` is invalid. `name` must be ascii because it is ' + 'used on __name__ of the method' + ) + raise ValueError(msg % name) + self._set_properties(extensions.descriptors) def set_property(self, callable, name=None, reify=False): -- cgit v1.2.3 From e094ab229eed6f8bf9e7a6a4d4406faefece41e4 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 20:26:22 -0800 Subject: Added py3 support --- pyramid/tests/test_config/test_factories.py | 6 +++++- pyramid/util.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_config/test_factories.py b/pyramid/tests/test_config/test_factories.py index 5ae486c4b..e93ba6908 100644 --- a/pyramid/tests/test_config/test_factories.py +++ b/pyramid/tests/test_config/test_factories.py @@ -120,13 +120,17 @@ class TestFactoriesMixin(unittest.TestCase): def boomshaka(r): pass name = text_(b'La Pe\xc3\xb1a', 'utf-8') config.add_request_method(boomshaka, name=name) + + name2 = b'La Pe\xc3\xb1a' + config.add_request_method(boomshaka, name=name2) + exts = config.registry.getUtility(IRequestExtensions) inst = InstancePropertyMixin() def set_extensions(): inst._set_extensions(exts) + self.assertRaises(ValueError, set_extensions) - self.assertTrue(name in exts.methods) class TestDeprecatedFactoriesMixinMethods(unittest.TestCase): def setUp(self): diff --git a/pyramid/util.py b/pyramid/util.py index e9f5760a6..6ab621fd4 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -113,7 +113,7 @@ class InstancePropertyMixin(object): method = fn.__get__(self, self.__class__) try: setattr(self, name, method) - except UnicodeEncodeError: + except (UnicodeEncodeError, TypeError): msg = ( '`name="%s"` is invalid. `name` must be ascii because it is ' 'used on __name__ of the method' -- cgit v1.2.3 From 1e0d648503fd992323737c7c702be204337e1e36 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 7 Feb 2015 12:33:03 -0800 Subject: Raise error at configuration time --- pyramid/config/factories.py | 15 +++++++++--- pyramid/tests/test_config/test_factories.py | 21 +++++++--------- pyramid/tests/test_util.py | 38 +++++++++++++++++++++++++++++ pyramid/util.py | 27 +++++++++++++------- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py index 15cfb796f..4b2517ff1 100644 --- a/pyramid/config/factories.py +++ b/pyramid/config/factories.py @@ -15,8 +15,12 @@ from pyramid.traversal import DefaultRootFactory from pyramid.util import ( action_method, InstancePropertyMixin, + get_callable_name, ) +from pyramid.compat import native_ + + class FactoriesConfiguratorMixin(object): @action_method def set_root_factory(self, factory): @@ -33,9 +37,10 @@ class FactoriesConfiguratorMixin(object): factory = self.maybe_dotted(factory) if factory is None: factory = DefaultRootFactory + def register(): self.registry.registerUtility(factory, IRootFactory) - self.registry.registerUtility(factory, IDefaultRootFactory) # b/c + self.registry.registerUtility(factory, IDefaultRootFactory) # b/c intr = self.introspectable('root factories', None, @@ -44,7 +49,7 @@ class FactoriesConfiguratorMixin(object): intr['factory'] = factory self.action(IRootFactory, register, introspectables=(intr,)) - _set_root_factory = set_root_factory # bw compat + _set_root_factory = set_root_factory # bw compat @action_method def set_session_factory(self, factory): @@ -60,6 +65,7 @@ class FactoriesConfiguratorMixin(object): achieve the same purpose. """ factory = self.maybe_dotted(factory) + def register(): self.registry.registerUtility(factory, ISessionFactory) intr = self.introspectable('session factory', None, @@ -89,6 +95,7 @@ class FactoriesConfiguratorMixin(object): can be used to achieve the same purpose. """ factory = self.maybe_dotted(factory) + def register(): self.registry.registerUtility(factory, IRequestFactory) intr = self.introspectable('request factory', None, @@ -173,6 +180,8 @@ class FactoriesConfiguratorMixin(object): callable, name=name, reify=reify) elif name is None: name = callable.__name__ + else: + name = get_callable_name(name) def register(): exts = self.registry.queryUtility(IRequestExtensions) @@ -224,9 +233,9 @@ class FactoriesConfiguratorMixin(object): 'set_request_propery() is deprecated as of Pyramid 1.5; use ' 'add_request_method() with the property=True argument instead') + @implementer(IRequestExtensions) class _RequestExtensions(object): def __init__(self): self.descriptors = {} self.methods = {} - diff --git a/pyramid/tests/test_config/test_factories.py b/pyramid/tests/test_config/test_factories.py index 35677a91b..42bb5accc 100644 --- a/pyramid/tests/test_config/test_factories.py +++ b/pyramid/tests/test_config/test_factories.py @@ -128,24 +128,21 @@ class TestFactoriesMixin(unittest.TestCase): def test_add_request_method_with_text_type_name(self): from pyramid.interfaces import IRequestExtensions - from pyramid.compat import text_ - from pyramid.util import InstancePropertyMixin + from pyramid.compat import text_, PY3 + from pyramid.exceptions import ConfigurationError config = self._makeOne(autocommit=True) def boomshaka(r): pass - name = text_(b'La Pe\xc3\xb1a', 'utf-8') - config.add_request_method(boomshaka, name=name) - name2 = b'La Pe\xc3\xb1a' - config.add_request_method(boomshaka, name=name2) + def get_bad_name(): + if PY3: # pragma: nocover + name = b'La Pe\xc3\xb1a' + else: # pragma: nocover + name = text_(b'La Pe\xc3\xb1a', 'utf-8') - exts = config.registry.getUtility(IRequestExtensions) - inst = InstancePropertyMixin() - - def set_extensions(): - inst._set_extensions(exts) + config.add_request_method(boomshaka, name=name) - self.assertRaises(ValueError, set_extensions) + self.assertRaises(ConfigurationError, get_bad_name) class TestDeprecatedFactoriesMixinMethods(unittest.TestCase): def setUp(self): diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index ac5ea0683..405fe927a 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -124,6 +124,21 @@ class Test_InstancePropertyMixin(unittest.TestCase): self.assertEqual(1, foo.x) self.assertEqual(2, foo.y) + def test__make_property_unicode(self): + from pyramid.compat import text_ + from pyramid.exceptions import ConfigurationError + + cls = self._getTargetClass() + if PY3: # pragma: nocover + name = b'La Pe\xc3\xb1a' + else: # pragma: nocover + name = text_(b'La Pe\xc3\xb1a', 'utf-8') + + def make_bad_name(): + cls._make_property(lambda x: 1, name=name, reify=True) + + self.assertRaises(ConfigurationError, make_bad_name) + def test__set_properties_with_dict(self): foo = self._makeOne() x_name, x_fn = foo._make_property(lambda _: 1, name='x', reify=True) @@ -619,7 +634,30 @@ class TestActionInfo(unittest.TestCase): "Line 0 of file filename:\n linerepr ") +class TestCallableName(unittest.TestCase): + def test_valid_ascii(self): + from pyramid.util import get_callable_name + name = u'hello world' + self.assertEquals(get_callable_name(name), name) + + def test_invalid_ascii(self): + from pyramid.util import get_callable_name + from pyramid.compat import text_, PY3 + from pyramid.exceptions import ConfigurationError + + def get_bad_name(): + if PY3: # pragma: nocover + name = b'La Pe\xc3\xb1a' + else: # pragma: nocover + name = text_(b'La Pe\xc3\xb1a', 'utf-8') + + get_callable_name(name) + + self.assertRaises(ConfigurationError, get_bad_name) + + def dummyfunc(): pass + class Dummy(object): pass diff --git a/pyramid/util.py b/pyramid/util.py index c036c1c2e..7e8535aaf 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -22,6 +22,7 @@ from pyramid.compat import ( string_types, text_, PY3, + native_ ) from pyramid.interfaces import IActionInfo @@ -55,7 +56,7 @@ class InstancePropertyMixin(object): raise ValueError('cannot reify a property') elif name is not None: fn = lambda this: callable(this) - fn.__name__ = name + fn.__name__ = get_callable_name(name) fn.__doc__ = callable.__doc__ else: name = callable.__name__ @@ -111,14 +112,7 @@ class InstancePropertyMixin(object): def _set_extensions(self, extensions): for name, fn in iteritems_(extensions.methods): method = fn.__get__(self, self.__class__) - try: - setattr(self, name, method) - except (UnicodeEncodeError, TypeError): - msg = ( - '`name="%s"` is invalid. `name` must be ascii because it is ' - 'used on __name__ of the method' - ) - raise ValueError(msg % name) + setattr(self, name, method) self._set_properties(extensions.descriptors) @@ -558,3 +552,18 @@ def action_method(wrapped): functools.update_wrapper(wrapper, wrapped) wrapper.__docobj__ = wrapped return wrapper + + +def get_callable_name(name): + """ + Verifies that the ``name`` is ascii and will raise a ``ConfigurationError`` + if it is not. + """ + try: + return native_(name, 'ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + msg = ( + '`name="%s"` is invalid. `name` must be ascii because it is ' + 'used on __name__ of the method' + ) + raise ConfigurationError(msg % name) -- cgit v1.2.3 From 4a86b211fe7d294d2c598b42bc80e0c150a08443 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 7 Feb 2015 12:34:31 -0800 Subject: Remove `native_` import, not used anymore --- pyramid/config/factories.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py index 4b2517ff1..10678df55 100644 --- a/pyramid/config/factories.py +++ b/pyramid/config/factories.py @@ -18,8 +18,6 @@ from pyramid.util import ( get_callable_name, ) -from pyramid.compat import native_ - class FactoriesConfiguratorMixin(object): @action_method -- cgit v1.2.3 From fd840237d4eb374c0d3f4ac2bb394aefaa43d40c Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 7 Feb 2015 17:33:39 -0800 Subject: Fix py32 support --- pyramid/tests/test_util.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index 405fe927a..371cd8703 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -1,9 +1,11 @@ import unittest from pyramid.compat import PY3 + class Test_InstancePropertyMixin(unittest.TestCase): def _makeOne(self): cls = self._getTargetClass() + class Foo(cls): pass return Foo() @@ -637,8 +639,14 @@ class TestActionInfo(unittest.TestCase): class TestCallableName(unittest.TestCase): def test_valid_ascii(self): from pyramid.util import get_callable_name - name = u'hello world' - self.assertEquals(get_callable_name(name), name) + from pyramid.compat import text_, PY3 + + if PY3: # pragma: nocover + name = b'hello world' + else: # pragma: nocover + name = text_(b'hello world', 'utf-8') + + self.assertEquals(get_callable_name(name), 'hello world') def test_invalid_ascii(self): from pyramid.util import get_callable_name -- cgit v1.2.3