[Grok-dev] view predicates in Grok?

Souheil CHELFOUH trollfot at gmail.com
Mon Jan 4 18:04:01 EST 2010


This is interesting, this whole predicate stuff, but, technically and
very concreatly, where would we plug that ?
Views, as multi adapters, are fetched through the classical publisher
mechanism, how can we plug our own modifications, without messing up
too deep into the machine ?
Grokcore.view, up to now, is mostly a way to not write zcml and
doesn't do much more. This is an extra step, isn't it ?
What would it affect, effectively ?

2010/1/4 Chris McDonough <chrism at plope.com>:
> Martijn Faassen wrote:
>> Hey Paul,
>>
>> This is extremely helpful, thank you very much (and to Chris for helping
>> him). It becomes easier to talk about it.
>>
>> Do I understand correctly that a predicate function's return value is
>> what is being checked here? I.e. in this case:
>>
>>     grok.predicate(foo="some value")
>>
>> a predicate 'foo' is looked up and called with context and request, and
>> if it returns "some value" then the predicate applies.
>
> No, a predicate callable is called with context and request, and returns True
> or False.
>
> Here's an example of something that might be called at configuration time
>
> def make_predicates(request_method=None):
>     predicates = []
>     if request_method is not None:
>         def request_method_predicate(context, request):
>             return request.method == request_method
>         predicates.append(request_method)
>     return predicates
>
> ... where "make_predicates" is called as the result of processing a ZCML
> directive or martian directive related to a single view.  A more real-world
> collection of predicates set up similarly is in the "_make_predicates" function
> inside http://svn.repoze.org/repoze.bfg/trunk/repoze/bfg/configuration.py
>
> Hopefully, knowing this, something like this starts to make sense:
>
> class Foo(grok.View):
>     grok.predicates(request_method='GET')
>     ...
>
>>
>> Paul Wilson wrote:
>> [snip]
>>> It's also worth noting that the BFG system allows you to define a list of
>>> predicate functions that are also involved in the view selection process.
>>> For example, you can define a function:
>>>
>>> def predicate1(request, context):
>>>      if request.header['foo'] == 'bar' and
>>>         context.foo == 'bar':
>>>              return True
>>>
>>> and specify it as follows:
>>>
>>> class FooView(grok.View):
>>>      grok.context(...)
>>>      grok.name(...)
>>>      grok.predicate(containment=MyContainer,
>>>                     custom_predicates=[predicate1,
>>>                                        predicate2,
>>>                                        predicate3])
>>>      ...
>>>
>>> This allows any kind of logical spelling to be given as part of the view
>>> matching process, inside or outside of the domain of requests and contexts.
>>> Want your views to be selected based on prevailing weather conditions? No
>>> problem!
>>>
>>> I did entertain the idea of allowing the provided predicates to be used within
>>> your predicate function:
>>>
>>> class FooView(grok.View)
>>>      grok.context(...)
>>>      grok.name(...)
>>>      grok.predicate.containment(MyContainer)
>>>      grok.predicate.custom_predicates=predicate1 # Can also be a sequence
>>>      ...
>>>
>>> def predicate1(request, context):
>>>      if grok.predicate.request_method('POST') and
>>>         context.foo == 'bar':
>>>              return True
>>>
>>> Using some deep Python magic this is probably possible, but it is
>>> unnecessary magic;
>>> the request API is simple enough anyway for you to be able to feasibly
>>> recreate any of
>>> the predicate's work anyway! However, splitting the predicates out
>>> like this would allow us
>>> to use martian's built in checkers to perform validation on predicates
>>> in a natural way. Also,
>>> we could inherit predicates from parent views too:
>>>
>>> class POSTView(grok.View):
>>>      grok.predicate.request_method('POST')
>>>
>>> Any thoughts?
>>
>> Are the "standard" BFG predicates registered globally?
>
> They are not "registered", per se.  A set of "convenience" predicates exists in
> the _make_predicates function I mentioned previously within
> http://svn.repoze.org/repoze.bfg/trunk/repoze/bfg/configuration.py .
> Predicates that we didn't anticipate are addable via a "custom_predicates"
> argument to view configuration.
>
>> Would it make
>> sense to register custom predicates through Martian, perhaps with a
>> decorator like this?
>>
>> @grok.view_predicate('predicate1')
>> def predicate1(request, context):
>>     ...
>
> That's up to you.  My personal opinion: no.  It'd be too throw-and-catch; the
> framework needn't provide any predicate "registrations" unless the
> "custom_predicates" mechanism of providing.. well, custom predicates.. doesn't
> work for some reason.
>
>> This might also make it easier for predicates to reuse each other, as
>> the decorator would just help to register the predicate itself and not
>> alter the function's behavior otherwise. Validation on grok.predicate
>> could then also be done pretty easily.
>>
>> Or is it not good to be global here and better to register this stuff
>> locally? The main issue I can see is naming clashes as there is only a
>> single namespace available, but that may be acceptable.
>
> I personally wouldn't treat adding new convenience predicates as any sort of
> registration problem.  Instead, I'd just have the martian directive accept
> keyword arguments that relate to "built-in" predicates and inline those
> predicate definitions into a closure within the configuration logic.  When you
> want to add a new convenience predicate, change that closure.  Cases not
> covered by convenience predicates can be handled by the user passing
> "custom_predicates=(pred1, pred2)" to the directive.
>
> - C
> _______________________________________________
> Grok-dev mailing list
> Grok-dev at zope.org
> https://mail.zope.org/mailman/listinfo/grok-dev
>


More information about the Grok-dev mailing list