Making an interface the default module context

View: New views
12 Messages — Rating Filter:   Alert me  

Making an interface the default module context

by Martin Aspeli :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

Let's say I have a module like:

  ...

  class IFoo(Schema):
      pass

  class FooView(grok.View):
      grok.require('hello')

Here, Schema is imported from elsewhere, and is just a marker interface,
i.e.:

  class Schema(Interface):
     pass

Schema exists purely to make IFoo above grokkable with some optional
directives.

In the example above, I'd hoped that the context for FooView would
default to IFoo if there was no other obvious context (e.g. a model).
IFoo could be a marker interface, for example, which espouses a new view.

However, FooView does not know its context, so I have to use
grok.context(). I tried to let Schema provide IContext, and also to let
IFoo provide IContext explicitly via alsoProvides(). Neither seems to stick.

Is it possible to infer that the context for FooView should be IFoo in
this case?

Martin

--
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Philipp von Weitershausen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martin Aspeli wrote:

> Let's say I have a module like:
>
>  ...
>
>  class IFoo(Schema):
>      pass
>
>  class FooView(grok.View):
>      grok.require('hello')
>
> Here, Schema is imported from elsewhere, and is just a marker interface,
> i.e.:
>
>  class Schema(Interface):
>     pass
>
> Schema exists purely to make IFoo above grokkable with some optional
> directives.
>
> In the example above, I'd hoped that the context for FooView would
> default to IFoo if there was no other obvious context (e.g. a model).

Despite popular belief, grok doesn't actually use magic ;).

> IFoo could be a marker interface, for example, which espouses a new view.
>
> However, FooView does not know its context, so I have to use
> grok.context(). I tried to let Schema provide IContext, and also to let
> IFoo provide IContext explicitly via alsoProvides(). Neither seems to
> stick.

If grok.context() isn't present it looks for something that *implements*
IContext, not provides.

> Is it possible to infer that the context for FooView should be IFoo in
> this case?

If you can somehow find a rule by which this interface is found, then
yes, it's possible. You'll have to override grokcore.component's
ContextGrokker which looks at the module, determines the implicit module
context and then uses the grok.context() directive to store this
implicit context so that it'll look to subsequent grokkers as if
grok.context() was used.

So what you can do is write something like that:

   from grokcore.component.meta import ContextGrokker

   class MyContextGrokker(martian.GlobalGrokker):
       # execute this grokker before grokcore.component's ContextGrokker
       martian.priority(martian.priority.bind().get(ContextGrokker) + 1)

       def grok(self, name, module, module_info, config, **kw):
           context = grok.context.bind().get(module=module)
           if context is None:
               # grok.context() wasn't used explicitly so let's try
               # to find an implicit context by our rules and then
               # set it
               implicit_context = somehow_determine_from(module)
               grok.context.set(module, implicit_context)

All you now have to do is write this 'somehow_determine_from(module)'
algorithm that looks at a module and finds your IFoo.
_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martin Aspeli :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Philipp von Weitershausen wrote:

> Martin Aspeli wrote:
>> Let's say I have a module like:
>>
>>  ...
>>
>>  class IFoo(Schema):
>>      pass
>>
>>  class FooView(grok.View):
>>      grok.require('hello')
>>
>> Here, Schema is imported from elsewhere, and is just a marker interface,
>> i.e.:
>>
>>  class Schema(Interface):
>>     pass
>>
>> Schema exists purely to make IFoo above grokkable with some optional
>> directives.
>>
>> In the example above, I'd hoped that the context for FooView would
>> default to IFoo if there was no other obvious context (e.g. a model).
>
> Despite popular belief, grok doesn't actually use magic ;).

Do you prefer to be called "illusionists"? :)

I'm not sure if this is borderline magic or not... I figured it was
analogous to "the IContext-implementing class is the context".

>> IFoo could be a marker interface, for example, which espouses a new view.
>>
>> However, FooView does not know its context, so I have to use
>> grok.context(). I tried to let Schema provide IContext, and also to let
>> IFoo provide IContext explicitly via alsoProvides(). Neither seems to
>> stick.
>
> If grok.context() isn't present it looks for something that *implements*
> IContext, not provides.

Yes, I figured.

>> Is it possible to infer that the context for FooView should be IFoo in
>> this case?
>
> If you can somehow find a rule by which this interface is found, then
> yes, it's possible. You'll have to override grokcore.component's
> ContextGrokker which looks at the module, determines the implicit module
> context and then uses the grok.context() directive to store this
> implicit context so that it'll look to subsequent grokkers as if
> grok.context() was used.
>
> So what you can do is write something like that:
>
>    from grokcore.component.meta import ContextGrokker
>
>    class MyContextGrokker(martian.GlobalGrokker):
>        # execute this grokker before grokcore.component's ContextGrokker
>        martian.priority(martian.priority.bind().get(ContextGrokker) + 1)
>
>        def grok(self, name, module, module_info, config, **kw):
>            context = grok.context.bind().get(module=module)
>            if context is None:
>                # grok.context() wasn't used explicitly so let's try
>                # to find an implicit context by our rules and then
>                # set it
>                implicit_context = somehow_determine_from(module)
>                grok.context.set(module, implicit_context)
>
> All you now have to do is write this 'somehow_determine_from(module)'
> algorithm that looks at a module and finds your IFoo.

Maybe scan for something that provides IContext, if nothing implements it?

I'm sure it can be done. My question is whether it's a good idea and
something worth having in Grok itself.

Martin

--
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Philipp von Weitershausen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martin Aspeli wrote:
>> Despite popular belief, grok doesn't actually use magic ;).
>
> Do you prefer to be called "illusionists"? :)

Yes, much better! :)

>> If you can somehow find a rule by which this interface is found, then
>> yes, it's possible. You'll have to override grokcore.component's
>> ContextGrokker which looks at the module, determines the implicit
>> module context and then uses the grok.context() directive to store
>> this implicit context so that it'll look to subsequent grokkers as if
>> grok.context() was used.
>>
>> So what you can do is write something like that:
>>
>>    from grokcore.component.meta import ContextGrokker
>>
>>    class MyContextGrokker(martian.GlobalGrokker):
>>        # execute this grokker before grokcore.component's ContextGrokker
>>        martian.priority(martian.priority.bind().get(ContextGrokker) + 1)
>>
>>        def grok(self, name, module, module_info, config, **kw):
>>            context = grok.context.bind().get(module=module)
>>            if context is None:
>>                # grok.context() wasn't used explicitly so let's try
>>                # to find an implicit context by our rules and then
>>                # set it
>>                implicit_context = somehow_determine_from(module)
>>                grok.context.set(module, implicit_context)
>>
>> All you now have to do is write this 'somehow_determine_from(module)'
>> algorithm that looks at a module and finds your IFoo.
>
> Maybe scan for something that provides IContext, if nothing implements it?

Sure, though I find it awkward having to write:

   class IFoo(Schema):
       pass

   alsoProvides(IFoo, IContext)

If you're trying to find implicit contexts that are interfaces, it'd be
easier to look for interfaces that extend a certain interface, e.g. in
your case that Schema thing. Here's what that could look like:

   def somehow_determine_from(module):
       results = []

       for name in dir(module):
           obj = module.getattr(module)
           if martian.util.defined_locally(obj, module.__name__):
               # obj wasn't imported into the module, it was
               # actually defined there
               if IInterface.providedBy(obj) and obj.extends(Schema):
                   results.append(obj)

       if not results:
          return None
       elif len(results) > 1:
          return grokcore.component.scan.AMIBIGUOUS_COMPONENT

       return results[0]


> I'm sure it can be done. My question is whether it's a good idea and
> something worth having in Grok itself.

Maybe. If the function above were generalized a bit, it could have a
place in grokcore.component or martian. We should see if this pattern
comes up more often, though, and if it actually solves your problem.

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martin Aspeli :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Philipp von Weitershausen <philipp <at> weitershausen.de> writes:

> If you're trying to find implicit contexts that are interfaces, it'd be
> easier to look for interfaces that extend a certain interface

How about looking for cases where either the interface or a base interface
provides IContext?

On a related note, I think it'd be nice to be able to do:

class IFoo(Interface):
    grok.interface_provides(IContext)

which would be equivalent ot

class IFoo(Interface):
    pass
alsoProvides(IFoo, IContext)

> > I'm sure it can be done. My question is whether it's a good idea and
> > something worth having in Grok itself.
>
> Maybe. If the function above were generalized a bit, it could have a
> place in grokcore.component or martian. We should see if this pattern
> comes up more often, though, and if it actually solves your problem.

Agree. I think it's useful in the case where you want to provide a view or
viewlet or adapter on a marker interface, certainly.

On the other hand, it's not so hard to write grok.context(IFoo). :)

Martin


_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Philipp von Weitershausen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martin Aspeli wrote:
> Philipp von Weitershausen <philipp <at> weitershausen.de> writes:
>
>> If you're trying to find implicit contexts that are interfaces, it'd be
>> easier to look for interfaces that extend a certain interface
>
> How about looking for cases where either the interface or a base interface
> provides IContext?

It seems easier to check if the interface extends IContext

> On a related note, I think it'd be nice to be able to do:
>
> class IFoo(Interface):
>     grok.interface_provides(IContext)
>
> which would be equivalent ot
>
> class IFoo(Interface):
>     pass
> alsoProvides(IFoo, IContext)

I don't see the necessity to invent a syntax for this right now.

>>> I'm sure it can be done. My question is whether it's a good idea and
>>> something worth having in Grok itself.
>> Maybe. If the function above were generalized a bit, it could have a
>> place in grokcore.component or martian. We should see if this pattern
>> comes up more often, though, and if it actually solves your problem.
>
> Agree. I think it's useful in the case where you want to provide a view or
> viewlet or adapter on a marker interface, certainly.
>
> On the other hand, it's not so hard to write grok.context(IFoo). :)

Indeed.

At least for Grok I personally don't have the intent of changing the
implicit context rules. That doesn't mean you couldn't explore
alternatives and enlighten us with some lessons learned :). For Grok I'd
personally prefer a bit more conservatism right now. We *are* trying to
get towards a 1.0 release, after all, and have other things on our list
for that.
_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martijn Faassen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hey,

Just double-checking, but you do know about module-level use of
grok.context(), right?

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martijn Faassen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Philipp von Weitershausen wrote:
[snip]
> At least for Grok I personally don't have the intent of changing the
> implicit context rules. That doesn't mean you couldn't explore
> alternatives and enlighten us with some lessons learned :). For Grok I'd
> personally prefer a bit more conservatism right now. We *are* trying to
> get towards a 1.0 release, after all, and have other things on our list
> for that.

Agreed we should be careful here.

That said, auto-associating with an interface that extends IContext
sounds like a reasonable approach. It should of course fail in the face
of ambiguity (a class *and* a model being around).

This would introduce auto-association with interfaces. I think that's a
reasonably safe behavior if we require that IContext is extended, and is
more or less analogous to what happens with classes as far as I can see.

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martin Aspeli :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martijn Faassen wrote:
> Hey,
>
> Just double-checking, but you do know about module-level use of
> grok.context(), right?

Nope. :-)

I'm guessing that'd fix this, though.

Martin

--
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Philipp von Weitershausen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martijn Faassen wrote:

> Philipp von Weitershausen wrote:
> [snip]
>> At least for Grok I personally don't have the intent of changing the
>> implicit context rules. That doesn't mean you couldn't explore
>> alternatives and enlighten us with some lessons learned :). For Grok
>> I'd personally prefer a bit more conservatism right now. We *are*
>> trying to get towards a 1.0 release, after all, and have other things
>> on our list for that.
>
> Agreed we should be careful here.
>
> That said, auto-associating with an interface that extends IContext
> sounds like a reasonable approach. It should of course fail in the face
> of ambiguity (a class *and* a model being around).

Of course.

> This would introduce auto-association with interfaces. I think that's a
> reasonably safe behavior if we require that IContext is extended, and is
> more or less analogous to what happens with classes as far as I can see.

Yeah. Well, if somebody's willing to extend grokcore.component as
described here, I won't say no :).
_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Martijn Faassen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Philipp von Weitershausen wrote:
[snip]
>> This would introduce auto-association with interfaces. I think that's
>> a reasonably safe behavior if we require that IContext is extended,
>> and is more or less analogous to what happens with classes as far as I
>> can see.
>
> Yeah. Well, if somebody's willing to extend grokcore.component as
> described here, I won't say no :).

One thing I worry about is as this is an instance, it might
auto-associate even with an imported interface. We need to make sure
that this isn't the case.

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev

Re: Making an interface the default module context

by Philipp von Weitershausen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martijn Faassen wrote:

> Philipp von Weitershausen wrote:
> [snip]
>>> This would introduce auto-association with interfaces. I think that's
>>> a reasonably safe behavior if we require that IContext is extended,
>>> and is more or less analogous to what happens with classes as far as
>>> I can see.
>>
>> Yeah. Well, if somebody's willing to extend grokcore.component as
>> described here, I won't say no :).
>
> One thing I worry about is as this is an instance, it might
> auto-associate even with an imported interface. We need to make sure
> that this isn't the case.

Indeed. martian's scan_for_classes wisely uses the defined_locally check
for that. If it were extended to scan for interfaces as well, that check
would have to be applied to them as well.

All that said, in my experience apps quickly outgrow the restrictions
that are required for using this automatic mapping of views and other
adapters to implicit contexts.

While it's great to have automatic mapping when you start out and just
write a bunch of classes in one module, I find that when introduce
interfaces, you tend to have so many components anyways that it's wise
to split up the code over multiple modules. At that point you should
also have understood what grok.context() does and why it's necessary.
_______________________________________________
Grok-dev mailing list
Grok-dev@...
http://mail.zope.org/mailman/listinfo/grok-dev
LightInTheBox - Buy quality products at wholesale price