[Zope3-checkins] CVS: Zope3/src/zope/app/container - _zope_app_container_contained.c:1.1.2.1 contained.py:1.1.2.5

Jim Fulton jim at zope.com
Wed Sep 17 09:01:19 EDT 2003


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

Modified Files:
      Tag: parentgeddon-branch
	contained.py 
Added Files:
      Tag: parentgeddon-branch
	_zope_app_container_contained.c 
Log Message:
Reimplemented the ContainedProxy to be a persistent proxy.

Had to make some changes to zodb to support persistent proxies.
I've termorarily broken conflict resolution.



=== Added File Zope3/src/zope/app/container/_zope_app_container_contained.c ===
/*############################################################################
#
# 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.
#
############################################################################*/

#include "Python.h"
#include "persistence/persistence.h"
#include "persistence/persistenceAPI.h"

typedef struct {
  PyPersist_HEAD                 
  PyObject *po_serial;            
  PyObject *po_weaklist;          
  PyObject *proxy_object;
  PyObject *__parent__;
  PyObject *__name__;
} ProxyObject;

typedef struct {
    PyTypeObject *proxytype;
    int (*check)(PyObject *obj);
    PyObject *(*create)(PyObject *obj);
    PyObject *(*getobject)(PyObject *proxy);
} ProxyInterface;

#define Proxy_GET_OBJECT(ob)   (((ProxyObject *)(ob))->proxy_object)

/* Supress inclusion of the original proxy.h */
#define _proxy_H_ 1

/* Incude the proxy C source */
#include "zope/proxy/_zope_proxy_proxy.c"

#define SPECIAL(NAME) (                        \
    *(NAME) == '_' &&                          \
      (((NAME)[1] == 'p' && (NAME)[2] == '_')  \
       ||                                      \
       ((NAME)[1] == '_' && (                  \
         strcmp((NAME), "__parent__") == 0     \
         ||                                    \
         strcmp((NAME), "__name__") == 0       \
         ||                                    \
         strcmp((NAME), "__getstate__") == 0   \
         ||                                    \
         strcmp((NAME), "__setstate__") == 0   \
         ||                                    \
         strcmp((NAME), "__getnewargs__") == 0 \
         ||                                    \
         strcmp((NAME), "__reduce__") == 0     \
         ||                                    \
         strcmp((NAME), "__reduce_ex__") == 0  \
         ))                                    \
       ))
      
static PyObject *
CP_getattro(PyObject *self, PyObject *name)
{
  char *cname;

  cname = PyString_AsString(name);
  if (cname == NULL)
    return NULL;

  if (SPECIAL(cname))
    /* delegate to persistent */
    return PyPersist_TYPE->tp_getattro(self, name);

  /* Use the wrapper version to delegate */
  return wrap_getattro(self, name);
}

static int
CP_setattro(PyObject *self, PyObject *name, PyObject *v)
{
  char *cname;

  cname = PyString_AsString(name);
  if (cname == NULL)
    return -1;

  if (SPECIAL(cname))
    /* delegate to persistent */
    return PyPersist_TYPE->tp_setattro(self, name, v);

  /* Use the wrapper version to delegate */
  return wrap_setattro(self, name, v);
}

static PyObject *
CP_getstate(ProxyObject *self)
{
  return Py_BuildValue("OO", 
                       self->__parent__ ? self->__parent__ : Py_None,
                       self->__name__   ? self->__name__   : Py_None
                       );
}

static PyObject *
CP_getnewargs(ProxyObject *self)
{
  return Py_BuildValue("(O)", self->proxy_object);
}

static PyObject *
CP_setstate(ProxyObject *self, PyObject *state)
{
  if(! PyArg_ParseTuple(state, "OO", &self->__parent__, &self->__name__))
    return NULL;
  Py_INCREF(self->__parent__);
  Py_INCREF(self->__name__);
  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject *
CP_reduce(ProxyObject *self)
{
  return Py_BuildValue("O(O)(OO)",
                       self->ob_type,
                       self->proxy_object,
                       self->__parent__ ? self->__parent__ : Py_None,
                       self->__name__   ? self->__name__   : Py_None
                       );
}

static PyObject *
CP_reduce_ex(ProxyObject *self, PyObject *proto)
{
  return CP_reduce(self);
}

static PyMethodDef
CP_methods[] = {
  {"__getstate__", (PyCFunction)CP_getstate, METH_NOARGS, 
   "Get the object state"},
  {"__setstate__", (PyCFunction)CP_setstate, METH_O, 
   "Set the object state"},
  {"__getnewargs__", (PyCFunction)CP_getnewargs, METH_NOARGS, 
   "Get the arguments that must be passed to __new__"},
  {"__reduce__", (PyCFunction)CP_reduce, METH_NOARGS, 
   "Reduce the object to constituent parts."},
  {"__reduce_ex__", (PyCFunction)CP_reduce_ex, METH_O, 
   "Reduce the object to constituent parts."},
  {NULL, NULL},
};


/* Code to access structure members by accessing attributes */

#include "structmember.h"

static PyMemberDef CP_members[] = {
  {"_p_serial", T_OBJECT, offsetof(ProxyObject, po_serial)},
  {"__parent__", T_OBJECT, offsetof(ProxyObject, __parent__)},
  {"__name__", T_OBJECT, offsetof(ProxyObject, __name__)},
  {NULL}	/* Sentinel */
};

static int
CP_traverse(ProxyObject *self, visitproc visit, void *arg)
{
  if (self->po_serial != NULL && visit(self->po_serial, arg) < 0)
    return -1;
  if (self->po_weaklist != NULL && visit(self->po_weaklist, arg) < 0)
    return -1;
  if (self->proxy_object != NULL && visit(self->proxy_object, arg) < 0)
    return -1;
  if (self->__parent__ != NULL && visit(self->__parent__, arg) < 0)
    return -1;
  if (self->__name__ != NULL && visit(self->__name__, arg) < 0)
    return -1;
  
  return 0;
}

static int
CP_clear(ProxyObject *self)
{
  /* XXXX Drop references that may have created reference
     cycles. Immutable objects do not have to define this method
     since they can never directly create reference cycles. Note
     that the object must still be valid after calling this
     method (don't just call Py_DECREF() on a reference). The
     collector will call this method if it detects that this
     object is involved in a reference cycle.
  */
  Py_XDECREF(self->po_serial);
  self->po_serial = NULL;
  Py_XDECREF(self->po_weaklist);
  self->po_weaklist = NULL;
  Py_XDECREF(self->proxy_object);
  self->proxy_object = NULL;
  Py_XDECREF(self->__parent__);
  self->__parent__ = NULL;
  Py_XDECREF(self->__name__);
  self->__name__ = NULL;
  return 0;
}

static void
CP_dealloc(ProxyObject *self)
{
  PyObject_GC_UnTrack((PyObject *)self);
  CP_clear(self);
  self->ob_type->tp_free((PyObject*)self);
}

#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
init_zope_app_container_contained(void)
{
  PyObject *m;
        
  /* Try to fake out compiler nag function */
  if (0) init_zope_proxy_proxy();
  
  m = Py_InitModule3("_zope_app_container_contained", 
                     module_functions, module___doc__);

  if (m == NULL)
    return;

  if (empty_tuple == NULL)
    empty_tuple = PyTuple_New(0);

  /* Initialize the PyPersist_C_API and the type objects. */
  PyPersist_C_API = PyCObject_Import("persistence._persistence", "C_API");
  if (PyPersist_C_API == NULL)
    return;

  
  ProxyType.tp_name = "zope.app.container.contained.ContainedProxyBase";
  ProxyType.ob_type = &PyType_Type;
  ProxyType.tp_base = PyPersist_TYPE;
  ProxyType.tp_getattro = CP_getattro;
  ProxyType.tp_setattro = CP_setattro;
  ProxyType.tp_members = CP_members;
  ProxyType.tp_methods = CP_methods;
  ProxyType.tp_traverse = (traverseproc) CP_traverse;
  ProxyType.tp_clear = (inquiry) CP_clear;
  ProxyType.tp_dealloc = (destructor) CP_dealloc;
  ProxyType.tp_weaklistoffset = offsetof(ProxyObject, po_weaklist);

  if (PyType_Ready(&ProxyType) < 0)
    return;

  Py_INCREF(&ProxyType);
  PyModule_AddObject(m, "ContainedProxyBase", (PyObject *)&ProxyType);
}


=== Zope3/src/zope/app/container/contained.py 1.1.2.4 => 1.1.2.5 ===
--- Zope3/src/zope/app/container/contained.py:1.1.2.4	Mon Sep 15 14:12:30 2003
+++ Zope3/src/zope/app/container/contained.py	Wed Sep 17 09:00:48 2003
@@ -17,8 +17,6 @@
 """
 
 from zope.app import zapi
-from zope.app.decorator import DecoratedSecurityCheckerDescriptor
-from zope.app.decorator import DecoratorSpecificationDescriptor
 from zope.app.event.objectevent import ObjectEvent, modified
 from zope.app.event import publish
 from zope.app.i18n import ZopeMessageIDFactory as _
@@ -33,6 +31,13 @@
 from zope.exceptions import DuplicationError
 from zope.proxy import ProxyBase, getProxiedObject
 import zope.interface
+from zope.app.container._zope_app_container_contained import ContainedProxyBase
+from zope.app.container._zope_app_container_contained import getProxiedObject
+from zope.security.checker import selectChecker, CombinedChecker
+from zope.interface.declarations import ObjectSpecificationDescriptor
+from zope.interface.declarations import getObjectSpecification
+from zope.interface.declarations import ObjectSpecification
+from zope.interface import providedBy
 
 class Contained(object):
     """Stupid mix-in that defines __parent__ and __name__ attributes
@@ -546,66 +551,6 @@
     object.__name__ = None
     modified(container)
 
-
-class ContainedProxy(ProxyBase):
-    """Contained-object proxy
-
-    This is a picklable proxy that can be put around objects that
-    don't implemeny IContained.
-
-    >>> l = [1, 2, 3]
-    >>> p = ContainedProxy(l, "Dad", "p")
-    >>> p
-    [1, 2, 3]
-    >>> p.__parent__
-    'Dad'
-    >>> p.__name__
-    'p'
-
-    >>> import pickle
-    >>> p2 = pickle.loads(pickle.dumps(p))
-    >>> p2
-    [1, 2, 3]
-    >>> p2.__parent__
-    'Dad'
-    >>> p2.__name__
-    'p'
-    
-    
-    """
-
-    zope.interface.implements(IContained)
-
-    __slots__ = '__parent__', '__name__'
-    __safe_for_unpickling__ = True
-
-    def __new__(self, ob, container=None, name=None):
-        return ProxyBase.__new__(self, ob)
-
-    def __init__(self, ob, container=None, name=None):
-        ProxyBase.__init__(self, ob)
-        self.__parent__ = container
-        self.__name__ = name
-
-    def __reduce__(self, proto=None):
-        return (ContainedProxy,
-                (getProxiedObject(self), 
-                 self.__parent__, self.__name__),
-                )
-
-    __reduce_ex__ = __reduce__
-
-    __providedBy__ = DecoratorSpecificationDescriptor()
-
-    __Security_checker__ = DecoratedSecurityCheckerDescriptor()
-
-    def _p_oid(self):
-        # I'm not persistent, Dagnabit.
-        raise AttributeError, '_p_oid'
-
-    _p_oid = property(_p_oid)
-
-
 class NameChooser:
 
     zope.interface.implements(INameChooser)
@@ -665,3 +610,89 @@
         self.checkName(n, object)
                 
         return n
+
+
+class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):
+    """Support for interface declarations on decorators
+
+    >>> from zope.interface import *
+    >>> class I1(Interface):
+    ...     pass
+    >>> class I2(Interface):
+    ...     pass
+    >>> class I3(Interface):
+    ...     pass
+    >>> class I4(Interface):
+    ...     pass
+
+    >>> class D1(ContainedProxy):
+    ...   implements(I1)
+
+
+    >>> class D2(ContainedProxy):
+    ...   implements(I2)
+
+    >>> class X:
+    ...   implements(I3)
+
+    >>> x = X()
+    >>> directlyProvides(x, I4)
+
+    Interfaces of X are ordered with the directly-provided interfaces first
+
+    >>> [interface.getName() 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.getName() for interface in list(providedBy(D1(x)))]
+    ['I4', 'I3', 'I1', 'IContained', 'IPersistent']
+
+    >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
+    ['I4', 'I3', 'I1', 'IContained', 'IPersistent', 'I2']
+    """
+    def __get__(self, inst, cls=None):
+        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)
+
+
+class DecoratedSecurityCheckerDescriptor(object):
+    """Descriptor for a Decorator that provides a decorated security checker.
+    """
+    def __get__(self, inst, cls=None):
+        if inst is None:
+            return self
+        else:
+            proxied_object = getProxiedObject(inst)
+            checker = getattr(proxied_object, '__Security_checker__', None)
+            if checker is None:
+                checker = selectChecker(proxied_object)
+            wrapper_checker = selectChecker(inst)
+            if wrapper_checker is None:
+                return checker
+            elif checker is None:
+                return wrapper_checker
+            else:
+                return CombinedChecker(wrapper_checker, checker)
+
+
+class ContainedProxy(ContainedProxyBase):
+
+    zope.interface.implements(IContained)
+
+    __providedBy__ = DecoratorSpecificationDescriptor()
+
+    __Security_checker__ = DecoratedSecurityCheckerDescriptor()
+
+    def __eq__(self, other):
+        return self is other
+    




More information about the Zope3-Checkins mailing list