From 66cda3dbdf336e82b395a8b99e637509e23967bd Mon Sep 17 00:00:00 2001 From: cguardia Date: Sat, 16 Apr 2011 21:51:03 -0500 Subject: start playing with paster command to show matching views for url --- pyramid/config.py | 17 +++++++ pyramid/paster.py | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 1 + 3 files changed, 152 insertions(+) diff --git a/pyramid/config.py b/pyramid/config.py index 9fda75daa..ef520e053 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2441,6 +2441,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if xhr: def xhr_predicate(context, request): return request.is_xhr + xhr_predicate.__text__ = "XHR = True" weights.append(1 << 1) predicates.append(xhr_predicate) h.update('xhr:%r' % bool(xhr)) @@ -2448,6 +2449,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if request_method is not None: def request_method_predicate(context, request): return request.method == request_method + msg = "Request method = %s" + request_method_predicate.__text__ = msg % request_method weights.append(1 << 2) predicates.append(request_method_predicate) h.update('request_method:%r' % request_method) @@ -2459,6 +2462,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, raise ConfigurationError(why[0]) def path_info_predicate(context, request): return path_info_val.match(request.path_info) is not None + msg = "path_info = %s" + path_info_predicate.__text__ = msg % path_info weights.append(1 << 3) predicates.append(path_info_predicate) h.update('path_info:%r' % path_info) @@ -2471,6 +2476,11 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if request_param_val is None: return request_param in request.params return request.params.get(request_param) == request_param_val + if request_param_val is None: + msg = "request_param %s" % request_param + else: + msg = "request_param %s = %s" % (request_param, request_param_val) + request_param_predicate.__text__ = msg weights.append(1 << 4) predicates.append(request_param_predicate) h.update('request_param:%r=%r' % (request_param, request_param_val)) @@ -2491,6 +2501,11 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if val is None: return False return header_val.match(val) is not None + if header_val is None: + msg = "header %s" % header_name + else: + msg = "header %s = %s" % (header_name, header_val) + header_predicate.__text__ = msg weights.append(1 << 5) predicates.append(header_predicate) h.update('header:%r=%r' % (header_name, header_val)) @@ -2654,6 +2669,7 @@ def preserve_view_attrs(view, wrapped_view): pass try: wrapped_view.__predicated__ = view.__predicated__ + wrapped_view.__predicates__ = view.__predicates__ except AttributeError: pass try: @@ -2791,6 +2807,7 @@ class ViewDeriver(object): return all((predicate(context, request) for predicate in predicates)) predicate_wrapper.__predicated__ = checker + predicate_wrapper.__predicates__ = predicates return predicate_wrapper @wraps_view diff --git a/pyramid/paster.py b/pyramid/paster.py index bc1573fb8..7ff77522e 100644 --- a/pyramid/paster.py +++ b/pyramid/paster.py @@ -195,3 +195,137 @@ class PRoutesCommand(PCommand): (IViewClassifier, request_iface, Interface), IView, name='', default=None) self.out(fmt % (route.name, route.pattern, view_callable)) + +class PViewsCommand(PCommand): + """Print, for a given URL, the views that might match. Underneath each + potentially matching route, list the predicates required. Underneath + each route+predicate set, print each view that might match and its + predicates. + + This command accepts three positional arguments: + + ``config_file`` -- specifies the PasteDeploy config file to use + for the interactive shell. + + ``section_name`` -- specifies the section name in the PasteDeploy + config file that represents the application. + + ``url`` -- specifies the URL that will be used to find matching views. + + Example:: + + $ paster proutes myapp.ini main url + + .. note:: You should use a ``section_name`` that refers to the + actual ``app`` section in the config file that points at + your Pyramid app without any middleware wrapping, or this + command will almost certainly fail. + """ + summary = "Print all views in an application that might match a URL" + min_args = 3 + max_args = 3 + stdout = sys.stdout + + parser = Command.standard_parser(simulate=True) + + def out(self, msg): # pragma: no cover + print msg + + def _find_view(self, url, registry): + """ + Accept ``url`` and ``registry``; create a :term:`request` and + find a :app:`Pyramid` view based on introspection of :term:`view + configuration` within the application registry; return the view. + """ + from zope.interface import providedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IRootFactory + from pyramid.interfaces import IRouteRequest + from pyramid.interfaces import IRequestFactory + from pyramid.interfaces import IRoutesMapper + from pyramid.interfaces import ITraverser + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.request import Request + from pyramid.traversal import DefaultRootFactory + from pyramid.traversal import ResourceTreeTraverser + + q = registry.queryUtility + root_factory = q(IRootFactory, default=DefaultRootFactory) + routes_mapper = q(IRoutesMapper) + request_factory = q(IRequestFactory, default=Request) + + adapters = registry.adapters + request = None + + # create the request + environ = { + 'wsgi.url_scheme':'http', + 'SERVER_NAME':'localhost', + 'SERVER_PORT':'8080', + 'REQUEST_METHOD':'GET', + 'PATH_INFO':url, + } + request = request_factory(environ) + context = None + attrs = request.__dict__ + attrs['registry'] = registry + request_iface = IRequest + + # find the root object + root_factory = root_factory + if routes_mapper is not None: + info = routes_mapper(request) + match, route = info['match'], info['route'] + if route is not None: + attrs['matchdict'] = match + attrs['matched_route'] = route + + request_iface = registry.queryUtility( + IRouteRequest, + name=route.name, + default=IRequest) + root_factory = route.factory or root_factory + + root = root_factory(request) + attrs['root'] = root + + # find a context + traverser = adapters.queryAdapter(root, ITraverser) + if traverser is None: + traverser = ResourceTreeTraverser(root) + tdict = traverser(request) + context, view_name, subpath, traversed, vroot, vroot_path =( + tdict['context'], tdict['view_name'], tdict['subpath'], + tdict['traversed'], tdict['virtual_root'], + tdict['virtual_root_path']) + attrs.update(tdict) + + # find a view callable + context_iface = providedBy(context) + view_callable = adapters.lookup( + (IViewClassifier, request_iface, context_iface), + IView, name=view_name, default=None) + + return view_callable + + def command(self): + from pyramid.interfaces import IMultiView + + config_file, section_name, url = self.args + app = self.get_app(config_file, section_name, loadapp=self.loadapp[0]) + registry = app.registry + view = self._find_view(url, registry) + self.out('') + self.out(url) + if IMultiView.providedBy(view): + for dummy, view_wrapper, dummy in view.views: + self.out('') + for p in view_wrapper.__predicates__: + text = getattr(p, '__text__', p.__name__) + self.out(" %s" % text) + self.out(" %s" % str(view_wrapper.__original_view__)) + else: + self.out('') + self.out(view) + diff --git a/setup.py b/setup.py index 7c7c80040..4ab4cca82 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,7 @@ setup(name='pyramid', [paste.paster_command] pshell=pyramid.paster:PShellCommand proutes=pyramid.paster:PRoutesCommand + pviews=pyramid.paster:PViewsCommand [console_scripts] bfg2pyramid = pyramid.fixers.fix_bfg_imports:main """ -- cgit v1.2.3 From 94c2dc0bae9cf14cc6a5548119933e4477d07042 Mon Sep 17 00:00:00 2001 From: cguardia Date: Mon, 18 Apr 2011 15:14:24 -0500 Subject: test adding theme as a submodule --- .gitmodules | 3 +++ docs/.gitignore | 1 - docs/Makefile | 3 ++- docs/_themes | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 160000 docs/_themes diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..45397942b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs/_themes"] + path = docs/_themes + url = git://github.com/Pylons/pylons_sphinx_theme.git diff --git a/docs/.gitignore b/docs/.gitignore index 1e9e0413c..d4e11e5ea 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,3 +1,2 @@ _build -_themes diff --git a/docs/Makefile b/docs/Makefile index 1d032cf45..3fbf56d0a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -85,4 +85,5 @@ epub: @echo "Build finished. The epub file is in _build/epub." _themes: - git clone git://github.com/Pylons/pylons_sphinx_theme.git _themes + git submodule init + git submodule update diff --git a/docs/_themes b/docs/_themes new file mode 160000 index 000000000..53898ec57 --- /dev/null +++ b/docs/_themes @@ -0,0 +1 @@ +Subproject commit 53898ec579a1c31e8780824c0a255eca004e0e56 -- cgit v1.2.3 From f2d5cb59deba682d7c1d461ab5e90ba1802d42ac Mon Sep 17 00:00:00 2001 From: cguardia Date: Mon, 18 Apr 2011 21:41:37 -0500 Subject: fixed makefile to update theme submodule correctly --- docs/Makefile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 3fbf56d0a..21e91d114 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -25,7 +25,7 @@ help: clean: -rm -rf _build/* -html: _themes +html: theme mkdir -p _build/html _build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @@ -47,7 +47,7 @@ pickle: web: pickle -htmlhelp: _themes +htmlhelp: theme mkdir -p _build/htmlhelp _build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @@ -84,6 +84,5 @@ epub: @echo @echo "Build finished. The epub file is in _build/epub." -_themes: - git submodule init - git submodule update +theme: + cd ..;git submodule update --init;cd docs -- cgit v1.2.3 From 9c0b0adf505444831704879a00f299ad74837284 Mon Sep 17 00:00:00 2001 From: cguardia Date: Tue, 19 Apr 2011 02:04:30 -0500 Subject: added requirement file to test rtd integration --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..d94f7c98b --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pyramid -- cgit v1.2.3 From 5d150878d489ee90737f3a35e609adbb55de53c3 Mon Sep 17 00:00:00 2001 From: cguardia Date: Tue, 19 Apr 2011 02:15:48 -0500 Subject: changed requirements file to test rtd integration --- requirements.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requirements.txt b/requirements.txt index d94f7c98b..f79a2aab7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,5 @@ pyramid +zope.configuration +zope.deprecation +zope.component +repoze.sphinx.autointerface -- cgit v1.2.3 From 1b395e6d43b9450ea652d9addb675936b507ea52 Mon Sep 17 00:00:00 2001 From: cguardia Date: Sun, 24 Apr 2011 23:58:32 -0500 Subject: finished paster views command and 100% test coverage --- pyramid/config.py | 21 +- pyramid/paster.py | 158 ++++++++++++--- pyramid/tests/test_config.py | 18 +- pyramid/tests/test_paster.py | 443 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 604 insertions(+), 36 deletions(-) diff --git a/pyramid/config.py b/pyramid/config.py index ef520e053..6206d64c4 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2441,7 +2441,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if xhr: def xhr_predicate(context, request): return request.is_xhr - xhr_predicate.__text__ = "XHR = True" + xhr_predicate.__text__ = "xhr = True" weights.append(1 << 1) predicates.append(xhr_predicate) h.update('xhr:%r' % bool(xhr)) @@ -2449,7 +2449,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if request_method is not None: def request_method_predicate(context, request): return request.method == request_method - msg = "Request method = %s" + msg = "request method = %s" request_method_predicate.__text__ = msg % request_method weights.append(1 << 2) predicates.append(request_method_predicate) @@ -2513,6 +2513,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if accept is not None: def accept_predicate(context, request): return accept in request.accept + accept_predicate.__text__ = "accept = %s" % accept weights.append(1 << 6) predicates.append(accept_predicate) h.update('accept:%r' % accept) @@ -2520,6 +2521,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if containment is not None: def containment_predicate(context, request): return find_interface(context, containment) is not None + containment_predicate.__text__ = "containment = %s" % containment weights.append(1 << 7) predicates.append(containment_predicate) h.update('containment:%r' % hash(containment)) @@ -2527,6 +2529,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if request_type is not None: def request_type_predicate(context, request): return request_type.providedBy(request) + msg = "request type = %s" % request_type + request_type_predicate.__text__ = msg weights.append(1 << 8) predicates.append(request_type_predicate) h.update('request_type:%r' % hash(request_type)) @@ -2545,6 +2549,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, tvalue = tgenerate(m) m['traverse'] = traversal_path(tvalue) return True + traverse_predicate.__text__ = "traverse = True" # This isn't actually a predicate, it's just a infodict # modifier that injects ``traverse`` into the matchdict. As a # result, the ``traverse_predicate`` function above always @@ -2554,6 +2559,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if custom: for num, predicate in enumerate(custom): + if not hasattr(predicate, '__text__'): + predicate.__text__ = "custom predicate" predicates.append(predicate) # using hash() here rather than id() is intentional: we # want to allow custom predicates that are part of @@ -2667,9 +2674,14 @@ def preserve_view_attrs(view, wrapped_view): wrapped_view.__call_permissive__ = view.__call_permissive__ except AttributeError: pass + try: + wrapped_view.__permission__ = view.__permission__ + except AttributeError: + pass try: wrapped_view.__predicated__ = view.__predicated__ - wrapped_view.__predicates__ = view.__predicates__ + wrapped_view.__predicates__ = [p.__text__ + for p in view.__predicates__] except AttributeError: pass try: @@ -2757,6 +2769,7 @@ class ViewDeriver(object): raise Forbidden(msg, result) _secured_view.__call_permissive__ = view _secured_view.__permitted__ = _permitted + _secured_view.__permission__ = permission wrapped_view = _secured_view return wrapped_view @@ -2830,6 +2843,8 @@ class ViewDeriver(object): attr_view.__accept__ = accept attr_view.__order__ = order attr_view.__phash__ = phash + attr_view.__view_attr__ = self.kw.get('attr') + attr_view.__permission__ = self.kw.get('permission') return attr_view @wraps_view diff --git a/pyramid/paster.py b/pyramid/paster.py index 7ff77522e..4437db497 100644 --- a/pyramid/paster.py +++ b/pyramid/paster.py @@ -231,6 +231,17 @@ class PViewsCommand(PCommand): def out(self, msg): # pragma: no cover print msg + def _find_multi_routes(self, mapper, request): + infos = [] + path = request.environ['PATH_INFO'] + # find all routes that match path, regardless of predicates + for route in mapper.get_routes(): + match = route.match(path) + if match is not None: + info = {'match':match, 'route':route} + infos.append(info) + return infos + def _find_view(self, url, registry): """ Accept ``url`` and ``registry``; create a :term:`request` and @@ -238,12 +249,14 @@ class PViewsCommand(PCommand): configuration` within the application registry; return the view. """ from zope.interface import providedBy + from zope.interface import implements from pyramid.interfaces import IRequest from pyramid.interfaces import IRootFactory from pyramid.interfaces import IRouteRequest from pyramid.interfaces import IRequestFactory from pyramid.interfaces import IRoutesMapper from pyramid.interfaces import ITraverser + from pyramid.interfaces import IMultiView from pyramid.interfaces import IView from pyramid.interfaces import IViewClassifier from pyramid.request import Request @@ -258,6 +271,32 @@ class PViewsCommand(PCommand): adapters = registry.adapters request = None + class RoutesMultiView(object): + implements(IMultiView) + + def __init__(self, infos, context_iface, subpath): + self.views = [] + for info in infos: + match, route = info['match'], info['route'] + if route is not None: + request_iface = registry.queryUtility( + IRouteRequest, + name=route.name, + default=IRequest) + view = adapters.lookup( + (IViewClassifier, request_iface, context_iface), + IView, name='', default=None) + if view is None: + continue + view.__predicates__ = [p.__text__ + for p in route.predicates] + view.__route_attrs__ = {'matchdict': match, + 'matched_route': route, + 'subpath': subpath} + view.__view_attr__ = '' + self.views.append((None, view, None)) + + # create the request environ = { 'wsgi.url_scheme':'http', @@ -268,24 +307,28 @@ class PViewsCommand(PCommand): } request = request_factory(environ) context = None + routes_multiview = None attrs = request.__dict__ attrs['registry'] = registry request_iface = IRequest # find the root object - root_factory = root_factory if routes_mapper is not None: - info = routes_mapper(request) - match, route = info['match'], info['route'] - if route is not None: - attrs['matchdict'] = match - attrs['matched_route'] = route - - request_iface = registry.queryUtility( - IRouteRequest, - name=route.name, - default=IRequest) - root_factory = route.factory or root_factory + infos = self._find_multi_routes(routes_mapper, request) + if len(infos) == 1: + info = infos[0] + match, route = info['match'], info['route'] + if route is not None: + attrs['matchdict'] = match + attrs['matched_route'] = route + + request_iface = registry.queryUtility( + IRouteRequest, + name=route.name, + default=IRequest) + root_factory = route.factory or root_factory + if len(infos) > 1: + routes_multiview = infos root = root_factory(request) attrs['root'] = root @@ -303,29 +346,94 @@ class PViewsCommand(PCommand): # find a view callable context_iface = providedBy(context) - view_callable = adapters.lookup( - (IViewClassifier, request_iface, context_iface), - IView, name=view_name, default=None) - - return view_callable + if routes_multiview is None: + view = adapters.lookup( + (IViewClassifier, request_iface, context_iface), + IView, name=view_name, default=None) + else: + view = RoutesMultiView(infos, context_iface, subpath) + + # routes are not registered with a view name + if view is None: + view = adapters.lookup( + (IViewClassifier, request_iface, context_iface), + IView, name='', default=None) + # we don't want a multiview here + if IMultiView.providedBy(view): + view = None + + if view is not None: + view.__request_attrs__ = attrs + + return view + + def output_route_attrs(self, attrs): + if 'matched_route' in attrs: + route = attrs['matched_route'] + self.out(" route name: %s" % route.name) + self.out(" route pattern: %s" % route.pattern) + self.out(" route path: %s" % route.path) + self.out(" subpath: %s" % '/'.join(attrs['subpath'])) + + def output_view_attrs(self, attrs): + self.out(" context: %s" % attrs['context']) + self.out(" view name: %s" % attrs['view_name']) + + def output_multiview_info(self, view_wrapper): + name = view_wrapper.__name__ + module = view_wrapper.__module__ + attr = view_wrapper.__view_attr__ + route_attrs = getattr(view_wrapper, '__route_attrs__', {}) + self.out('') + self.out(" View:") + self.out(" -----") + self.out(" %s.%s.%s" % (module, name, attr)) + self.output_route_attrs(route_attrs) + permission = getattr(view_wrapper, '__permission__', None) + if permission is not None: + self.out(" required permission = %s" % permission) + predicates = getattr(view_wrapper, '__predicates__', None) + if predicates is not None: + for text in predicates: + self.out(" %s" % text) + + def output_view_info(self, view): + if view is not None: + name = getattr(view, '__name__', view.__class__.__name__) + module = view.__module__ + else: + module = 'Not found' + name = '' + self.out('') + self.out(" View:") + self.out(" -----") + self.out(" %s.%s" % (module, name)) + permission = getattr(view, '__permission__', None) + if permission is not None: + self.out(" required permission = %s" % permission) + predicates = getattr(view, '__predicates__', None) + if predicates is not None: + for text in predicates: + self.out(" %s" % text) def command(self): from pyramid.interfaces import IMultiView config_file, section_name, url = self.args + if not url.startswith('/'): + url = '/%s' % url app = self.get_app(config_file, section_name, loadapp=self.loadapp[0]) registry = app.registry view = self._find_view(url, registry) self.out('') - self.out(url) + self.out("URL = %s" % url) + if view is not None: + self.output_view_attrs(view.__request_attrs__) + self.output_route_attrs(view.__request_attrs__) if IMultiView.providedBy(view): for dummy, view_wrapper, dummy in view.views: - self.out('') - for p in view_wrapper.__predicates__: - text = getattr(p, '__text__', p.__name__) - self.out(" %s" % text) - self.out(" %s" % str(view_wrapper.__original_view__)) + self.output_multiview_info(view_wrapper) else: - self.out('') - self.out(view) + self.output_view_info(view) + self.out('') diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index d2ff65878..d5903d4fb 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -4218,7 +4218,7 @@ class Test__make_predicates(unittest.TestCase): accept='accept', containment='containment', request_type='request_type', - custom=('a',) + custom=(DummyCustomPredicate(),), ) order2, _, _ = self._callFUT( xhr='xhr', @@ -4229,7 +4229,7 @@ class Test__make_predicates(unittest.TestCase): accept='accept', containment='containment', request_type='request_type', - custom=('a',) + custom=(DummyCustomPredicate(),), ) order3, _, _ = self._callFUT( xhr='xhr', @@ -4322,7 +4322,7 @@ class Test__make_predicates(unittest.TestCase): request_type='request_type', ) order9, _, _ = self._callFUT( - custom=('a',), + custom=(DummyCustomPredicate(),), ) self.failUnless(order1 > order2) self.failUnless(order2 > order3) @@ -4339,7 +4339,7 @@ class Test__make_predicates(unittest.TestCase): request_method='request_method', ) order2, _, _ = self._callFUT( - custom=('a',), + custom=(DummyCustomPredicate(),), ) self.failUnless(order1 < order2) @@ -4349,7 +4349,7 @@ class Test__make_predicates(unittest.TestCase): ) order2, _, _ = self._callFUT( request_method='request_method', - custom=('a',), + custom=(DummyCustomPredicate(),), ) self.failUnless(order1 > order2) @@ -4360,7 +4360,7 @@ class Test__make_predicates(unittest.TestCase): ) order2, _, _ = self._callFUT( request_method='request_method', - custom=('a',), + custom=(DummyCustomPredicate(),), ) self.failUnless(order1 < order2) @@ -4372,7 +4372,7 @@ class Test__make_predicates(unittest.TestCase): order2, _, _ = self._callFUT( xhr='xhr', request_method='request_method', - custom=('a',), + custom=(DummyCustomPredicate(),), ) self.failUnless(order1 > order2) @@ -4977,6 +4977,10 @@ class DummyStaticURLInfo: def add(self, name, spec, **kw): self.added.append((name, spec, kw)) +class DummyCustomPredicate(object): + def __init__(self): + self.__text__ = 'custom predicate' + def dummy_view(request): return 'OK' diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py index 35349b7c7..85a79b681 100644 --- a/pyramid/tests/test_paster.py +++ b/pyramid/tests/test_paster.py @@ -248,7 +248,419 @@ class TestPRoutesCommand(unittest.TestCase): result = command._get_mapper(app) self.assertEqual(result.__class__, RoutesMapper) +class TestPViewsCommand(unittest.TestCase): + def _getTargetClass(self): + from pyramid.paster import PViewsCommand + return PViewsCommand + + def _makeOne(self): + return self._getTargetClass()('pviews') + + def test__find_view_no_match(self): + from pyramid.registry import Registry + registry = Registry() + self._register_mapper(registry, []) + command = self._makeOne() + result = command._find_view('/a', registry) + self.assertEqual(result, None) + + def test__find_view_no_match_multiview_registered(self): + from zope.interface import implements + from zope.interface import providedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + from pyramid.traversal import DefaultRootFactory + from pyramid.registry import Registry + registry = Registry() + class View1(object): + implements(IMultiView) + request = DummyRequest({'PATH_INFO':'/a'}) + root = DefaultRootFactory(request) + root_iface = providedBy(root) + registry.registerAdapter(View1(), + (IViewClassifier, IRequest, root_iface), + IMultiView) + self._register_mapper(registry, []) + command = self._makeOne() + result = command._find_view('/x', registry) + self.assertEqual(result, None) + + def test__find_view_traversal(self): + from zope.interface import providedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IView + from pyramid.traversal import DefaultRootFactory + from pyramid.registry import Registry + registry = Registry() + def view1(): pass + request = DummyRequest({'PATH_INFO':'/a'}) + root = DefaultRootFactory(request) + root_iface = providedBy(root) + registry.registerAdapter(view1, + (IViewClassifier, IRequest, root_iface), + IView, name='a') + self._register_mapper(registry, []) + command = self._makeOne() + result = command._find_view('/a', registry) + self.assertEqual(result, view1) + + def test__find_view_traversal_multiview(self): + from zope.interface import implements + from zope.interface import providedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + from pyramid.traversal import DefaultRootFactory + from pyramid.registry import Registry + registry = Registry() + class View1(object): + implements(IMultiView) + request = DummyRequest({'PATH_INFO':'/a'}) + root = DefaultRootFactory(request) + root_iface = providedBy(root) + view = View1() + registry.registerAdapter(view, + (IViewClassifier, IRequest, root_iface), + IMultiView, name='a') + self._register_mapper(registry, []) + command = self._makeOne() + result = command._find_view('/a', registry) + self.assertEqual(result, view) + + def test__find_view_route_no_multiview(self): + from zope.interface import Interface + from zope.interface import implements + from pyramid.interfaces import IRouteRequest + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IView + from pyramid.registry import Registry + registry = Registry() + def view():pass + class IMyRoot(Interface): + pass + class IMyRoute(Interface): + pass + registry.registerAdapter(view, + (IViewClassifier, IMyRoute, IMyRoot), + IView, '') + registry.registerUtility(IMyRoute, IRouteRequest, name='a') + class Factory(object): + implements(IMyRoot) + def __init__(self, request): + pass + routes = [DummyRoute('a', '/a', factory=Factory), + DummyRoute('b', '/b', factory=Factory, will_match=False)] + self._register_mapper(registry, routes) + command = self._makeOne() + result = command._find_view('/a', registry) + self.assertEqual(result, view) + + def test__find_view_route_multiview_no_view_registered(self): + from zope.interface import Interface + from zope.interface import implements + from pyramid.interfaces import IRouteRequest + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IRootFactory + from pyramid.registry import Registry + registry = Registry() + def view1():pass + def view2():pass + class IMyRoot(Interface): + pass + class IMyRoute1(Interface): + pass + class IMyRoute2(Interface): + pass + registry.registerUtility(IMyRoute1, IRouteRequest, name='a') + registry.registerUtility(IMyRoute2, IRouteRequest, name='b') + class Factory(object): + implements(IMyRoot) + def __init__(self, request): + pass + registry.registerUtility(Factory, IRootFactory) + routes = [DummyRoute('a', '/a'), + DummyRoute('b', '/a')] + self._register_mapper(registry, routes) + command = self._makeOne() + result = command._find_view('/a', registry) + self.failUnless(IMultiView.providedBy(result)) + + def test__find_view_route_multiview(self): + from zope.interface import Interface + from zope.interface import implements + from pyramid.interfaces import IRouteRequest + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IRootFactory + from pyramid.registry import Registry + registry = Registry() + def view1():pass + def view2():pass + class IMyRoot(Interface): + pass + class IMyRoute1(Interface): + pass + class IMyRoute2(Interface): + pass + registry.registerAdapter(view1, + (IViewClassifier, IMyRoute1, IMyRoot), + IView, '') + registry.registerAdapter(view2, + (IViewClassifier, IMyRoute2, IMyRoot), + IView, '') + registry.registerUtility(IMyRoute1, IRouteRequest, name='a') + registry.registerUtility(IMyRoute2, IRouteRequest, name='b') + class Factory(object): + implements(IMyRoot) + def __init__(self, request): + pass + registry.registerUtility(Factory, IRootFactory) + routes = [DummyRoute('a', '/a'), + DummyRoute('b', '/a')] + self._register_mapper(registry, routes) + command = self._makeOne() + result = command._find_view('/a', registry) + self.failUnless(IMultiView.providedBy(result)) + self.assertEqual(len(result.views), 2) + self.failUnless((None, view1, None) in result.views) + self.failUnless((None, view2, None) in result.views) + + def test__find_multi_routes_all_match(self): + command = self._makeOne() + def factory(request): pass + routes = [DummyRoute('a', '/a', factory=factory), + DummyRoute('b', '/a', factory=factory)] + mapper = DummyMapper(*routes) + request = DummyRequest({'PATH_INFO':'/a'}) + result = command._find_multi_routes(mapper, request) + self.assertEqual(result, [{'match':True, 'route':routes[0]}, + {'match':True, 'route':routes[1]}]) + + def test__find_multi_routes_some_match(self): + command = self._makeOne() + def factory(request): pass + routes = [DummyRoute('a', '/a', factory=factory, will_match=False), + DummyRoute('b', '/a', factory=factory)] + mapper = DummyMapper(*routes) + request = DummyRequest({'PATH_INFO':'/a'}) + result = command._find_multi_routes(mapper, request) + self.assertEqual(result, [{'match':True, 'route':routes[1]}]) + + def test__find_multi_routes_none_match(self): + command = self._makeOne() + def factory(request): pass + routes = [DummyRoute('a', '/a', factory=factory, will_match=False), + DummyRoute('b', '/a', factory=factory, will_match=False)] + mapper = DummyMapper(*routes) + request = DummyRequest({'PATH_INFO':'/a'}) + result = command._find_multi_routes(mapper, request) + self.assertEqual(result, []) + def test_views_command_not_found(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + command._find_view = lambda arg1, arg2: None + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[5], ' Not found.') + + def test_views_command_not_found_url_starts_without_slash(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + command._find_view = lambda arg1, arg2: None + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', 'a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[5], ' Not found.') + + def test_views_command_single_view_traversal(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context', view_name='a') + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') + + def test_views_command_single_view_traversal_with_permission(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context', view_name='a') + view.__permission__ = 'test' + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[8], ' required permission = test') + + def test_views_command_single_view_traversal_with_predicates(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context', view_name='a') + view.__predicates__ = ['predicate = x'] + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[8], ' predicate = x') + + def test_views_command_single_view_route(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + route = DummyRoute('a', '/a') + view = DummyView(context='context', view_name='a', + matched_route=route, subpath='') + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[4], ' route name: a') + self.assertEqual(L[5], ' route pattern: /a') + self.assertEqual(L[6], ' route path: /a') + self.assertEqual(L[7], ' subpath: ') + self.assertEqual(L[11], ' pyramid.tests.test_paster.DummyView') + + def test_views_command_multiview(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context') + view.__name__ = 'view' + view.__view_attr__ = 'call' + multiview = DummyMultiView(view, context='context', view_name='a') + command._find_view = lambda arg1, arg2: multiview + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') + + def test_views_command_multiview_with_permission(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context') + view.__name__ = 'view' + view.__view_attr__ = 'call' + view.__permission__ = 'test' + multiview = DummyMultiView(view, context='context', view_name='a') + command._find_view = lambda arg1, arg2: multiview + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') + self.assertEqual(L[8], ' required permission = test') + + def test_views_command_multiview_with_predicates(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view = DummyView(context='context') + view.__name__ = 'view' + view.__view_attr__ = 'call' + view.__predicates__ = ['predicate = x'] + multiview = DummyMultiView(view, context='context', view_name='a') + command._find_view = lambda arg1, arg2: multiview + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[2], ' context: context') + self.assertEqual(L[3], ' view name: a') + self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') + self.assertEqual(L[8], ' predicate = x') + + def _register_mapper(self, registry, routes): + from pyramid.interfaces import IRoutesMapper + mapper = DummyMapper(*routes) + registry.registerUtility(mapper, IRoutesMapper) + class TestGetApp(unittest.TestCase): def _callFUT(self, config_file, section_name, loadapp): from pyramid.paster import get_app @@ -336,8 +748,37 @@ class DummyMapper(object): return self.routes class DummyRoute(object): - def __init__(self, name, pattern, factory=None): + def __init__(self, name, pattern, factory=None, will_match=True): self.name = name + self.path = pattern self.pattern = pattern self.factory = factory + if not will_match: + self.will_match = None + else: + self.will_match = will_match + self.predicates = [] + + def match(self, route): + return self.will_match +class DummyRequest: + application_url = 'http://example.com:5432' + script_name = '' + def __init__(self, environ): + self.environ = environ + self.matchdict = {} + +class DummyView(object): + def __init__(self, **attrs): + self.__request_attrs__ = attrs + +class DummyMultiView(object): + from zope.interface import implements + from pyramid.interfaces import IMultiView + implements(IMultiView) + + def __init__(self, *views, **attrs): + self.views = [(None, view, None) for view in views] + self.__request_attrs__ = attrs + -- cgit v1.2.3 From a9e7e6f2d1761995ad8f6345de3b7f901530797b Mon Sep 17 00:00:00 2001 From: cguardia Date: Mon, 25 Apr 2011 10:51:47 -0500 Subject: added to contibutor list --- CONTRIBUTORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 75f9e9166..f2195de70 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -131,6 +131,8 @@ Contributors - Malthe Borch, 2011/02/28 +- Carlos de la Guardia, 2011/03/29 + - Joel Bohman, 2011/04/16 - Juliusz Gonera, 2011/04/17 -- cgit v1.2.3 From 3080ffd838ca3c163b3aeb35b63a774bcddedb92 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 27 Apr 2011 00:52:30 -0500 Subject: use __doc__ instead of __text__ for predicate description --- pyramid/config.py | 24 ++++++++++++------------ pyramid/paster.py | 2 +- pyramid/tests/test_config.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pyramid/config.py b/pyramid/config.py index a24392302..5008e42fb 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2486,7 +2486,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if xhr: def xhr_predicate(context, request): return request.is_xhr - xhr_predicate.__text__ = "xhr = True" + xhr_predicate.__doc__ = "xhr = True" weights.append(1 << 1) predicates.append(xhr_predicate) h.update('xhr:%r' % bool(xhr)) @@ -2495,7 +2495,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, def request_method_predicate(context, request): return request.method == request_method msg = "request method = %s" - request_method_predicate.__text__ = msg % request_method + request_method_predicate.__doc__ = msg % request_method weights.append(1 << 2) predicates.append(request_method_predicate) h.update('request_method:%r' % request_method) @@ -2508,7 +2508,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, def path_info_predicate(context, request): return path_info_val.match(request.path_info) is not None msg = "path_info = %s" - path_info_predicate.__text__ = msg % path_info + path_info_predicate.__doc__ = msg % path_info weights.append(1 << 3) predicates.append(path_info_predicate) h.update('path_info:%r' % path_info) @@ -2525,7 +2525,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, msg = "request_param %s" % request_param else: msg = "request_param %s = %s" % (request_param, request_param_val) - request_param_predicate.__text__ = msg + request_param_predicate.__doc__ = msg weights.append(1 << 4) predicates.append(request_param_predicate) h.update('request_param:%r=%r' % (request_param, request_param_val)) @@ -2550,7 +2550,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, msg = "header %s" % header_name else: msg = "header %s = %s" % (header_name, header_val) - header_predicate.__text__ = msg + header_predicate.__doc__ = msg weights.append(1 << 5) predicates.append(header_predicate) h.update('header:%r=%r' % (header_name, header_val)) @@ -2558,7 +2558,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if accept is not None: def accept_predicate(context, request): return accept in request.accept - accept_predicate.__text__ = "accept = %s" % accept + accept_predicate.__doc__ = "accept = %s" % accept weights.append(1 << 6) predicates.append(accept_predicate) h.update('accept:%r' % accept) @@ -2566,7 +2566,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if containment is not None: def containment_predicate(context, request): return find_interface(context, containment) is not None - containment_predicate.__text__ = "containment = %s" % containment + containment_predicate.__doc__ = "containment = %s" % containment weights.append(1 << 7) predicates.append(containment_predicate) h.update('containment:%r' % hash(containment)) @@ -2575,7 +2575,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, def request_type_predicate(context, request): return request_type.providedBy(request) msg = "request type = %s" % request_type - request_type_predicate.__text__ = msg + request_type_predicate.__doc__ = msg weights.append(1 << 8) predicates.append(request_type_predicate) h.update('request_type:%r' % hash(request_type)) @@ -2594,7 +2594,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, tvalue = tgenerate(m) m['traverse'] = traversal_path(tvalue) return True - traverse_predicate.__text__ = "traverse = True" + traverse_predicate.__doc__ = "traverse = True" # This isn't actually a predicate, it's just a infodict # modifier that injects ``traverse`` into the matchdict. As a # result, the ``traverse_predicate`` function above always @@ -2604,8 +2604,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if custom: for num, predicate in enumerate(custom): - if not hasattr(predicate, '__text__'): - predicate.__text__ = "custom predicate" + if not hasattr(predicate, '__doc__'): + predicate.__doc__ = "custom predicate" predicates.append(predicate) # using hash() here rather than id() is intentional: we # want to allow custom predicates that are part of @@ -2725,7 +2725,7 @@ def preserve_view_attrs(view, wrapped_view): pass try: wrapped_view.__predicated__ = view.__predicated__ - wrapped_view.__predicates__ = [p.__text__ + wrapped_view.__predicates__ = [p.__doc__ for p in view.__predicates__] except AttributeError: pass diff --git a/pyramid/paster.py b/pyramid/paster.py index a94b4f2d3..368b5de5d 100644 --- a/pyramid/paster.py +++ b/pyramid/paster.py @@ -293,7 +293,7 @@ class PViewsCommand(PCommand): IView, name='', default=None) if view is None: continue - view.__predicates__ = [p.__text__ + view.__predicates__ = [p.__doc__ for p in route.predicates] view.__route_attrs__ = {'matchdict': match, 'matched_route': route, diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index f52d194b6..2bd24ac26 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -5049,7 +5049,7 @@ class DummyStaticURLInfo: class DummyCustomPredicate(object): def __init__(self): - self.__text__ = 'custom predicate' + self.__doc__ = 'custom predicate' def dummy_view(request): return 'OK' -- cgit v1.2.3 From dd13d9f238fd216485df2233967ecfbf809f38bd Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 27 Apr 2011 00:57:50 -0500 Subject: removed line that will never be executed --- pyramid/config.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyramid/config.py b/pyramid/config.py index 5008e42fb..0891ce6df 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2604,8 +2604,6 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if custom: for num, predicate in enumerate(custom): - if not hasattr(predicate, '__doc__'): - predicate.__doc__ = "custom predicate" predicates.append(predicate) # using hash() here rather than id() is intentional: we # want to allow custom predicates that are part of -- cgit v1.2.3 From 10b8a7120f35497bfea83d2ade2c2915c96861d4 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 27 Apr 2011 02:00:30 -0400 Subject: use __doc__ instead of __text__ to represent predicate output; inject bfg.routes.matchdict into environ to prevent return of wrong subpath; expose __predicates__ as actual predicates rather than text for ease of copying (although i dont like it) --- pyramid/config.py | 46 ++++++++++++++++++++--------------------- pyramid/paster.py | 13 ++++++------ pyramid/tests/test_paster.py | 49 ++++++++++++++++++++++---------------------- 3 files changed, 53 insertions(+), 55 deletions(-) diff --git a/pyramid/config.py b/pyramid/config.py index 6206d64c4..a0c3f7a00 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2440,17 +2440,16 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if xhr: def xhr_predicate(context, request): + """xhr = True""" return request.is_xhr - xhr_predicate.__text__ = "xhr = True" weights.append(1 << 1) predicates.append(xhr_predicate) h.update('xhr:%r' % bool(xhr)) if request_method is not None: def request_method_predicate(context, request): + """request_method = %s""" % request_method return request.method == request_method - msg = "request method = %s" - request_method_predicate.__text__ = msg % request_method weights.append(1 << 2) predicates.append(request_method_predicate) h.update('request_method:%r' % request_method) @@ -2461,9 +2460,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, except re.error, why: raise ConfigurationError(why[0]) def path_info_predicate(context, request): + """path_info = %s""" % path_info return path_info_val.match(request.path_info) is not None - msg = "path_info = %s" - path_info_predicate.__text__ = msg % path_info weights.append(1 << 3) predicates.append(path_info_predicate) h.update('path_info:%r' % path_info) @@ -2472,15 +2470,15 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, request_param_val = None if '=' in request_param: request_param, request_param_val = request_param.split('=', 1) - def request_param_predicate(context, request): - if request_param_val is None: - return request_param in request.params - return request.params.get(request_param) == request_param_val if request_param_val is None: msg = "request_param %s" % request_param else: msg = "request_param %s = %s" % (request_param, request_param_val) - request_param_predicate.__text__ = msg + def request_param_predicate(context, request): + """%s""" % msg + if request_param_val is None: + return request_param in request.params + return request.params.get(request_param) == request_param_val weights.append(1 << 4) predicates.append(request_param_predicate) h.update('request_param:%r=%r' % (request_param, request_param_val)) @@ -2494,43 +2492,42 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, header_val = re.compile(header_val) except re.error, why: raise ConfigurationError(why[0]) + if header_val is None: + msg = "header %s" % header_name + else: + msg = "header %s = %s" % (header_name, header_val) def header_predicate(context, request): + """%s""" % msg if header_val is None: return header_name in request.headers val = request.headers.get(header_name) if val is None: return False return header_val.match(val) is not None - if header_val is None: - msg = "header %s" % header_name - else: - msg = "header %s = %s" % (header_name, header_val) - header_predicate.__text__ = msg weights.append(1 << 5) predicates.append(header_predicate) h.update('header:%r=%r' % (header_name, header_val)) if accept is not None: def accept_predicate(context, request): + """accept = %s""" % accept return accept in request.accept - accept_predicate.__text__ = "accept = %s" % accept weights.append(1 << 6) predicates.append(accept_predicate) h.update('accept:%r' % accept) if containment is not None: def containment_predicate(context, request): + """containment = %s""" % containment return find_interface(context, containment) is not None - containment_predicate.__text__ = "containment = %s" % containment weights.append(1 << 7) predicates.append(containment_predicate) h.update('containment:%r' % hash(containment)) if request_type is not None: def request_type_predicate(context, request): + """request_type = %s""" % request_type return request_type.providedBy(request) - msg = "request type = %s" % request_type - request_type_predicate.__text__ = msg weights.append(1 << 8) predicates.append(request_type_predicate) h.update('request_type:%r' % hash(request_type)) @@ -2549,7 +2546,6 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, tvalue = tgenerate(m) m['traverse'] = traversal_path(tvalue) return True - traverse_predicate.__text__ = "traverse = True" # This isn't actually a predicate, it's just a infodict # modifier that injects ``traverse`` into the matchdict. As a # result, the ``traverse_predicate`` function above always @@ -2559,8 +2555,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if custom: for num, predicate in enumerate(custom): - if not hasattr(predicate, '__text__'): - predicate.__text__ = "custom predicate" + if getattr(predicate, '__doc__', None) is None: + predicate.__doc__ = "" predicates.append(predicate) # using hash() here rather than id() is intentional: we # want to allow custom predicates that are part of @@ -2680,8 +2676,10 @@ def preserve_view_attrs(view, wrapped_view): pass try: wrapped_view.__predicated__ = view.__predicated__ - wrapped_view.__predicates__ = [p.__text__ - for p in view.__predicates__] + except AttributeError: + pass + try: + wrapped_view.__predicates__ = view.__predicates__ except AttributeError: pass try: diff --git a/pyramid/paster.py b/pyramid/paster.py index 4437db497..a7d813bbc 100644 --- a/pyramid/paster.py +++ b/pyramid/paster.py @@ -288,8 +288,7 @@ class PViewsCommand(PCommand): IView, name='', default=None) if view is None: continue - view.__predicates__ = [p.__text__ - for p in route.predicates] + view.__predicates__ = list(route.predicates) view.__route_attrs__ = {'matchdict': match, 'matched_route': route, 'subpath': subpath} @@ -321,7 +320,7 @@ class PViewsCommand(PCommand): if route is not None: attrs['matchdict'] = match attrs['matched_route'] = route - + request.environ['bfg.routes.matchdict'] = match request_iface = registry.queryUtility( IRouteRequest, name=route.name, @@ -394,8 +393,8 @@ class PViewsCommand(PCommand): self.out(" required permission = %s" % permission) predicates = getattr(view_wrapper, '__predicates__', None) if predicates is not None: - for text in predicates: - self.out(" %s" % text) + for predicate in predicates: + self.out(" %s" % predicate.__doc__) def output_view_info(self, view): if view is not None: @@ -413,8 +412,8 @@ class PViewsCommand(PCommand): self.out(" required permission = %s" % permission) predicates = getattr(view, '__predicates__', None) if predicates is not None: - for text in predicates: - self.out(" %s" % text) + for predicate in predicates: + self.out(" %s" % predicate.__doc__) def command(self): from pyramid.interfaces import IMultiView diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py index 85a79b681..4d7220524 100644 --- a/pyramid/tests/test_paster.py +++ b/pyramid/tests/test_paster.py @@ -350,8 +350,8 @@ class TestPViewsCommand(unittest.TestCase): implements(IMyRoot) def __init__(self, request): pass - routes = [DummyRoute('a', '/a', factory=Factory), - DummyRoute('b', '/b', factory=Factory, will_match=False)] + routes = [DummyRoute('a', '/a', factory=Factory, matchdict={}), + DummyRoute('b', '/b', factory=Factory)] self._register_mapper(registry, routes) command = self._makeOne() result = command._find_view('/a', registry) @@ -380,8 +380,8 @@ class TestPViewsCommand(unittest.TestCase): def __init__(self, request): pass registry.registerUtility(Factory, IRootFactory) - routes = [DummyRoute('a', '/a'), - DummyRoute('b', '/a')] + routes = [DummyRoute('a', '/a', matchdict={}), + DummyRoute('b', '/a', matchdict={})] self._register_mapper(registry, routes) command = self._makeOne() result = command._find_view('/a', registry) @@ -418,8 +418,8 @@ class TestPViewsCommand(unittest.TestCase): def __init__(self, request): pass registry.registerUtility(Factory, IRootFactory) - routes = [DummyRoute('a', '/a'), - DummyRoute('b', '/a')] + routes = [DummyRoute('a', '/a', matchdict={}), + DummyRoute('b', '/a', matchdict={})] self._register_mapper(registry, routes) command = self._makeOne() result = command._find_view('/a', registry) @@ -431,29 +431,29 @@ class TestPViewsCommand(unittest.TestCase): def test__find_multi_routes_all_match(self): command = self._makeOne() def factory(request): pass - routes = [DummyRoute('a', '/a', factory=factory), - DummyRoute('b', '/a', factory=factory)] + routes = [DummyRoute('a', '/a', factory=factory, matchdict={}), + DummyRoute('b', '/a', factory=factory, matchdict={})] mapper = DummyMapper(*routes) request = DummyRequest({'PATH_INFO':'/a'}) result = command._find_multi_routes(mapper, request) - self.assertEqual(result, [{'match':True, 'route':routes[0]}, - {'match':True, 'route':routes[1]}]) + self.assertEqual(result, [{'match':{}, 'route':routes[0]}, + {'match':{}, 'route':routes[1]}]) def test__find_multi_routes_some_match(self): command = self._makeOne() def factory(request): pass - routes = [DummyRoute('a', '/a', factory=factory, will_match=False), - DummyRoute('b', '/a', factory=factory)] + routes = [DummyRoute('a', '/a', factory=factory), + DummyRoute('b', '/a', factory=factory, matchdict={})] mapper = DummyMapper(*routes) request = DummyRequest({'PATH_INFO':'/a'}) result = command._find_multi_routes(mapper, request) - self.assertEqual(result, [{'match':True, 'route':routes[1]}]) + self.assertEqual(result, [{'match':{}, 'route':routes[1]}]) def test__find_multi_routes_none_match(self): command = self._makeOne() def factory(request): pass - routes = [DummyRoute('a', '/a', factory=factory, will_match=False), - DummyRoute('b', '/a', factory=factory, will_match=False)] + routes = [DummyRoute('a', '/a', factory=factory), + DummyRoute('b', '/a', factory=factory)] mapper = DummyMapper(*routes) request = DummyRequest({'PATH_INFO':'/a'}) result = command._find_multi_routes(mapper, request) @@ -541,8 +541,10 @@ class TestPViewsCommand(unittest.TestCase): registry = Registry() L = [] command.out = L.append + def predicate(): + """predicate = x""" view = DummyView(context='context', view_name='a') - view.__predicates__ = ['predicate = x'] + view.__predicates__ = [predicate] command._find_view = lambda arg1, arg2: view app = DummyApp() app.registry = registry @@ -563,7 +565,7 @@ class TestPViewsCommand(unittest.TestCase): registry = Registry() L = [] command.out = L.append - route = DummyRoute('a', '/a') + route = DummyRoute('a', '/a', matchdict={}) view = DummyView(context='context', view_name='a', matched_route=route, subpath='') command._find_view = lambda arg1, arg2: view @@ -637,10 +639,12 @@ class TestPViewsCommand(unittest.TestCase): registry = Registry() L = [] command.out = L.append + def predicate(): + """predicate = x""" view = DummyView(context='context') view.__name__ = 'view' view.__view_attr__ = 'call' - view.__predicates__ = ['predicate = x'] + view.__predicates__ = [predicate] multiview = DummyMultiView(view, context='context', view_name='a') command._find_view = lambda arg1, arg2: multiview app = DummyApp() @@ -748,19 +752,16 @@ class DummyMapper(object): return self.routes class DummyRoute(object): - def __init__(self, name, pattern, factory=None, will_match=True): + def __init__(self, name, pattern, factory=None, matchdict=None): self.name = name self.path = pattern self.pattern = pattern self.factory = factory - if not will_match: - self.will_match = None - else: - self.will_match = will_match + self.matchdict = matchdict self.predicates = [] def match(self, route): - return self.will_match + return self.matchdict class DummyRequest: application_url = 'http://example.com:5432' -- cgit v1.2.3 From 8abf0a3c996a22dbf9b3ed4602df026a87686a74 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:11:59 -0500 Subject: code refactoring for showing route->view relationship more correctly; tests and docs for pull request --- docs/narr/urldispatch.rst | 4 ++ docs/narr/viewconfig.rst | 97 +++++++++++++++++++++++++++ pyramid/config.py | 31 +++++---- pyramid/paster.py | 132 ++++++++++++++++++++----------------- pyramid/tests/test_config.py | 22 +++++++ pyramid/tests/test_paster.py | 153 +++++++++++++++++++++++++++++++++---------- 6 files changed, 328 insertions(+), 111 deletions(-) diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 1024dd188..a180003d0 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -1121,6 +1121,10 @@ a developer to understand either of them in detail. It also means that we can allow a developer to combine :term:`URL dispatch` and :term:`traversal` in various exceptional cases as documented in :ref:`hybrid_chapter`. +To gain a better understanding of how routes and views are associated in a +real application, you can use the ``paster pviews`` command, as documented +in :ref:`displaying_matching_views`. + References ---------- diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 743cc016e..d99e5bed5 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -732,3 +732,100 @@ found will be printed to ``stderr``, and the browser representation of the error will include the same information. See :ref:`environment_chapter` for more information about how, and where to set these values. +.. index:: + pair: matching views; printing + single: paster pviews + +.. _displaying_matching_views: + +Displaying Matching Views for a Given URL +----------------------------------------- + +For a big application with several views, it can be hard to keep the view +configuration details in your head, even if you defined all the views +yourself. You can use the ``paster pviews`` command in a terminal window to +print a summary of matching routes and views for a given URL in your +application. The ``paster pviews`` command accepts three arguments. The +first argument to ``pviews`` is the path to your application's ``.ini`` file. +The second is the ``app`` section name inside the ``.ini`` file which points +to your application. The third is the URL to test for matching views. + +Here is an example for a simple view configuration using :term:`traversal`: + +.. code-block:: text + :linenos: + + $ ../bin/paster pviews development.ini tutorial /FrontPage + + URL = /FrontPage + + context: + view name: + + View: + ----- + tutorial.views.view_page + required permission = view + +The output always has the requested URL at the top and below that all the +views that matched with their view configuration details. In this example +only one view matches, so there is just a single *View* section. For each +matching view, the full code path to the associated view callable is shown, +along with any permissions and predicates that are part of that view +configuration. + +A more complex configuration might generate something like this: + +.. code-block:: text + :linenos: + + $ ../bin/paster pviews development.ini shootout /about + + URL = /about + + context: + view name: about + + Route: + ------ + route name: about + route pattern: /about + route path: /about + subpath: + route predicates (request method = GET) + + View: + ----- + shootout.views.about_view + required permission = view + view predicates (request_param testing, header X/header) + + Route: + ------ + route name: about_post + route pattern: /about + route path: /about + subpath: + route predicates (request method = POST) + + View: + ----- + shootout.views.about_view_post + required permission = view + view predicates (request_param test) + + View: + ----- + shootout.views.about_view_post2 + required permission = view + view predicates (request_param test2) + +In this case, we are dealing with a :term:`URL dispatch` application. This +specific URL has two matching routes. The matching route information is +displayed first, followed by any views that are associated with that route. +As you can see from the second matching route output, a route can be +associated with more than one view. + +For a URL that doesn't match any views, ``paster pviews`` will simply print +out a *Not found* message. + diff --git a/pyramid/config.py b/pyramid/config.py index 9aa7031e0..ca76cafb4 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2485,16 +2485,17 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if xhr: def xhr_predicate(context, request): - """xhr = True""" return request.is_xhr + xhr_predicate.__text__ = "xhr = True" weights.append(1 << 1) predicates.append(xhr_predicate) h.update('xhr:%r' % bool(xhr)) if request_method is not None: def request_method_predicate(context, request): - """request_method = %s""" % request_method return request.method == request_method + text = "request method = %s" + request_method_predicate.__text__ = text % request_method weights.append(1 << 2) predicates.append(request_method_predicate) h.update('request_method:%r' % request_method) @@ -2505,8 +2506,9 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, except re.error, why: raise ConfigurationError(why[0]) def path_info_predicate(context, request): - """path_info = %s""" % path_info return path_info_val.match(request.path_info) is not None + text = "path_info = %s" + path_info_predicate.__text__ = text % path_info weights.append(1 << 3) predicates.append(path_info_predicate) h.update('path_info:%r' % path_info) @@ -2516,14 +2518,14 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if '=' in request_param: request_param, request_param_val = request_param.split('=', 1) if request_param_val is None: - msg = "request_param %s" % request_param + text = "request_param %s" % request_param else: - msg = "request_param %s = %s" % (request_param, request_param_val) + text = "request_param %s = %s" % (request_param, request_param_val) def request_param_predicate(context, request): - """%s""" % msg if request_param_val is None: return request_param in request.params return request.params.get(request_param) == request_param_val + request_param_predicate.__text__ = text weights.append(1 << 4) predicates.append(request_param_predicate) h.update('request_param:%r=%r' % (request_param, request_param_val)) @@ -2538,41 +2540,42 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, except re.error, why: raise ConfigurationError(why[0]) if header_val is None: - msg = "header %s" % header_name + text = "header %s" % header_name else: - msg = "header %s = %s" % (header_name, header_val) + text = "header %s = %s" % (header_name, header_val) def header_predicate(context, request): - """%s""" % msg if header_val is None: return header_name in request.headers val = request.headers.get(header_name) if val is None: return False return header_val.match(val) is not None + header_predicate.__text__ = text weights.append(1 << 5) predicates.append(header_predicate) h.update('header:%r=%r' % (header_name, header_val)) if accept is not None: def accept_predicate(context, request): - """accept = %s""" % accept return accept in request.accept + accept_predicate.__text__ = "accept = %s" % accept weights.append(1 << 6) predicates.append(accept_predicate) h.update('accept:%r' % accept) if containment is not None: def containment_predicate(context, request): - """containment = %s""" % containment return find_interface(context, containment) is not None + containment_predicate.__text__ = "containment = %s" % containment weights.append(1 << 7) predicates.append(containment_predicate) h.update('containment:%r' % hash(containment)) if request_type is not None: def request_type_predicate(context, request): - """request_type = %s""" % request_type return request_type.providedBy(request) + text = "request_type = %s" + request_type_predicate.__text__ = text % request_type weights.append(1 << 8) predicates.append(request_type_predicate) h.update('request_type:%r' % hash(request_type)) @@ -2600,8 +2603,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None, if custom: for num, predicate in enumerate(custom): - if getattr(predicate, '__doc__', None) is None: - predicate.__doc__ = "" + if getattr(predicate, '__text__', None) is None: + predicate.__text__ = "" predicates.append(predicate) # using hash() here rather than id() is intentional: we # want to allow custom predicates that are part of diff --git a/pyramid/paster.py b/pyramid/paster.py index 15a50458a..f82246fea 100644 --- a/pyramid/paster.py +++ b/pyramid/paster.py @@ -201,6 +201,9 @@ class PRoutesCommand(PCommand): IView, name='', default=None) self.out(fmt % (route.name, route.pattern, view_callable)) + +from pyramid.interfaces import IMultiView + class PViewsCommand(PCommand): """Print, for a given URL, the views that might match. Underneath each potentially matching route, list the predicates required. Underneath @@ -260,10 +263,9 @@ class PViewsCommand(PCommand): from pyramid.interfaces import IRouteRequest from pyramid.interfaces import IRequestFactory from pyramid.interfaces import IRoutesMapper - from pyramid.interfaces import ITraverser - from pyramid.interfaces import IMultiView from pyramid.interfaces import IView from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import ITraverser from pyramid.request import Request from pyramid.traversal import DefaultRootFactory from pyramid.traversal import ResourceTreeTraverser @@ -279,7 +281,7 @@ class PViewsCommand(PCommand): class RoutesMultiView(object): implements(IMultiView) - def __init__(self, infos, context_iface, subpath): + def __init__(self, infos, context_iface, root_factory, request): self.views = [] for info in infos: match, route = info['match'], info['route'] @@ -293,11 +295,18 @@ class PViewsCommand(PCommand): IView, name='', default=None) if view is None: continue - view.__predicates__ = list(route.predicates) - view.__route_attrs__ = {'matchdict': match, - 'matched_route': route, - 'subpath': subpath} - view.__view_attr__ = '' + view.__request_attrs__ = {} + view.__request_attrs__['matchdict'] = match + view.__request_attrs__['matched_route'] = route + root_factory = route.factory or root_factory + root = root_factory(request) + traverser = adapters.queryAdapter(root, ITraverser) + if traverser is None: + traverser = ResourceTreeTraverser(root) + tdict = traverser(request) + view.__request_attrs__.update(tdict) + if not hasattr(view, '__view_attr__'): + view.__view_attr__ = '' self.views.append((None, view, None)) @@ -355,7 +364,7 @@ class PViewsCommand(PCommand): (IViewClassifier, request_iface, context_iface), IView, name=view_name, default=None) else: - view = RoutesMultiView(infos, context_iface, subpath) + view = RoutesMultiView(infos, context_iface, root_factory, request) # routes are not registered with a view name if view is None: @@ -371,58 +380,52 @@ class PViewsCommand(PCommand): return view - def output_route_attrs(self, attrs): - if 'matched_route' in attrs: - route = attrs['matched_route'] - self.out(" route name: %s" % route.name) - self.out(" route pattern: %s" % route.pattern) - self.out(" route path: %s" % route.path) - self.out(" subpath: %s" % '/'.join(attrs['subpath'])) - - def output_view_attrs(self, attrs): - self.out(" context: %s" % attrs['context']) - self.out(" view name: %s" % attrs['view_name']) - - def output_multiview_info(self, view_wrapper): - name = view_wrapper.__name__ - module = view_wrapper.__module__ - attr = view_wrapper.__view_attr__ - route_attrs = getattr(view_wrapper, '__route_attrs__', {}) - self.out('') - self.out(" View:") - self.out(" -----") - self.out(" %s.%s.%s" % (module, name, attr)) - self.output_route_attrs(route_attrs) - permission = getattr(view_wrapper, '__permission__', None) - if permission is not None: - self.out(" required permission = %s" % permission) - predicates = getattr(view_wrapper, '__predicates__', None) - if predicates is not None: - for predicate in predicates: - self.out(" %s" % predicate.__doc__) - - def output_view_info(self, view): - if view is not None: - name = getattr(view, '__name__', view.__class__.__name__) - module = view.__module__ + def output_route_attrs(self, attrs, indent): + route = attrs['matched_route'] + self.out("%sroute name: %s" % (indent, route.name)) + self.out("%sroute pattern: %s" % (indent, route.pattern)) + self.out("%sroute path: %s" % (indent, route.path)) + self.out("%ssubpath: %s" % (indent, '/'.join(attrs['subpath']))) + predicates = ', '.join([p.__text__ for p in route.predicates]) + if predicates != '': + self.out("%sroute predicates (%s)" % (indent, predicates)) + + def output_view_info(self, view_wrapper, level=1): + indent = " " * level + name = getattr(view_wrapper, '__name__', '') + module = getattr(view_wrapper, '__module__', '') + attr = getattr(view_wrapper, '__view_attr__', None) + request_attrs = getattr(view_wrapper, '__request_attrs__', {}) + if attr is not None: + view_callable = "%s.%s.%s" % (module, name, attr) else: - module = 'Not found' - name = '' + attr = view_wrapper.__class__.__name__ + if attr == 'function': + attr = name + view_callable = "%s.%s" % (module, attr) self.out('') - self.out(" View:") - self.out(" -----") - self.out(" %s.%s" % (module, name)) - permission = getattr(view, '__permission__', None) - if permission is not None: - self.out(" required permission = %s" % permission) - predicates = getattr(view, '__predicates__', None) - if predicates is not None: - for predicate in predicates: - self.out(" %s" % predicate.__doc__) + if 'matched_route' in request_attrs: + self.out("%sRoute:" % indent) + self.out("%s------" % indent) + self.output_route_attrs(request_attrs, indent) + permission = getattr(view_wrapper, '__permission__', None) + if not IMultiView.providedBy(view_wrapper): + # single view for this route, so repeat call without route data + del request_attrs['matched_route'] + self.output_view_info(view_wrapper, level+1) + else: + self.out("%sView:" % indent) + self.out("%s-----" % indent) + self.out("%s%s" % (indent, view_callable)) + permission = getattr(view_wrapper, '__permission__', None) + if permission is not None: + self.out("%srequired permission = %s" % (indent, permission)) + predicates = getattr(view_wrapper, '__predicates__', None) + if predicates is not None: + predicate_text = ', '.join([p.__text__ for p in predicates]) + self.out("%sview predicates (%s)" % (indent, predicate_text)) def command(self): - from pyramid.interfaces import IMultiView - config_file, section_name, url = self.args if not url.startswith('/'): url = '/%s' % url @@ -431,13 +434,20 @@ class PViewsCommand(PCommand): view = self._find_view(url, registry) self.out('') self.out("URL = %s" % url) + self.out('') if view is not None: - self.output_view_attrs(view.__request_attrs__) - self.output_route_attrs(view.__request_attrs__) + self.out(" context: %s" % view.__request_attrs__['context']) + self.out(" view name: %s" % view.__request_attrs__['view_name']) if IMultiView.providedBy(view): for dummy, view_wrapper, dummy in view.views: - self.output_multiview_info(view_wrapper) + self.output_view_info(view_wrapper) + if IMultiView.providedBy(view_wrapper): + for dummy, mv_view_wrapper, dummy in view_wrapper.views: + self.output_view_info(mv_view_wrapper, level=2) else: - self.output_view_info(view) + if view is not None: + self.output_view_info(view) + else: + self.out(" Not found.") self.out('') diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index 2bd24ac26..f583cc783 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -4477,6 +4477,28 @@ class Test__make_predicates(unittest.TestCase): self.assertEqual(info, {'match': {'a':'a', 'b':'b', 'traverse':('1', 'a', 'b')}}) + def test_predicate_text_is_correct(self): + _, predicates, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + header='header', + accept='accept', + containment='containment', + request_type='request_type', + custom=(DummyCustomPredicate(),)) + self.assertEqual(predicates[0].__text__, 'xhr = True') + self.assertEqual(predicates[1].__text__, + 'request method = request_method') + self.assertEqual(predicates[2].__text__, 'path_info = path_info') + self.assertEqual(predicates[3].__text__, 'request_param param') + self.assertEqual(predicates[4].__text__, 'header header') + self.assertEqual(predicates[5].__text__, 'accept = accept') + self.assertEqual(predicates[6].__text__, 'containment = containment') + self.assertEqual(predicates[7].__text__, 'request_type = request_type') + self.assertEqual(predicates[8].__text__, '') + class TestMultiView(unittest.TestCase): def _getTargetClass(self): from pyramid.config import MultiView diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py index 8a5ef7003..2239d81ea 100644 --- a/pyramid/tests/test_paster.py +++ b/pyramid/tests/test_paster.py @@ -545,7 +545,7 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[5], ' Not found.') + self.assertEqual(L[3], ' Not found.') def test_views_command_not_found_url_starts_without_slash(self): from pyramid.registry import Registry @@ -562,7 +562,7 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[5], ' Not found.') + self.assertEqual(L[3], ' Not found.') def test_views_command_single_view_traversal(self): from pyramid.registry import Registry @@ -580,9 +580,30 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.DummyView') + + def test_views_command_single_view_function_traversal(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + def view(): pass + view.__request_attrs__ = {'context': 'context', 'view_name': 'a'} + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.view') def test_views_command_single_view_traversal_with_permission(self): from pyramid.registry import Registry @@ -601,10 +622,10 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') - self.assertEqual(L[8], ' required permission = test') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[9], ' required permission = test') def test_views_command_single_view_traversal_with_predicates(self): from pyramid.registry import Registry @@ -612,8 +633,8 @@ class TestPViewsCommand(unittest.TestCase): registry = Registry() L = [] command.out = L.append - def predicate(): - """predicate = x""" + def predicate(): pass + predicate.__text__ = "predicate = x" view = DummyView(context='context', view_name='a') view.__predicates__ = [predicate] command._find_view = lambda arg1, arg2: view @@ -625,10 +646,10 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.DummyView') - self.assertEqual(L[8], ' predicate = x') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[9], ' view predicates (predicate = x)') def test_views_command_single_view_route(self): from pyramid.registry import Registry @@ -648,13 +669,70 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[4], ' route name: a') - self.assertEqual(L[5], ' route pattern: /a') - self.assertEqual(L[6], ' route path: /a') - self.assertEqual(L[7], ' subpath: ') - self.assertEqual(L[11], ' pyramid.tests.test_paster.DummyView') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[6], ' Route:') + self.assertEqual(L[8], ' route name: a') + self.assertEqual(L[9], ' route pattern: /a') + self.assertEqual(L[10], ' route path: /a') + self.assertEqual(L[11], ' subpath: ') + self.assertEqual(L[15], ' pyramid.tests.test_paster.DummyView') + + def test_views_command_multi_view_nested(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + view1 = DummyView(context='context', view_name='a1') + view1.__name__ = 'view1' + view1.__view_attr__ = 'call' + multiview1 = DummyMultiView(view1, context='context', view_name='a1') + multiview2 = DummyMultiView(multiview1, context='context', + view_name='a') + command._find_view = lambda arg1, arg2: multiview2 + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.DummyMultiView') + self.assertEqual(L[12], ' pyramid.tests.test_paster.view1.call') + + def test_views_command_single_view_route_with_route_predicates(self): + from pyramid.registry import Registry + command = self._makeOne() + registry = Registry() + L = [] + command.out = L.append + def predicate(): pass + predicate.__text__ = "predicate = x" + route = DummyRoute('a', '/a', matchdict={}, predicate=predicate) + view = DummyView(context='context', view_name='a', + matched_route=route, subpath='') + command._find_view = lambda arg1, arg2: view + app = DummyApp() + app.registry = registry + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') + result = command.command() + self.assertEqual(result, None) + self.assertEqual(L[1], 'URL = /a') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[6], ' Route:') + self.assertEqual(L[8], ' route name: a') + self.assertEqual(L[9], ' route pattern: /a') + self.assertEqual(L[10], ' route path: /a') + self.assertEqual(L[11], ' subpath: ') + self.assertEqual(L[12], ' route predicates (predicate = x)') + self.assertEqual(L[16], ' pyramid.tests.test_paster.DummyView') def test_views_command_multiview(self): from pyramid.registry import Registry @@ -675,9 +753,9 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.view.call') def test_views_command_multiview_with_permission(self): from pyramid.registry import Registry @@ -699,10 +777,10 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') - self.assertEqual(L[8], ' required permission = test') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.view.call') + self.assertEqual(L[9], ' required permission = test') def test_views_command_multiview_with_predicates(self): from pyramid.registry import Registry @@ -710,8 +788,8 @@ class TestPViewsCommand(unittest.TestCase): registry = Registry() L = [] command.out = L.append - def predicate(): - """predicate = x""" + def predicate(): pass + predicate.__text__ = "predicate = x" view = DummyView(context='context') view.__name__ = 'view' view.__view_attr__ = 'call' @@ -726,10 +804,10 @@ class TestPViewsCommand(unittest.TestCase): result = command.command() self.assertEqual(result, None) self.assertEqual(L[1], 'URL = /a') - self.assertEqual(L[2], ' context: context') - self.assertEqual(L[3], ' view name: a') - self.assertEqual(L[7], ' pyramid.tests.test_paster.view.call') - self.assertEqual(L[8], ' predicate = x') + self.assertEqual(L[3], ' context: context') + self.assertEqual(L[4], ' view name: a') + self.assertEqual(L[8], ' pyramid.tests.test_paster.view.call') + self.assertEqual(L[9], ' view predicates (predicate = x)') def _register_mapper(self, registry, routes): from pyramid.interfaces import IRoutesMapper @@ -823,13 +901,16 @@ class DummyMapper(object): return self.routes class DummyRoute(object): - def __init__(self, name, pattern, factory=None, matchdict=None): + def __init__(self, name, pattern, factory=None, + matchdict=None, predicate=None): self.name = name self.path = pattern self.pattern = pattern self.factory = factory self.matchdict = matchdict self.predicates = [] + if predicate is not None: + self.predicates = [predicate] def match(self, route): return self.matchdict -- cgit v1.2.3 From 288c6635d780fb05c01cc0e6de0f29cf602c1122 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:22:31 -0500 Subject: Revert "changed requirements file to test rtd integration" This reverts commit 5d150878d489ee90737f3a35e609adbb55de53c3. --- requirements.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index f79a2aab7..d94f7c98b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1 @@ pyramid -zope.configuration -zope.deprecation -zope.component -repoze.sphinx.autointerface -- cgit v1.2.3 From aa0ca066b4c0cd45427193053b5de7c0f3954ae6 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:23:14 -0500 Subject: Revert "added requirement file to test rtd integration" This reverts commit 9c0b0adf505444831704879a00f299ad74837284. --- requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d94f7c98b..000000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pyramid -- cgit v1.2.3 From c570d82c02687ef6264b83cfd51c229acfeffb3b Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:24:02 -0500 Subject: Revert "fixed makefile to update theme submodule correctly" This reverts commit f2d5cb59deba682d7c1d461ab5e90ba1802d42ac. --- docs/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 21e91d114..3fbf56d0a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -25,7 +25,7 @@ help: clean: -rm -rf _build/* -html: theme +html: _themes mkdir -p _build/html _build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @@ -47,7 +47,7 @@ pickle: web: pickle -htmlhelp: theme +htmlhelp: _themes mkdir -p _build/htmlhelp _build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @@ -84,5 +84,6 @@ epub: @echo @echo "Build finished. The epub file is in _build/epub." -theme: - cd ..;git submodule update --init;cd docs +_themes: + git submodule init + git submodule update -- cgit v1.2.3 From e87f1885d78df1c4f832912a2031291093517fa0 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:25:05 -0500 Subject: Revert "test adding theme as a submodule" This reverts commit 94c2dc0bae9cf14cc6a5548119933e4477d07042. --- .gitmodules | 3 --- docs/.gitignore | 1 + docs/Makefile | 3 +-- docs/_themes | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 .gitmodules delete mode 160000 docs/_themes diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 45397942b..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "docs/_themes"] - path = docs/_themes - url = git://github.com/Pylons/pylons_sphinx_theme.git diff --git a/docs/.gitignore b/docs/.gitignore index d4e11e5ea..1e9e0413c 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,2 +1,3 @@ _build +_themes diff --git a/docs/Makefile b/docs/Makefile index 3fbf56d0a..1d032cf45 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -85,5 +85,4 @@ epub: @echo "Build finished. The epub file is in _build/epub." _themes: - git submodule init - git submodule update + git clone git://github.com/Pylons/pylons_sphinx_theme.git _themes diff --git a/docs/_themes b/docs/_themes deleted file mode 160000 index 53898ec57..000000000 --- a/docs/_themes +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 53898ec579a1c31e8780824c0a255eca004e0e56 -- cgit v1.2.3 From 127f51481cc47e9507bd4d87973a11e5dbab97c2 Mon Sep 17 00:00:00 2001 From: cguardia Date: Wed, 4 May 2011 15:50:19 -0500 Subject: changed __doc__ to __text__ in dummy custom predicate --- pyramid/tests/test_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index d8f8d89a0..9f7873ab5 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -4497,7 +4497,7 @@ class Test__make_predicates(unittest.TestCase): self.assertEqual(predicates[5].__text__, 'accept = accept') self.assertEqual(predicates[6].__text__, 'containment = containment') self.assertEqual(predicates[7].__text__, 'request_type = request_type') - self.assertEqual(predicates[8].__text__, '') + self.assertEqual(predicates[8].__text__, 'custom predicate') class TestMultiView(unittest.TestCase): def _getTargetClass(self): @@ -5073,7 +5073,7 @@ class DummyStaticURLInfo: class DummyCustomPredicate(object): def __init__(self): - self.__doc__ = 'custom predicate' + self.__text__ = 'custom predicate' def dummy_view(request): return 'OK' -- cgit v1.2.3