From 8964ac5a6c041430efcc5bc9d40a13a2d472c968 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 17 Nov 2010 19:59:25 -0500 Subject: get rid of extraneous note --- pyramid/request.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyramid/request.py b/pyramid/request.py index 43a4a3aa2..2f9ca5819 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -259,9 +259,6 @@ class Request(WebobRequest): scheme, and port) for a named :app:`Pyramid` :term:`route configuration`. - .. note:: Calling :meth:`pyramid.Request.route_path` can be used to - achieve the same result as :func:`pyramid.url.route_path`. - This is a convenience method. The result of calling :meth:`pyramid.request.Request.route_path` is the same as calling :func:`pyramid.url.route_path` with an explicit ``request`` -- cgit v1.2.3 From 485ef6938f8314567ad49c16589de9e31fac383f Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 17 Nov 2010 21:58:55 -0500 Subject: gardening --- TODO.txt | 137 +++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/TODO.txt b/TODO.txt index def6fe687..959f16af9 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,6 +1,81 @@ :mod:`repoze.bfg` TODOs ======================= +Must-Have (before 1.0) +---------------------- + +- Test on GAE, Jython, PyPy, IronPython. + +- Add docs for httpexceptions module for each webob.exc class that inherits + from WSGIHTTPException. + +- Add a ``handler`` ZCML directive. This implies some slightly dicey + refactoring of the configurator to allow it to generate ZCML + "discriminators" for views and routes. + +- Provide a .flash API on session object. + +- Make default renderer work (renderer registered with no name, which is + active for every view unless the view names a specific renderer). + +- Use ``@register_view`` instead of ``@view_config`` and change view docs to + use "view registration" instead of "view configuration". + +- Remove calls to config.begin()/config.end() from startup config code in + tutorials and paster templates (no longer required). + +- SQLAlchemy idiomatics: + + mcdonc: those paster templates all look pretty good... the + only thing i'd consider is adjusting your config variable names to match + exactly what sqlalchemy uses as parameter names, see here: + http://www.sqlalchemy.org/docs/core/engines.html + + mcdonc: especially in the pylons_sqla ini file, where the db + initialization is mixed in w/ the app config... + + ... i'd use "sqlalchemy.PARAMETER" for all of the sqla + settings, so it could easily be handed to engine_from_config w/o any need + to parse by hand + + mcdonc: in the other ini files, where sqlalchemy is given its + own part, the "sqlalchemy." prefix probably isn't necessary, but matching + the parameter names (e.g. 'url' instead of 'db_string') is still probably + a good idea + +- Non-bwcompat use of threadlocals that need to be documented or ameliorated: + + security.principals_allowed_by_permission + + resource.OverrideProvider._get_overrides: can't credibly be removed, + because it stores an overrideprovider as a module-scope global. + + traversal.traverse: this API is a stepchild, and needs to be changed. + + Configurator.add_translation_dirs: not passed any context but a message, + can't credibly be removed. + +- Better ``config.add_handler`` documentation. + +Should-Have +----------- + +- Create a ``docs`` directory for each paster template. + +- Remove "BFG" from Pyramid-specific environ variables. + +- translationdir ZCML directive use of ``path_spec`` should maybe die. + +- Add CRSF token creation/checking machinery (only "should have" vs. "must + have" because I'm not sure it belongs in Pyramid.. it definitely must exist + in formgen libraries, and *might* belong in Pyramid). + +- Change "Cleaning up After a Request" in the urldispatch chapter to + use ``request.add_response_callback``. + +Nice-to-Have +------------ + - Supply ``X-Vhm-Host`` support. - Basic WSGI documentation (pipeline / app / server). @@ -50,65 +125,7 @@ - Raise an exception when a value in response_headerlist is not a string or decide to encode. -- Change "Cleaning up After a Request" in the urldispatch chapter to - use ``request.add_response_callback``. - -- Update App engine chapter. - -- Browser id? - -- .flash API on session. - -- CRSF token machinery - -- ``add_handler`` documentation. - -- ``handler`` ZCML directive. - -- ``docs`` directory for each paster template. - -- "BFG" in environ variables. - -- Test on GAE, Jython, PyPy, IronPython. - -- Add docs for httpexceptions. - -- RendererHelper -> RendererInfo? - -- translationdir ZCML directive use of ``path_spec`` should maybe die. - -- SQLAlchemy idiomatics: - - mcdonc: those paster templates all look pretty good... the - only thing i'd consider is adjusting your config variable names to match - exactly what sqlalchemy uses as parameter names, see here: - http://www.sqlalchemy.org/docs/core/engines.html - - mcdonc: especially in the pylons_sqla ini file, where the db - initialization is mixed in w/ the app config... - - ... i'd use "sqlalchemy.PARAMETER" for all of the sqla - settings, so it could easily be handed to engine_from_config w/o any need - to parse by hand - - mcdonc: in the other ini files, where sqlalchemy is given its - own part, the "sqlalchemy." prefix probably isn't necessary, but matching - the parameter names (e.g. 'url' instead of 'db_string') is still probably - a good idea - -- Default renderer. +- Update App engine chapter with less creaky directions. -- Non-bwcompat use of threadlocals: +- Add functionality that mocks the behavior of ``repoze.browserid``. - security.principals_allowed_by_permission - - resource.OverrideProvider._get_overrides: can't credibly be removed, - because it stores an overrideprovider as a module-scope global. - - traversal.traverse: this API is a stepchild, and needs to be changed. - - Configurator.add_translation_dirs: not passed any context but a message, - can't credibly be removed. - -- Use ``@register_view`` instead of ``@view_config`` and change view docs to - use "view registration" instead of "view configuration". -- cgit v1.2.3 From 0511437d5250d249accda26ba6435ab737f8c0c5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 17 Nov 2010 21:59:21 -0500 Subject: not BFG no mo --- TODO.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.txt b/TODO.txt index 959f16af9..f12dcee73 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,5 @@ -:mod:`repoze.bfg` TODOs -======================= +Pyramid TODOs +============= Must-Have (before 1.0) ---------------------- -- cgit v1.2.3 From 34c59071c28e18aeec87c7a244e38ed22e2f35c6 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 03:27:44 -0500 Subject: ocd break: sort imports --- pyramid/configuration.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pyramid/configuration.py b/pyramid/configuration.py index 3f959aabf..63b1f70d7 100644 --- a/pyramid/configuration.py +++ b/pyramid/configuration.py @@ -24,6 +24,8 @@ from pyramid.interfaces import IChameleonTranslate from pyramid.interfaces import IDebugLogger from pyramid.interfaces import IDefaultPermission from pyramid.interfaces import IDefaultRootFactory +from pyramid.interfaces import IException +from pyramid.interfaces import IExceptionResponse from pyramid.interfaces import IExceptionViewClassifier from pyramid.interfaces import ILocaleNegotiator from pyramid.interfaces import IMultiView @@ -36,34 +38,32 @@ from pyramid.interfaces import IRootFactory from pyramid.interfaces import IRouteRequest from pyramid.interfaces import IRoutesMapper from pyramid.interfaces import ISecuredView +from pyramid.interfaces import ISessionFactory from pyramid.interfaces import IStaticURLInfo from pyramid.interfaces import ITranslationDirectories from pyramid.interfaces import ITraverser from pyramid.interfaces import IView from pyramid.interfaces import IViewClassifier -from pyramid.interfaces import IExceptionResponse -from pyramid.interfaces import IException -from pyramid.interfaces import ISessionFactory from pyramid import chameleon_text from pyramid import chameleon_zpt -from pyramid.mako_templating import renderer_factory as mako_renderer_factory from pyramid import renderers -from pyramid.renderers import RendererHelper from pyramid.authorization import ACLAuthorizationPolicy from pyramid.compat import all from pyramid.compat import md5 from pyramid.events import ApplicationCreated +from pyramid.exceptions import ConfigurationError from pyramid.exceptions import Forbidden from pyramid.exceptions import NotFound from pyramid.exceptions import PredicateMismatch -from pyramid.exceptions import ConfigurationError from pyramid.i18n import get_localizer from pyramid.log import make_stream_logger +from pyramid.mako_templating import renderer_factory as mako_renderer_factory from pyramid.path import caller_package -from pyramid.path import package_path from pyramid.path import package_of +from pyramid.path import package_path from pyramid.registry import Registry +from pyramid.renderers import RendererHelper from pyramid.request import route_request_iface from pyramid.resource import PackageOverrides from pyramid.resource import resolve_resource_spec @@ -72,12 +72,12 @@ from pyramid.static import StaticURLInfo from pyramid.threadlocal import get_current_registry from pyramid.threadlocal import get_current_request from pyramid.threadlocal import manager -from pyramid.traversal import traversal_path from pyramid.traversal import DefaultRootFactory from pyramid.traversal import find_interface +from pyramid.traversal import traversal_path from pyramid.urldispatch import RoutesMapper -from pyramid.view import render_view_to_response from pyramid.view import default_exceptionresponse_view +from pyramid.view import render_view_to_response MAX_ORDER = 1 << 30 DEFAULT_PHASH = md5().hexdigest() -- cgit v1.2.3 From 85ee02b24caf0bf6b491b5ecf7ad84c29ca8c75c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 04:21:22 -0500 Subject: - Make test suite pass on Jython (requires PasteScript trunk, presumably to be 1.7.4). --- CHANGES.txt | 3 +++ pyramid/tests/test_configuration.py | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 604f28cf4..14b2c569d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -12,6 +12,9 @@ Features - Add a ``pyramid.request.Request.route_path`` API. This is a convenience method of the request which calls ``pyramid.url.route_url``. +- Make test suite pass on Jython (requires PasteScript trunk, presumably to + be 1.7.4). + Bug Fixes --------- diff --git a/pyramid/tests/test_configuration.py b/pyramid/tests/test_configuration.py index ded17cb33..0d8905f7c 100644 --- a/pyramid/tests/test_configuration.py +++ b/pyramid/tests/test_configuration.py @@ -2940,6 +2940,7 @@ class ConfiguratorTests(unittest.TestCase): pyramid.tests) def test_scan_integration(self): + import os from zope.interface import alsoProvides from pyramid.interfaces import IRequest from pyramid.view import render_view_to_response @@ -3011,8 +3012,12 @@ class ConfiguratorTests(unittest.TestCase): result = render_view_to_response(ctx, req, 'another_stacked_class2') self.assertEqual(result, 'another_stacked_class') - self.assertRaises(TypeError, - render_view_to_response, ctx, req, 'basemethod') + if not os.name.startswith('java'): + # on Jython, a class without an __init__ apparently accepts + # any number of arguments without raising a TypeError. + + self.assertRaises(TypeError, + render_view_to_response, ctx, req, 'basemethod') result = render_view_to_response(ctx, req, 'method1') self.assertEqual(result, 'method1') -- cgit v1.2.3 From e57f5c2dd29f6bd88158a4b84ef67694fd33ba47 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 04:41:50 -0500 Subject: fix race condition test failure (seen on Jython) --- pyramid/authentication.py | 6 +++++- pyramid/tests/test_authentication.py | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 4849d2c41..86d725bcf 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -286,6 +286,7 @@ EXPIRE = object() class AuthTktCookieHelper(object): auth_tkt = auth_tkt # for tests + now = None # for tests userid_type_decoders = { 'int':int, @@ -373,7 +374,10 @@ class AuthTktCookieHelper(object): except self.auth_tkt.BadTicket: return None - now = time.time() + now = self.now # service tests + + if now is None: + now = time.time() if self.timeout and ( (timestamp + self.timeout) < now ): return None diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index 69762fdb0..d9d0c2c97 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -411,8 +411,10 @@ class TestAuthTktCookieHelper(unittest.TestCase): def test_identify_cookie_reissue(self): import time - plugin = self._makeOne('secret', timeout=5000, reissue_time=0) - plugin.auth_tkt.timestamp = time.time() + plugin = self._makeOne('secret', timeout=10, reissue_time=0) + now = time.time() + plugin.auth_tkt.timestamp = now + plugin.now = now + 1 request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=bogus'}) result = plugin.identify(request) self.failUnless(result) -- cgit v1.2.3 From 165020a7ba21d0bbebaaefd142b70c28d278ea83 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 09:42:17 -0500 Subject: gardening --- TODO.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TODO.txt b/TODO.txt index f12dcee73..fe411f749 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,11 +4,6 @@ Pyramid TODOs Must-Have (before 1.0) ---------------------- -- Test on GAE, Jython, PyPy, IronPython. - -- Add docs for httpexceptions module for each webob.exc class that inherits - from WSGIHTTPException. - - Add a ``handler`` ZCML directive. This implies some slightly dicey refactoring of the configurator to allow it to generate ZCML "discriminators" for views and routes. @@ -60,6 +55,11 @@ Must-Have (before 1.0) Should-Have ----------- +- Try to make test suite pass on PyPy, IronPython. + +- Add docs for httpexceptions module for each webob.exc class that inherits + from WSGIHTTPException. + - Create a ``docs`` directory for each paster template. - Remove "BFG" from Pyramid-specific environ variables. -- cgit v1.2.3 From 3b913e3f8a2cb4afbe57033643fd998cdde0217b Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 09:42:41 -0500 Subject: add pypyenv, change ignores for things that are directories to end in a slash --- .gitignore | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 5d46de01f..706f6493d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,10 @@ *.pt.py *.txt.py .coverage -env26 -env24 -env27 -jyenv +env26/ +env24/ +env27/ +jyenv/ +pypyenv/ build/ dist/ -- cgit v1.2.3 From 1e467e1bacc915d1e00bdce189e35f5afb568132 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 09:43:18 -0500 Subject: we dont actually need coverage (and it fails on pypy) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c2d11384f..c1939f73c 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ install_requires=[ if platform.system() == 'Java': tests_require = install_requires + ['WebTest'] else: - tests_require= install_requires + ['Sphinx', 'docutils', 'coverage', + tests_require= install_requires + ['Sphinx', 'docutils', 'WebTest', 'repoze.sphinx.autointerface'] if sys.version_info[:2] < (2, 6): -- cgit v1.2.3 From a66593d25e77f1a0e749f5590b45498bbaa66755 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 18 Nov 2010 16:56:05 -0500 Subject: - Fix apparent failures when calling ``pyramid.traversal.find_model(root, path)`` or ``pyramid.traversal.traverse(path)`` when ``path`` is (erroneously) a Unicode object. The user is meant to pass these APIs a string object, never a Unicode object. In practice, however, users indeed pass Unicode. Because the string that is passed must be ASCII encodeable, now, if they pass a Unicode object, its data is eagerly converted to an ASCII string rather than being passed along to downstream code as a convenience to the user and to prevent puzzling second-order failures from cropping up (all failures will occur within ``pyramid.traversal.traverse`` rather than later down the line as the result of calling ``traversal_path``). --- CHANGES.txt | 12 ++++++++++++ pyramid/tests/test_traversal.py | 26 ++++++++++++++++++++++++++ pyramid/traversal.py | 13 ++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 14b2c569d..0720034b2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -28,6 +28,18 @@ Bug Fixes - The ``pyramid_alchemy`` paster template had a typo, preventing an import from working. +- Fix apparent failures when calling ``pyramid.traversal.find_model(root, + path)`` or ``pyramid.traversal.traverse(path)`` when ``path`` is + (erroneously) a Unicode object. The user is meant to pass these APIs a + string object, never a Unicode object. In practice, however, users indeed + pass Unicode. Because the string that is passed must be ASCII encodeable, + now, if they pass a Unicode object, its data is eagerly converted to an + ASCII string rather than being passed along to downstream code as a + convenience to the user and to prevent puzzling second-order failures from + cropping up (all failures will occur within ``pyramid.traversal.traverse`` + rather than later down the line as the result of calling + ``traversal_path``). + Backwards Incompatibilities --------------------------- diff --git a/pyramid/tests/test_traversal.py b/pyramid/tests/test_traversal.py index 2deb5982c..3245d6302 100644 --- a/pyramid/tests/test_traversal.py +++ b/pyramid/tests/test_traversal.py @@ -522,6 +522,32 @@ class FindModelTests(unittest.TestCase): self.assertEqual(root.wascontext, True) self.assertEqual(root.request.environ['PATH_INFO'], '/') + def test_absolute_unicode_found(self): + # test for bug wiggy found in wild, traceback stack: + # root = u'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF' + # wiggy's code: section=find_model(page, root) + # find_model L76: D = traverse(model, path) + # traverse L291: return traverser(request) + # __call__ line 568: vpath_tuple = traversal_path(vpath) + # lru_cached line 91: f(*arg) + # traversal_path line 443: path.encode('ascii') + # UnicodeEncodeError: 'ascii' codec can't encode characters in + # position 1-12: ordinal not in range(128) + # + # solution: encode string to ascii in pyramid.traversal.traverse + # before passing it along to webob as path_info + from pyramid.traversal import ModelGraphTraverser + unprintable = DummyContext() + root = DummyContext(unprintable) + unprintable.__parent__ = root + unprintable.__name__ = unicode( + '/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8') + root.__parent__ = None + root.__name__ = None + traverser = ModelGraphTraverser + self._registerTraverser(traverser) + result = self._callFUT(root, u'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF') + self.assertEqual(result, unprintable) class ModelPathTests(unittest.TestCase): def _callFUT(self, model, *elements): diff --git a/pyramid/traversal.py b/pyramid/traversal.py index e928c33f7..fb73ad906 100644 --- a/pyramid/traversal.py +++ b/pyramid/traversal.py @@ -228,7 +228,7 @@ def traverse(model, path): object supplied to the function as the ``model`` argument. If an empty string is passed as ``path``, the ``model`` passed in will be returned. Model path strings must be escaped in the following - manner: each Unicode path segment must be encoded as UTF-8 and as + manner: each Unicode path segment must be encoded as UTF-8 and each path segment must escaped via Python's :mod:`urllib.quote`. For example, ``/path/to%20the/La%20Pe%C3%B1a`` (absolute) or ``to%20the/La%20Pe%C3%B1a`` (relative). The @@ -272,6 +272,17 @@ def traverse(model, path): else: path = '' + # The user is supposed to pass us a string object, never Unicode. In + # practice, however, users indeed pass Unicode to this API. If they do + # pass a Unicode object, its data *must* be entirely encodeable to ASCII, + # so we encode it here as a convenience to the user and to prevent + # second-order failures from cropping up (all failures will occur at this + # step rather than later down the line as the result of calling + # ``traversal_path``). + + if isinstance(path, unicode): + path = path.encode('ascii') + if path and path[0] == '/': model = find_root(model) -- cgit v1.2.3