[Zope3-Users] Re: Utility Local to an Annotation?

Martin Aspeli optilude at gmx.net
Fri Apr 27 19:14:20 EDT 2007


Hi Derek,

>>> b - In the Atom syndication format, UUIDs are necessary for two things. 
>>> One, the overall feed has a UUID. This is easy - I'm storing them in a 
>>> site-local named utility, indexed by the feed annotation object.
>> What do yuo mean "indexed by"?
> 
> Hand the utility a feed annotation, get back a uuid for the feed.
> 
>> Also, is this UUID not just another aspect of feed "metadata" and thus a
>> candidate for the container annotation?
> 
> This was the original plan, but I was convinced to go with the more
> generalized solution of a uuid utility. I guess I can cache it in the
> container annotation, but that's an optimization and tangential to this
> discussion.

I don't think it's tangental. When we discussed this before, I was under 
the impression you wanted to have automatically assigned UUIDs to 
content objects. That sounded like something which should (a) be 
external to that object and (b) be centralised, with a key-reference 
type functionality in the same way as zope.app.intid, to allow semantics 
like "I have a UUID, now where is the object that it belongs to".

I still thing this sounds like useful, general behaviour.

However, now we are also talking about UUIDs of "feeds", which are 
implemented as views. I'm assuming the same feed gets the same UUID each 
time (if it does not, then you just generate it in the view, 
dynamically, which is simple).

If the feed needs metadata, and this metadata is context-specific, then 
storing that metadata in an annotation on the feed source (the 
container) seems sensible. However, the feed UUID is then just another 
part of that metadata.

The advantage of the utility approach is that it can generalised a lot. 
You can index based on generic container events, for example. If the 
feed/annotation is being managed explicitly, then why bother trying to 
fire "contentish" events and dealing with things like key-references for 
something which is in an annotation of an object?

The only reason I'd see for a central utility keeping track of UUIDs and 
feeds would be if you needed some kind of global UUID-to-feed lookup 
service.

If you do choose to just treat the feed UUID as metadata, there is of 
course no reason why you can't share the UUID-generating code between 
the feed annotation and the more general global UUID registry/id utility.

>>  Two, 
>>> each entry in a feed has a UUID. A content item that is an entry (a 
>>> file, in the current case) can, however, be in multiple feeds and needs 
>>> a different UUID in each. Thus, I need to be able to look up UUIDs by 
>>> the content object that will be rendered as a feed entry and look them 
>>> up relative to the feed, rather than globally.
>>>
>> That sounds to me like you want a composite UUID - a UUID utility gives each
>> content item a UUID (which is not feed-specific, and stays in line with the
>> general concept of a content object UUID). The one you put in the feed is
>> the feed's UUID and the object's UUID are combined. You could possibly use
>> some kind of hash if you needed to.
> 
> I considered this. I have a certain understanding of what I'm doing that
> precludes the combinatorial UUID approach, but no one I talk to seems to
> grasp it, so I think I will air it here so we can discuss it.
> 
> I am using RFC 4122 type 1 UUIDs. These are (practically) guaranteed
> universally unique, as they are based on spatial (MAC address) and
> temporal (CPU clock time) location. They have safeguards built in for
> things like multiple CPUs and resetting the CPU clock.
> 
> However, they are only (practically) guaranteed universally unique if
> *everyone* follows the same algorithm. If you use a different algorithm
> for computing your UUIDs, then they may collide with my RFC 4122 ones,
> since your algorithm doesn't compute them the same way and thus may use
> different, supposedly unique information included in a different way
> that results in the same UUID that I generate. Highly unlikely, but
> vastly more likely than if we all follow the RFC. Thus, to me, part of
> being a good citizen of the UUID world is to follow the exact RFC 4122
> algorithm, so we can all get along without collisions.
> 
> There is no provision in RFC 4122 for combining two UUIDs to generate a
> third, still unique, UUID. So, in my mind, combining two UUIDs, by
> whatever method, results in a relative UID, not a UUID.
> 
> Granted, I live in a fantasy world where everyone plays by the same RFC
> 4122 rules. Still, it's a nice world and I want to do what I can to
> encourage others to join me in it. So, I want to generate
> strictly-compliant RFC 4122 UUIDs for use in my product (and my utility
> makes it easy for others to use them elsewhere in Zope).
> 
> Thus I take the hard road, here. Is there a flaw in my reasoning?

I understand this problem, and it makes sense. I think it's a good line 
to take. However, does the spec say the UUID *has* to be RFC 4122 type 
1? If not, then a plain concatenation (no hash) of a UUID, with some 
separator that's not going to be output by the UUID seems valid enough 
to me. If you have two universally unique ids, then a combination of 
them must also be universally unique.

If the spec says it must be that exact format, or you're religiously 
bent on them, you'll need a different approach. You then essentially 
need a UUID that doesn't describe an object, but which describes an 
(object, feed) combination.

Are the *only* inputs to the RFC 4122 algorithm MAC address and system 
clock? If there are more inputs, e.g. an arbitrary object id, you could 
use them, I think.

You could of course annotate each and every item in the container with a 
list of FeedIdentity objects or something like that and let each one of 
those have a UUID, but that seems lame, inefficient and  difficult to 
keep up-to-date and in sync.

You could have a different approach, whereby you have a utility like:

class IFeedUUIDContainer(Interface):

     def register(feed, obj):
         """Register the given object for the given feed, return a UUID
         """

     def get_object(feed, uuid):
         """Find an object given a feed and an object UUID
         """


     def get_uuid(feed, obj):
         """Find an object's UUID in the given feed
         """

The idea here is that each time you look up an object or register it 
with the utility to obtain a UUID, you pass the object *and* the feed. 
Internally, this utility would need to store something like a dict (with 
keys for each feed) of dicts (with keys for object UUIDs) of keyrefs. 
This is a different API to zope.app.intid, and quite feed-specific but 
would work.

Now, notice each method here basically takes a feed as a key. That 
smells annotation/adaptation to me. So you could do this:

class IFeed(Interface):

     feed_uuid = Attribute("Feed's UUID")

     title = Attribute("Feed title")

class Feed(Persistent):
     implements(IFeed, IAttributeAnnotatable)

     feed_uuid = None
     title = u""

let's say we have a container 'parent', and we need a new feed 
configured for this:

   >>> KEY = 'vice.feed.metadata'
   >>> annotations = IAnnotations(parent)
   >>> feed = annotations.setdefault(KEY, Feed())

Now, 'feed' is a persistent object in an annotation on 'parent'. If you 
need to keep feeds in a PersistentList or OOBTree under that key, do 
that instead.

Then you can store object UUIDs for a feed in annotations on that object.

   >>> feed_annotations = IAnnotations(feed)

The problem is how to register all necessary objects with the 
feed_annations. You could do this lazily (create a new UUID only when 
needed, and flush old ones sometimes) or try to keep it all up to date 
with events (in which case look at the events zope.app.intid needs to 
keep track of).

Martin



More information about the Zope3-users mailing list