Hi All!

I've encountered what I believe to be a bug in Pyramid and I hope you can 
help me find a solution or workaround :-)

I have some rather redundant code in Pyramid views and I'm trying to 
refactor it into a decorator.  The idea is that this decorator will return 
a Pyramid view function decorated with @view_config and the redundant code 
will be put into this "generated" function so that it automagically applies 
in all view functions.  This works fine, but as soon as I move my decorator 
to a seperate module and import it (it needs to be used from multiple 
modules that define views) then I get HTTP 404 errors.

I've taken a look at the Pyramid and Venusian source code, but I'm not 
familiar with some of the more advanced stuff going on in Venusian to 
properly determine exactly why this doesn't work.

I've attached an SSCCE[1] (~100 lines of code,with comments) that 
demonstrates this problem.  Can you please take a look at it and confirm 
that this is a bug (or not)?

Note: I've tried to keep this as close to possible to how it's used in the 
real application.  Keep in mind that this is legacy code and I'm not behind 
all the decisions (e.g. the do-it-yourself-RPC framework ;-)

Thanks,
André Caron

[1]: http://sscce.org/

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/pylons-discuss/-/V39AjAbHCmgJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.

# -*- coding: utf-8 -*-

from pyramid.view import view_config

def rpc_method_imported(method_name, argument_names=[]):
    def decorator(f):
        @view_config(route_name=method_name, renderer='json')
        def nested_view(request):
            # do stuff with 'method_name' and 'argument_names' here.
            return f(request)
        return nested_view
    return decorator
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pyramid.config import Configurator
from pyramid.view import view_config
from wsgiref.simple_server import make_server

from other_module import rpc_method_imported

#
# Simple Pyramid view, defined using recommended style.
#
# View is bound to URL "http://127.0.0.1:8080/";.
#

@view_config(route_name='regular-view', renderer='json')
def regular_view(request):
    """Defined using the recommended syntax."""
    return {'answer': 42, 'view': 'regular-view'}

#
# Pyramid view generated by a decorator.  There is no way to resolve this
# view using 'configurator.scan()'.  The URL is correctly registed below
# (see standard output for "proof"), yet the URL for the view function
# always produces a HTTP 404.
#
# View is bound to URL "http://127.0.0.1:8080/remote-call-1";.
#

@rpc_method_imported('object.method-1', argument_names=['foo','bar'])
def nested_view_core(request):
    """Wrapped into a Pyramid view by another decorator."""
    return {'answer': 42, 'view': 'object.method-1'}

#
# Exactly the same thing as above, but the decorator is defined in the
# current module insted of being imported.  Somehow, this one gets
# resolved correctly.
#
# View is bound to URL "http://127.0.0.1:8080/remote-call-2";.
#

def rpc_method_local(method_name, argument_names=[]):
    """Exact same thing as 'other_module.rpc_method_imported'."""
    def decorator(f):
        @view_config(route_name=method_name, renderer='json')
        def nested_view(request):
            # do stuff with 'method_name' and 'argument_names' here.
            return f(request)
        return nested_view
    return decorator

@rpc_method_local('object.method-2', argument_names=['foo','bar'])
def nested_view_core(request):
    """Wrapped into a Pyramid view by another decorator."""
    return {'answer': 42, 'view': 'object.method-2'}

#
# Pyramid + WSGI server start-up.
#

if __name__ == '__main__':
    configurator = Configurator()

    # Register application view functions.
    configurator.scan('__main__')     # doesn't resolve 'object.method-1'.
    configurator.scan('other_module') # doesn't resolve 'object.method-1'.

    # Bind view functions to URLs.
    configurator.add_route('regular-view', '/')
    configurator.add_route('object.method-1', '/remote-call-1')
    configurator.add_route('object.method-2', '/remote-call-2')

    # Finish preparing application.
    application = configurator.make_wsgi_app()

    # Show that URLs are properly registered.
    routes = configurator.get_routes_mapper().get_routes()
    for route in routes:
        print route.pattern, '->', route.name

    # Start accepting HTTP requests.
    server = make_server('0.0.0.0', 8080, application)
    server.serve_forever()

Reply via email to