Best way to add dynamic default argument to view_config

136 views
Skip to first unread message

Jason

unread,
Aug 28, 2012, 5:07:22 PM8/28/12
to pylons-...@googlegroups.com
Hello,

I'm trying to move on from pyramid_handlers to using config.add_route and view_config for increased configuration options (and I think it will be better organized), but there is one throwback I want to keep. Almost all of my view-callables will need the view_config option "matchparam={'action': <function_name>}" where function_name is the name of the view-callable def. What would be the best way to achieve this?

I think I could subclass view_config and override the __call__ method to add it as a parameter as seen below, but is this advisable?

class action_config(view_config):
    def __call__(self, wrapped):
        self.matchparam = {'action': wrapped.__name__}
        return view_config.__call__(self, wrapped)


Thanks for feedback,

Jason

John Anderson

unread,
Aug 28, 2012, 7:30:56 PM8/28/12
to pylons-...@googlegroups.com
I think what you are looking for his view_defaults:

http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/viewconfig.html
http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/api/view.html#pyramid.view.view_defaults
> --
> 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/-/jhpE8lLT7A8J.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/pylons-discuss?hl=en.

Jason

unread,
Aug 29, 2012, 9:21:21 AM8/29/12
to pylons-...@googlegroups.com
Unfortunately the "function_name" part of the predicate will be different for every view-callable, so view_defaults won't work -- unless a custom predicate could inspect the given request to see the current view-callable def name?

-- 
Jason 

Chris Lambacher

unread,
Aug 29, 2012, 11:31:59 AM8/29/12
to pylons-...@googlegroups.com
Hi,

I converted away from handlers to using the match_param view_defaults and view_config with the match_param option. I found that often enough I wanted to override the method name as the action that is was no big deal to always use match_param (since I was very frequently using the name option of the action decorator). I have a semi fleshed out example below. If you *really* want to default to the name of the method, then you'll need to write your own decorator that then calls view_config as you show below. Note that your example you use matchparam instead of match_param.

config.add_route('someroute_index', 'someroute')
config.add_route('someroute', 'someroute/{action}')

@view_defaults(route_name='someroute')
class SomeView(object):
    def __init__(self, request):
          self.request = request

    @view_config(route_name='someroute_index', renderer='index_renderer.mak')
    def index(self):
        ....

    @view_config(match_param='action=edit', request_method='POST', renderer='edit_renderer.mak')
     def save(self):
         ....

    @view_config(match_param='action=edit', renderer='edit_renderer.mak')
     def edit(self):
         ...

     @view_config(match_param='action=jsonaction', renderer='json')
     def json_action(self):
         ...


I also played around with setting up action to allow empty string instead of using the someaction_index route, but that was pretty annoying in request.route_path where you would need to do request.route_path('someroute', action=''), it just ended up looking cleaner to have a separate route for the "index" condition.

-Chris

--
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/-/jhpE8lLT7A8J.
To post to this group, send email to pylons-...@googlegroups.com.
To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.



--
Christopher Lambacher
ch...@kateandchris.net

Jason

unread,
Aug 29, 2012, 1:39:37 PM8/29/12
to pylons-...@googlegroups.com

On Wednesday, August 29, 2012 11:32:06 AM UTC-4, Chris Lambacher wrote:
Hi,

I converted away from handlers to using the match_param view_defaults and view_config with the match_param option. I found that often enough I wanted to override the method name as the action that is was no big deal to always use match_param (since I was very frequently using the name option of the action decorator). I have a semi fleshed out example below. If you *really* want to default to the name of the method, then you'll need to write your own decorator that then calls view_config as you show below. Note that your example you use matchparam instead of match_param.

config.add_route('someroute_index', 'someroute')
config.add_route('someroute', 'someroute/{action}')

@view_defaults(route_name='someroute')
class SomeView(object):
    def __init__(self, request):
          self.request = request

    @view_config(route_name='someroute_index', renderer='index_renderer.mak')
    def index(self):
        ....

    @view_config(match_param='action=edit', request_method='POST', renderer='edit_renderer.mak')
     def save(self):
         ....

    @view_config(match_param='action=edit', renderer='edit_renderer.mak')
     def edit(self):
         ...

     @view_config(match_param='action=jsonaction', renderer='json')
     def json_action(self):
         ...


I also played around with setting up action to allow empty string instead of using the someaction_index route, but that was pretty annoying in request.route_path where you would need to do request.route_path('someroute', action=''), it just ended up looking cleaner to have a separate route for the "index" condition.

-Chris


It turns out the match_param parameter of view_config no longer accepts a dict, so it wouldn't have worked like that anyway. What I ended up doing is to subclass view_config (it's actually a class) and doing some string formatting. For some reason calling view_config.__call__(self, wrapped) does not work in the child class. In PDB everything has the same values either way, but if I call the parent classes __call__ the view will not be matched. I have no idea why this is. Here is my new decorator:

from pyramid.view import view_config

class action_config(view_config):

    """ Extends Pyramid.view.view_config to always use the wrapped functions

        as a predicate match for the 'action' parameter in the matchdict.

        

        This requires the matching route to have {action} in its matchdict.

    """

    

    def __call__(self, wrapped):

        # if no name is given use the name of the function to match

        # against the 'action' matchdict parameter

        name = getattr(self, 'name', wrapped.__name__)

        

        try:    

            mp = self.match_param

        except AttributeError:

            mp = 'action={0}'.format(name)

        else:

            if not isinstance(mp, tuple):

                mp = (mp,)

                

            mpdict = dict(paramstr.split('=') for paramstr in mp)

            mpdict['action'] = name

            

            mp = ('{0}={1}'.format(k, v) for k,v in mpdict.items())

            

        self.match_param = mp

        

        # This doesn't work, but copying the code into this method (as below)

        # works fine???

        #return view_config.__call__(self, wrapped)

    

        settings = self.__dict__.copy()

        def callback(context, name, ob):

            config = context.config.with_package(info.module)

            config.add_view(view=ob, **settings)

            

        info = self.venusian.attach(wrapped, callback, category='pyramid')


        if info.scope == 'class':

            # if the decorator was attached to a method in a class, or

            # otherwise executed at class scope, we need to set an

            # 'attr' into the settings if one isn't already in there

            if settings.get('attr') is None:

                settings['attr'] = wrapped.__name__


        settings['_info'] = info.codeinfo # fbo "action_method"

        return wrapped 

Everything below my commented out return statement is exactly copied from pyramid.view.view_config.__call__, but I don't know why calling it directly doesn't work.

I'll be doing the same as you in my initial move from pyramid_handlers and using view_defaults(route_name='bleh') on the handler classes.

--
Jason
Reply all
Reply to author
Forward
0 new messages