[Zope3-checkins] CVS: Zope3/src/zope/context - declarations.py:1.1 wrapper.c:1.22

Jim Fulton jim@zope.com
Sat, 31 May 2003 18:13:09 -0400


Update of /cvs-repository/Zope3/src/zope/context
In directory cvs.zope.org:/tmp/cvs-serv21814/src/zope/context

Modified Files:
	wrapper.c 
Added Files:
	declarations.py 
Log Message:
Implemented object interface specifications for wrappers/decorators.


=== Added File Zope3/src/zope/context/declarations.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Support for interface declarations on decorators

>>> from zope.context import Wrapper
>>> from zope.interface import *
>>> class I1(Interface):
...     pass
>>> class I2(Interface):
...     pass
>>> class I3(Interface):
...     pass
>>> class I4(Interface):
...     pass

>>> class D1(Wrapper):
...   implements(I1)


>>> class D2(Wrapper):
...   implements(I2)

>>> class X:
...   implements(I3)

>>> x = X()
>>> directlyProvides(x, I4)

Interfaces of X are ordered with the directly-provided interfaces first

>>> [interface.__name__ for interface in list(providedBy(x))]
['I4', 'I3']

When we decorate objects, what order should the interfaces come in?
One could argue that decorators are less specific, so they should come last.

>>> [interface.__name__ for interface in list(providedBy(D1(x)))]
['I4', 'I3', 'I1']

>>> [interface.__name__ for interface in list(providedBy(D2(D1(x))))]
['I4', 'I3', 'I1', 'I2']

$Id: declarations.py,v 1.1 2003/05/31 22:12:38 jim Exp $
"""

from zope.proxy import getProxiedObject
from zope.interface import providedBy
from zope.interface.declarations import getObjectSpecification
from zope.interface.declarations import ObjectSpecification
from zope.interface.declarations import ObjectSpecificationDescriptor

class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):

    def __get__(self, inst, cls):
        if inst is None:
            return getObjectSpecification(cls)
        else:
            provided = providedBy(getProxiedObject(inst))

            # Use type rather than __class__ because inst is a proxy and
            # will return the proxied object's class.
            cls = type(inst) 
            return ObjectSpecification(provided, cls)

decoratorSpecificationDescriptor = DecoratorSpecificationDescriptor()


=== Zope3/src/zope/context/wrapper.c 1.21 => 1.22 ===
--- Zope3/src/zope/context/wrapper.c:1.21	Thu May 29 15:31:20 2003
+++ Zope3/src/zope/context/wrapper.c	Sat May 31 18:12:38 2003
@@ -729,6 +729,8 @@
                   strcmp(name_as_string, "__reduce__") == 0
                   ||
                   strcmp(name_as_string, "__reduce_ex__") == 0
+                  ||
+                  strcmp(name_as_string, "__providedBy__") == 0
                   )
                  )
                  );
@@ -1684,7 +1686,17 @@
 void
 initwrapper(void)
 {
-    PyObject *m;
+    PyObject *m, *descr;
+
+    /* Get the __providedBy__ descr */
+    m = PyImport_ImportModule("zope.context.declarations");
+    if (m == NULL)
+        return;
+    descr = PyObject_GetAttrString(m, "decoratorSpecificationDescriptor");
+    Py_DECREF(m);
+    if (descr == NULL) 
+        return;
+    
 
     if (Proxy_Import() < 0)
         return;
@@ -1708,6 +1720,10 @@
     WrapperType.tp_alloc = PyType_GenericAlloc;
     WrapperType.tp_free = _PyObject_GC_Del;
     if (PyType_Ready(&WrapperType) < 0)
+        return;
+
+    /* Install the __providedBy__ descr */
+    if (PyDict_SetItemString(WrapperType.tp_dict, "__providedBy__", descr) < 0)
         return;
 
     Py_INCREF(&WrapperType);