[Cubicweb] Integrating CubicWeb views into Pyramid (long)

Christophe de Vienne christophe at unlish.com
Wed Aug 6 00:51:48 CEST 2014


Hi Florent,

Le 05/08/2014 10:20, Florent Cayré a écrit :
> Hi Christophe,
>
> thanks for sharing your thoughts and pushing that hard towards a good
> Pyramid/CubicWeb integration.

My pleasure (so far :-p)


> [...]
>
> Le 04/08/2014 20:59, Christophe de Vienne a écrit :
>> [snip]
>>
>> Registering a View
>> ~~~~~~~~~~~~~~~~~~
>>
>> When we register a view in Pyramid, we pass various parameters to the
>> "add_view" function (or view_config decorator).
>>
>> Three of them are the informations used for the first phase of the view
>> selection (later I call them the main predicates triplet):
>>
>> - context
>
> What kind of information does this context hold? From what follows in 
> you email,
> I understand it does not hold what you call "runtime" information like 
> the user
> that performs the request and the web-session data. Is this "context" 
> entirely
> known at view "registration time" (as opposed to "web-request time")?

The context is built in the first phase of the request handling, by the 
root factory.
In the case of CubicWeb, it will be ResultSet.


>
>> - name
>> - request_type
>>
>> Other parameters are predicates, like `accept`, `xhr` etc. These are 
>> evaluated
>> in a second phase, once the view(s) matching the first three are found.
>>
>
> These are thus evaluated at web-request time, correct? Why not use 
> these to
> evaluate the CW predicates? More on this later.
>
> Maybe we should split CW predicates into two categories in the long 
> term: some may
> be more as a context (and evaluated and registration time if my 
> understanding is
> correct). This could be a performance improvement, but nothing 
> required in a first
> approach.

I don't see a case were a predicate could be evaluated at registration time.
There are some interesting things to study to speedup the predicate 
evaluation though, but imo not this one.


> [...]
>
>> Use a custom IMultiView
>> ~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Implements a IMultiView (see pyramid.config.views.MultiView) that 
>> lookups in
>> the CW registry in hits __discriminator__.
>>
>> One instance of this class would be registered for each __regid__, 
>> like with
>> the ViewMapper-based solution.
>>
>> Pros
>>
>>     *   Not too difficult to implement
>>
>>     *   Respect more the pyramid API: the lookup is performed at a 
>> moment it is
>>         expected by pyramid. In the end, pyramid will know the right 
>> view, and
>>         any other system looking up for a view will find an actual 
>> one, not a
>>         pseudo one.
>>
>> Cons
>>
>>     *   The CW views are not registered directly in pyramid
>>
>>     *   Still doing two lookups in two different registries.
>>
>
>
> IMHO, this is a first step we could make because:
>
> * removing CW registries is not the goal you just mentioned, which 
> seems more
>   important to me in the short term
>
> * the second cons you mention is not that bad: in this scenario, the 
> Pyramid
>   registry is more like a one-element list per __regid__, which should 
> not be a
>   hard performance penalty
>
> * it really looks like a natural and simple approach, not a hack: not 
> difficult
>   to understand, easy to debug... ok for me, at least as a first step

I do think it is a good first step, as it fulfill the goal and would be 
compatible, api-wise, with more elaborate solutions.


>
>> Use CW predicates in add_view (basic)
>>
>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Here we add a "cwselect" predicate to pyramid, that makes it able to 
>> evaluate
>> the cubicweb predicates.
>>
>> Pros
>>
>>     *   We by-pass the CW registry
>>
>> Cons
>>
>>     *   We loose the cw predicate weigths
>
> I am -1 because of this last point.

And your are most probably right, but it is still interesting to give 
access to the cw predicates to the pyramid developers. So we should do 
it, even if not the solution to our problem.


>
>>
>> Use CW predicates in add_view + total ordering
>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Here we choose to drop the runtime evaluation of the predicates weight.
>>
>> Instead, we evaluate the weight of a predicate when it matches, and 
>> use that to
>>
>> sort the views in the registry.
>>
>
> I do not understand this: is the predicate weight evaluated or not? If 
> yes, when?

The weight is evaluated once and for all at registration.
At runtime, only the match/not match part of it is interesting.


>
>> This would need either a slight change of the pyramid MultiView, 
>> which would
>> sort the views in this new order we compute instead of the default 
>> one, or a
>> change in the 'make' function so that the order of the view includes the
>>
>> To use this system, we would need to duplicate the view registering 
>> when the
>> expression has some "or" operators in it. The idea is to obtain 
>> 'and-only'
>> predicate expressions for add_view.
>>
>> The only blocking point against that would be if some actual cw 
>> predicates
>> returns a variable weight depending on the context, because it would 
>> make it
>> impossible to pre-evaluate an expression weight if it matches.
>>
>
> This depends on what the context is (see my first question about what 
> the context
> holds): the logged-in user (known at web-request time) for example, is 
> often used
> to compute a predicate weight (match_user_groups 
> <http://docs.cubicweb.org/devrepo/vreg.html?highlight=match_user_groups#cubicweb.predicates.match_user_groups>) 
> and so the web query parameters
> (in match_form_kwargs 
> <http://docs.cubicweb.org/devrepo/vreg.html?highlight=match_user_groups#cubicweb.predicates.match_form_params> 
> for example, but there is a complete list in the CW doc).

Ok. Is this context-related weight variation actually used to choose 
between several views in a real-life application ?
I personally fail to imagine a case were belonging to 2 groups instead 
of one would make a difference.


>
>> Pros
>>
>>     * By-pass the CW registry
>>     * Very integrated solution
>>
>> Cons
>>
>>     * We force the predicates to have a fixed value when they match.
>>
>
> I do not understand this, but the impression I got reading your email 
> is that the
> Pyramid registry ordering thing is too static to be used as a 
> selection mecanism.
> However you mentioned a second predicate evaluation step at the 
> beginning of you
> email, that should fulfill CW needs unless I misunderstood all this.

The registry ordering is used at the second step, for all remaining 
predicates.
The first step only match on a request type, a context type and a view name.

I have the impression that in most (if not all) cases, the views (and I 
am talking only about the views) could be ordered even before any actual 
evaluation of the predicates.

For example, let's consider the two expressions :

     __select__ = is_instance('Event')

and

     __select__ = is_instance('Event') & match_user_groups('managers')

If the first one matches, its weight would be 1.0
It the second one matches, its weight would be 2.0

Hence, the second one has a higher priority. If it matches, we don't 
need to evaluate the first one -> it would have a lesser weight whether 
it matches or not.

This only works if 1) we have no 'or' 2) the predicates have a fixed 
weight once in the expression.

For point 1), the solution is to split the expression and register the 
view twice (or more). For example :

     __select__ = is_instance("Event") & match_user_groups('managers') | 
is_instance("SmallEvent") & match_user_groups("users")

A view with such a select would be registered twice, with different 
expressions:

     is_instance("Event") & match_user_groups('managers')

and

     is_instance("SmallEvent") & match_user_groups("users")

For point 2), I am not aware of examples were the weight variation is 
actually important in the selection process.

This approach reduce a little the possibilities of the selection system, 
but makes it probably faster in many cases, and maybe easier to optimize 
since the boolean arithmetics replaces the current complex one.


>
>> Use CW predicates in add_view + cw predicate weight
>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Add runtine evalution of predicate weigths into pyramid.
>>
>
> This looks like a nice second step to me, but I am still unsure what 
> the benefits
> would be: drop CW registries completely? If you think that Pyramid 
> registries do
> not fit (which I am still unsure, see my previous question), we will 
> more end-up
> with a re-implementation of CW registry features in Pyramid, which may 
> (or not)
> be interesting for the Pyramid community. Paul probably has a good 
> idea of the
> answer.

It is indeed not a first intention solution.
But sooner or later we will wonder if it make sens to merge the CW 
registry in the Pyramid one.
It may not, but it may too. :)


I hope I made it clearer

Cheers,

Christophe



More information about the Cubicweb mailing list