[Zope3-checkins] CVS: Zope3/src/zope/app/services - field.py:1.5

Steve Alexander steve@cat-box.net
Fri, 10 Jan 2003 13:46:58 -0500


Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv6406/src/zope/app/services

Modified Files:
	field.py 
Log Message:
Created a ComponentLocation field to specify a location by path or by
dotted module name.


=== Zope3/src/zope/app/services/field.py 1.4 => 1.5 ===
--- Zope3/src/zope/app/services/field.py:1.4	Thu Jan  9 14:13:49 2003
+++ Zope3/src/zope/app/services/field.py	Fri Jan 10 13:46:26 2003
@@ -22,6 +22,9 @@
 from zope.app.traversing import traverse
 from zope.exceptions import NotFoundError
 from zope.app.interfaces.services.field import IComponentPath
+from zope.app.interfaces.services.field import IComponentLocation
+from zope.component import getServiceManager, getAdapter
+from zope.app.interfaces.services.service import INameResolver
 
 class ComponentPath(Field):
 
@@ -47,3 +50,50 @@
         if not self.type.isImplementedBy(component):
             raise ValidationError("Wrong component type", value)
 
+class ComponentLocation(Field):
+
+    __implements__ = IComponentLocation
+
+    _type = unicode
+
+    def __init__(self, type, *args, **kw):
+        self.type = type
+        super(ComponentLocation, self).__init__(*args, **kw)
+
+    def _validate(self, value):
+        super(ComponentLocation, self)._validate(value)
+        component = locateComponent(value, self.context, self.type)
+
+
+def locateComponent(location, context, interface=None):
+    '''Located a component by traversal, or by a dotted module name.
+
+    If 'interface' is given, check that the located componenent implements
+    the given interface.
+    '''
+    if location.startswith('/'):
+        try:
+            component = traverse(context, location)
+        except NotFoundError:
+            raise ValidationError('Path for non-existent object', location)
+    else:
+        # Assume location is a dotted module name
+        if location.startswith('.'):
+            # Catch the error of thinking that this is just like 
+            # a leading dot in zcml.
+            raise ValidationError(
+                    "Module name must not start with a '.'", location)
+        # XXX Need to be careful here. Jim was going to look
+        #     at whether a checkedResolve method is needed.
+        servicemanager = getServiceManager(context)
+        resolver = getAdapter(servicemanager, INameResolver)
+        try:
+            component = resolver.resolve(location)
+        except ImportError:
+            raise ValidationError("Cannot resolve module name", location)
+
+    if interface is not None and not interface.isImplementedBy(component):
+        raise ValidationError(
+                'Component must be %s' % interface, location)
+
+    return component