[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