[PEAK] Contextual / DecoratorTools.classy oddity

Sergey Schetinin maluke at gmail.com
Fri Aug 1 13:12:41 EDT 2008


I ended up implementing my own system for services which suites my
needs very well. Maybe a future version of Contextual will support my
use cases, but so far I was just fighting with it, so rolling out my
own is justified. I'll describe what I came up with cause I'm quite
happy with how it turned out, and as I said, maybe Phillip will decide
to include some similar features in Contextual. I attach the
implementation which is about 150 lines long and includes some ad-hoc
test suite.

First of all I didn't want service to be lazily initialized, so one
has to call Service.activate() to make it available. Also, to take
example from Contextual documentation, if Counter was already active
in current state ExtendedCounter would fail to activate because if any
service is active it has to be available via all service classes it
overrides. Also, subclassing services overrides them and overriding is
transitive, so if C overrides B and B overrides A, then C implicitly
overrides A.

There are only a few state manipulations possible:
 * instantiate a new, empty one: State()
 * get current state object: State.get()
 * create a nested state: State.get().child()
 * and make state current (__enter__ / __exit__)

Nested states allow overriding of already activated services, so this
would work:

Counter.activate()
with State.get().child():
    ExtendedCounter.activate()
    assert ExtendedCounter.get() is Counter.get()


There a root state that is the default one for all threads, so any
services that are not thread-safe should only be activated in nested
states.

Optional lazy activation would be trivial to add, but I really don't
need it, the requirement to explicitly activate services turned out to
be a very good decision in my case. Also, this makes possible for
service constructors to take parameters (which can be passed to
activate()).



> The issue here is that B and C have their own unique metaclasses, which are
> not derived from one another.  Specifically, Service creates a unique
> metaclass for each derived class, and these independent metaclasses can't be
> mixed.  You need to do something like this if you want to inherit from more
> than one Service subclass:
>
>    class D(B, C):
>        class __metaclass__(type(B), type(C)):
>            pass
>
> I've personally never needed to multiple-inherit Services, so didn't notice.
>  It's a bit of a wart, I suppose, but I'm not sure whether I care, or if
> it's a good idea to do in the first place.  (That is, there might be other
> negative consequences of doing it.)
>
> Anyway, the limitation here is of peak.context, which as I've mentioned
> previously, isn't really ready for prime time.  "classy" on its own doesn't
> do this, it's the metaclass-per-Service-subclass that's the cause here.
>
>



-- 
Best Regards,
Sergey Schetinin

http://s3bk.com/ -- S3 Backup
http://word-to-html.com/ -- Word to HTML Converter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: services.py
Type: text/x-python
Size: 6006 bytes
Desc: not available
Url : http://www.eby-sarna.com/pipermail/peak/attachments/20080801/95289ad8/services.py


More information about the PEAK mailing list