Re: Schema-by-interface options
Martin Aspeli <[email protected]> Sun, 24 Sep 2006 13:03:28 +0100
| Newsgroups | gmane.comp.web.zope.plone.archetypes.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Kapil,
> yes, flavors are on disk keyed by name. created events would be
> subscribed by a handler adapting the content to flavorprovider, and
> setting applicable site wide flavors, although its a bit of science
> fiction till it gets ported to zope 2.10 and has access to the new
> persistent registry stuff.
It's not science fiction to me working on 3.0. The future's good. :)
>> I'm not sure it has to be done with monkey-patching as such. My
>> solution basically looked like this:
>>
>> BaseObject's Schema() does: schema = ISchemaComposer(self)()
>>
>> the SchemaComposer's __call__ method would look up adapters to
>> ISchemaProvider - which could come from local or global site managers
>>
>> each ISchemaProvider would provide a part of a Schema object (still
>> not attached to a class or instance)
>>
>> the final schema would be cached (keyed on __class__ in the current
>> implementation, though I realise that may be too restrictive) and then
>> returned
>>
>> subsequent lookups would use the cache until invalidated via an event
>>
>> you need to run class-gen to build out methods (on the class, in my
>> case) for AT to work - the schema composer took care of this.
>>
>> I wouldn't call this monkey patching. All it does is defer the
>> decision of what Schema() should return until run-time (i.e. the first
>> time it's called/after the cache is invalidated).
>>
>> However, I'm agreeing with you that the subscriber-based version will
>> work with the kind of decoupling/indirection that ContentFlavors
>> favours (sorry), and that the above solution makes per-instance much
>> more difficult unnecessarily.
>>
>
> the above solution is broken for the use cases you've presented, is what
> i've been try relate. you want to use possibly local settings to modify
> globals. ie. as soon as you have site specific adapters in place, let's
> say two different schemas in place on sites with overlapping fields,
> they both dump possibly incompatibly on the class, and you have broken
> behavior. classgen on the class IS monkey patching a global variable.
Yes true. The schema cache could be site-local rather than global in a
module, but what ClassGen does scribbles all over the __dict__.
> the only reason it works in at, is because its by convention done only
> once, but its not reliable when you have different schemas trying to do
> it at runtime on the same class.
Agree.
>> Yes. My solution had an 'order' attribute that specifies an int, and
>> it's sorted by this. klass.schema was 0, and other could use numbers
>> as they wished. But I never liked this. Note that this is how menus
>> work in Zope 3...
>
> i think its just as much of an issue in zope3 as much as it is here,
> needing awareness of configuration space ordering, esp. when ordering
> has semantic importance to the runtime is really not fun. maybe its okay
> for z3, where its meant to be an app server not a product, but requiring
> plone end users/admins to deal with it is just a recipe for frustration.
True. But end users/admins will typically deal with (i.e. change) local
things, in which case you can store them in an ordered list and provide
a proper UI to re-order if necessary (which is what I presume you do).
>> The only negative I can think of here, really, is that if you
>> uninstall the thing that provided the "global" (site-local) schema,
>> you need to find all the content objects that have it attached. You
>> can build some safety into that, of course - if the flavour can't be
>> found, don't bomb. But it still seems a bit more tricky.
>
> this safety net, is already done in content flavors during runtime
> composition, with logging, and the content cleaned up when flavors are
> edited.
Good. We probably want some kind of general utility function to perform
clean-up as well, but that should be trivial.
> i was trying to demonstrate a new primitive to utilize z3
> interfaces/schema specifications that delegated to local components for
> a z3 solution that allowed for global application of local behavior
> without per instance modifications and without stomping on a global
> variable. still not sure if its feasible, but perhaps worth exploring.
Stephan Richter & co are doing stuff like that. GenericSetup is *kindof*
like that. Check out http://svn.zope.org/z3c.baseregistry, which I think
does something like what you're talking about (I may be wrong).
>> I trust you to get things like caches right. :)
>>
>
> i added some caches stats in debug mode into the user interface for
> verification ;-), the global cache only gets one miss per ordered flavor
> set schema, the local cache with weakrefs, approaches 98% cache hit
> success.
Like I said, trust you. ;)
> most of AT uses the field.getAccessor( instance ) semantic, which is
> fine, but yes its anti-pattern for composition and mutable schemas to
> spell accessor names directly on instances, since their all volatile
> (_v_ prefixed), but code doing that would be broken anyways if a flavor
> was removed. experience with ATSENG has shown its not an issue in
> practice. ie. context.Schema['rabbit_soup']
Ben was saying we should have something like :
def get(flavor, key)
def set(flavor, key, value)
in BaseObject, where 'flavor' is a namespace and key was the key of a
field *in that flavor* (so that you could have two flavors with the same
field name).
getAccessor() could return any callable, meaning it didn't have to be
something on the object. The first real problem I found was in security
checks that would go look for the accessor on a class and check its
security assertions. But again, fixing all this is a lot of AT surgery
that may be quite risky. Since you never change things at runtime
anyway, this should be safe.
But - what does ContentFlavors do when two flavors provide the same
field id?
>> So, specifically, this is what I'd like to do:
>>
>> 1. Merge current trunk into 1.5 whitmo-schema-by-iface so that it's
>> 1.5 compatible. This contains more fun with interfaces and so on that
>> helps all of this.
>>
>> 2. This uses schema = ISchema(self). The adapter factory here is a
>> class that does things that scares me - like 'self =
>> ImplicitAquisitonWrapper(schema)' in __init__(). Yipes. :) We can do
>> it better (imho) by using a function as a custom adapter factory -
>> this is trivial.
>
> could you give a link?
http://dev.plone.org/archetypes/browser/Archetypes/branches/whitmo-schema-by-iface/Schema/adapters.py
Instead, I'd suggest:
@zope.component.implementer(ISchema)
@zope.component.adapter(IBaseObject)
def schemaAdapterFactory(context):
return context.schema
<adapter factory=".adapters.schemaAdapterFactory" />
Then, if ContentFlavors wanted to return something different, I'd do:
@zope.component.implementer(ISchema)
@zope.component.adapter(IFlavorAware)
def schemaAdapterFactory(context):
return IFlavorSchemaProvider(self).schema
<five:implements
class="Products.Archetypes.BaseObject.BaseObject"
interface=".interfaces.IFlavorAware"
/>
<adapter factory=".aware.schemaAdapterFactory" />
>> 3. I also think the aq-wrapping in Schema() should stay in the
>> Schema() method, so that it does:
>>
>> def Schema(self):
>> schema = ISchema(self)
>> return ImplicitAcquisitonWrapper(schema)
The above examples assume this is the case, btw.
>> That way, at least we're not requiring all ISchema adapters to
>> remember to aq-wrap (which may even lead to some funny semantics if
>> the ISchema adapter is used elsewhere).
>>
>
> sounds good.
Good.
>> 4. We slap a big, scary note on the ISchema interface that people
>> need to worry about generating methods, and caches.
>
> and rabbits with big pointy teeth ;-)
Were-Rabbit!
>> Oh - and can we eventually move this to AT svn?
>
> yes.
Like... now? :)
Looking through the code now. I'd like to fix up whit's branch, and then
do a branch of ContentFlavors to make use of it.
Martin
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV