r13368 - in Products.Archetypes/trunk: . Products/Archetypes Products/Archetypes/interfaces Products/Archetypes/tests

"David Glick" <[email protected]>
Newsgroups gmane.comp.web.zope.plone.archetypes.cvs
Message-ID <[email protected]>
Author: davisagli
Date: Mon Dec 20 00:42:24 2010
New Revision: 13368

Added:
   Products.Archetypes/trunk/Products/Archetypes/uuid.py
      - copied unchanged from r13363, Products.Archetypes/branches/plip10778-plone.uuid/Products/Archetypes/uuid.py
Modified:
   Products.Archetypes/trunk/   (props changed)
   Products.Archetypes/trunk/CHANGES.txt
   Products.Archetypes/trunk/Products/Archetypes/   (props changed)
   Products.Archetypes/trunk/Products/Archetypes/Field.py
   Products.Archetypes/trunk/Products/Archetypes/ReferenceEngine.py
   Products.Archetypes/trunk/Products/Archetypes/Referenceable.py
   Products.Archetypes/trunk/Products/Archetypes/UIDCatalog.py
   Products.Archetypes/trunk/Products/Archetypes/configure.zcml
   Products.Archetypes/trunk/Products/Archetypes/implements.zcml
   Products.Archetypes/trunk/Products/Archetypes/interfaces/referenceable.py
   Products.Archetypes/trunk/Products/Archetypes/tests/layer.py
   Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceCatalog.py
   Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceable.py
   Products.Archetypes/trunk/Products/Archetypes/utils.py
   Products.Archetypes/trunk/setup.py
Log:
merge PLIP 10778

Modified: Products.Archetypes/trunk/CHANGES.txt
==============================================================================
--- Products.Archetypes/trunk/CHANGES.txt	(original)
+++ Products.Archetypes/trunk/CHANGES.txt	Mon Dec 20 00:42:24 2010
@@ -4,6 +4,19 @@
 1.7 - Unreleased
 ----------------
 
+- Fix Referenceable, UIDCatalog to support references to non-Archetypes-based
+  content.
+  [toutpt]
+
+- Use the new `plone.uuid` package to generate UUIDs. The UID() method is now
+  an alias for ``IUUID(obj)``, which is the new preferred means of looking up
+  a UUID, since this can also work for non-Archetypes content. Archetypes
+  provides an IUUID() adapter that returns the value stored in the Archetypes
+  UID attribute. For new content, UUIDs are generated using
+  `plone.uuid.interfaces.IUUIDGenerator`, although old content will not (and
+  need not) be migrated.
+  [optilude]
+
 - Handle getCharset() returning None in Field.encode/decode.
   [elro]
 

Modified: Products.Archetypes/trunk/Products/Archetypes/Field.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/Field.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/Field.py	Mon Dec 20 00:42:24 2010
@@ -90,6 +90,8 @@
 
 from Products.Archetypes.interfaces import IFieldDefaultProvider
 
+from plone.uuid.interfaces import IUUID
+
 # Import conditionally, so we don't introduce a hard depdendency
 try:
     from plone.i18n.normalizer.interfaces import IUserPreferredFileNameNormalizer
@@ -1780,7 +1782,7 @@
             return res
 
         rd = {}
-        [rd.__setitem__(r.UID(), r) for r in res]
+        [rd.__setitem__(IUUID(r, None), r) for r in res]
 
         refs = instance.at_ordered_refs
         order = refs[self.relationship]
@@ -1861,7 +1863,7 @@
             if isinstance(v, basestring):
                 uids.append(v)
             else:
-                uids.append(v.UID())
+                uids.append(IUUID(v, None))
 
         add = [v for v in uids if v and v not in targetUIDs]
         sub = [t for t in targetUIDs if t not in uids]
@@ -1897,7 +1899,7 @@
         relationship
         """
         rc = getToolByName(instance, REFERENCE_CATALOG)
-        brains = rc(sourceUID=instance.UID(),
+        brains = rc(sourceUID=IUUID(instance, None),
                     relationship=self.relationship)
         res = [b.targetUID for b in brains]
         if not self.multiValued and not aslist:

Modified: Products.Archetypes/trunk/Products/Archetypes/ReferenceEngine.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/ReferenceEngine.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/ReferenceEngine.py	Mon Dec 20 00:42:24 2010
@@ -31,6 +31,7 @@
 from Products.ZCatalog.Catalog import Catalog
 from Products import CMFCore
 
+from plone.uuid.interfaces import IUUID
 
 _www = os.path.join(os.path.dirname(__file__), 'www')
 _catalog_dtml = os.path.join(os.path.dirname(CMFCore.__file__), 'dtml')
@@ -84,7 +85,7 @@
 
     def UID(self):
         """the uid method for compat"""
-        return getattr(aq_base(self), UUID_ATTR)
+        return IUUID(self, None)
 
     ###
     # Convenience methods
@@ -494,11 +495,10 @@
             if not self.isReferenceable(uobject):
                 raise ReferenceException, "%r not referenceable" % uobject
 
-            # shasattr() doesn't work here
-            if not getattr(aq_base(uobject), UUID_ATTR, None):
+            uuid = IUUID(uobject, None)
+            if uuid is None:
                 uuid = self._getUUIDFor(uobject)
-            else:
-                uuid = getattr(uobject, UUID_ATTR)
+                
         else:
             uuid = obj
             obj = None
@@ -528,7 +528,7 @@
         else:
             annotation = sobj._getReferenceAnnotations()
             try:
-                annotation._delObject(referenceObject.UID())
+                annotation._delObject(IUUID(referenceObject, None))
             except (AttributeError, KeyError):
                 pass
 
@@ -652,4 +652,3 @@
     self._setObject(id, c)
     if REQUEST is not None:
         return self.manage_main(self, REQUEST,update_menu=1)
-

Modified: Products.Archetypes/trunk/Products/Archetypes/Referenceable.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/Referenceable.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/Referenceable.py	Mon Dec 20 00:42:24 2010
@@ -1,5 +1,7 @@
 from zope.interface import implements
 
+from plone.uuid.interfaces import IUUID
+
 from Products.Archetypes import config
 from Products.Archetypes.exceptions import ReferenceException
 from Products.Archetypes.interfaces import IReferenceable
@@ -113,7 +115,7 @@
 
     def _register(self, reference_manager=None):
         """register with the archetype tool for a unique id"""
-        if self.UID() is not None:
+        if IUUID(self, None) is not None:
             return
 
         if reference_manager is None:
@@ -142,10 +144,10 @@
             delattr(self, config.REFERENCE_ANNOTATION)
 
     def UID(self):
-        return getattr(self, config.UUID_ATTR, None)
+        return IUUID(self, None)
 
     def _setUID(self, uid):
-        old_uid = self.UID()
+        old_uid = IUUID(self, None)
         if old_uid is None:
             # Nothing to be done.
             return
@@ -243,8 +245,11 @@
         # TODO Should we ever get here after the isCopy flag addition??
         # If the object has no UID or the UID already exists, then
         # we should get a new one
-        if (not shasattr(self,config.UUID_ATTR) or
-            len(uc(UID=self.UID()))):
+        
+        uuid = IUUID(self, None)
+        
+        if (uuid is None or
+            len(uc(UID=uuid))):
             setattr(self, config.UUID_ATTR, None)
 
         self._register()

Modified: Products.Archetypes/trunk/Products/Archetypes/UIDCatalog.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/UIDCatalog.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/UIDCatalog.py	Mon Dec 20 00:42:24 2010
@@ -3,6 +3,8 @@
 import time
 import urllib
 from zope.interface import implements
+from zope import component
+from zope import interface
 
 from App.class_init import InitializeClass
 from App.special_dtml import DTMLFile
@@ -22,6 +24,9 @@
 from Products.Archetypes.config import TOOL_NAME
 from Products.Archetypes.interfaces import IUIDCatalog
 from Products.Archetypes.utils import getRelURL
+from plone.indexer.interfaces import IIndexableObject
+from plone.indexer.decorator import indexer
+from plone.uuid.interfaces import IUUID, IUUIDAware
 
 _catalog_dtml = os.path.join(os.path.dirname(CMFCore.__file__), 'dtml')
 logger = logging.getLogger('Archetypes')
@@ -133,6 +138,21 @@
 
 _marker=[]
 
+#let rewrite Title indexer with plone.indexer
+@indexer(interface.Interface, IUIDCatalog)
+def Title(obj):
+    title = obj.Title()
+    if isinstance(title, unicode):
+        return title.encode('utf-8')
+    try:
+        return str(title)
+    except UnicodeDecodeError:
+        return obj.getId()
+
+@indexer(IUUIDAware, IUIDCatalog)
+def UID_indexer(obj):
+    return IUUID(obj, None)
+
 class UIDResolver(Base):
 
     security = ClassSecurityInfo()
@@ -199,18 +219,16 @@
     security.declareProtected(ManageZCatalogEntries, 'catalog_object')
     def catalog_object(self, object, uid, idxs=[],
                        update_metadata=1, pghandler=None):
-        w = IndexableObjectWrapper(object)
-        try:
-            # pghandler argument got added in Zope 2.8
-            ZCatalog.catalog_object(self, w, uid, idxs,
-                                    update_metadata, pghandler=pghandler)
-        except TypeError:
-            try:
-                # update_metadata argument got added somewhere into
-                # the Zope 2.6 line (?)
-                ZCatalog.catalog_object(self, w, uid, idxs, update_metadata)
-            except TypeError:
-                ZCatalog.catalog_object(self, w, uid, idxs)
+
+        w = object
+        if not IIndexableObject.providedBy(object):
+            # This is the CMF 2.2 compatible approach, which should be used going forward
+            wrapper = component.queryMultiAdapter((object, self), IIndexableObject)
+            if wrapper is not None:
+                w = wrapper
+
+        ZCatalog.catalog_object(self, w, uid, idxs,
+                                update_metadata, pghandler=pghandler)
 
     def _catalogObject(self, obj, path):
         """Catalog the object. The object will be cataloged with the absolute

Modified: Products.Archetypes/trunk/Products/Archetypes/configure.zcml
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/configure.zcml	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/configure.zcml	Mon Dec 20 00:42:24 2010
@@ -10,6 +10,7 @@
       package="plone.i18n" />
 
   <include package="plone.folder"/>
+  <include package="plone.uuid" />
 
   <include package="Products.CMFFormController" />
   <include package="Products.CMFQuickInstallerTool" />
@@ -34,6 +35,9 @@
   <adapter
       factory=".traverse.ImageTraverser" />
 
+  <adapter
+      factory=".uuid.referenceableUUID" />
+
   <five:deprecatedManageAddDelete
       class=".ReferenceEngine.Reference" />
 
@@ -70,4 +74,7 @@
   <five:deprecatedManageAddDelete
       class=".examples.SimpleType.SimpleType" />
 
+  <adapter factory=".UIDCatalog.Title" name="Title" />
+  <adapter factory=".UIDCatalog.UID_indexer" name="UID" />
+
 </configure>

Modified: Products.Archetypes/trunk/Products/Archetypes/implements.zcml
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/implements.zcml	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/implements.zcml	Mon Dec 20 00:42:24 2010
@@ -6,5 +6,11 @@
          zcml:condition="installed plone.locking">
     <implements interface="plone.locking.interfaces.ITTWLockable" />
   </class>
+  
+  <!-- Let all AT objects support the IUUID protocol and associated views -->
+  <class class=".BaseObject.BaseObject"
+         zcml:condition="installed plone.uuid">
+      <implements interface="plone.uuid.interfaces.IUUIDAware" />
+  </class>
 
 </configure>

Modified: Products.Archetypes/trunk/Products/Archetypes/interfaces/referenceable.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/interfaces/referenceable.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/interfaces/referenceable.py	Mon Dec 20 00:42:24 2010
@@ -1,6 +1,6 @@
-from zope.interface import Interface
+from plone.uuid.interfaces import IUUIDAware
 
-class IReferenceable(Interface):
+class IReferenceable(IUUIDAware):
     """ Referenceable """
 
     def getRefs(relationship=None):

Modified: Products.Archetypes/trunk/Products/Archetypes/tests/layer.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/tests/layer.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/tests/layer.py	Mon Dec 20 00:42:24 2010
@@ -31,6 +31,9 @@
         import Products.PlacelessTranslationService
         zcml.load_config('configure.zcml', Products.PlacelessTranslationService)
 
+        import plone.uuid
+        zcml.load_config('configure.zcml', plone.uuid)
+
     setUp = classmethod(setUp)
 
     def tearDown(cls):

Modified: Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceCatalog.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceCatalog.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceCatalog.py	Mon Dec 20 00:42:24 2010
@@ -22,6 +22,12 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ################################################################################
+from zope import component
+from zope import interface
+from zope.event import notify
+from zope.lifecycleevent import ObjectCreatedEvent
+from plone.indexer.interfaces import IIndexableObject
+from Products.ZCatalog.interfaces import IZCatalog
 """
 Unittests for a reference Catalog
 
@@ -36,8 +42,42 @@
 from OFS.ObjectManager import BeforeDeleteException
 import transaction
 
+from plone.uuid.interfaces import IAttributeUUID, IUUID
+from plone.indexer import wrapper
+
+class DexterityLike(object):
+    """Create a new class non based on Archetypes"""
+    interface.implements(IAttributeUUID)
+
+    def __init__(self):
+        self.id = "myid"
+        self.portal_type = "dexterity_like"
+        self.path = []
+
+    def Title(self):
+        return u"My dexterity like content"
+
+    def getPhysicalPath(self):
+        if self.path[-1] != self.id:
+            self.path.append(self.id)
+        return self.path
+
+    def manage_fixupOwnershipAfterAdd(self):
+        pass
+    
+    def getId(self):
+        return self.id
+
+
 class ReferenceCatalogTests(ATSiteTestCase):
 
+    def afterSetUp(self):
+        #register the test class as indexable with plone.indexer default
+        sm = component.getSiteManager()
+        sm.registerAdapter(factory=wrapper.IndexableObjectWrapper,
+                           required=(interface.Interface, IZCatalog),
+                           provided=IIndexableObject)
+
     def verifyBrains(self):
         uc = getattr(self.portal, config.UID_CATALOG)
         rc = getattr(self.portal, config.REFERENCE_CATALOG)
@@ -273,7 +313,51 @@
         links3 = [o3U, o2U]
         obj1.update(sortedlinks=links3)
         self.assertEqual(obj1.getRawSortedlinks(), links3)
+    def test_TitleIndexer(self):
+        uc = getattr(self.portal, config.UID_CATALOG)
+        dext = DexterityLike()
+        dext.path = list(self.folder.getPhysicalPath())
+        self.folder[dext.id] = dext
+        uc.catalog_object(dext, '/'.join(dext.getPhysicalPath()))
+        results = uc(Title=dext.Title())
+        self.failUnless(len(results)==1)
+        self.failUnless(type(dext.Title())==unicode)
+        self.failUnless(type(results[0].Title)==str)
+
+    def test_UIDIndexer(self):
+        uc = getattr(self.portal, config.UID_CATALOG)
+        dext = DexterityLike()
+        dext.path = list(self.folder.getPhysicalPath())
+        self.folder[dext.id] = dext
+        notify(ObjectCreatedEvent(dext)) #it supposed to add uuid attribute
+
+        #catalog dext instance
+        uc.catalog_object(dext, '/'.join(dext.getPhysicalPath()))
+
+        #check lookup
+        uuid = IUUID(dext, None)
+        results = uc(UID=uuid)
+
+        self.failUnless(len(results)==1)
+        self.failUnless(results[0].UID==uuid)
+        self.failUnless(results[0].Title==str(dext.Title()))
+
+    def test_reference_non_archetypes_content(self):
+        #create a archetype based content instance
+        ob = makeContent(self.folder, portal_type='DDocument',id='mydocument')
+        uc = getattr(self.portal, config.UID_CATALOG)
+        uc.catalog_object(ob, '/'.join(ob.getPhysicalPath()))
+        #create a non archetype based content
+        dext = DexterityLike()
+        dext.path = list(self.folder.getPhysicalPath())
+        self.folder[dext.id] = dext
+        notify(ObjectCreatedEvent(dext)) #it supposed to add uuid attribute
+        uc.catalog_object(dext, '/'.join(dext.getPhysicalPath()))
+        #TODO: create the relation between those
+        ob.setRelated(dext)
+        related = ob.getRelated()
 
+        self.failUnless(related==dext)
 
 def test_suite():
     from unittest import TestSuite, makeSuite

Modified: Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceable.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceable.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/tests/test_referenceable.py	Mon Dec 20 00:42:24 2010
@@ -32,6 +32,7 @@
 from Products.Archetypes.examples import *
 from Products.Archetypes.config import *
 from Products.Archetypes.atapi import DisplayList
+from plone.uuid.interfaces import IUUIDAware, IUUID
 
 class BaseReferenceableTests(ATSiteTestCase):
 
@@ -64,6 +65,14 @@
         self.failUnless(hasattr(aq_base(doc), UUID_ATTR))
         self.failUnless(getattr(aq_base(doc), UUID_ATTR, None))
 
+    def test_uuid(self):
+        doc = makeContent( self.folder
+                           , portal_type='DDocument'
+                           , title='Foo' )
+
+        self.failUnless(IUUIDAware.providedBy(doc))
+        uuid = IUUID(doc, None)
+        self.failUnless(uuid == doc.UID())
 
     def test_renamedontchangeUID( self ):
         catalog = self.portal.uid_catalog

Modified: Products.Archetypes/trunk/Products/Archetypes/utils.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/utils.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/utils.py	Mon Dec 20 00:42:24 2010
@@ -1,19 +1,12 @@
 import logging
 import os
-import socket
 import sys
-from random import random
-from time import time
 from inspect import getargs, getmro
 from types import ClassType, MethodType
 from UserDict import UserDict as BaseDict
 
-try:
-    from hashlib import md5
-except:
-    from md5 import md5
-
 import transaction
+from zope.component import getUtility
 from zope.i18n import translate
 from zope.i18nmessageid import Message
 
@@ -28,40 +21,14 @@
 from Products.Archetypes.config import DEBUG_SECURITY
 from Products.statusmessages.interfaces import IStatusMessage
 
-try:
-    _v_network = str(socket.gethostbyname(socket.gethostname()))
-except:
-    _v_network = str(random() * 100000000000000000L)
+from plone.uuid.interfaces import IUUIDGenerator
 
 def make_uuid(*args):
-    t = str(time() * 1000L)
-    r = str(random()*100000000000000000L)
-    data = t +' '+ r +' '+ _v_network +' '+ str(args)
-    uid = md5(data).hexdigest()
-    return uid
-
-# linux kernel uid generator. It's a little bit slower but a little bit better
-KERNEL_UUID = '/proc/sys/kernel/random/uuid'
+    generator = getUtility(IUUIDGenerator)
+    return generator()
 
 logger = logging.getLogger('Archetypes')
 
-if os.path.isfile(KERNEL_UUID):
-    HAS_KERNEL_UUID = True
-    def uuid_gen():
-        fp = open(KERNEL_UUID, 'r')
-        while 1:
-            uid = fp.read()[:-1]
-            fp.seek(0)
-            yield uid
-    uid_gen = uuid_gen()
-
-    def kernel_make_uuid(*args):
-        return uid_gen.next()
-else:
-    HAS_KERNEL_UUID = False
-    kernel_make_uuid = make_uuid
-
-
 def fixSchema(schema):
     """Fix persisted schema from AT < 1.3 (UserDict-based)
     to work with the new fixed order schema."""

Modified: Products.Archetypes/trunk/setup.py
==============================================================================
--- Products.Archetypes/trunk/setup.py	(original)
+++ Products.Archetypes/trunk/setup.py	Mon Dec 20 00:42:24 2010
@@ -62,6 +62,7 @@
           'Products.statusmessages',
           'Products.validation',
           'plone.folder',
+          'plone.uuid',
           'plone.app.folder',
           'Acquisition',
           'DateTime',

------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.