[Zope-Checkins] CVS: Zope/lib/python/ComputedAttribute - _ComputedAttribute.c:1.2 __init__.py:1.2 setup.py:1.2 tests.py:1.2

Jim Fulton cvs-admin at zope.org
Fri Nov 28 11:45:00 EST 2003


Update of /cvs-repository/Zope/lib/python/ComputedAttribute
In directory cvs.zope.org:/tmp/cvs-serv4100/lib/python/ComputedAttribute

Added Files:
	_ComputedAttribute.c __init__.py setup.py tests.py 
Log Message:
Reimplemented computed attributes using new-style extension classes.


=== Zope/lib/python/ComputedAttribute/_ComputedAttribute.c 1.1 => 1.2 ===
--- /dev/null	Fri Nov 28 11:45:00 2003
+++ Zope/lib/python/ComputedAttribute/_ComputedAttribute.c	Fri Nov 28 11:44:59 2003
@@ -0,0 +1,117 @@
+/*****************************************************************************
+
+  Copyright (c) 1996-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 "ExtensionClass.h"
+
+#define UNLESS(E) if(!(E))
+#define OBJECT(O) ((PyObject*)(O))
+
+typedef struct {
+  PyObject_HEAD
+  PyObject *callable;
+  int level;
+} CA;
+
+static PyObject *
+CA__init__(CA *self, PyObject *args)
+{
+  PyObject *callable;
+  int level=0;
+
+  UNLESS(PyArg_ParseTuple(args,"O|i",&callable, &level)) return NULL;
+
+  if (level > 0) 
+    {
+      callable=PyObject_CallFunction(OBJECT(self->ob_type), "Oi", 
+				     callable, level-1);
+      UNLESS (callable) return NULL;
+      self->level=level;
+    }
+  else
+    {
+      Py_INCREF(callable);
+      self->level=0;
+    }
+
+  self->callable=callable;
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static void
+CA_dealloc(CA *self)     
+{
+  Py_DECREF(self->callable);
+  Py_DECREF(self->ob_type);
+  PyMem_DEL(self);
+}
+
+static PyObject *
+CA_of(CA *self, PyObject *args)
+{
+  if (self->level > 0) 
+    {
+      Py_INCREF(self->callable);
+      return self->callable;
+    }
+
+  if (PyString_Check(self->callable))
+    {
+      /* Special case string as simple alias. */
+      PyObject *o;
+
+      UNLESS (PyArg_ParseTuple(args,"O", &o)) return NULL;
+      return PyObject_GetAttr(o, self->callable);
+    }
+
+  return PyObject_CallObject(self->callable, args);
+}
+
+static struct PyMethodDef CA_methods[] = {
+  {"__init__",(PyCFunction)CA__init__, METH_VARARGS, ""},
+  {"__of__",  (PyCFunction)CA_of,      METH_VARARGS, ""},
+  {NULL,		NULL}		/* sentinel */
+};
+
+static PyExtensionClass ComputedAttributeType = {
+  PyObject_HEAD_INIT(NULL) 0,
+  "ComputedAttribute", sizeof(CA),
+  0,
+  (destructor)CA_dealloc,
+  0,0,0,0,0,   0,0,0,   0,0,0,0,0,   0,0,
+  "ComputedAttribute(callable) -- Create a computed attribute",
+  METHOD_CHAIN(CA_methods), 
+  (void*)(EXTENSIONCLASS_BINDABLE_FLAG)
+};
+
+static struct PyMethodDef methods[] = {
+  {NULL,		NULL}
+};
+
+void
+init_ComputedAttribute(void)
+{
+  PyObject *m, *d;
+
+  UNLESS(ExtensionClassImported) return;
+  
+  /* Create the module and add the functions */
+  m = Py_InitModule4("_ComputedAttribute", methods,
+	   "Provide Computed Attributes\n\n"
+	   "$Id$\n",
+		     OBJECT(NULL),PYTHON_API_VERSION);
+
+  d = PyModule_GetDict(m);
+  PyExtensionClass_Export(d,"ComputedAttribute",ComputedAttributeType);
+}


=== Zope/lib/python/ComputedAttribute/__init__.py 1.1 => 1.2 ===
--- /dev/null	Fri Nov 28 11:45:00 2003
+++ Zope/lib/python/ComputedAttribute/__init__.py	Fri Nov 28 11:44:59 2003
@@ -0,0 +1 @@
+from _ComputedAttribute import *


=== Zope/lib/python/ComputedAttribute/setup.py 1.1 => 1.2 ===
--- /dev/null	Fri Nov 28 11:45:00 2003
+++ Zope/lib/python/ComputedAttribute/setup.py	Fri Nov 28 11:44:59 2003
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+
+from distutils.core import setup, Extension
+setup(name="_ComputedAttribute", version="2.0",
+      ext_modules=[
+         Extension("_ComputedAttribute", ["_ComputedAttribute.c"],
+                   include_dirs = ['.', '../ExtensionClass'],
+                   depends = ['../ExtensionClass/ExtensionClass.h']),
+         ])
+


=== Zope/lib/python/ComputedAttribute/tests.py 1.1 => 1.2 ===
--- /dev/null	Fri Nov 28 11:45:00 2003
+++ Zope/lib/python/ComputedAttribute/tests.py	Fri Nov 28 11:44:59 2003
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Computed Attributes
+
+Computed attributes work much like properties:
+
+>>> import math
+>>> class Point(Base):
+...    def __init__(self, x, y):
+...        self.x, self.y = x, y
+...    length = ComputedAttribute(lambda self: math.sqrt(self.x**2+self.y**2))
+
+>>> p = Point(3, 4)
+>>> "%.1f" % p.length
+'5.0'
+
+Except that you can also use computed attributes with instances:
+
+>>> p.angle = ComputedAttribute(lambda self: math.atan(self.y*1.0/self.x))
+>>> "%.2f" % p.angle
+'0.93'
+
+$Id$
+"""
+
+def test_wrapper_support():
+    """Wrapper support
+
+    To support acquisition wrappers, computed attributes have a level.
+    The computation is only done when the level is zero. Retrieving a
+    computed attribute with a level > 0 returns a computed attribute
+    with a decremented level.
+
+    >>> class X(Base):
+    ...     pass
+
+    >>> x = X()
+    >>> x.n = 1
+    >>> x.n2 = ComputedAttribute(lambda self: self.n*2)
+    >>> x.n2
+    2
+    >>> x.n2.__class__.__name__
+    'int'
+
+    >>> x.n2 = ComputedAttribute(lambda self: self.n*2, 2)
+    >>> x.n2.__class__.__name__
+    'ComputedAttribute'
+    >>> x.n2 = x.n2
+    >>> x.n2.__class__.__name__
+    'ComputedAttribute'
+    >>> x.n2 = x.n2
+    >>> x.n2.__class__.__name__
+    'int'
+    
+    """
+
+import unittest
+from doctest import DocTestSuite
+from ExtensionClass import Base
+from ComputedAttribute import ComputedAttribute
+
+def test_suite():
+    return unittest.TestSuite((DocTestSuite(),))
+
+if __name__ == '__main__': unittest.main()




More information about the Zope-Checkins mailing list