]> granicus.if.org Git - python/commitdiff
Merge of descr-branch back into trunk.
authorTim Peters <tim.peters@gmail.com>
Thu, 2 Aug 2001 04:15:00 +0000 (04:15 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 2 Aug 2001 04:15:00 +0000 (04:15 +0000)
57 files changed:
Include/Python.h
Include/abstract.h
Include/ceval.h
Include/classobject.h
Include/descrobject.h [new file with mode: 0644]
Include/dictobject.h
Include/eval.h
Include/funcobject.h
Include/listobject.h
Include/modsupport.h
Include/object.h
Include/objimpl.h
Include/patchlevel.h
Include/pythonrun.h
Lib/pickle.py
Lib/repr.py
Lib/test/test_descr.py [new file with mode: 0644]
Lib/test/test_generators.py
Lib/types.py
Makefile.pre.in
Misc/NEWS
Modules/Setup.dist
Modules/cPickle.c
Modules/config.c.in
Modules/xxsubtype.c [new file with mode: 0644]
Objects/abstract.c
Objects/bufferobject.c
Objects/cellobject.c
Objects/classobject.c
Objects/complexobject.c
Objects/descrobject.c [new file with mode: 0644]
Objects/dictobject.c
Objects/fileobject.c
Objects/floatobject.c
Objects/frameobject.c
Objects/funcobject.c
Objects/intobject.c
Objects/iterobject.c
Objects/listobject.c
Objects/longobject.c
Objects/methodobject.c
Objects/moduleobject.c
Objects/object.c
Objects/rangeobject.c
Objects/sliceobject.c
Objects/stringobject.c
Objects/tupleobject.c
Objects/typeobject.c
Objects/unicodeobject.c
PC/config.c
PCbuild/pythoncore.dsp
PLAN.txt [new file with mode: 0644]
Python/bltinmodule.c
Python/ceval.c
Python/exceptions.c
Python/import.c
Python/pythonrun.c

index f9c33d42fc082fb414a2f8502e061c08d4d201a3..9757a70914371397483ba744e5875127bc35cf11 100644 (file)
@@ -89,6 +89,7 @@
 #include "sliceobject.h"
 #include "cellobject.h"
 #include "iterobject.h"
+#include "descrobject.h"
 
 #include "codecs.h"
 #include "pyerrors.h"
index 9082edb0b83fd849f283ae346cd781b562976608..799438e2b1dc91ed621e54ce10594511babfa10b 100644 (file)
@@ -294,6 +294,17 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
        */
 
 
+
+     DL_IMPORT(PyObject *) PyObject_Call(PyObject *callable_object,
+                                        PyObject *args, PyObject *kw);
+
+       /*
+
+        Call a callable Python object, callable_object, with
+        arguments and keywords arguments.  The 'args' argument can not be
+        NULL, but the 'kw' argument can be NULL.
+
+       */
      
      DL_IMPORT(PyObject *) PyObject_CallObject(PyObject *callable_object,
                                                PyObject *args);
index 0fc5cbabfe0b5275c9fcfd188ab903a674aa3a30..ae4d8583c6cc96226cf11d8bb809b5365f76cc6d 100644 (file)
@@ -45,6 +45,9 @@ DL_IMPORT(int) Py_MakePendingCalls(void);
 DL_IMPORT(void) Py_SetRecursionLimit(int);
 DL_IMPORT(int) Py_GetRecursionLimit(void);
 
+DL_IMPORT(char *) PyEval_GetFuncName(PyObject *);
+DL_IMPORT(char *) PyEval_GetFuncDesc(PyObject *);
+
 /* Interface for threads.
 
    A module that plans to do a blocking system call (or something else
index 3b25c7447d633565bf15c0a122f2f36f441f07a4..3bd535e1c35a581855644637a0876b084b575ea0 100644 (file)
@@ -47,10 +47,6 @@ extern DL_IMPORT(PyObject *) PyInstance_New(PyObject *, PyObject *,
 extern DL_IMPORT(PyObject *) PyInstance_NewRaw(PyObject *, PyObject *);
 extern DL_IMPORT(PyObject *) PyMethod_New(PyObject *, PyObject *, PyObject *);
 
-extern DL_IMPORT(PyObject *) PyMethod_Function(PyObject *);
-extern DL_IMPORT(PyObject *) PyMethod_Self(PyObject *);
-extern DL_IMPORT(PyObject *) PyMethod_Class(PyObject *);
-
 /* Macros for direct access to these values. Type checks are *not*
    done, so use with care. */
 #define PyMethod_GET_FUNCTION(meth) \
diff --git a/Include/descrobject.h b/Include/descrobject.h
new file mode 100644 (file)
index 0000000..b6fc521
--- /dev/null
@@ -0,0 +1,32 @@
+/* XXX getter, setter, getsetlist and wrapperbase need 'Py'-prefixed names */
+
+typedef PyObject *(*getter)(PyObject *, void *);
+typedef int (*setter)(PyObject *, PyObject *, void *);
+
+struct getsetlist {
+       char *name;
+       getter get;
+       setter set;
+       void *closure;
+};
+
+typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
+                                void *wrapped);
+
+struct wrapperbase {
+       char *name;
+       wrapperfunc wrapper;
+       char *doc;
+};
+
+extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
+extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
+                                              struct memberlist *);
+extern DL_IMPORT(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
+                                              struct getsetlist *);
+extern DL_IMPORT(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
+                                               struct wrapperbase *, void *);
+extern DL_IMPORT(int) PyDescr_IsData(PyObject *);
+
+extern DL_IMPORT(PyObject *) PyDictProxy_New(PyObject *);
+extern DL_IMPORT(PyObject *) PyWrapper_New(PyObject *, PyObject *);
index 4f5f94a115c5f055bcd026fac6f3f41b49d460a2..abc8ed567d0c5631b13ae2bd1a5870cd27d95d4f 100644 (file)
@@ -7,9 +7,83 @@ extern "C" {
 
 /* Dictionary object type -- mapping from hashable object to object */
 
+/*
+There are three kinds of slots in the table:
+
+1. Unused.  me_key == me_value == NULL
+   Does not hold an active (key, value) pair now and never did.  Unused can
+   transition to Active upon key insertion.  This is the only case in which
+   me_key is NULL, and is each slot's initial state.
+
+2. Active.  me_key != NULL and me_key != dummy and me_value != NULL
+   Holds an active (key, value) pair.  Active can transition to Dummy upon
+   key deletion.  This is the only case in which me_value != NULL.
+
+3. Dummy.  me_key == dummy and me_value == NULL
+   Previously held an active (key, value) pair, but that was deleted and an
+   active pair has not yet overwritten the slot.  Dummy can transition to
+   Active upon key insertion.  Dummy slots cannot be made Unused again
+   (cannot have me_key set to NULL), else the probe sequence in case of
+   collision would have no way to know they were once active.
+
+Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to
+hold a search finger.  The me_hash field of Unused or Dummy slots has no
+meaning otherwise.
+*/
+
+/* PyDict_MINSIZE is the minimum size of a dictionary.  This many slots are
+ * allocated directly in the dict object (in the ma_smalltable member).
+ * It must be a power of 2, and at least 4.  8 allows dicts with no more
+ * than 5 active entries to live in ma_smalltable (and so avoid an
+ * additional malloc); instrumentation suggested this suffices for the
+ * majority of dicts (consisting mostly of usually-small instance dicts and
+ * usually-small dicts created to pass keyword arguments).
+ */
+#define PyDict_MINSIZE 8
+
+typedef struct {
+       long me_hash;      /* cached hash code of me_key */
+       PyObject *me_key;
+       PyObject *me_value;
+#ifdef USE_CACHE_ALIGNED
+       long    aligner;
+#endif
+} PyDictEntry;
+
+/*
+To ensure the lookup algorithm terminates, there must be at least one Unused
+slot (NULL key) in the table.
+The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
+ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
+values == the number of Active items).
+To avoid slowing down lookups on a near-full table, we resize the table when
+it's two-thirds full.
+*/
+typedef struct _dictobject PyDictObject;
+struct _dictobject {
+       PyObject_HEAD
+       int ma_fill;  /* # Active + # Dummy */
+       int ma_used;  /* # Active */
+
+       /* The table contains ma_mask + 1 slots, and that's a power of 2.
+        * We store the mask instead of the size because the mask is more
+        * frequently needed.
+        */
+       int ma_mask;
+
+       /* ma_table points to ma_smalltable for small tables, else to
+        * additional malloc'ed memory.  ma_table is never NULL!  This rule
+        * saves repeated runtime null-tests in the workhorse getitem and
+        * setitem calls.
+        */
+       PyDictEntry *ma_table;
+       PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash);
+       PyDictEntry ma_smalltable[PyDict_MINSIZE];
+};
+
 extern DL_IMPORT(PyTypeObject) PyDict_Type;
 
-#define PyDict_Check(op) ((op)->ob_type == &PyDict_Type)
+#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type)
 
 extern DL_IMPORT(PyObject *) PyDict_New(void);
 extern DL_IMPORT(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
@@ -23,6 +97,7 @@ extern DL_IMPORT(PyObject *) PyDict_Values(PyObject *mp);
 extern DL_IMPORT(PyObject *) PyDict_Items(PyObject *mp);
 extern DL_IMPORT(int) PyDict_Size(PyObject *mp);
 extern DL_IMPORT(PyObject *) PyDict_Copy(PyObject *mp);
+extern DL_IMPORT(int) PyDict_Update(PyObject *mp, PyObject *other);
 
 
 extern DL_IMPORT(PyObject *) PyDict_GetItemString(PyObject *dp, char *key);
index 2a45009025781a170f8237d1595460227ba54d2f..f9334a75f073a83816eafdf1ea98a0d6636f3588 100644 (file)
@@ -9,6 +9,14 @@ extern "C" {
 
 DL_IMPORT(PyObject *) PyEval_EvalCode(PyCodeObject *, PyObject *, PyObject *);
 
+DL_IMPORT(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
+                                       PyObject *globals,
+                                       PyObject *locals,
+                                       PyObject **args, int argc,
+                                       PyObject **kwds, int kwdc,
+                                       PyObject **defs, int defc,
+                                       PyObject *closure);
+
 #ifdef __cplusplus
 }
 #endif
index 8cedeb7efdcb9afa38fde4bf8dcaa713428a2169..6b1e389b7ce762257c00da142a174170130fa78d 100644 (file)
@@ -42,6 +42,13 @@ extern DL_IMPORT(int) PyFunction_SetClosure(PyObject *, PyObject *);
 #define PyFunction_GET_CLOSURE(func) \
        (((PyFunctionObject *)func) -> func_closure)
 
+/* The classmethod and staticmethod types lives here, too */
+extern DL_IMPORT(PyTypeObject) PyClassMethod_Type;
+extern DL_IMPORT(PyTypeObject) PyStaticMethod_Type;
+
+extern DL_IMPORT(PyObject *) PyClassMethod_New(PyObject *);
+extern DL_IMPORT(PyObject *) PyStaticMethod_New(PyObject *);
+
 #ifdef __cplusplus
 }
 #endif
index 73ac724e08f0271e04a7cea062c3bc1aa9bdfbd6..af1368c987b298bec197b95ae353f3dd6ba2bd90 100644 (file)
@@ -26,7 +26,7 @@ typedef struct {
 
 extern DL_IMPORT(PyTypeObject) PyList_Type;
 
-#define PyList_Check(op) ((op)->ob_type == &PyList_Type)
+#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type)
 
 extern DL_IMPORT(PyObject *) PyList_New(int size);
 extern DL_IMPORT(int) PyList_Size(PyObject *);
index 4a40499eb564ff34d1f3ec5d9c739d31acf38b3a..8ef343c6d755f22961739db540230349dc5270c5 100644 (file)
@@ -22,8 +22,8 @@ extern DL_IMPORT(int) PyModule_AddObject(PyObject *, char *, PyObject *);
 extern DL_IMPORT(int) PyModule_AddIntConstant(PyObject *, char *, long);
 extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
 
-#define PYTHON_API_VERSION 1010
-#define PYTHON_API_STRING "1010"
+#define PYTHON_API_VERSION 1011
+#define PYTHON_API_STRING "1011"
 /* The API version is maintained (independently from the Python version)
    so we can detect mismatches between the interpreter and dynamically
    loaded modules.  These are diagnosed by an error message but
@@ -37,6 +37,8 @@ extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
    Please add a line or two to the top of this log for each API
    version change:
 
+   17-Jul-2001 GvR     1011    Descr-branch, just to be on the safe side
+
    25-Jan-2001  FLD     1010    Parameters added to PyCode_New() and
                                 PyFrame_New(); Python 2.1a2
 
index 0765748e9fcd7bf1ba65c795b35fe63796c220a6..d81d4c20a29e97765a41b430db6d6ad7148dda1e 100644 (file)
@@ -202,6 +202,11 @@ typedef long (*hashfunc)(PyObject *);
 typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
 typedef PyObject *(*getiterfunc) (PyObject *);
 typedef PyObject *(*iternextfunc) (PyObject *);
+typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
+typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
+typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
+typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
+typedef PyObject *(*allocfunc)(struct _typeobject *, int);
 
 typedef struct _typeobject {
        PyObject_VAR_HEAD
@@ -255,18 +260,48 @@ typedef struct _typeobject {
        getiterfunc tp_iter;
        iternextfunc tp_iternext;
 
+       /* Attribute descriptor and subclassing stuff */
+       struct PyMethodDef *tp_methods;
+       struct memberlist *tp_members;
+       struct getsetlist *tp_getset;
+       struct _typeobject *tp_base;
+       PyObject *tp_dict;
+       descrgetfunc tp_descr_get;
+       descrsetfunc tp_descr_set;
+       long tp_dictoffset;
+       initproc tp_init;
+       allocfunc tp_alloc;
+       newfunc tp_new;
+       destructor tp_free; /* Low-level free-memory routine */
+       PyObject *tp_bases;
+       PyObject *tp_mro; /* method resolution order */
+       PyObject *tp_defined;
+
 #ifdef COUNT_ALLOCS
        /* these must be last and never explicitly initialized */
-       int tp_alloc;
-       int tp_free;
+       int tp_allocs;
+       int tp_frees;
        int tp_maxalloc;
        struct _typeobject *tp_next;
 #endif
 } PyTypeObject;
 
-extern DL_IMPORT(PyTypeObject) PyType_Type; /* The type of type objects */
 
-#define PyType_Check(op) ((op)->ob_type == &PyType_Type)
+/* Generic type check */
+extern DL_IMPORT(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *);
+#define PyObject_TypeCheck(ob, tp) \
+       ((ob)->ob_type == (tp) || PyType_IsSubtype((ob)->ob_type, (tp)))
+
+extern DL_IMPORT(PyTypeObject) PyType_Type; /* Metatype */
+extern DL_IMPORT(PyTypeObject) PyBaseObject_Type; /* Most base object type */
+
+#define PyType_Check(op) PyObject_TypeCheck(op, &PyType_Type)
+
+extern DL_IMPORT(int) PyType_InitDict(PyTypeObject *);
+extern DL_IMPORT(PyObject *) PyType_GenericAlloc(PyTypeObject *, int);
+extern DL_IMPORT(PyObject *) PyType_GenericNew(PyTypeObject *,
+                                              PyObject *, PyObject *);
+extern DL_IMPORT(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
 
 /* Generic operations on objects */
 extern DL_IMPORT(int) PyObject_Print(PyObject *, FILE *, int);
@@ -283,6 +318,10 @@ extern DL_IMPORT(int) PyObject_HasAttrString(PyObject *, char *);
 extern DL_IMPORT(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
 extern DL_IMPORT(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
 extern DL_IMPORT(int) PyObject_HasAttr(PyObject *, PyObject *);
+extern DL_IMPORT(PyObject **) _PyObject_GetDictPtr(PyObject *);
+extern DL_IMPORT(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
+extern DL_IMPORT(int) PyObject_GenericSetAttr(PyObject *,
+                                             PyObject *, PyObject *);
 extern DL_IMPORT(long) PyObject_Hash(PyObject *);
 extern DL_IMPORT(int) PyObject_IsTrue(PyObject *);
 extern DL_IMPORT(int) PyObject_Not(PyObject *);
@@ -357,6 +396,18 @@ given type object has a specified feature.
 /* tp_iter is defined */
 #define Py_TPFLAGS_HAVE_ITER (1L<<7)
 
+/* Experimental stuff for healing the type/class split */
+#define Py_TPFLAGS_HAVE_CLASS (1L<<8)
+
+/* Set if the type object is dynamically allocated */
+#define Py_TPFLAGS_HEAPTYPE (1L<<9)
+
+/* Set if the type allows subclassing */
+#define Py_TPFLAGS_BASETYPE (1L<<10)
+
+/* Set if the type's __dict__ may change */
+#define Py_TPFLAGS_DYNAMICTYPE (1L<<11)
+
 #define Py_TPFLAGS_DEFAULT  ( \
                              Py_TPFLAGS_HAVE_GETCHARBUFFER | \
                              Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@@ -364,6 +415,7 @@ given type object has a specified feature.
                              Py_TPFLAGS_HAVE_RICHCOMPARE | \
                              Py_TPFLAGS_HAVE_WEAKREFS | \
                              Py_TPFLAGS_HAVE_ITER | \
+                             Py_TPFLAGS_HAVE_CLASS | \
                             0)
 
 #define PyType_HasFeature(t,f)  (((t)->tp_flags & (f)) != 0)
@@ -412,8 +464,8 @@ extern DL_IMPORT(void) _Py_ResetReferences(void);
 
 #ifndef Py_TRACE_REFS
 #ifdef COUNT_ALLOCS
-#define _Py_Dealloc(op) ((op)->ob_type->tp_free++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
-#define _Py_ForgetReference(op) ((op)->ob_type->tp_free++)
+#define _Py_Dealloc(op) ((op)->ob_type->tp_frees++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
+#define _Py_ForgetReference(op) ((op)->ob_type->tp_frees++)
 #else /* !COUNT_ALLOCS */
 #define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op))
 #define _Py_ForgetReference(op) /*empty*/
index 4aa38d5673d4074b9f9633b0716003c329c8aa60..18cece8e2516f6fec4c8d436197ccc6f7990ce50 100644 (file)
@@ -236,7 +236,13 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
 #define PyObject_GC_Fini(op)
 #define PyObject_AS_GC(op) (op)
 #define PyObject_FROM_GC(op) (op)
+#define PyType_IS_GC(t) 0
+#define PyObject_IS_GC(o) 0
+#define PyObject_AS_GC(o) (o)
+#define PyObject_FROM_GC(o) (o)
+#define PyType_BASICSIZE(t) ((t)->tp_basicsize)
+#define PyType_SET_BASICSIZE(t, s) ((t)->tp_basicsize = (s))
+
 #else
 
 /* Add the object into the container set */
@@ -269,6 +275,13 @@ typedef struct _gc_head {
 /* Get the object given the PyGC_Head */
 #define PyObject_FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
 
+/* Calculate tp_basicsize excluding PyGC_HEAD_SIZE if applicable */
+#define PyType_BASICSIZE(t) (!PyType_IS_GC(t) ? (t)->tp_basicsize : \
+                            (t)->tp_basicsize - PyGC_HEAD_SIZE)
+#define PyType_SET_BASICSIZE(t, s) (!PyType_IS_GC(t) ? \
+                       ((t)->tp_basicsize = (s)) : \
+                       ((t)->tp_basicsize  = (s) + PyGC_HEAD_SIZE))
+
 extern DL_IMPORT(void) _PyGC_Dump(PyGC_Head *);
 
 #endif /* WITH_CYCLE_GC */
index dddc28f017a24f9b9c6b2cc9af46aefe447123e4..85ffacb2b00dcd5993bd3b0f5082848668ebcb95 100644 (file)
 #define PY_MINOR_VERSION       2
 #define PY_MICRO_VERSION       0
 #define PY_RELEASE_LEVEL       PY_RELEASE_LEVEL_ALPHA
-#define PY_RELEASE_SERIAL      0
+#define PY_RELEASE_SERIAL      1
 
 /* Version as a string */
-#define PY_VERSION             "2.2a0"
+#define PY_VERSION             "2.2a1"
 
 /* Historic */
-#define PATCHLEVEL             "2.2a0"
+#define PATCHLEVEL             "2.2a1"
 
 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
    Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */
index 6e9821bf7fcdf8da701a94d7319ace1ea06d9d30..7d947dffe4b6faac8ca1ccb763c355bb02fb0147 100644 (file)
@@ -92,10 +92,10 @@ DL_IMPORT(const char *) Py_GetBuildInfo(void);
 DL_IMPORT(PyObject *) _PyBuiltin_Init(void);
 DL_IMPORT(PyObject *) _PySys_Init(void);
 DL_IMPORT(void) _PyImport_Init(void);
-DL_IMPORT(void) init_exceptions(void);
+DL_IMPORT(void) _PyExc_Init(void);
 
 /* Various internal finalizers */
-DL_IMPORT(void) fini_exceptions(void);
+DL_IMPORT(void) _PyExc_Fini(void);
 DL_IMPORT(void) _PyImport_Fini(void);
 DL_IMPORT(void) PyMethod_Fini(void);
 DL_IMPORT(void) PyFrame_Fini(void);
index f6cbea8f182a84a1c8439b4076fe673369398300..c92dac276c6247e9a98dd7f3a89fec24018d5ed0 100644 (file)
@@ -504,6 +504,7 @@ class Pickler:
     dispatch[ClassType] = save_global
     dispatch[FunctionType] = save_global
     dispatch[BuiltinFunctionType] = save_global
+    dispatch[TypeType] = save_global
 
 
 def _keep_alive(x, memo):
index c2d3ed59f4e311cd8a6e94e2d176332818b7029a..f9cfcf647aa76648b1ff6da1ebc2d414d5dba43d 100644 (file)
@@ -62,7 +62,7 @@ class Repr:
             s = s + ': ' + self.repr1(x[key], level-1)
         if n > self.maxdict: s = s + ', ...'
         return '{' + s + '}'
-    def repr_string(self, x, level):
+    def repr_str(self, x, level):
         s = `x[:self.maxstring]`
         if len(s) > self.maxstring:
             i = max(0, (self.maxstring-3)/2)
@@ -70,7 +70,7 @@ class Repr:
             s = `x[:i] + x[len(x)-j:]`
             s = s[:i] + '...' + s[len(s)-j:]
         return s
-    def repr_long_int(self, x, level):
+    def repr_long(self, x, level):
         s = `x` # XXX Hope this isn't too slow...
         if len(s) > self.maxlong:
             i = max(0, (self.maxlong-3)/2)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
new file mode 100644 (file)
index 0000000..92f79d5
--- /dev/null
@@ -0,0 +1,829 @@
+# Test descriptor-related enhancements
+
+from test_support import verify, verbose
+from copy import deepcopy
+
+def testunop(a, res, expr="len(a)", meth="__len__"):
+    if verbose: print "checking", expr
+    dict = {'a': a}
+    verify(eval(expr, dict) == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    verify(m(a) == res)
+    bm = getattr(a, meth)
+    verify(bm() == res)
+
+def testbinop(a, b, res, expr="a+b", meth="__add__"):
+    if verbose: print "checking", expr
+    dict = {'a': a, 'b': b}
+    verify(eval(expr, dict) == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    verify(m(a, b) == res)
+    bm = getattr(a, meth)
+    verify(bm(b) == res)
+
+def testternop(a, b, c, res, expr="a[b:c]", meth="__getslice__"):
+    if verbose: print "checking", expr
+    dict = {'a': a, 'b': b, 'c': c}
+    verify(eval(expr, dict) == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    verify(m(a, b, c) == res)
+    bm = getattr(a, meth)
+    verify(bm(b, c) == res)
+
+def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"):
+    if verbose: print "checking", stmt
+    dict = {'a': deepcopy(a), 'b': b}
+    exec stmt in dict
+    verify(dict['a'] == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    dict['a'] = deepcopy(a)
+    m(dict['a'], b)
+    verify(dict['a'] == res)
+    dict['a'] = deepcopy(a)
+    bm = getattr(dict['a'], meth)
+    bm(b)
+    verify(dict['a'] == res)
+
+def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"):
+    if verbose: print "checking", stmt
+    dict = {'a': deepcopy(a), 'b': b, 'c': c}
+    exec stmt in dict
+    verify(dict['a'] == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    dict['a'] = deepcopy(a)
+    m(dict['a'], b, c)
+    verify(dict['a'] == res)
+    dict['a'] = deepcopy(a)
+    bm = getattr(dict['a'], meth)
+    bm(b, c)
+    verify(dict['a'] == res)
+
+def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
+    if verbose: print "checking", stmt
+    dict = {'a': deepcopy(a), 'b': b, 'c': c, 'd': d}
+    exec stmt in dict
+    verify(dict['a'] == res)
+    t = type(a)
+    m = getattr(t, meth)
+    verify(m == t.__dict__[meth])
+    dict['a'] = deepcopy(a)
+    m(dict['a'], b, c, d)
+    verify(dict['a'] == res)
+    dict['a'] = deepcopy(a)
+    bm = getattr(dict['a'], meth)
+    bm(b, c, d)
+    verify(dict['a'] == res)
+
+def lists():
+    if verbose: print "Testing list operations..."
+    testbinop([1], [2], [1,2], "a+b", "__add__")
+    testbinop([1,2,3], 2, 1, "b in a", "__contains__")
+    testbinop([1,2,3], 4, 0, "b in a", "__contains__")
+    testbinop([1,2,3], 1, 2, "a[b]", "__getitem__")
+    testternop([1,2,3], 0, 2, [1,2], "a[b:c]", "__getslice__")
+    testsetop([1], [2], [1,2], "a+=b", "__iadd__")
+    testsetop([1,2], 3, [1,2,1,2,1,2], "a*=b", "__imul__")
+    testunop([1,2,3], 3, "len(a)", "__len__")
+    testbinop([1,2], 3, [1,2,1,2,1,2], "a*b", "__mul__")
+    testbinop([1,2], 3, [1,2,1,2,1,2], "b*a", "__rmul__")
+    testset2op([1,2], 1, 3, [1,3], "a[b]=c", "__setitem__")
+    testset3op([1,2,3,4], 1, 3, [5,6], [1,5,6,4], "a[b:c]=d", "__setslice__")
+
+def dicts():
+    if verbose: print "Testing dict operations..."
+    testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__")
+    testbinop({1:2,3:4}, 1, 1, "b in a", "__contains__")
+    testbinop({1:2,3:4}, 2, 0, "b in a", "__contains__")
+    testbinop({1:2,3:4}, 1, 2, "a[b]", "__getitem__")
+    d = {1:2,3:4}
+    l1 = []
+    for i in d.keys(): l1.append(i)
+    l = []
+    for i in iter(d): l.append(i)
+    verify(l == l1)
+    l = []
+    for i in d.__iter__(): l.append(i)
+    verify(l == l1)
+    l = []
+    for i in dictionary.__iter__(d): l.append(i)
+    verify(l == l1)
+    d = {1:2, 3:4}
+    testunop(d, 2, "len(a)", "__len__")
+    verify(eval(repr(d), {}) == d)
+    verify(eval(d.__repr__(), {}) == d)
+    testset2op({1:2,3:4}, 2, 3, {1:2,2:3,3:4}, "a[b]=c", "__setitem__")
+
+binops = {
+    'add': '+',
+    'sub': '-',
+    'mul': '*',
+    'div': '/',
+    'mod': '%',
+    'divmod': 'divmod',
+    'pow': '**',
+    'lshift': '<<',
+    'rshift': '>>',
+    'and': '&',
+    'xor': '^',
+    'or': '|',
+    'cmp': 'cmp',
+    'lt': '<',
+    'le': '<=',
+    'eq': '==',
+    'ne': '!=',
+    'gt': '>',
+    'ge': '>=',
+    }
+
+for name, expr in binops.items():
+    if expr.islower():
+        expr = expr + "(a, b)"
+    else:
+        expr = 'a %s b' % expr
+    binops[name] = expr
+
+unops = {
+    'pos': '+',
+    'neg': '-',
+    'abs': 'abs',
+    'invert': '~',
+    'int': 'int',
+    'long': 'long',
+    'float': 'float',
+    'oct': 'oct',
+    'hex': 'hex',
+    }
+
+for name, expr in unops.items():
+    if expr.islower():
+        expr = expr + "(a)"
+    else:
+        expr = '%s a' % expr
+    unops[name] = expr
+
+def numops(a, b, skip=[]):
+    dict = {'a': a, 'b': b}
+    for name, expr in binops.items():
+        if name not in skip:
+            name = "__%s__" % name
+            if hasattr(a, name):
+                res = eval(expr, dict)
+                testbinop(a, b, res, expr, name)
+    for name, expr in unops.items():
+        name = "__%s__" % name
+        if hasattr(a, name):
+            res = eval(expr, dict)
+            testunop(a, res, expr, name)
+
+def ints():
+    if verbose: print "Testing int operations..."
+    numops(100, 3)
+
+def longs():
+    if verbose: print "Testing long operations..."
+    numops(100L, 3L)
+
+def floats():
+    if verbose: print "Testing float operations..."
+    numops(100.0, 3.0)
+
+def complexes():
+    if verbose: print "Testing complex operations..."
+    numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge'])
+    class Number(complex):
+        __slots__ = ['prec']
+        def __init__(self, *args, **kwds):
+            self.prec = kwds.get('prec', 12)
+        def __repr__(self):
+            prec = self.prec
+            if self.imag == 0.0:
+                return "%.*g" % (prec, self.real)
+            if self.real == 0.0:
+                return "%.*gj" % (prec, self.imag)
+            return "(%.*g+%.*gj)" % (prec, self.real, prec, self.imag)
+        __str__ = __repr__
+    a = Number(3.14, prec=6)
+    verify(`a` == "3.14")
+    verify(a.prec == 6)
+
+def spamlists():
+    if verbose: print "Testing spamlist operations..."
+    import copy, xxsubtype as spam
+    def spamlist(l, memo=None):
+        import xxsubtype as spam
+        return spam.spamlist(l)
+    # This is an ugly hack:
+    copy._deepcopy_dispatch[spam.spamlist] = spamlist
+
+    testbinop(spamlist([1]), spamlist([2]), spamlist([1,2]), "a+b", "__add__")
+    testbinop(spamlist([1,2,3]), 2, 1, "b in a", "__contains__")
+    testbinop(spamlist([1,2,3]), 4, 0, "b in a", "__contains__")
+    testbinop(spamlist([1,2,3]), 1, 2, "a[b]", "__getitem__")
+    testternop(spamlist([1,2,3]), 0, 2, spamlist([1,2]),
+               "a[b:c]", "__getslice__")
+    testsetop(spamlist([1]), spamlist([2]), spamlist([1,2]),
+              "a+=b", "__iadd__")
+    testsetop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*=b", "__imul__")
+    testunop(spamlist([1,2,3]), 3, "len(a)", "__len__")
+    testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*b", "__mul__")
+    testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "b*a", "__rmul__")
+    testset2op(spamlist([1,2]), 1, 3, spamlist([1,3]), "a[b]=c", "__setitem__")
+    testset3op(spamlist([1,2,3,4]), 1, 3, spamlist([5,6]),
+               spamlist([1,5,6,4]), "a[b:c]=d", "__setslice__")
+    # Test subclassing
+    class C(spam.spamlist):
+        def foo(self): return 1
+    a = C()
+    verify(a == [])
+    verify(a.foo() == 1)
+    a.append(100)
+    verify(a == [100])
+    verify(a.getstate() == 0)
+    a.setstate(42)
+    verify(a.getstate() == 42)
+
+def spamdicts():
+    if verbose: print "Testing spamdict operations..."
+    import copy, xxsubtype as spam
+    def spamdict(d, memo=None):
+        import xxsubtype as spam
+        sd = spam.spamdict()
+        for k, v in d.items(): sd[k] = v
+        return sd
+    # This is an ugly hack:
+    copy._deepcopy_dispatch[spam.spamdict] = spamdict
+
+    testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__")
+    testbinop(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__")
+    testbinop(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__")
+    testbinop(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__")
+    d = spamdict({1:2,3:4})
+    l1 = []
+    for i in d.keys(): l1.append(i)
+    l = []
+    for i in iter(d): l.append(i)
+    verify(l == l1)
+    l = []
+    for i in d.__iter__(): l.append(i)
+    verify(l == l1)
+    l = []
+    for i in type(spamdict({})).__iter__(d): l.append(i)
+    verify(l == l1)
+    straightd = {1:2, 3:4}
+    spamd = spamdict(straightd)
+    testunop(spamd, 2, "len(a)", "__len__")
+    testunop(spamd, repr(straightd), "repr(a)", "__repr__")
+    testset2op(spamdict({1:2,3:4}), 2, 3, spamdict({1:2,2:3,3:4}),
+               "a[b]=c", "__setitem__")
+    # Test subclassing
+    class C(spam.spamdict):
+        def foo(self): return 1
+    a = C()
+    verify(a.items() == [])
+    verify(a.foo() == 1)
+    a['foo'] = 'bar'
+    verify(a.items() == [('foo', 'bar')])
+    verify(a.getstate() == 0)
+    a.setstate(100)
+    verify(a.getstate() == 100)
+
+def pydicts():
+    if verbose: print "Testing Python subclass of dict..."
+    verify(issubclass(dictionary, dictionary))
+    verify(isinstance({}, dictionary))
+    d = dictionary()
+    verify(d == {})
+    verify(d.__class__ is dictionary)
+    verify(isinstance(d, dictionary))
+    class C(dictionary):
+        state = -1
+        def __init__(self, *a, **kw):
+            if a:
+                assert len(a) == 1
+                self.state = a[0]
+            if kw:
+                for k, v in kw.items(): self[v] = k
+        def __getitem__(self, key):
+            return self.get(key, 0)
+        def __setitem__(self, key, value):
+            assert isinstance(key, type(0))
+            dictionary.__setitem__(self, key, value)
+        def setstate(self, state):
+            self.state = state
+        def getstate(self):
+            return self.state
+    verify(issubclass(C, dictionary))
+    a1 = C(12)
+    verify(a1.state == 12)
+    a2 = C(foo=1, bar=2)
+    verify(a2[1] == 'foo' and a2[2] == 'bar')
+    a = C()
+    verify(a.state == -1)
+    verify(a.getstate() == -1)
+    a.setstate(0)
+    verify(a.state == 0)
+    verify(a.getstate() == 0)
+    a.setstate(10)
+    verify(a.state == 10)
+    verify(a.getstate() == 10)
+    verify(a[42] == 0)
+    a[42] = 24
+    verify(a[42] == 24)
+    if verbose: print "pydict stress test ..."
+    N = 50
+    for i in range(N):
+        a[i] = C()
+        for j in range(N):
+            a[i][j] = i*j
+    for i in range(N):
+        for j in range(N):
+            verify(a[i][j] == i*j)
+
+def pylists():
+    if verbose: print "Testing Python subclass of list..."
+    class C(list):
+        def __getitem__(self, i):
+            return list.__getitem__(self, i) + 100
+        def __getslice__(self, i, j):
+            return (i, j)
+    a = C()
+    a.extend([0,1,2])
+    verify(a[0] == 100)
+    verify(a[1] == 101)
+    verify(a[2] == 102)
+    verify(a[100:200] == (100,200))
+
+def metaclass():
+    if verbose: print "Testing __metaclass__..."
+    global C
+    class C:
+        __metaclass__ = type
+        def __init__(self):
+            self.__state = 0
+        def getstate(self):
+            return self.__state
+        def setstate(self, state):
+            self.__state = state
+    a = C()
+    verify(a.getstate() == 0)
+    a.setstate(10)
+    verify(a.getstate() == 10)
+    class D:
+        class __metaclass__(type):
+            def myself(cls): return cls
+    verify(D.myself() == D)
+
+import sys
+MT = type(sys)
+
+def pymods():
+    if verbose: print "Testing Python subclass of module..."
+    global log
+    log = []
+    class MM(MT):
+        def __init__(self):
+            MT.__init__(self)
+        def __getattr__(self, name):
+            log.append(("getattr", name))
+            return MT.__getattr__(self, name)
+        def __setattr__(self, name, value):
+            log.append(("setattr", name, value))
+            MT.__setattr__(self, name, value)
+        def __delattr__(self, name):
+            log.append(("delattr", name))
+            MT.__delattr__(self, name)
+    a = MM()
+    a.foo = 12
+    x = a.foo
+    del a.foo
+    verify(log == [('getattr', '__init__'),
+                   ('getattr', '__setattr__'),
+                   ("setattr", "foo", 12),
+                   ("getattr", "foo"),
+                   ('getattr', '__delattr__'),
+                   ("delattr", "foo")], log)
+
+def multi():
+    if verbose: print "Testing multiple inheritance..."
+    global C
+    class C(object):
+        def __init__(self):
+            self.__state = 0
+        def getstate(self):
+            return self.__state
+        def setstate(self, state):
+            self.__state = state
+    a = C()
+    verify(a.getstate() == 0)
+    a.setstate(10)
+    verify(a.getstate() == 10)
+    class D(dictionary, C):
+        def __init__(self):
+            type({}).__init__(self)
+            C.__init__(self)
+    d = D()
+    verify(d.keys() == [])
+    d["hello"] = "world"
+    verify(d.items() == [("hello", "world")])
+    verify(d["hello"] == "world")
+    verify(d.getstate() == 0)
+    d.setstate(10)
+    verify(d.getstate() == 10)
+    verify(D.__mro__ == (D, dictionary, C, object))
+
+def diamond():
+    if verbose: print "Testing multiple inheritance special cases..."
+    class A(object):
+        def spam(self): return "A"
+    verify(A().spam() == "A")
+    class B(A):
+        def boo(self): return "B"
+        def spam(self): return "B"
+    verify(B().spam() == "B")
+    verify(B().boo() == "B")
+    class C(A):
+        def boo(self): return "C"
+    verify(C().spam() == "A")
+    verify(C().boo() == "C")
+    class D(B, C): pass
+    verify(D().spam() == "B")
+    verify(D().boo() == "B")
+    verify(D.__mro__ == (D, B, C, A, object))
+    class E(C, B): pass
+    verify(E().spam() == "B")
+    verify(E().boo() == "C")
+    verify(E.__mro__ == (E, C, B, A, object))
+    class F(D, E): pass
+    verify(F().spam() == "B")
+    verify(F().boo() == "B")
+    verify(F.__mro__ == (F, D, E, B, C, A, object))
+    class G(E, D): pass
+    verify(G().spam() == "B")
+    verify(G().boo() == "C")
+    verify(G.__mro__ == (G, E, D, C, B, A, object))
+
+def objects():
+    if verbose: print "Testing object class..."
+    a = object()
+    verify(a.__class__ == object == type(a))
+    b = object()
+    verify(a is not b)
+    verify(not hasattr(a, "foo"))
+    try:
+        a.foo = 12
+    except TypeError:
+        pass
+    else:
+        verify(0, "object() should not allow setting a foo attribute")
+    verify(not hasattr(object(), "__dict__"))
+
+    class Cdict(object):
+        pass
+    x = Cdict()
+    verify(x.__dict__ is None)
+    x.foo = 1
+    verify(x.foo == 1)
+    verify(x.__dict__ == {'foo': 1})
+
+def slots():
+    if verbose: print "Testing __slots__..."
+    class C0(object):
+        __slots__ = []
+    x = C0()
+    verify(not hasattr(x, "__dict__"))
+    verify(not hasattr(x, "foo"))
+
+    class C1(object):
+        __slots__ = ['a']
+    x = C1()
+    verify(not hasattr(x, "__dict__"))
+    verify(x.a == None)
+    x.a = 1
+    verify(x.a == 1)
+    del x.a
+    verify(x.a == None)
+
+    class C3(object):
+        __slots__ = ['a', 'b', 'c']
+    x = C3()
+    verify(not hasattr(x, "__dict__"))
+    verify(x.a is None)
+    verify(x.b is None)
+    verify(x.c is None)
+    x.a = 1
+    x.b = 2
+    x.c = 3
+    verify(x.a == 1)
+    verify(x.b == 2)
+    verify(x.c == 3)
+
+def dynamics():
+    if verbose: print "Testing __dynamic__..."
+    verify(object.__dynamic__ == 0)
+    verify(list.__dynamic__ == 0)
+    class S1:
+        __metaclass__ = type
+    verify(S1.__dynamic__ == 0)
+    class S(object):
+        pass
+    verify(C.__dynamic__ == 0)
+    class D(object):
+        __dynamic__ = 1
+    verify(D.__dynamic__ == 1)
+    class E(D, S):
+        pass
+    verify(E.__dynamic__ == 1)
+    class F(S, D):
+        pass
+    verify(F.__dynamic__ == 1)
+    try:
+        S.foo = 1
+    except (AttributeError, TypeError):
+        pass
+    else:
+        verify(0, "assignment to a static class attribute should be illegal")
+    D.foo = 1
+    verify(D.foo == 1)
+    # Test that dynamic attributes are inherited
+    verify(E.foo == 1)
+    verify(F.foo == 1)
+    class SS(D):
+        __dynamic__ = 0
+    verify(SS.__dynamic__ == 0)
+    verify(SS.foo == 1)
+    try:
+        SS.foo = 1
+    except (AttributeError, TypeError):
+        pass
+    else:
+        verify(0, "assignment to SS.foo should be illegal")
+
+def errors():
+    if verbose: print "Testing errors..."
+
+    try:
+        class C(list, dictionary):
+            pass
+    except TypeError:
+        pass
+    else:
+        verify(0, "inheritance from both list and dict should be illegal")
+
+    try:
+        class C(object, None):
+            pass
+    except TypeError:
+        pass
+    else:
+        verify(0, "inheritance from non-type should be illegal")
+    class Classic:
+        pass
+
+    try:
+        class C(object, Classic):
+            pass
+    except TypeError:
+        pass
+    else:
+        verify(0, "inheritance from object and Classic should be illegal")
+
+    try:
+        class C(int):
+            pass
+    except TypeError:
+        pass
+    else:
+        verify(0, "inheritance from int should be illegal")
+
+    try:
+        class C(object):
+            __slots__ = 1
+    except TypeError:
+        pass
+    else:
+        verify(0, "__slots__ = 1 should be illegal")
+
+    try:
+        class C(object):
+            __slots__ = [1]
+    except TypeError:
+        pass
+    else:
+        verify(0, "__slots__ = [1] should be illegal")
+
+def classmethods():
+    if verbose: print "Testing class methods..."
+    class C(object):
+        def foo(*a): return a
+        goo = classmethod(foo)
+    c = C()
+    verify(C.goo(1) == (C, 1))
+    verify(c.goo(1) == (C, 1))
+    verify(c.foo(1) == (c, 1))
+    class D(C):
+        pass
+    d = D()
+    verify(D.goo(1) == (D, 1))
+    verify(d.goo(1) == (D, 1))
+    verify(d.foo(1) == (d, 1))
+    verify(D.foo(d, 1) == (d, 1))
+
+def staticmethods():
+    if verbose: print "Testing static methods..."
+    class C(object):
+        def foo(*a): return a
+        goo = staticmethod(foo)
+    c = C()
+    verify(C.goo(1) == (1,))
+    verify(c.goo(1) == (1,))
+    verify(c.foo(1) == (c, 1,))
+    class D(C):
+        pass
+    d = D()
+    verify(D.goo(1) == (1,))
+    verify(d.goo(1) == (1,))
+    verify(d.foo(1) == (d, 1))
+    verify(D.foo(d, 1) == (d, 1))
+
+def classic():
+    if verbose: print "Testing classic classes..."
+    class C:
+        def foo(*a): return a
+        goo = classmethod(foo)
+    c = C()
+    verify(C.goo(1) == (C, 1))
+    verify(c.goo(1) == (C, 1))
+    verify(c.foo(1) == (c, 1))
+    class D(C):
+        pass
+    d = D()
+    verify(D.goo(1) == (D, 1))
+    verify(d.goo(1) == (D, 1))
+    verify(d.foo(1) == (d, 1))
+    verify(D.foo(d, 1) == (d, 1))
+
+def compattr():
+    if verbose: print "Testing computed attributes..."
+    class C(object):
+        class computed_attribute(object):
+            def __init__(self, get, set=None):
+                self.__get = get
+                self.__set = set
+            def __get__(self, obj, type=None):
+                return self.__get(obj)
+            def __set__(self, obj, value):
+                return self.__set(obj, value)
+        def __init__(self):
+            self.__x = 0
+        def __get_x(self):
+            x = self.__x
+            self.__x = x+1
+            return x
+        def __set_x(self, x):
+            self.__x = x
+        x = computed_attribute(__get_x, __set_x)
+    a = C()
+    verify(a.x == 0)
+    verify(a.x == 1)
+    a.x = 10
+    verify(a.x == 10)
+    verify(a.x == 11)
+
+def newslot():
+    if verbose: print "Testing __new__ slot override..."
+    class C(list):
+        def __new__(cls):
+            self = list.__new__(cls)
+            self.foo = 1
+            return self
+        def __init__(self):
+            self.foo = self.foo + 2
+    a = C()
+    verify(a.foo == 3)
+    verify(a.__class__ is C)
+    class D(C):
+        pass
+    b = D()
+    verify(b.foo == 3)
+    verify(b.__class__ is D)
+
+class PerverseMetaType(type):
+    def mro(cls):
+        L = type.mro(cls)
+        L.reverse()
+        return L
+
+def altmro():
+    if verbose: print "Testing mro() and overriding it..."
+    class A(object):
+        def f(self): return "A"
+    class B(A):
+        pass
+    class C(A):
+        def f(self): return "C"
+    class D(B, C):
+        pass
+    verify(D.mro() == [D, B, C, A, object] == list(D.__mro__))
+    verify(D().f() == "C")
+    class X(A,B,C,D):
+        __metaclass__ = PerverseMetaType
+    verify(X.__mro__ == (object, A, C, B, D, X))
+    verify(X().f() == "A")
+
+def overloading():
+    if verbose: print "testing operator overloading..."
+
+    class B(object):
+        "Intermediate class because object doesn't have a __setattr__"
+
+    class C(B):
+
+        def __getattr__(self, name):
+            if name == "foo":
+                return ("getattr", name)
+            else:
+                return B.__getattr__(self, name)
+        def __setattr__(self, name, value):
+            if name == "foo":
+                self.setattr = (name, value)
+            else:
+                return B.__setattr__(self, name, value)
+        def __delattr__(self, name):
+            if name == "foo":
+                self.delattr = name
+            else:
+                return B.__delattr__(self, name)
+
+        def __getitem__(self, key):
+            return ("getitem", key)
+        def __setitem__(self, key, value):
+            self.setitem = (key, value)
+        def __delitem__(self, key):
+            self.delitem = key
+
+        def __getslice__(self, i, j):
+            return ("getslice", i, j)
+        def __setslice__(self, i, j, value):
+            self.setslice = (i, j, value)
+        def __delslice__(self, i, j):
+            self.delslice = (i, j)
+
+    a = C()
+    verify(a.foo == ("getattr", "foo"))
+    a.foo = 12
+    verify(a.setattr == ("foo", 12))
+    del a.foo
+    verify(a.delattr == "foo")
+
+    verify(a[12] == ("getitem", 12))
+    a[12] = 21
+    verify(a.setitem == (12, 21))
+    del a[12]
+    verify(a.delitem == 12)
+
+    verify(a[0:10] == ("getslice", 0, 10))
+    a[0:10] = "foo"
+    verify(a.setslice == (0, 10, "foo"))
+    del a[0:10]
+    verify(a.delslice == (0, 10))
+
+def all():
+    lists()
+    dicts()
+    ints()
+    longs()
+    floats()
+    complexes()
+    spamlists()
+    spamdicts()
+    pydicts()
+    pylists()
+    metaclass()
+    pymods()
+    multi()
+    diamond()
+    objects()
+    slots()
+    dynamics()
+    errors()
+    classmethods()
+    staticmethods()
+    classic()
+    compattr()
+    newslot()
+    altmro()
+    overloading()
+
+all()
+
+if verbose: print "All OK"
index 2a174c3d811db34a2e7e5fa3b734f0fc95fbaf0b..72a70ec4713b6d59ed3a53355387346a7e79befd 100644 (file)
@@ -380,10 +380,16 @@ From the Iterators list, about the types of these things.
 >>> i = g()
 >>> type(i)
 <type 'generator'>
+
+XXX dir(object) *generally* doesn't return useful stuff in descr-branch.
 >>> dir(i)
+[]
+
+Was hoping to see this instead:
 ['gi_frame', 'gi_running', 'next']
+
 >>> print i.next.__doc__
-next() -- get the next value, or raise StopIteration
+x.next() -> the next value, or raise StopIteration
 >>> iter(i) is i
 1
 >>> import types
@@ -399,7 +405,7 @@ And more, added later.
 >>> i.gi_running = 42
 Traceback (most recent call last):
   ...
-TypeError: object has read-only attributes
+TypeError: 'generator' object has only read-only attributes (assign to .gi_running)
 >>> def g():
 ...     yield me.gi_running
 >>> me = g()
index 95600a3b9aa8d964dc72f95aa02b549fb921be6b..d60ee56d7e821bff9512c70f32ff061c799e25fd 100644 (file)
@@ -7,7 +7,8 @@ from __future__ import generators
 import sys
 
 NoneType = type(None)
-TypeType = type(NoneType)
+TypeType = type
+ObjectType = object
 
 IntType = type(0)
 LongType = type(0L)
@@ -22,8 +23,8 @@ UnicodeType = type(u'')
 BufferType = type(buffer(''))
 
 TupleType = type(())
-ListType = type([])
-DictType = DictionaryType = type({})
+ListType = list
+DictType = DictionaryType = dictionary
 
 def _f(): pass
 FunctionType = type(_f)
@@ -71,4 +72,9 @@ except TypeError:
 SliceType = type(slice(0))
 EllipsisType = type(Ellipsis)
 
+DictIterType = type(iter({}))
+SequenceIterType = type(iter([]))
+FunctionIterType = type(iter(lambda: 0, 0))
+DictProxyType = type(TypeType.__dict__)
+
 del sys, _f, _C, _x                     # Not for export
index 9fbf29d8f0cbaf05bdc6b85569275002c1da96d4..ff22ef3e694c686f359aa68b81232eaf325770be 100644 (file)
@@ -237,6 +237,7 @@ OBJECT_OBJS=        \
                Objects/classobject.o \
                Objects/cobject.o \
                Objects/complexobject.o \
+               Objects/descrobject.o \
                Objects/fileobject.o \
                Objects/floatobject.o \
                Objects/frameobject.o \
@@ -438,6 +439,7 @@ PYTHON_HEADERS= \
                Include/tupleobject.h \
                Include/listobject.h \
                Include/iterobject.h \
+               Include/descrobject.h \
                Include/dictobject.h \
                Include/methodobject.h \
                Include/moduleobject.h \
index db4fbde80930478ce51a1e6440c8f8d72b73143f..d93ab8658a3146e19ff941b53032654ad9c0c359 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,17 @@ What's New in Python 2.2a1?
 
 Core
 
+- TENTATIVELY, a large amount of code implementing much of what's
+  described in PEP 252 (Making Types Look More Like Classes) and PEP
+  253 (Subtyping Built-in Types) was added.  This will be released
+  with Python 2.2a1.  Documentation will be provided separately
+  through http://www.python.org/2.2/.  The purpose of releasing this
+  with Python 2.2a1 is to test backwards compatibility.  It is
+  possible, though not likely, that a decision is made not to release
+  this code as part of 2.2 final, if any serious backwards
+  incompapatibilities are found during alpha testing that cannot be
+  repaired.
+
 - Generators were added; this is a new way to create an iterator (see
   below) using what looks like a simple function containing one or
   more 'yield' statements.  See PEP 255.  Since this adds a new
index 9114414f1269c5c78ff2c6676a19b088ca6f6f9d..e9c2a949a6c69ca41eb8dc5d1ab757b8d1359576 100644 (file)
@@ -464,3 +464,5 @@ GLHACK=-Dclear=__GLclear
 # Example -- included for reference only:
 # xx xxmodule.c
 
+# Another example -- the 'xxsubtype' module shows C-level subtyping in action
+xxsubtype xxsubtype.c
index e3cc58d07ef070c63b79bd4f04ada493d0de4b81..b27339f568cab7db9ef07245cfecc2f3ce958449 100644 (file)
@@ -1869,6 +1869,10 @@ save(Picklerobject *self, PyObject *args, int  pers_save) {
                 res = save_tuple(self, args);
                 goto finally;
             }
+           if (type == &PyType_Type) {
+               res = save_global(self, args, NULL);
+               goto finally;
+           }
             break;
 
         case 'l':
index 5a5878fe9a0fa3c08dc50059421f0ae5bdf3155e..0d5e8b061ac21595d43ab587a00bce3c93d6ef82 100644 (file)
@@ -37,7 +37,7 @@ struct _inittab _PyImport_Inittab[] = {
        {"__main__", NULL},
        {"__builtin__", NULL},
        {"sys", NULL},
-       {"exceptions", init_exceptions},
+       {"exceptions", NULL},
 
        /* Sentinel */
        {0, 0}
diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c
new file mode 100644 (file)
index 0000000..60d8c7d
--- /dev/null
@@ -0,0 +1,233 @@
+#include "Python.h"
+
+/* Examples showing how to subtype the builtin list and dict types from C. */
+
+/* spamlist -- a list subtype */
+
+typedef struct {
+       PyListObject list;
+       int state;
+} spamlistobject;
+
+static PyObject *
+spamlist_getstate(spamlistobject *self, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":getstate"))
+               return NULL;
+       return PyInt_FromLong(self->state);
+}
+
+static PyObject *
+spamlist_setstate(spamlistobject *self, PyObject *args)
+{
+       int state;
+
+       if (!PyArg_ParseTuple(args, "i:setstate", &state))
+               return NULL;
+       self->state = state;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyMethodDef spamlist_methods[] = {
+       {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
+               "getstate() -> state"},
+       {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
+               "setstate(state)"},
+       {NULL,  NULL},
+};
+
+staticforward PyTypeObject spamlist_type;
+
+static int
+spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
+{
+       if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
+               return -1;
+       self->state = 0;
+       return 0;
+}
+
+static PyTypeObject spamlist_type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "spamlist",
+       sizeof(spamlistobject),
+       0,
+       0,                                      /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       0,                                      /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       spamlist_methods,                       /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       &PyList_Type,                           /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       (initproc)spamlist_init,                /* tp_init */
+       0,                                      /* tp_alloc */
+       0,                                      /* tp_new */
+};
+
+/* spamdict -- a dict subtype */
+
+typedef struct {
+       PyDictObject dict;
+       int state;
+} spamdictobject;
+
+static PyObject *
+spamdict_getstate(spamdictobject *self, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":getstate"))
+               return NULL;
+       return PyInt_FromLong(self->state);
+}
+
+static PyObject *
+spamdict_setstate(spamdictobject *self, PyObject *args)
+{
+       int state;
+
+       if (!PyArg_ParseTuple(args, "i:setstate", &state))
+               return NULL;
+       self->state = state;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyMethodDef spamdict_methods[] = {
+       {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
+               "getstate() -> state"},
+       {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
+               "setstate(state)"},
+       {NULL,  NULL},
+};
+
+staticforward PyTypeObject spamdict_type;
+
+static int
+spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
+{
+       if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
+               return -1;
+       self->state = 0;
+       return 0;
+}
+
+static PyTypeObject spamdict_type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "spamdict",
+       sizeof(spamdictobject),
+       0,
+       0,                                      /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       0,                                      /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       spamdict_methods,                       /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       &PyDict_Type,                           /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       (initproc)spamdict_init,                /* tp_init */
+       0,                                      /* tp_alloc */
+       0,                                      /* tp_new */
+};
+
+PyObject *
+spam_bench(PyObject *self, PyObject *args)
+{
+       PyObject *obj, *name, *res;
+       int n = 1000;
+       time_t t0, t1;
+
+       if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n))
+               return NULL;
+       t0 = clock();
+       while (--n >= 0) {
+               res = PyObject_GetAttr(obj, name);
+               if (res == NULL)
+                       return NULL;
+               Py_DECREF(res);
+       }
+       t1 = clock();
+       return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
+}
+
+static PyMethodDef xxsubtype_functions[] = {
+       {"bench",       spam_bench,     METH_VARARGS},
+       {NULL,          NULL}           /* sentinel */
+};
+
+DL_EXPORT(void)
+initxxsubtype(void)
+{
+       PyObject *m, *d;
+
+       m = Py_InitModule("xxsubtype", xxsubtype_functions);
+       if (m == NULL)
+               return;
+
+       if (PyType_InitDict(&spamlist_type) < 0)
+               return;
+       if (PyType_InitDict(&spamdict_type) < 0)
+               return;
+
+       d = PyModule_GetDict(m);
+       if (d == NULL)
+               return;
+
+       Py_INCREF(&spamlist_type);
+       if (PyDict_SetItemString(d, "spamlist",
+                                (PyObject *) &spamlist_type) < 0)
+               return;
+
+       Py_INCREF(&spamdict_type);
+       if (PyDict_SetItemString(d, "spamdict",
+                                (PyObject *) &spamdict_type) < 0)
+               return;
+}
index 63fe7d51225177da639b0f20c3345e2308113f0c..a0f075f6081b84bca51a8100ff000d9340856fde 100644 (file)
@@ -1588,6 +1588,24 @@ PyObject_CallObject(PyObject *o, PyObject *a)
        return r;
 }
 
+PyObject *
+PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+        ternaryfunc call;
+
+       if ((call = func->ob_type->tp_call) != NULL) {
+               PyObject *result = (*call)(func, arg, kw);
+               if (result == NULL && !PyErr_Occurred())
+                       PyErr_SetString(
+                               PyExc_SystemError,
+                               "NULL result without error in PyObject_Call");
+               return result;
+       }
+       PyErr_Format(PyExc_TypeError, "object is not callable: %s",
+                    PyString_AS_STRING(PyObject_Repr(func)));
+       return NULL;
+}
+
 PyObject *
 PyObject_CallFunction(PyObject *callable, char *format, ...)
 {
@@ -1746,7 +1764,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
                }
        }
        else if (PyType_Check(cls)) {
-               retval = ((PyObject *)(inst->ob_type) == cls);
+               retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
        }
        else if (!PyInstance_Check(inst)) {
                if (__class__ == NULL) {
index 1a17ec5ba8c915702ddd7124fe18f22e0652e4f5..4c213ce975c7e7dbbf0dbee869e2310f0c69b01e 100644 (file)
@@ -537,21 +537,21 @@ PyTypeObject PyBuffer_Type = {
        "buffer",
        sizeof(PyBufferObject),
        0,
-       (destructor)buffer_dealloc, /*tp_dealloc*/
-       0,              /*tp_print*/
-       0,              /*tp_getattr*/
-       0,              /*tp_setattr*/
-       (cmpfunc)buffer_compare, /*tp_compare*/
-       (reprfunc)buffer_repr, /*tp_repr*/
-       0,              /*tp_as_number*/
-       &buffer_as_sequence,    /*tp_as_sequence*/
-       0,              /*tp_as_mapping*/
-       (hashfunc)buffer_hash,  /*tp_hash*/
-       0,              /*tp_call*/
-       (reprfunc)buffer_str,           /*tp_str*/
-       0,              /*tp_getattro*/
-       0,              /*tp_setattro*/
-       &buffer_as_buffer,      /*tp_as_buffer*/
-       Py_TPFLAGS_DEFAULT,     /*tp_flags*/
-       0,              /*tp_doc*/
+       (destructor)buffer_dealloc,             /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       (cmpfunc)buffer_compare,                /* tp_compare */
+       (reprfunc)buffer_repr,                  /* tp_repr */
+       0,                                      /* tp_as_number */
+       &buffer_as_sequence,                    /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)buffer_hash,                  /* tp_hash */
+       0,                                      /* tp_call */
+       (reprfunc)buffer_str,                   /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       &buffer_as_buffer,                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
 };
index 66fc8d1d52134c0165371a82501bea407ef08102..9a3677640228580f9b56dfaa7dc15c975e288d14 100644 (file)
@@ -106,7 +106,7 @@ PyTypeObject PyCell_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
index 06f6714d9a99d3c4cf179e9c51e1afe008bf01c8..c4b1d8e1f9b9f04875bd5c4736f0622380d631cd 100644 (file)
@@ -36,12 +36,12 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
                        return NULL;
        }
        if (name == NULL || !PyString_Check(name)) {
-               PyErr_SetString(PyExc_SystemError,
+               PyErr_SetString(PyExc_TypeError,
                                "PyClass_New: name must be a string");
                return NULL;
        }
        if (dict == NULL || !PyDict_Check(dict)) {
-               PyErr_SetString(PyExc_SystemError,
+               PyErr_SetString(PyExc_TypeError,
                                "PyClass_New: dict must be a dictionary");
                return NULL;
        }
@@ -67,14 +67,14 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
        else {
                int i;
                if (!PyTuple_Check(bases)) {
-                       PyErr_SetString(PyExc_SystemError,
+                       PyErr_SetString(PyExc_TypeError,
                                        "PyClass_New: bases must be a tuple");
                        return NULL;
                }
                i = PyTuple_Size(bases);
                while (--i >= 0) {
                        if (!PyClass_Check(PyTuple_GetItem(bases, i))) {
-                               PyErr_SetString(PyExc_SystemError,
+                               PyErr_SetString(PyExc_TypeError,
                                        "PyClass_New: base must be a class");
                                return NULL;
                        }
@@ -106,6 +106,18 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
        return (PyObject *) op;
 }
 
+static PyObject *
+class_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *name, *bases, *dict;
+       static char *kwlist[] = {"name", "bases", "dict", 0};
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist,
+                                        &name, &bases, &dict))
+               return NULL;
+       return PyClass_New(bases, dict, name);
+}
+
 /* Class methods */
 
 static void
@@ -149,6 +161,8 @@ class_getattr(register PyClassObject *op, PyObject *name)
        register PyObject *v;
        register char *sname = PyString_AsString(name);
        PyClassObject *class;
+       descrgetfunc f;
+
        if (sname[0] == '_' && sname[1] == '_') {
                if (strcmp(sname, "__dict__") == 0) {
                        if (PyEval_GetRestricted()) {
@@ -186,6 +200,11 @@ class_getattr(register PyClassObject *op, PyObject *name)
                Py_DECREF(v);
                v = w;
        }
+       f = v->ob_type->tp_descr_get;
+       if (f == NULL)
+               Py_INCREF(v);
+       else
+               v = f(v, (PyObject *)NULL, (PyObject *)op);
        return v;
 }
 
@@ -396,7 +415,7 @@ PyTypeObject PyClass_Type = {
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        0,                                      /* tp_hash */
-       0,                                      /* tp_call */
+       PyInstance_New,                         /* tp_call */
        (reprfunc)class_str,                    /* tp_str */
        (getattrofunc)class_getattr,            /* tp_getattro */
        (setattrofunc)class_setattr,            /* tp_setattro */
@@ -404,6 +423,22 @@ PyTypeObject PyClass_Type = {
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
        0,                                      /* tp_doc */
        (traverseproc)class_traverse,           /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       class_new,                              /* tp_new */
 };
 
 int
@@ -531,7 +566,7 @@ instance_dealloc(register PyInstanceObject *inst)
        /* compensate for boost in _Py_NewReference; note that
         * _Py_RefTotal was also boosted; we'll knock that down later.
         */
-       inst->ob_type->tp_alloc--;
+       inst->ob_type->tp_allocs--;
 #endif
 #else /* !Py_TRACE_REFS */
        /* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
@@ -564,7 +599,7 @@ instance_dealloc(register PyInstanceObject *inst)
 #endif
        if (--inst->ob_refcnt > 0) {
 #ifdef COUNT_ALLOCS
-               inst->ob_type->tp_free--;
+               inst->ob_type->tp_frees--;
 #endif
                return; /* __del__ added a reference; don't delete now */
        }
@@ -572,7 +607,7 @@ instance_dealloc(register PyInstanceObject *inst)
        _Py_ForgetReference((PyObject *)inst);
 #ifdef COUNT_ALLOCS
        /* compensate for increment in _Py_ForgetReference */
-       inst->ob_type->tp_free--;
+       inst->ob_type->tp_frees--;
 #endif
 #ifndef WITH_CYCLE_GC
        inst->ob_type = NULL;
@@ -619,6 +654,8 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
 {
        register PyObject *v;
        PyClassObject *class;
+       descrgetfunc f;
+
        class = NULL;
        v = PyDict_GetItem(inst->in_dict, name);
        if (v == NULL) {
@@ -628,17 +665,20 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
        }
        Py_INCREF(v);
        if (class != NULL) {
-               if (PyFunction_Check(v)) {
-                       PyObject *w = PyMethod_New(v, (PyObject *)inst,
-                                                  (PyObject *)class);
+               f = v->ob_type->tp_descr_get;
+               if (f != NULL) {
+                       PyObject *w = f(v, (PyObject *)inst,
+                                       (PyObject *)(inst->in_class));
                        Py_DECREF(v);
                        v = w;
                }
                else if (PyMethod_Check(v)) {
-                       PyObject *im_class = PyMethod_Class(v);
+                       /* XXX This should be a tp_descr_get slot of
+                          PyMethodObjects */
+                       PyObject *im_class = PyMethod_GET_CLASS(v);
                        /* Only if classes are compatible */
                        if (PyClass_IsSubclass((PyObject *)class, im_class)) {
-                               PyObject *im_func = PyMethod_Function(v);
+                               PyObject *im_func = PyMethod_GET_FUNCTION(v);
                                PyObject *w = PyMethod_New(im_func,
                                                (PyObject *)inst, im_class);
                                Py_DECREF(v);
@@ -1814,6 +1854,23 @@ instance_iternext(PyInstanceObject *self)
        return NULL;
 }
 
+static PyObject *
+instance_call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+       PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
+       if (call == NULL) {
+               PyInstanceObject *inst = (PyInstanceObject*) func;
+               PyErr_Clear();
+               PyErr_Format(PyExc_AttributeError,
+                            "%.200s instance has no __call__ method",
+                            PyString_AsString(inst->in_class->cl_name));
+               return NULL;
+       }
+       res = PyObject_Call(call, arg, kw);
+       Py_DECREF(call);
+       return res;
+}
+
 
 static PyNumberMethods instance_as_number = {
        (binaryfunc)instance_add,               /* nb_add */
@@ -1868,7 +1925,7 @@ PyTypeObject PyInstance_Type = {
        &instance_as_sequence,                  /* tp_as_sequence */
        &instance_as_mapping,                   /* tp_as_mapping */
        (hashfunc)instance_hash,                /* tp_hash */
-       0,                                      /* tp_call */
+       instance_call,                          /* tp_call */
        (reprfunc)instance_str,                 /* tp_str */
        (getattrofunc)instance_getattr,         /* tp_getattro */
        (setattrofunc)instance_setattr,         /* tp_setattro */
@@ -1921,36 +1978,6 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
        return (PyObject *)im;
 }
 
-PyObject *
-PyMethod_Function(register PyObject *im)
-{
-       if (!PyMethod_Check(im)) {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       return ((PyMethodObject *)im)->im_func;
-}
-
-PyObject *
-PyMethod_Self(register PyObject *im)
-{
-       if (!PyMethod_Check(im)) {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       return ((PyMethodObject *)im)->im_self;
-}
-
-PyObject *
-PyMethod_Class(register PyObject *im)
-{
-       if (!PyMethod_Check(im)) {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       return ((PyMethodObject *)im)->im_class;
-}
-
 /* Class method methods */
 
 #define OFF(x) offsetof(PyMethodObject, x)
@@ -2028,43 +2055,52 @@ instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
 static PyObject *
 instancemethod_repr(PyMethodObject *a)
 {
-       char buf[240];
-       PyInstanceObject *self = (PyInstanceObject *)(a->im_self);
+       char buffer[240];
+       PyObject *self = a->im_self;
        PyObject *func = a->im_func;
-       PyClassObject *class = (PyClassObject *)(a->im_class);
-       PyObject *fclassname, *iclassname, *funcname;
-       char *fcname, *icname, *fname;
-       fclassname = class->cl_name;
-       if (PyFunction_Check(func)) {
-               funcname = ((PyFunctionObject *)func)->func_name;
-               Py_INCREF(funcname);
-       }
-       else {
-               funcname = PyObject_GetAttrString(func,"__name__");
-               if (funcname == NULL)
-                       PyErr_Clear();
+       PyObject *klass = a->im_class;
+       PyObject *funcname = NULL, *klassname = NULL, *result = NULL;
+       char *sfuncname = "?", *sklassname = "?";
+
+       funcname = PyObject_GetAttrString(func, "__name__");
+       if (funcname == NULL)
+               PyErr_Clear();
+       else if (!PyString_Check(funcname)) {
+               Py_DECREF(funcname);
+               funcname = NULL;
        }
-       if (funcname != NULL && PyString_Check(funcname))
-               fname = PyString_AS_STRING(funcname);
        else
-               fname = "?";
-       if (fclassname != NULL && PyString_Check(fclassname))
-               fcname = PyString_AsString(fclassname);
+               sfuncname = PyString_AS_STRING(funcname);
+       klassname = PyObject_GetAttrString(klass, "__name__");
+       if (klassname == NULL)
+               PyErr_Clear();
+       else if (!PyString_Check(klassname)) {
+               Py_DECREF(klassname);
+               klassname = NULL;
+       }
        else
-               fcname = "?";
+               sklassname = PyString_AS_STRING(klassname);
        if (self == NULL)
-               sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
+               sprintf(buffer, "<unbound method %.100s.%.100s>",
+                       sklassname, sfuncname);
        else {
-               iclassname = self->in_class->cl_name;
-               if (iclassname != NULL && PyString_Check(iclassname))
-                       icname = PyString_AsString(iclassname);
-               else
-                       icname = "?";
-               sprintf(buf, "<method %.60s.%.60s of %.60s instance at %p>",
-                       fcname, fname, icname, self);
+               /* XXX Shouldn't use repr() here! */
+               PyObject *selfrepr = PyObject_Repr(self);
+               if (selfrepr == NULL)
+                       goto fail;
+               if (!PyString_Check(selfrepr)) {
+                       Py_DECREF(selfrepr);
+                       goto fail;
+               }
+               sprintf(buffer, "<bound method %.60s.%.60s of %.60s>",
+                       sklassname, sfuncname, PyString_AS_STRING(selfrepr));
+               Py_DECREF(selfrepr);
        }
+       result = PyString_FromString(buffer);
+  fail:
        Py_XDECREF(funcname);
-       return PyString_FromString(buf);
+       Py_XDECREF(klassname);
+       return result;
 }
 
 static long
@@ -2105,6 +2141,57 @@ instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg)
        return 0;
 }
 
+static PyObject *
+instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+       PyObject *self = PyMethod_GET_SELF(func);
+       PyObject *class = PyMethod_GET_CLASS(func);
+       PyObject *result;
+
+       func = PyMethod_GET_FUNCTION(func);
+       if (self == NULL) {
+               /* Unbound methods must be called with an instance of
+                  the class (or a derived class) as first argument */
+               int ok;
+               if (PyTuple_Size(arg) >= 1)
+                       self = PyTuple_GET_ITEM(arg, 0);
+               if (self == NULL)
+                       ok = 0;
+               else {
+                       ok = PyObject_IsInstance(self, class);
+                       if (ok < 0)
+                               return NULL;
+               }
+               if (!ok) {
+                       PyErr_Format(PyExc_TypeError,
+                                    "unbound method %s%s must be "
+                                    "called with instance as first argument",
+                                    PyEval_GetFuncName(func),
+                                    PyEval_GetFuncDesc(func));
+                       return NULL;
+               }
+               Py_INCREF(arg);
+       }
+       else {
+               int argcount = PyTuple_Size(arg);
+               PyObject *newarg = PyTuple_New(argcount + 1);
+               int i;
+               if (newarg == NULL)
+                       return NULL;
+               Py_INCREF(self);
+               PyTuple_SET_ITEM(newarg, 0, self);
+               for (i = 0; i < argcount; i++) {
+                       PyObject *v = PyTuple_GET_ITEM(arg, i);
+                       Py_XINCREF(v);
+                       PyTuple_SET_ITEM(newarg, i+1, v);
+               }
+               arg = newarg;
+       }
+       result = PyObject_Call((PyObject *)func, arg, kw);
+       Py_DECREF(arg);
+       return result;
+}
+
 PyTypeObject PyMethod_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
@@ -2121,7 +2208,7 @@ PyTypeObject PyMethod_Type = {
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        (hashfunc)instancemethod_hash,          /* tp_hash */
-       0,                                      /* tp_call */
+       instancemethod_call,                    /* tp_call */
        0,                                      /* tp_str */
        (getattrofunc)instancemethod_getattro,  /* tp_getattro */
        (setattrofunc)instancemethod_setattro,  /* tp_setattro */
index 34dbab0becaaaf98a6689ff1d177fad4dd202228..9a66c0c593eda484e3912357e9850fd253003f94 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef WITHOUT_COMPLEX
 
 #include "Python.h"
+#include "structmember.h"
 
 /* Precisions used by repr() and str(), respectively.
 
@@ -182,6 +183,17 @@ c_powi(Py_complex x, long n)
 
 }
 
+static PyObject *
+complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
+{
+       PyObject *op;
+
+       op = PyType_GenericAlloc(type, 0);
+       if (op != NULL)
+               ((PyComplexObject *)op)->cval = cval;
+       return op;
+}
+
 PyObject *
 PyComplex_FromCComplex(Py_complex cval)
 {
@@ -196,6 +208,15 @@ PyComplex_FromCComplex(Py_complex cval)
        return (PyObject *) op;
 }
 
+static PyObject *
+complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
+{
+       Py_complex c;
+       c.real = real;
+       c.imag = imag;
+       return complex_subtype_from_c_complex(type, c);
+}
+
 PyObject *
 PyComplex_FromDoubles(double real, double imag)
 {
@@ -559,19 +580,261 @@ static PyMethodDef complex_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
+static struct memberlist complex_members[] = {
+       {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
+       {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
+       {0},
+};
 
 static PyObject *
-complex_getattr(PyComplexObject *self, char *name)
-{
-       if (strcmp(name, "real") == 0)
-               return (PyObject *)PyFloat_FromDouble(self->cval.real);
-       else if (strcmp(name, "imag") == 0)
-               return (PyObject *)PyFloat_FromDouble(self->cval.imag);
-       else if (strcmp(name, "__members__") == 0)
-               return Py_BuildValue("[ss]", "imag", "real");
-       return Py_FindMethod(complex_methods, (PyObject *)self, name);
+complex_subtype_from_string(PyTypeObject *type, PyObject *v)
+{
+       extern double strtod(const char *, char **);
+       const char *s, *start;
+       char *end;
+       double x=0.0, y=0.0, z;
+       int got_re=0, got_im=0, done=0;
+       int digit_or_dot;
+       int sw_error=0;
+       int sign;
+       char buffer[256]; /* For errors */
+       char s_buffer[256];
+       int len;
+
+       if (PyString_Check(v)) {
+               s = PyString_AS_STRING(v);
+               len = PyString_GET_SIZE(v);
+       }
+       else if (PyUnicode_Check(v)) {
+               if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
+                       PyErr_SetString(PyExc_ValueError,
+                                "complex() literal too large to convert");
+                       return NULL;
+               }
+               if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
+                                           PyUnicode_GET_SIZE(v),
+                                           s_buffer,
+                                           NULL))
+                       return NULL;
+               s = s_buffer;
+               len = (int)strlen(s);
+       }
+       else if (PyObject_AsCharBuffer(v, &s, &len)) {
+               PyErr_SetString(PyExc_TypeError,
+                               "complex() arg is not a string");
+               return NULL;
+       }
+
+       /* position on first nonblank */
+       start = s;
+       while (*s && isspace(Py_CHARMASK(*s)))
+               s++;
+       if (s[0] == '\0') {
+               PyErr_SetString(PyExc_ValueError,
+                               "complex() arg is an empty string");
+               return NULL;
+       }
+
+       z = -1.0;
+       sign = 1;
+       do {
+
+               switch (*s) {
+
+               case '\0':
+                       if (s-start != len) {
+                               PyErr_SetString(
+                                       PyExc_ValueError,
+                                       "complex() arg contains a null byte");
+                               return NULL;
+                       }
+                       if(!done) sw_error=1;
+                       break;
+
+               case '-':
+                       sign = -1;
+                               /* Fallthrough */
+               case '+':
+                       if (done)  sw_error=1;
+                       s++;
+                       if  (  *s=='\0'||*s=='+'||*s=='-'  ||
+                              isspace(Py_CHARMASK(*s))  )  sw_error=1;
+                       break;
+
+               case 'J':
+               case 'j':
+                       if (got_im || done) {
+                               sw_error = 1;
+                               break;
+                       }
+                       if  (z<0.0) {
+                               y=sign;
+                       }
+                       else{
+                               y=sign*z;
+                       }
+                       got_im=1;
+                       s++;
+                       if  (*s!='+' && *s!='-' )
+                               done=1;
+                       break;
+
+               default:
+                       if (isspace(Py_CHARMASK(*s))) {
+                               while (*s && isspace(Py_CHARMASK(*s)))
+                                       s++;
+                               if (s[0] != '\0')
+                                       sw_error=1;
+                               else
+                                       done = 1;
+                               break;
+                       }
+                       digit_or_dot =
+                               (*s=='.' || isdigit(Py_CHARMASK(*s)));
+                       if  (done||!digit_or_dot) {
+                               sw_error=1;
+                               break;
+                       }
+                       errno = 0;
+                       PyFPE_START_PROTECT("strtod", return 0)
+                               z = strtod(s, &end) ;
+                       PyFPE_END_PROTECT(z)
+                               if (errno != 0) {
+                                       sprintf(buffer,
+                                         "float() out of range: %.150s", s);
+                                       PyErr_SetString(
+                                               PyExc_ValueError,
+                                               buffer);
+                                       return NULL;
+                               }
+                       s=end;
+                       if  (*s=='J' || *s=='j') {
+
+                               break;
+                       }
+                       if  (got_re) {
+                               sw_error=1;
+                               break;
+                       }
+
+                               /* accept a real part */
+                       x=sign*z;
+                       got_re=1;
+                       if  (got_im)  done=1;
+                       z = -1.0;
+                       sign = 1;
+                       break;
+
+               }  /* end of switch  */
+
+       } while (*s!='\0' && !sw_error);
+
+       if (sw_error) {
+               PyErr_SetString(PyExc_ValueError,
+                               "complex() arg is a malformed string");
+               return NULL;
+       }
+
+       return complex_subtype_from_doubles(type, x, y);
+}
+
+static PyObject *
+complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *r, *i, *tmp;
+       PyNumberMethods *nbr, *nbi = NULL;
+       Py_complex cr, ci;
+       int own_r = 0;
+       static char *kwlist[] = {"real", "imag", 0};
+
+       r = Py_False;
+       i = NULL;
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist,
+                                        &r, &i))
+               return NULL;
+       if (PyString_Check(r) || PyUnicode_Check(r))
+               return complex_subtype_from_string(type, r);
+       if ((nbr = r->ob_type->tp_as_number) == NULL ||
+           nbr->nb_float == NULL ||
+           (i != NULL &&
+            ((nbi = i->ob_type->tp_as_number) == NULL ||
+             nbi->nb_float == NULL))) {
+               PyErr_SetString(PyExc_TypeError,
+                          "complex() arg can't be converted to complex");
+               return NULL;
+       }
+       /* XXX Hack to support classes with __complex__ method */
+       if (PyInstance_Check(r)) {
+               static PyObject *complexstr;
+               PyObject *f;
+               if (complexstr == NULL) {
+                       complexstr = PyString_InternFromString("__complex__");
+                       if (complexstr == NULL)
+                               return NULL;
+               }
+               f = PyObject_GetAttr(r, complexstr);
+               if (f == NULL)
+                       PyErr_Clear();
+               else {
+                       PyObject *args = Py_BuildValue("()");
+                       if (args == NULL)
+                               return NULL;
+                       r = PyEval_CallObject(f, args);
+                       Py_DECREF(args);
+                       Py_DECREF(f);
+                       if (r == NULL)
+                               return NULL;
+                       own_r = 1;
+               }
+       }
+       if (PyComplex_Check(r)) {
+               cr = ((PyComplexObject*)r)->cval;
+               if (own_r) {
+                       Py_DECREF(r);
+               }
+       }
+       else {
+               tmp = PyNumber_Float(r);
+               if (own_r) {
+                       Py_DECREF(r);
+               }
+               if (tmp == NULL)
+                       return NULL;
+               if (!PyFloat_Check(tmp)) {
+                       PyErr_SetString(PyExc_TypeError,
+                                       "float(r) didn't return a float");
+                       Py_DECREF(tmp);
+                       return NULL;
+               }
+               cr.real = PyFloat_AsDouble(tmp);
+               Py_DECREF(tmp);
+               cr.imag = 0.0;
+       }
+       if (i == NULL) {
+               ci.real = 0.0;
+               ci.imag = 0.0;
+       }
+       else if (PyComplex_Check(i))
+               ci = ((PyComplexObject*)i)->cval;
+       else {
+               tmp = (*nbi->nb_float)(i);
+               if (tmp == NULL)
+                       return NULL;
+               ci.real = PyFloat_AsDouble(tmp);
+               Py_DECREF(tmp);
+               ci.imag = 0.;
+       }
+       cr.real -= ci.imag;
+       cr.imag += ci.real;
+       return complex_subtype_from_c_complex(type, cr);
 }
 
+static char complex_doc[] =
+"complex(real[, imag]) -> complex number\n\
+\n\
+Create a complex number from a real part and an optional imaginary part.\n\
+This is equivalent to (real + imag*1j) where imag defaults to 0.";
+
 static PyNumberMethods complex_as_number = {
        (binaryfunc)complex_add,                /* nb_add */
        (binaryfunc)complex_sub,                /* nb_subtract */
@@ -606,7 +869,7 @@ PyTypeObject PyComplex_Type = {
        0,
        (destructor)complex_dealloc,            /* tp_dealloc */
        (printfunc)complex_print,               /* tp_print */
-       (getattrfunc)complex_getattr,           /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        (reprfunc)complex_repr,                 /* tp_repr */
@@ -616,14 +879,28 @@ PyTypeObject PyComplex_Type = {
        (hashfunc)complex_hash,                 /* tp_hash */
        0,                                      /* tp_call */
        (reprfunc)complex_str,                  /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
-       0,                                      /* tp_doc */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       complex_doc,                            /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
        complex_richcompare,                    /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       complex_methods,                        /* tp_methods */
+       complex_members,                        /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       complex_new,                            /* tp_new */
 };
 
 #endif
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
new file mode 100644 (file)
index 0000000..40629f6
--- /dev/null
@@ -0,0 +1,854 @@
+/* Descriptors -- a new, flexible way to describe attributes */
+
+#include "Python.h"
+#include "structmember.h" /* Why is this not included in Python.h? */
+
+/* Various kinds of descriptor objects */
+
+#define COMMON \
+       PyObject_HEAD \
+       PyTypeObject *d_type; \
+       PyObject *d_name
+
+typedef struct {
+       COMMON;
+} PyDescrObject;
+
+typedef struct {
+       COMMON;
+       PyMethodDef *d_method;
+} PyMethodDescrObject;
+
+typedef struct {
+       COMMON;
+       struct memberlist *d_member;
+} PyMemberDescrObject;
+
+typedef struct {
+       COMMON;
+       struct getsetlist *d_getset;
+} PyGetSetDescrObject;
+
+typedef struct {
+       COMMON;
+       struct wrapperbase *d_base;
+       void *d_wrapped; /* This can be any function pointer */
+} PyWrapperDescrObject;
+
+static void
+descr_dealloc(PyDescrObject *descr)
+{
+       Py_XDECREF(descr->d_type);
+       Py_XDECREF(descr->d_name);
+       PyObject_DEL(descr);
+}
+
+static char *
+descr_name(PyDescrObject *descr)
+{
+       if (descr->d_name != NULL && PyString_Check(descr->d_name))
+               return PyString_AS_STRING(descr->d_name);
+       else
+               return "?";
+}
+
+static PyObject *
+descr_repr(PyDescrObject *descr, char *format)
+{
+       char buffer[500];
+
+       sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name);
+       return PyString_FromString(buffer);
+}
+
+static PyObject *
+method_repr(PyMethodDescrObject *descr)
+{
+       return descr_repr((PyDescrObject *)descr, 
+                         "<method '%.300s' of '%.100s' objects>");
+}
+
+static PyObject *
+member_repr(PyMemberDescrObject *descr)
+{
+       return descr_repr((PyDescrObject *)descr, 
+                         "<member '%.300s' of '%.100s' objects>");
+}
+
+static PyObject *
+getset_repr(PyGetSetDescrObject *descr)
+{
+       return descr_repr((PyDescrObject *)descr, 
+                         "<attribute '%.300s' of '%.100s' objects>");
+}
+
+static PyObject *
+wrapper_repr(PyWrapperDescrObject *descr)
+{
+       return descr_repr((PyDescrObject *)descr, 
+                         "<slot wrapper '%.300s' of '%.100s' objects>");
+}
+
+static int
+descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
+         PyObject **pres)
+{
+       if (obj == NULL || obj == Py_None) {
+               Py_INCREF(descr);
+               *pres = (PyObject *)descr;
+               return 1;
+       }
+       if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.200s' for '%.100s' objects "
+                            "doesn't apply to '%.100s' object",
+                            descr_name((PyDescrObject *)descr),
+                            descr->d_type->tp_name,
+                            obj->ob_type->tp_name);
+               *pres = NULL;
+               return 1;
+       }
+       return 0;
+}
+
+static PyObject *
+method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
+{
+       PyObject *res;
+
+       if (descr_check((PyDescrObject *)descr, obj, type, &res))
+               return res;
+       return PyCFunction_New(descr->d_method, obj);
+}
+
+static PyObject *
+member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
+{
+       PyObject *res;
+
+       if (descr_check((PyDescrObject *)descr, obj, type, &res))
+               return res;
+       return PyMember_Get((char *)obj, descr->d_member,
+                           descr->d_member->name);
+}
+
+static PyObject *
+getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
+{
+       PyObject *res;
+
+       if (descr_check((PyDescrObject *)descr, obj, type, &res))
+               return res;
+       if (descr->d_getset->get != NULL)
+               return descr->d_getset->get(obj, descr->d_getset->closure);
+       PyErr_Format(PyExc_TypeError,
+                    "attribute '%300s' of '%.100s' objects is not readable",
+                    descr_name((PyDescrObject *)descr),
+                    descr->d_type->tp_name);
+       return NULL;
+}
+
+static PyObject *
+wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
+{
+       PyObject *res;
+
+       if (descr_check((PyDescrObject *)descr, obj, type, &res))
+               return res;
+       return PyWrapper_New((PyObject *)descr, obj);
+}
+
+static int
+descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
+              int *pres)
+{
+       assert(obj != NULL);
+       if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.200s' for '%.100s' objects "
+                            "doesn't apply to '%.100s' object",
+                            descr_name(descr),
+                            descr->d_type->tp_name,
+                            obj->ob_type->tp_name);
+               *pres = -1;
+               return 1;
+       }
+       return 0;
+}
+
+static int
+member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
+{
+       int res;
+
+       if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
+               return res;
+       return PyMember_Set((char *)obj, descr->d_member,
+                           descr->d_member->name, value);
+}
+
+static int
+getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
+{
+       int res;
+
+       if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
+               return res;
+       if (descr->d_getset->set != NULL)
+               return descr->d_getset->set(obj, value,
+                                           descr->d_getset->closure);
+       PyErr_Format(PyExc_TypeError,
+                    "attribute '%300s' of '%.100s' objects is not writable",
+                    descr_name((PyDescrObject *)descr),
+                    descr->d_type->tp_name);
+       return -1;
+}
+
+static PyObject *
+methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
+{
+       int argc;
+       PyObject *self, *func, *result;
+
+       /* Make sure that the first argument is acceptable as 'self' */
+       assert(PyTuple_Check(args));
+       argc = PyTuple_GET_SIZE(args);
+       if (argc < 1) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.300s' of '%.100s' "
+                            "object needs an argument",
+                            descr_name((PyDescrObject *)descr),
+                            descr->d_type->tp_name);
+               return NULL;
+       }
+       self = PyTuple_GET_ITEM(args, 0);
+       if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.200s' "
+                            "requires a '%.100s' object "
+                            "but received a '%.100s'",
+                            descr_name((PyDescrObject *)descr),
+                            descr->d_type->tp_name,
+                            self->ob_type->tp_name);
+               return NULL;
+       }
+
+       func = PyCFunction_New(descr->d_method, self);
+       if (func == NULL)
+               return NULL;
+       args = PyTuple_GetSlice(args, 1, argc);
+       if (args == NULL) {
+               Py_DECREF(func);
+               return NULL;
+       }
+       result = PyEval_CallObjectWithKeywords(func, args, kwds);
+       Py_DECREF(args);
+       Py_DECREF(func);
+       return result;
+}
+
+static PyObject *
+wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
+{
+       int argc;
+       PyObject *self, *func, *result;
+
+       /* Make sure that the first argument is acceptable as 'self' */
+       assert(PyTuple_Check(args));
+       argc = PyTuple_GET_SIZE(args);
+       if (argc < 1) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.300s' of '%.100s' "
+                            "object needs an argument",
+                            descr_name((PyDescrObject *)descr),
+                            descr->d_type->tp_name);
+               return NULL;
+       }
+       self = PyTuple_GET_ITEM(args, 0);
+       if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
+               PyErr_Format(PyExc_TypeError,
+                            "descriptor '%.200s' "
+                            "requires a '%.100s' object "
+                            "but received a '%.100s'",
+                            descr_name((PyDescrObject *)descr),
+                            descr->d_type->tp_name,
+                            self->ob_type->tp_name);
+               return NULL;
+       }
+
+       func = PyWrapper_New((PyObject *)descr, self);
+       if (func == NULL)
+               return NULL;
+       args = PyTuple_GetSlice(args, 1, argc);
+       if (args == NULL) {
+               Py_DECREF(func);
+               return NULL;
+       }
+       result = PyEval_CallObjectWithKeywords(func, args, kwds);
+       Py_DECREF(args);
+       Py_DECREF(func);
+       return result;
+}
+
+static PyObject *
+member_get_doc(PyMethodDescrObject *descr, void *closure)
+{
+       if (descr->d_method->ml_doc == NULL) {
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       return PyString_FromString(descr->d_method->ml_doc);
+}
+
+static struct memberlist descr_members[] = {
+       {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
+       {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
+       {0}
+};
+
+static struct getsetlist member_getset[] = {
+       {"__doc__", (getter)member_get_doc},
+       {0}
+};
+
+static PyObject *
+wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
+{
+       if (descr->d_base->doc == NULL) {
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       return PyString_FromString(descr->d_base->doc);
+}
+
+static struct getsetlist wrapper_getset[] = {
+       {"__doc__", (getter)wrapper_get_doc},
+       {0}
+};
+
+static PyTypeObject PyMethodDescr_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "method_descriptor",
+       sizeof(PyMethodDescrObject),
+       0,
+       (destructor)descr_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)method_repr,                  /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       (ternaryfunc)methoddescr_call,          /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       descr_members,                          /* tp_members */
+       member_getset,                          /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       (descrgetfunc)method_get,               /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+};
+
+static PyTypeObject PyMemberDescr_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "member_descriptor",
+       sizeof(PyMemberDescrObject),
+       0,
+       (destructor)descr_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)member_repr,                  /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       (ternaryfunc)0,                         /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       descr_members,                          /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       (descrgetfunc)member_get,               /* tp_descr_get */
+       (descrsetfunc)member_set,               /* tp_descr_set */
+};
+
+static PyTypeObject PyGetSetDescr_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "getset_descriptor",
+       sizeof(PyGetSetDescrObject),
+       0,
+       (destructor)descr_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)getset_repr,                  /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       (ternaryfunc)0,                         /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       descr_members,                          /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       (descrgetfunc)getset_get,               /* tp_descr_get */
+       (descrsetfunc)getset_set,               /* tp_descr_set */
+};
+
+static PyTypeObject PyWrapperDescr_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "wrapper_descriptor",
+       sizeof(PyWrapperDescrObject),
+       0,
+       (destructor)descr_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)wrapper_repr,                 /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       (ternaryfunc)wrapperdescr_call,         /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       descr_members,                          /* tp_members */
+       wrapper_getset,                         /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       (descrgetfunc)wrapper_get,              /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+};
+
+static PyDescrObject *
+descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
+{
+       PyDescrObject *descr;
+
+       descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
+       if (descr != NULL) {
+               Py_XINCREF(type);
+               descr->d_type = type;
+               descr->d_name = PyString_InternFromString(name);
+               if (descr->d_name == NULL) {
+                       Py_DECREF(descr);
+                       descr = NULL;
+               }
+       }
+       return descr;
+}
+
+PyObject *
+PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
+{
+       PyMethodDescrObject *descr;
+
+       descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
+                                                type, method->ml_name);
+       if (descr != NULL)
+               descr->d_method = method;
+       return (PyObject *)descr;
+}
+
+PyObject *
+PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
+{
+       PyMemberDescrObject *descr;
+
+       descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
+                                                type, member->name);
+       if (descr != NULL)
+               descr->d_member = member;
+       return (PyObject *)descr;
+}
+
+PyObject *
+PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
+{
+       PyGetSetDescrObject *descr;
+
+       descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
+                                                type, getset->name);
+       if (descr != NULL)
+               descr->d_getset = getset;
+       return (PyObject *)descr;
+}
+
+PyObject *
+PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
+{
+       PyWrapperDescrObject *descr;
+
+       descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
+                                                type, base->name);
+       if (descr != NULL) {
+               descr->d_base = base;
+               descr->d_wrapped = wrapped;
+       }
+       return (PyObject *)descr;
+}
+
+int
+PyDescr_IsData(PyObject *d)
+{
+       return d->ob_type->tp_descr_set != NULL;
+}
+
+
+/* --- Readonly proxy for dictionaries (actually any mapping) --- */
+
+/* This has no reason to be in this file except that adding new files is a
+   bit of a pain */
+
+typedef struct {
+       PyObject_HEAD
+       PyObject *dict;
+} proxyobject;
+
+static int
+proxy_len(proxyobject *pp)
+{
+       return PyObject_Size(pp->dict);
+}
+
+static PyObject *
+proxy_getitem(proxyobject *pp, PyObject *key)
+{
+       return PyObject_GetItem(pp->dict, key);
+}
+
+static PyMappingMethods proxy_as_mapping = {
+       (inquiry)proxy_len,                     /* mp_length */
+       (binaryfunc)proxy_getitem,              /* mp_subscript */
+       0,                                      /* mp_ass_subscript */
+};
+
+static int
+proxy_contains(proxyobject *pp, PyObject *key)
+{
+       return PySequence_Contains(pp->dict, key);
+}
+
+static PySequenceMethods proxy_as_sequence = {
+       0,                                      /* sq_length */
+       0,                                      /* sq_concat */
+       0,                                      /* sq_repeat */
+       0,                                      /* sq_item */
+       0,                                      /* sq_slice */
+       0,                                      /* sq_ass_item */
+       0,                                      /* sq_ass_slice */
+       (objobjproc)proxy_contains,             /* sq_contains */
+       0,                                      /* sq_inplace_concat */
+       0,                                      /* sq_inplace_repeat */
+};
+
+static PyObject *
+proxy_has_key(proxyobject *pp, PyObject *args)
+{
+       PyObject *key;
+
+       if (!PyArg_ParseTuple(args, "O:has_key", &key))
+               return NULL;
+       return PyInt_FromLong(PySequence_Contains(pp->dict, key));
+}
+
+static PyObject *
+proxy_get(proxyobject *pp, PyObject *args)
+{
+       PyObject *key, *def = Py_None;
+
+       if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
+               return NULL;
+       return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
+}
+
+static PyObject *
+proxy_keys(proxyobject *pp, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":keys"))
+               return NULL;
+       return PyMapping_Keys(pp->dict);
+}
+
+static PyObject *
+proxy_values(proxyobject *pp, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":values"))
+               return NULL;
+       return PyMapping_Values(pp->dict);
+}
+
+static PyObject *
+proxy_items(proxyobject *pp, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":items"))
+               return NULL;
+       return PyMapping_Items(pp->dict);
+}
+
+static PyObject *
+proxy_copy(proxyobject *pp, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":copy"))
+               return NULL;
+       return PyObject_CallMethod(pp->dict, "copy", NULL);
+}
+
+static PyMethodDef proxy_methods[] = {
+       {"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"},
+       {"get",     (PyCFunction)proxy_get,     METH_VARARGS, "XXX"},
+       {"keys",    (PyCFunction)proxy_keys,    METH_VARARGS, "XXX"},
+       {"values",  (PyCFunction)proxy_values,  METH_VARARGS, "XXX"},
+       {"items",   (PyCFunction)proxy_items,   METH_VARARGS, "XXX"},
+       {"copy",    (PyCFunction)proxy_copy,    METH_VARARGS, "XXX"},
+       {0}
+};
+
+static void
+proxy_dealloc(proxyobject *pp)
+{
+       Py_DECREF(pp->dict);
+       PyObject_DEL(pp);
+}
+
+static PyObject *
+proxy_getiter(proxyobject *pp)
+{
+       return PyObject_GetIter(pp->dict);
+}
+
+PyObject *
+proxy_str(proxyobject *pp)
+{
+       return PyObject_Str(pp->dict);
+}
+
+PyTypeObject proxytype = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                                      /* ob_size */
+       "dict-proxy",                           /* tp_name */
+       sizeof(proxyobject),                    /* tp_basicsize */
+       0,                                      /* tp_itemsize */
+       /* methods */
+       (destructor)proxy_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       &proxy_as_sequence,                     /* tp_as_sequence */
+       &proxy_as_mapping,                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       (reprfunc)proxy_str,                    /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       (getiterfunc)proxy_getiter,             /* tp_iter */
+       0,                                      /* tp_iternext */
+       proxy_methods,                          /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+};
+
+PyObject *
+PyDictProxy_New(PyObject *dict)
+{
+       proxyobject *pp;
+
+       pp = PyObject_NEW(proxyobject, &proxytype);
+       if (pp != NULL) {
+               Py_INCREF(dict);
+               pp->dict = dict;
+       }
+       return (PyObject *)pp;
+}
+
+
+/* --- Wrapper object for "slot" methods --- */
+
+/* This has no reason to be in this file except that adding new files is a
+   bit of a pain */
+
+typedef struct {
+       PyObject_HEAD
+       PyWrapperDescrObject *descr;
+       PyObject *self;
+} wrapperobject;
+
+static void
+wrapper_dealloc(wrapperobject *wp)
+{
+       Py_XDECREF(wp->descr);
+       Py_XDECREF(wp->self);
+       PyObject_DEL(wp);
+}
+
+static PyMethodDef wrapper_methods[] = {
+       {0}
+};
+
+static PyObject *
+wrapper_name(wrapperobject *wp)
+{
+       char *s = wp->descr->d_base->name;
+
+       return PyString_FromString(s);
+}
+
+static PyObject *
+wrapper_doc(wrapperobject *wp)
+{
+       char *s = wp->descr->d_base->doc;
+
+       if (s == NULL) {
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       else {
+               return PyString_FromString(s);
+       }
+}
+
+static struct getsetlist wrapper_getsets[] = {
+       {"__name__", (getter)wrapper_name},
+       {"__doc__", (getter)wrapper_doc},
+       {0}
+};
+
+static PyObject *
+wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
+{
+       wrapperfunc wrapper = wp->descr->d_base->wrapper;
+       PyObject *self = wp->self;
+
+       return (*wrapper)(self, args, wp->descr->d_wrapped);
+}
+
+PyTypeObject wrappertype = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                                      /* ob_size */
+       "method-wrapper",                       /* tp_name */
+       sizeof(wrapperobject),                  /* tp_basicsize */
+       0,                                      /* tp_itemsize */
+       /* methods */
+       (destructor)wrapper_dealloc,            /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       (ternaryfunc)wrapper_call,              /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       wrapper_methods,                        /* tp_methods */
+       0,                                      /* tp_members */
+       wrapper_getsets,                        /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+};
+
+PyObject *
+PyWrapper_New(PyObject *d, PyObject *self)
+{
+       wrapperobject *wp;
+       PyWrapperDescrObject *descr;
+
+       assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
+       descr = (PyWrapperDescrObject *)d;
+       assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
+
+       wp = PyObject_NEW(wrapperobject, &wrappertype);
+       if (wp != NULL) {
+               Py_INCREF(descr);
+               wp->descr = descr;
+               Py_INCREF(self);
+               wp->self = self;
+       }
+       return (PyObject *)wp;
+}
index c17664efc5f11367543447aa9c0b1df8625ed21d..ce4c578f421c1b11f3a7bfffc707ec4e63adbc56 100644 (file)
@@ -3,15 +3,8 @@
 
 #include "Python.h"
 
-/* MINSIZE is the minimum size of a dictionary.  This many slots are
- * allocated directly in the dict object (in the ma_smalltable member).
- * It must be a power of 2, and at least 4.  8 allows dicts with no more than
- * 5 active entries to live in ma_smalltable (and so avoid an additional
- * malloc); instrumentation suggested this suffices for the majority of
- * dicts (consisting mostly of usually-small instance dicts and usually-small
- * dicts created to pass keyword arguments).
- */
-#define MINSIZE 8
+typedef PyDictEntry dictentry;
+typedef PyDictObject dictobject;
 
 /* Define this out if you don't want conversion statistics on exit. */
 #undef SHOW_CONVERSION_COUNTS
@@ -116,69 +109,6 @@ equally good collision statistics, needed less code & used less memory.
 /* Object used as dummy key to fill deleted entries */
 static PyObject *dummy; /* Initialized by first call to newdictobject() */
 
-/*
-There are three kinds of slots in the table:
-
-1. Unused.  me_key == me_value == NULL
-   Does not hold an active (key, value) pair now and never did.  Unused can
-   transition to Active upon key insertion.  This is the only case in which
-   me_key is NULL, and is each slot's initial state.
-
-2. Active.  me_key != NULL and me_key != dummy and me_value != NULL
-   Holds an active (key, value) pair.  Active can transition to Dummy upon
-   key deletion.  This is the only case in which me_value != NULL.
-
-3. Dummy.  me_key == dummy and me_value == NULL
-   Previously held an active (key, value) pair, but that was deleted and an
-   active pair has not yet overwritten the slot.  Dummy can transition to
-   Active upon key insertion.  Dummy slots cannot be made Unused again
-   (cannot have me_key set to NULL), else the probe sequence in case of
-   collision would have no way to know they were once active.
-
-Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to
-hold a search finger.  The me_hash field of Unused or Dummy slots has no
-meaning otherwise.
-*/
-typedef struct {
-       long me_hash;      /* cached hash code of me_key */
-       PyObject *me_key;
-       PyObject *me_value;
-#ifdef USE_CACHE_ALIGNED
-       long    aligner;
-#endif
-} dictentry;
-
-/*
-To ensure the lookup algorithm terminates, there must be at least one Unused
-slot (NULL key) in the table.
-The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
-ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
-values == the number of Active items).
-To avoid slowing down lookups on a near-full table, we resize the table when
-it's two-thirds full.
-*/
-typedef struct dictobject dictobject;
-struct dictobject {
-       PyObject_HEAD
-       int ma_fill;  /* # Active + # Dummy */
-       int ma_used;  /* # Active */
-
-       /* The table contains ma_mask + 1 slots, and that's a power of 2.
-        * We store the mask instead of the size because the mask is more
-        * frequently needed.
-        */
-       int ma_mask;
-
-       /* ma_table points to ma_smalltable for small tables, else to
-        * additional malloc'ed memory.  ma_table is never NULL!  This rule
-        * saves repeated runtime null-tests in the workhorse getitem and
-        * setitem calls.
-        */
-       dictentry *ma_table;
-       dictentry *(*ma_lookup)(dictobject *mp, PyObject *key, long hash);
-       dictentry ma_smalltable[MINSIZE];
-};
-
 /* forward declarations */
 static dictentry *
 lookdict_string(dictobject *mp, PyObject *key, long hash);
@@ -196,12 +126,24 @@ show_counts(void)
 }
 #endif
 
-/* Set dictobject* mp to empty but w/ MINSIZE slots, using ma_smalltable. */
-#define empty_to_minsize(mp) do {                                      \
-       memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable));    \
+/* Initialization macros.
+   There are two ways to create a dict:  PyDict_New() is the main C API
+   function, and the tp_new slot maps to dict_new().  In the latter case we
+   can save a little time over what PyDict_New does because it's guaranteed
+   that the PyDictObject struct is already zeroed out.
+   Everyone except dict_new() should use EMPTY_TO_MINSIZE (unless they have
+   an excellent reason not to).
+*/
+
+#define INIT_NONZERO_DICT_SLOTS(mp) do {                               \
        (mp)->ma_table = (mp)->ma_smalltable;                           \
-       (mp)->ma_mask = MINSIZE - 1;                                    \
+       (mp)->ma_mask = PyDict_MINSIZE - 1;                             \
+    } while(0)
+
+#define EMPTY_TO_MINSIZE(mp) do {                                      \
+       memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable));    \
        (mp)->ma_used = (mp)->ma_fill = 0;                              \
+       INIT_NONZERO_DICT_SLOTS(mp);                                    \
     } while(0)
 
 PyObject *
@@ -219,7 +161,7 @@ PyDict_New(void)
        mp = PyObject_NEW(dictobject, &PyDict_Type);
        if (mp == NULL)
                return NULL;
-       empty_to_minsize(mp);
+       EMPTY_TO_MINSIZE(mp);
        mp->ma_lookup = lookdict_string;
 #ifdef SHOW_CONVERSION_COUNTS
        ++created;
@@ -418,7 +360,10 @@ insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
 {
        PyObject *old_value;
        register dictentry *ep;
-       ep = (mp->ma_lookup)(mp, key, hash);
+       typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long);
+
+       assert(mp->ma_lookup != NULL);
+       ep = mp->ma_lookup(mp, key, hash);
        if (ep->me_value != NULL) {
                old_value = ep->me_value;
                ep->me_value = value;
@@ -449,12 +394,12 @@ dictresize(dictobject *mp, int minused)
        dictentry *oldtable, *newtable, *ep;
        int i;
        int is_oldtable_malloced;
-       dictentry small_copy[MINSIZE];
+       dictentry small_copy[PyDict_MINSIZE];
 
        assert(minused >= 0);
 
        /* Find the smallest table size > minused. */
-       for (newsize = MINSIZE;
+       for (newsize = PyDict_MINSIZE;
             newsize <= minused && newsize > 0;
             newsize <<= 1)
                ;
@@ -468,7 +413,7 @@ dictresize(dictobject *mp, int minused)
        assert(oldtable != NULL);
        is_oldtable_malloced = oldtable != mp->ma_smalltable;
 
-       if (newsize == MINSIZE) {
+       if (newsize == PyDict_MINSIZE) {
                /* A large table is shrinking, or we can't get any smaller. */
                newtable = mp->ma_smalltable;
                if (newtable == oldtable) {
@@ -649,7 +594,7 @@ PyDict_Clear(PyObject *op)
        dictentry *ep, *table;
        int table_is_malloced;
        int fill;
-       dictentry small_copy[MINSIZE];
+       dictentry small_copy[PyDict_MINSIZE];
 #ifdef Py_DEBUG
        int i, n;
 #endif
@@ -674,7 +619,7 @@ PyDict_Clear(PyObject *op)
         */
        fill = mp->ma_fill;
        if (table_is_malloced)
-               empty_to_minsize(mp);
+               EMPTY_TO_MINSIZE(mp);
 
        else if (fill > 0) {
                /* It's a small table with something that needs to be cleared.
@@ -683,7 +628,7 @@ PyDict_Clear(PyObject *op)
                 */
                memcpy(small_copy, table, sizeof(small_copy));
                table = small_copy;
-               empty_to_minsize(mp);
+               EMPTY_TO_MINSIZE(mp);
        }
        /* else it's a small table that's already empty */
 
@@ -1042,32 +987,47 @@ dict_items(register dictobject *mp, PyObject *args)
 }
 
 static PyObject *
-dict_update(register dictobject *mp, PyObject *args)
+dict_update(PyObject *mp, PyObject *args)
+{
+       PyObject *other;
+
+       if (!PyArg_ParseTuple(args, "O:update", &other))
+               return NULL;
+       if (PyDict_Update(mp, other) < 0)
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+int
+PyDict_Update(PyObject *a, PyObject *b)
 {
+       register PyDictObject *mp, *other;
        register int i;
-       dictobject *other;
        dictentry *entry;
-       PyObject *param;
+
        /* We accept for the argument either a concrete dictionary object,
         * or an abstract "mapping" object.  For the former, we can do
         * things quite efficiently.  For the latter, we only require that
         * PyMapping_Keys() and PyObject_GetItem() be supported.
         */
-       if (!PyArg_ParseTuple(args, "O:update", &param))
-               return NULL;
-
-       if (PyDict_Check(param)) {
-               other = (dictobject*)param;
+       if (a == NULL || !PyDict_Check(a) || b == NULL) {
+               PyErr_BadInternalCall();
+               return -1;
+       }
+       mp = (dictobject*)a;
+       if (PyDict_Check(b)) {
+               other = (dictobject*)b;
                if (other == mp || other->ma_used == 0)
                        /* a.update(a) or a.update({}); nothing to do */
-                       goto done;
+                       return 0;
                /* Do one big resize at the start, rather than
                 * incrementally resizing as we insert new items.  Expect
                 * that there will be no (or few) overlapping keys.
                 */
                if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
                   if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
-                          return NULL;
+                          return -1;
                }
                for (i = 0; i <= other->ma_mask; i++) {
                        entry = &other->ma_table[i];
@@ -1081,7 +1041,7 @@ dict_update(register dictobject *mp, PyObject *args)
        }
        else {
                /* Do it the generic, slower way */
-               PyObject *keys = PyMapping_Keys(param);
+               PyObject *keys = PyMapping_Keys(b);
                PyObject *iter;
                PyObject *key, *value;
                int status;
@@ -1092,37 +1052,34 @@ dict_update(register dictobject *mp, PyObject *args)
                         * AttributeError to percolate up.  Might as well
                         * do the same for any other error.
                         */
-                       return NULL;
+                       return -1;
 
                iter = PyObject_GetIter(keys);
                Py_DECREF(keys);
                if (iter == NULL)
-                       return NULL;
+                       return -1;
 
                for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
-                       value = PyObject_GetItem(param, key);
+                       value = PyObject_GetItem(b, key);
                        if (value == NULL) {
                                Py_DECREF(iter);
                                Py_DECREF(key);
-                               return NULL;
+                               return -1;
                        }
                        status = PyDict_SetItem((PyObject*)mp, key, value);
                        Py_DECREF(key);
                        Py_DECREF(value);
                        if (status < 0) {
                                Py_DECREF(iter);
-                               return NULL;
+                               return -1;
                        }
                }
                Py_DECREF(iter);
                if (PyErr_Occurred())
                        /* Iterator completed, via error */
-                       return NULL;
+                       return -1;
        }
-       
-  done:
-       Py_INCREF(Py_None);
-       return Py_None;
+       return 0;
 }
 
 static PyObject *
@@ -1694,12 +1651,6 @@ static PyMethodDef mapp_methods[] = {
        {NULL,          NULL}   /* sentinel */
 };
 
-static PyObject *
-dict_getattr(dictobject *mp, char *name)
-{
-       return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
-}
-
 static int
 dict_contains(dictobject *mp, PyObject *key)
 {
@@ -1731,6 +1682,26 @@ static PySequenceMethods dict_as_sequence = {
        0,                                      /* sq_inplace_repeat */
 };
 
+static PyObject *
+dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *self;
+
+       assert(type != NULL && type->tp_alloc != NULL);
+       self = type->tp_alloc(type, 0);
+       if (self != NULL) {
+               PyDictObject *d = (PyDictObject *)self;
+               /* It's guaranteed that tp->alloc zeroed out the struct. */
+               assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0);
+               INIT_NONZERO_DICT_SLOTS(d);
+               d->ma_lookup = lookdict_string;
+#ifdef SHOW_CONVERSION_COUNTS
+               ++created;
+#endif
+       }
+       return self;
+}
+
 static PyObject *
 dict_iter(dictobject *dict)
 {
@@ -1745,7 +1716,7 @@ PyTypeObject PyDict_Type = {
        0,
        (destructor)dict_dealloc,               /* tp_dealloc */
        (printfunc)dict_print,                  /* tp_print */
-       (getattrfunc)dict_getattr,              /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        (cmpfunc)dict_compare,                  /* tp_compare */
        (reprfunc)dict_repr,                    /* tp_repr */
@@ -1755,17 +1726,29 @@ PyTypeObject PyDict_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
-       0,                                      /* tp_doc */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+       "dictionary type",                      /* tp_doc */
        (traverseproc)dict_traverse,            /* tp_traverse */
        (inquiry)dict_tp_clear,                 /* tp_clear */
        dict_richcompare,                       /* tp_richcompare */
        0,                                      /* tp_weaklistoffset */
        (getiterfunc)dict_iter,                 /* tp_iter */
        0,                                      /* tp_iternext */
+       mapp_methods,                           /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       dict_new,                               /* tp_new */
 };
 
 /* For backward compatibility with old dictionary interface */
@@ -1873,12 +1856,6 @@ static PyMethodDef dictiter_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
-static PyObject *
-dictiter_getattr(dictiterobject *di, char *name)
-{
-       return Py_FindMethod(dictiter_methods, (PyObject *)di, name);
-}
-
 static PyObject *dictiter_iternext(dictiterobject *di)
 {
        PyObject *key, *value;
@@ -1903,7 +1880,7 @@ PyTypeObject PyDictIter_Type = {
        /* methods */
        (destructor)dictiter_dealloc,           /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)dictiter_getattr,          /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
@@ -1913,7 +1890,7 @@ PyTypeObject PyDictIter_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,                     /* tp_flags */
@@ -1924,4 +1901,11 @@ PyTypeObject PyDictIter_Type = {
        0,                                      /* tp_weaklistoffset */
        (getiterfunc)dictiter_getiter,          /* tp_iter */
        (iternextfunc)dictiter_iternext,        /* tp_iternext */
+       dictiter_methods,                       /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
 };
index 18d15e1ae209fa95e25d827413be7e8d88f7cb69..e192e8b9c77c15ac2d6ed6bbd7f40eb86a3ea357 100644 (file)
@@ -1273,29 +1273,15 @@ static struct memberlist file_memberlist[] = {
 };
 
 static PyObject *
-file_getattr(PyFileObject *f, char *name)
+get_closed(PyFileObject *f, void *closure)
 {
-       PyObject *res;
-
-       res = Py_FindMethod(file_methods, (PyObject *)f, name);
-       if (res != NULL)
-               return res;
-       PyErr_Clear();
-       if (strcmp(name, "closed") == 0)
-               return PyInt_FromLong((long)(f->f_fp == 0));
-       return PyMember_Get((char *)f, file_memberlist, name);
+       return PyInt_FromLong((long)(f->f_fp == 0));
 }
 
-static int
-file_setattr(PyFileObject *f, char *name, PyObject *v)
-{
-       if (v == NULL) {
-               PyErr_SetString(PyExc_AttributeError,
-                               "can't delete file attributes");
-               return -1;
-       }
-       return PyMember_Set((char *)f, file_memberlist, name, v);
-}
+static struct getsetlist file_getsetlist[] = {
+       {"closed", (getter)get_closed, NULL, NULL},
+       {0},
+};
 
 static PyObject *
 file_getiter(PyObject *f)
@@ -1311,27 +1297,32 @@ PyTypeObject PyFile_Type = {
        0,
        (destructor)file_dealloc,               /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)file_getattr,              /* tp_getattr */
-       (setattrfunc)file_setattr,              /* tp_setattr */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
-       (reprfunc)file_repr,                    /* tp_repr */
+       (reprfunc)file_repr,                    /* tp_repr */
        0,                                      /* tp_as_number */
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,                     /* tp_flags */
-       0,                                      /* tp_doc */
-       0,                                      /* tp_traverse */
-       0,                                      /* tp_clear */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
        0,                                      /* tp_richcompare */
        0,                                      /* tp_weaklistoffset */
        file_getiter,                           /* tp_iter */
        0,                                      /* tp_iternext */
+       file_methods,                           /* tp_methods */
+       file_memberlist,                        /* tp_members */
+       file_getsetlist,                        /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
 
 /* Interface for the 'soft space' between print items. */
index d1ce09271244fe83e6a1b420470e96c35331a8d6..df88736abae291bbdb34f52c44b64279a747ce32 100644 (file)
@@ -636,6 +636,26 @@ float_float(PyObject *v)
 }
 
 
+static PyObject *
+float_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *x = Py_False; /* Integer zero */
+       static char *kwlist[] = {"x", 0};
+
+       assert(type == &PyFloat_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x))
+               return NULL;
+       if (PyString_Check(x))
+               return PyFloat_FromString(x, NULL);
+       return PyNumber_Float(x);
+}
+
+static char float_doc[] =
+"float(x) -> floating point number\n\
+\n\
+Convert a string or number to a floating point number, if possible.";
+
+
 static PyNumberMethods float_as_number = {
        (binaryfunc)float_add, /*nb_add*/
        (binaryfunc)float_sub, /*nb_subtract*/
@@ -679,22 +699,40 @@ PyTypeObject PyFloat_Type = {
        "float",
        sizeof(PyFloatObject),
        0,
-       (destructor)float_dealloc, /*tp_dealloc*/
-       (printfunc)float_print, /*tp_print*/
-       0,                      /*tp_getattr*/
-       0,                      /*tp_setattr*/
-       (cmpfunc)float_compare, /*tp_compare*/
-       (reprfunc)float_repr,   /*tp_repr*/
-       &float_as_number,       /*tp_as_number*/
-       0,                      /*tp_as_sequence*/
-       0,                      /*tp_as_mapping*/
-       (hashfunc)float_hash,   /*tp_hash*/
-        0,                     /*tp_call*/
-        (reprfunc)float_str,   /*tp_str*/
-       0,                      /*tp_getattro*/
-       0,                      /*tp_setattro*/
-       0,                      /*tp_as_buffer*/
-       Py_TPFLAGS_CHECKTYPES   /*tp_flags*/
+       (destructor)float_dealloc,              /* tp_dealloc */
+       (printfunc)float_print,                 /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       (cmpfunc)float_compare,                 /* tp_compare */
+       (reprfunc)float_repr,                   /* tp_repr */
+       &float_as_number,                       /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)float_hash,                   /* tp_hash */
+       0,                                      /* tp_call */
+       (reprfunc)float_str,                    /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       float_doc,                              /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       float_new,                              /* tp_new */
 };
 
 void
index 0801b932c516c55345c276a29f1c5027f08e6c0e..d327616618615fd1deda60f5dfaebfefff9e7f5b 100644 (file)
@@ -15,7 +15,6 @@ static struct memberlist frame_memberlist[] = {
        {"f_code",      T_OBJECT,       OFF(f_code),    RO},
        {"f_builtins",  T_OBJECT,       OFF(f_builtins),RO},
        {"f_globals",   T_OBJECT,       OFF(f_globals), RO},
-       {"f_locals",    T_OBJECT,       OFF(f_locals),  RO},
        {"f_lasti",     T_INT,          OFF(f_lasti),   RO},
        {"f_lineno",    T_INT,          OFF(f_lineno),  RO},
        {"f_restricted",T_INT,          OFF(f_restricted),RO},
@@ -27,18 +26,17 @@ static struct memberlist frame_memberlist[] = {
 };
 
 static PyObject *
-frame_getattr(PyFrameObject *f, char *name)
+frame_getlocals(PyFrameObject *f, void *closure)
 {
-       if (strcmp(name, "f_locals") == 0)
-               PyFrame_FastToLocals(f);
-       return PyMember_Get((char *)f, frame_memberlist, name);
+       PyFrame_FastToLocals(f);
+       Py_INCREF(f->f_locals);
+       return f->f_locals;
 }
 
-static int
-frame_setattr(PyFrameObject *f, char *name, PyObject *value)
-{
-       return PyMember_Set((char *)f, frame_memberlist, name, value);
-}
+static struct getsetlist frame_getsetlist[] = {
+       {"f_locals",    (getter)frame_getlocals, NULL, NULL},
+       {0}
+};
 
 /* Stack frames are allocated and deallocated at a considerable rate.
    In an attempt to improve the speed of function calls, we maintain a
@@ -177,8 +175,8 @@ PyTypeObject PyFrame_Type = {
        0,
        (destructor)frame_dealloc,              /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)frame_getattr,             /* tp_getattr */
-       (setattrfunc)frame_setattr,             /* tp_setattr */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
        0,                                      /* tp_as_number */
@@ -187,13 +185,22 @@ PyTypeObject PyFrame_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
-       0,                                      /* tp_setattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       PyObject_GenericSetAttr,                /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
        0,                                      /* tp_doc */
        (traverseproc)frame_traverse,           /* tp_traverse */
        (inquiry)frame_clear,                   /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       frame_memberlist,                       /* tp_members */
+       frame_getsetlist,                       /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
 
 PyFrameObject *
index 09c6cb80217d4fec6fc9bb705326d1d7ef1d64c1..311bcdeff995a5a164ef3d405e39b1f1539295c8 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "Python.h"
 #include "compile.h"
+#include "eval.h"
 #include "structmember.h"
 
 PyObject *
@@ -141,9 +142,8 @@ static struct memberlist func_memberlist[] = {
 };
 
 static PyObject *
-func_getattro(PyFunctionObject *op, PyObject *name)
+func_getattro(PyObject *op, PyObject *name)
 {
-       PyObject *rtn;
        char *sname = PyString_AsString(name);
        
        if (sname[0] != '_' && PyEval_GetRestricted()) {
@@ -152,25 +152,12 @@ func_getattro(PyFunctionObject *op, PyObject *name)
                return NULL;
        }
 
-       /* no API for PyMember_HasAttr() */
-       rtn = PyMember_Get((char *)op, func_memberlist, sname);
-
-       if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
-               PyErr_Clear();
-               if (op->func_dict != NULL) {
-                       rtn = PyDict_GetItem(op->func_dict, name);
-                       Py_XINCREF(rtn);
-               }
-               if (rtn == NULL)
-                       PyErr_SetObject(PyExc_AttributeError, name);
-       }
-       return rtn;
+       return PyObject_GenericGetAttr(op, name);
 }
 
 static int
-func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
+func_setattro(PyObject *op, PyObject *name, PyObject *value)
 {
-       int rtn;
        char *sname = PyString_AsString(name);
 
        if (PyEval_GetRestricted()) {
@@ -216,31 +203,7 @@ func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
                }
        }
 
-       rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
-       if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
-               PyErr_Clear();
-               if (op->func_dict == NULL) {
-                       /* don't create the dict if we're deleting an
-                        * attribute.  In that case, we know we'll get an
-                        * AttributeError.
-                        */
-                       if (value == NULL) {
-                               PyErr_SetString(PyExc_AttributeError, sname);
-                               return -1;
-                       }
-                       op->func_dict = PyDict_New();
-                       if (op->func_dict == NULL)
-                               return -1;
-               }
-                if (value == NULL)
-                       rtn = PyDict_DelItem(op->func_dict, name);
-                else
-                       rtn = PyDict_SetItem(op->func_dict, name, value);
-               /* transform KeyError into AttributeError */
-               if (rtn < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
-                       PyErr_SetString(PyExc_AttributeError, sname);
-       }
-       return rtn;
+       return PyObject_GenericSetAttr(op, name, value);
 }
 
 static void
@@ -314,31 +277,324 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
        return 0;
 }
 
+static PyObject *
+function_call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+       PyObject *result;
+       PyObject *argdefs;
+       PyObject **d, **k;
+       int nk, nd;
+
+       argdefs = PyFunction_GET_DEFAULTS(func);
+       if (argdefs != NULL && PyTuple_Check(argdefs)) {
+               d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0);
+               nd = PyTuple_Size(argdefs);
+       }
+       else {
+               d = NULL;
+               nd = 0;
+       }
+
+       if (kw != NULL && PyDict_Check(kw)) {
+               int pos, i;
+               nk = PyDict_Size(kw);
+               k = PyMem_NEW(PyObject *, 2*nk);
+               if (k == NULL) {
+                       PyErr_NoMemory();
+                       Py_DECREF(arg);
+                       return NULL;
+               }
+               pos = i = 0;
+               while (PyDict_Next(kw, &pos, &k[i], &k[i+1]))
+                       i += 2;
+               nk = i/2;
+               /* XXX This is broken if the caller deletes dict items! */
+       }
+       else {
+               k = NULL;
+               nk = 0;
+       }
+
+       result = PyEval_EvalCodeEx(
+               (PyCodeObject *)PyFunction_GET_CODE(func),
+               PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
+               &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
+               k, nk, d, nd,
+               PyFunction_GET_CLOSURE(func));
+
+       if (k != NULL)
+               PyMem_DEL(k);
+
+       return result;
+}
+
+/* Bind a function to an object */
+static PyObject *
+func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
+{
+       if (obj == Py_None)
+               obj = NULL;
+       return PyMethod_New(func, obj, type);
+}
+
 PyTypeObject PyFunction_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
        "function",
        sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
        0,
-       (destructor)func_dealloc,            /* tp_dealloc */
-       0,                                   /* tp_print */
-       0,                                   /* tp_getattr */
-       0,                                   /* tp_setattr */
-       0,                                   /* tp_compare */
-       (reprfunc)func_repr,                 /* tp_repr */
-       0,                                   /* tp_as_number */
-       0,                                   /* tp_as_sequence */
-       0,                                   /* tp_as_mapping */
-       0,                                   /* tp_hash */
-       0,                                   /* tp_call */
-       0,                                   /* tp_str */
-       (getattrofunc)func_getattro,         /* tp_getattro */
-       (setattrofunc)func_setattro,         /* tp_setattro */
-       0,                                   /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,  /* tp_flags */
-       0,                                   /* tp_doc */
-       (traverseproc)func_traverse,         /* tp_traverse */
-       0,                                   /* tp_clear */
-       0,                                   /* tp_richcompare */
+       (destructor)func_dealloc,               /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)func_repr,                    /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       function_call,                          /* tp_call */
+       0,                                      /* tp_str */
+       func_getattro,                          /* tp_getattro */
+       func_setattro,                          /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
+       0,                                      /* tp_doc */
+       (traverseproc)func_traverse,            /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
        offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       func_memberlist,                        /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       func_descr_get,                         /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       offsetof(PyFunctionObject, func_dict),  /* tp_dictoffset */
+};
+
+
+/* Class method object */
+
+/* A class method receives the class as implicit first argument,
+   just like an instance method receives the instance.
+   To declare a class method, use this idiom:
+
+     class C:
+         def f(cls, arg1, arg2, ...): ...
+        f = classmethod(f)
+   
+   It can be called either on the class (e.g. C.f()) or on an instance
+   (e.g. C().f()); the instance is ignored except for its class.
+   If a class method is called for a derived class, the derived class
+   object is passed as the implied first argument.
+
+   Class methods are different than C++ or Java static methods.
+   If you want those, see static methods below.
+*/
+
+typedef struct {
+       PyObject_HEAD
+       PyObject *cm_callable;
+} classmethod;
+
+static void
+cm_dealloc(classmethod *cm)
+{
+       Py_XDECREF(cm->cm_callable);
+       PyObject_DEL(cm);
+}
+
+static PyObject *
+cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+       classmethod *cm = (classmethod *)self;
+
+       if (cm->cm_callable == NULL) {
+               PyErr_SetString(PyExc_RuntimeError,
+                               "uninitialized classmethod object");
+               return NULL;
+       }
+       return PyMethod_New(cm->cm_callable,
+                           type, (PyObject *)(type->ob_type));
+}
+
+static int
+cm_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+       classmethod *cm = (classmethod *)self;
+       PyObject *callable;
+
+       if (!PyArg_ParseTuple(args, "O:callable", &callable))
+               return -1;
+       Py_INCREF(callable);
+       cm->cm_callable = callable;
+       return 0;
+}
+
+PyTypeObject PyClassMethod_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "classmethod",
+       sizeof(classmethod),
+       0,
+       (destructor)cm_dealloc,                 /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       cm_descr_get,                           /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       cm_init,                                /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       PyType_GenericNew,                      /* tp_new */
+};
+
+PyObject *
+PyClassMethod_New(PyObject *callable)
+{
+       classmethod *cm = (classmethod *)
+               PyType_GenericAlloc(&PyClassMethod_Type, 0);
+       if (cm != NULL) {
+               Py_INCREF(callable);
+               cm->cm_callable = callable;
+       }
+       return (PyObject *)cm;
+}
+
+
+/* Static method object */
+
+/* A static method does not receive an implicit first argument.
+   To declare a static method, use this idiom:
+
+     class C:
+         def f(arg1, arg2, ...): ...
+        f = staticmethod(f)
+
+   It can be called either on the class (e.g. C.f()) or on an instance
+   (e.g. C().f()); the instance is ignored except for its class.
+
+   Static methods in Python are similar to those found in Java or C++.
+   For a more advanced concept, see class methods above.
+*/
+
+typedef struct {
+       PyObject_HEAD
+       PyObject *sm_callable;
+} staticmethod;
+
+static void
+sm_dealloc(staticmethod *sm)
+{
+       Py_XDECREF(sm->sm_callable);
+       PyObject_DEL(sm);
+}
+
+static PyObject *
+sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+       staticmethod *sm = (staticmethod *)self;
+
+       if (sm->sm_callable == NULL) {
+               PyErr_SetString(PyExc_RuntimeError,
+                               "uninitialized staticmethod object");
+               return NULL;
+       }
+       Py_INCREF(sm->sm_callable);
+       return sm->sm_callable;
+}
+
+static int
+sm_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+       staticmethod *sm = (staticmethod *)self;
+       PyObject *callable;
+
+       if (!PyArg_ParseTuple(args, "O:callable", &callable))
+               return -1;
+       Py_INCREF(callable);
+       sm->sm_callable = callable;
+       return 0;
+}
+
+PyTypeObject PyStaticMethod_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "staticmethod",
+       sizeof(staticmethod),
+       0,
+       (destructor)sm_dealloc,                 /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       sm_descr_get,                           /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       sm_init,                                /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       PyType_GenericNew,                      /* tp_new */
 };
+
+PyObject *
+PyStaticMethod_New(PyObject *callable)
+{
+       staticmethod *sm = (staticmethod *)
+               PyType_GenericAlloc(&PyStaticMethod_Type, 0);
+       if (sm != NULL) {
+               Py_INCREF(callable);
+               sm->sm_callable = callable;
+       }
+       return (PyObject *)sm;
+}
index 282da201b82ea075b2f0935b739b2ffe0b6bbf56..e5106c566aefb39a1f7ffadb3fa9e2875e94f884 100644 (file)
@@ -742,6 +742,41 @@ int_hex(PyIntObject *v)
        return PyString_FromString(buf);
 }
 
+static PyObject *
+int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *x = NULL;
+       int base = -909;
+       static char *kwlist[] = {"x", "base", 0};
+
+       assert(type == &PyInt_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,
+                                        &x, &base))
+               return NULL;
+       if (x == NULL)
+               return PyInt_FromLong(0L);
+       if (base == -909)
+               return PyNumber_Int(x);
+       if (PyString_Check(x))
+               return PyInt_FromString(PyString_AS_STRING(x), NULL, base);
+       if (PyUnicode_Check(x))
+               return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x),
+                                        PyUnicode_GET_SIZE(x),
+                                        base);
+       PyErr_SetString(PyExc_TypeError,
+                       "int() can't convert non-string with explicit base");
+       return NULL;
+}
+
+static char int_doc[] =
+"int(x[, base]) -> integer\n\
+\n\
+Convert a string or number to an integer, if possible.  A floating point\n\
+argument will be truncated towards zero (this does not include a string\n\
+representation of a floating point number!)  When converting a string, use\n\
+the optional base.  It is an error to supply a base when converting a\n\
+non-string.";
+
 static PyNumberMethods int_as_number = {
        (binaryfunc)int_add,    /*nb_add*/
        (binaryfunc)int_sub,    /*nb_subtract*/
@@ -785,22 +820,40 @@ PyTypeObject PyInt_Type = {
        "int",
        sizeof(PyIntObject),
        0,
-       (destructor)int_dealloc, /*tp_dealloc*/
-       (printfunc)int_print, /*tp_print*/
-       0,              /*tp_getattr*/
-       0,              /*tp_setattr*/
-       (cmpfunc)int_compare, /*tp_compare*/
-       (reprfunc)int_repr, /*tp_repr*/
-       &int_as_number, /*tp_as_number*/
-       0,              /*tp_as_sequence*/
-       0,              /*tp_as_mapping*/
-       (hashfunc)int_hash, /*tp_hash*/
-        0,                     /*tp_call*/
-        0,                     /*tp_str*/
-       0,                      /*tp_getattro*/
-       0,                      /*tp_setattro*/
-       0,                      /*tp_as_buffer*/
-       Py_TPFLAGS_CHECKTYPES   /*tp_flags*/
+       (destructor)int_dealloc,                /* tp_dealloc */
+       (printfunc)int_print,                   /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       (cmpfunc)int_compare,                   /* tp_compare */
+       (reprfunc)int_repr,                     /* tp_repr */
+       &int_as_number,                         /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)int_hash,                     /* tp_hash */
+        0,                                     /* tp_call */
+        0,                                     /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       int_doc,                                /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       int_new,                                /* tp_new */
 };
 
 void
index c4f4e616b6279ec942bfbf68a0ffc2ea77284c47..e062c8ab71d1dfa88c514ce3beb8534aada232d8 100644 (file)
@@ -96,12 +96,6 @@ static PyMethodDef iter_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
-static PyObject *
-iter_getattr(seqiterobject *it, char *name)
-{
-       return Py_FindMethod(iter_methods, (PyObject *)it, name);
-}
-
 PyTypeObject PySeqIter_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                                      /* ob_size */
@@ -111,7 +105,7 @@ PyTypeObject PySeqIter_Type = {
        /* methods */
        (destructor)iter_dealloc,               /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)iter_getattr,              /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
@@ -121,7 +115,7 @@ PyTypeObject PySeqIter_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
@@ -132,6 +126,13 @@ PyTypeObject PySeqIter_Type = {
        0,                                      /* tp_weaklistoffset */
        (getiterfunc)iter_getiter,              /* tp_iter */
        (iternextfunc)iter_iternext,            /* tp_iternext */
+       iter_methods,                           /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
 };
 
 /* -------------------------------------- */
@@ -197,12 +198,6 @@ static PyMethodDef calliter_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
-static PyObject *
-calliter_getattr(calliterobject *it, char *name)
-{
-       return Py_FindMethod(calliter_methods, (PyObject *)it, name);
-}
-
 static PyObject *
 calliter_iternext(calliterobject *it)
 {
@@ -228,7 +223,7 @@ PyTypeObject PyCallIter_Type = {
        /* methods */
        (destructor)calliter_dealloc,           /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)calliter_getattr,          /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
@@ -238,7 +233,7 @@ PyTypeObject PyCallIter_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
@@ -249,4 +244,11 @@ PyTypeObject PyCallIter_Type = {
        0,                                      /* tp_weaklistoffset */
        (getiterfunc)iter_getiter,              /* tp_iter */
        (iternextfunc)calliter_iternext,        /* tp_iternext */
+       calliter_methods,                       /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
 };
index 7166ced8cb4fa074463910a7927a7a240ae2d435..b77cc0af0270b4238d82c0c95523aa036b4fc07f 100644 (file)
@@ -523,6 +523,10 @@ list_ass_slice(PyListObject *a, int ilow, int ihigh, PyObject *v)
                        Py_XDECREF(*p);
                PyMem_DEL(recycle);
        }
+       if (a->ob_size == 0 && a->ob_item != NULL) {
+               PyMem_FREE(a->ob_item);
+               a->ob_item = NULL;
+       }
        return 0;
 #undef b
 }
@@ -1289,16 +1293,18 @@ listsort(PyListObject *self, PyObject *args)
 {
        int err;
        PyObject *compare = NULL;
+       PyTypeObject *savetype;
 
        if (args != NULL) {
                if (!PyArg_ParseTuple(args, "|O:sort", &compare))
                        return NULL;
        }
+       savetype = self->ob_type;
        self->ob_type = &immutable_list_type;
        err = samplesortslice(self->ob_item,
                              self->ob_item + self->ob_size,
                              compare);
-       self->ob_type = &PyList_Type;
+       self->ob_type = savetype;
        if (err < 0)
                return NULL;
        Py_INCREF(Py_None);
@@ -1541,6 +1547,100 @@ list_richcompare(PyObject *v, PyObject *w, int op)
        return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
 }
 
+/* Adapted from newer code by Tim */
+static int
+list_fill(PyListObject *result, PyObject *v)
+{
+       PyObject *it;      /* iter(v) */
+       int n;             /* guess for result list size */
+       int i;
+
+       n = result->ob_size;
+
+       /* Special-case list(a_list), for speed. */
+       if (PyList_Check(v)) {
+               if (v == (PyObject *)result)
+                       return 0; /* source is destination, we're done */
+               return list_ass_slice(result, 0, n, v);
+       }
+
+       /* Empty previous contents */
+       if (n != 0) {
+               if (list_ass_slice(result, 0, n, (PyObject *)NULL) != 0)
+                       return -1;
+       }
+
+       /* Get iterator.  There may be some low-level efficiency to be gained
+        * by caching the tp_iternext slot instead of using PyIter_Next()
+        * later, but premature optimization is the root etc.
+        */
+       it = PyObject_GetIter(v);
+       if (it == NULL)
+               return -1;
+
+       /* Guess a result list size. */
+       n = -1;  /* unknown */
+       if (PySequence_Check(v) &&
+           v->ob_type->tp_as_sequence->sq_length) {
+               n = PySequence_Size(v);
+               if (n < 0)
+                       PyErr_Clear();
+       }
+       if (n < 0)
+               n = 8;  /* arbitrary */
+       NRESIZE(result->ob_item, PyObject*, n);
+       if (result->ob_item == NULL)
+               goto error;
+       for (i = 0; i < n; i++)
+               result->ob_item[i] = NULL;
+       result->ob_size = n;
+
+       /* Run iterator to exhaustion. */
+       for (i = 0; ; i++) {
+               PyObject *item = PyIter_Next(it);
+               if (item == NULL) {
+                       if (PyErr_Occurred())
+                               goto error;
+                       break;
+               }
+               if (i < n)
+                       PyList_SET_ITEM(result, i, item); /* steals ref */
+               else {
+                       int status = ins1(result, result->ob_size, item);
+                       Py_DECREF(item);  /* append creates a new ref */
+                       if (status < 0)
+                               goto error;
+               }
+       }
+
+       /* Cut back result list if initial guess was too large. */
+       if (i < n && result != NULL) {
+               if (list_ass_slice(result, i, n, (PyObject *)NULL) != 0)
+                       goto error;
+       }
+       Py_DECREF(it);
+       return 0;
+
+  error:
+       Py_DECREF(it);
+       return -1;
+}
+
+static int
+list_init(PyListObject *self, PyObject *args, PyObject *kw)
+{
+       PyObject *arg = NULL;
+       static char *kwlist[] = {"sequence", 0};
+
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
+               return -1;
+       if (arg != NULL)
+               return list_fill(self, arg);
+       if (self->ob_size > 0)
+               return list_ass_slice(self, 0, self->ob_size, (PyObject*)NULL);
+       return 0;
+}
+
 static char append_doc[] =
 "L.append(object) -- append object to end";
 static char extend_doc[] =
@@ -1573,12 +1673,6 @@ static PyMethodDef list_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
-static PyObject *
-list_getattr(PyListObject *f, char *name)
-{
-       return Py_FindMethod(list_methods, (PyObject *)f, name);
-}
-
 static PySequenceMethods list_as_sequence = {
        (inquiry)list_length,                   /* sq_length */
        (binaryfunc)list_concat,                /* sq_concat */
@@ -1592,6 +1686,10 @@ static PySequenceMethods list_as_sequence = {
        (intargfunc)list_inplace_repeat,        /* sq_inplace_repeat */
 };
 
+static char list_doc[] =
+"list() -> new list\n"
+"list(sequence) -> new list initialized from sequence's items";
+
 PyTypeObject PyList_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
@@ -1600,7 +1698,7 @@ PyTypeObject PyList_Type = {
        0,
        (destructor)list_dealloc,               /* tp_dealloc */
        (printfunc)list_print,                  /* tp_print */
-       (getattrfunc)list_getattr,              /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        (reprfunc)list_repr,                    /* tp_repr */
@@ -1610,14 +1708,29 @@ PyTypeObject PyList_Type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
-       0,                                      /* tp_doc */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+       list_doc,                               /* tp_doc */
        (traverseproc)list_traverse,            /* tp_traverse */
        (inquiry)list_clear,                    /* tp_clear */
        list_richcompare,                       /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       list_methods,                           /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       (initproc)list_init,                    /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       PyType_GenericNew,                      /* tp_new */
 };
 
 
@@ -1646,12 +1759,6 @@ static PyMethodDef immutable_list_methods[] = {
        {NULL,          NULL}           /* sentinel */
 };
 
-static PyObject *
-immutable_list_getattr(PyListObject *f, char *name)
-{
-       return Py_FindMethod(immutable_list_methods, (PyObject *)f, name);
-}
-
 static int
 immutable_list_ass(void)
 {
@@ -1678,7 +1785,7 @@ static PyTypeObject immutable_list_type = {
        0,
        0, /* Cannot happen */                  /* tp_dealloc */
        (printfunc)list_print,                  /* tp_print */
-       (getattrfunc)immutable_list_getattr,    /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0, /* Won't be called */                /* tp_compare */
        (reprfunc)list_repr,                    /* tp_repr */
@@ -1688,13 +1795,24 @@ static PyTypeObject immutable_list_type = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
-       0,                                      /* tp_doc */
+       list_doc,                               /* tp_doc */
        (traverseproc)list_traverse,            /* tp_traverse */
        0,                                      /* tp_clear */
        list_richcompare,                       /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       immutable_list_methods,                 /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_init */
        /* NOTE: This is *not* the standard list_type struct! */
 };
index 71bd1ce2e4c788ef79e46fcc8eb5ba0168f5fca3..28c3e5779387dc0391cdf1d1521b7eaa603c2767 100644 (file)
@@ -2031,6 +2031,43 @@ long_hex(PyObject *v)
        return long_format(v, 16, 1);
 }
 
+static PyObject *
+long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *x = NULL;
+       int base = -909;                     /* unlikely! */
+       static char *kwlist[] = {"x", "base", 0};
+
+       assert(type == &PyLong_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist,
+                                        &x, &base))
+               return NULL;
+       if (x == NULL)
+               return PyLong_FromLong(0L);
+       if (base == -909)
+               return PyNumber_Long(x);
+       else if (PyString_Check(x))
+               return PyLong_FromString(PyString_AS_STRING(x), NULL, base);
+       else if (PyUnicode_Check(x))
+               return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x),
+                                         PyUnicode_GET_SIZE(x),
+                                         base);
+       else {
+               PyErr_SetString(PyExc_TypeError,
+                       "long() can't convert non-string with explicit base");
+               return NULL;
+       }
+}
+
+static char long_doc[] =
+"long(x[, base]) -> integer\n\
+\n\
+Convert a string or number to a long integer, if possible.  A floating\n\
+point argument will be truncated towards zero (this does not include a\n\
+string representation of a floating point number!)  When converting a\n\
+string, use the optional base.  It is an error to supply a base when\n\
+converting a non-string.";
+
 static PyNumberMethods long_as_number = {
        (binaryfunc)    long_add,       /*nb_add*/
        (binaryfunc)    long_sub,       /*nb_subtract*/
@@ -2070,24 +2107,42 @@ static PyNumberMethods long_as_number = {
 
 PyTypeObject PyLong_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
-       0,
-       "long int",
-       sizeof(PyLongObject) - sizeof(digit),
-       sizeof(digit),
-       (destructor)long_dealloc,       /*tp_dealloc*/
-       0,                              /*tp_print*/
-       0,                              /*tp_getattr*/
-       0,                              /*tp_setattr*/
-       (cmpfunc)long_compare,          /*tp_compare*/
-       (reprfunc)long_repr,            /*tp_repr*/
-       &long_as_number,                /*tp_as_number*/
-       0,                              /*tp_as_sequence*/
-       0,                              /*tp_as_mapping*/
-       (hashfunc)long_hash,            /*tp_hash*/
-        0,                             /*tp_call*/
-        (reprfunc)long_str,            /*tp_str*/
-       0,                              /*tp_getattro*/
-       0,                              /*tp_setattro*/
-       0,                              /*tp_as_buffer*/
-       Py_TPFLAGS_CHECKTYPES           /*tp_flags*/
+       0,                                      /* ob_size */
+       "long",                                 /* tp_name */
+       sizeof(PyLongObject) - sizeof(digit),   /* tp_basicsize */
+       sizeof(digit),                          /* tp_itemsize */
+       (destructor)long_dealloc,               /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       (cmpfunc)long_compare,                  /* tp_compare */
+       (reprfunc)long_repr,                    /* tp_repr */
+       &long_as_number,                        /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)long_hash,                    /* tp_hash */
+        0,                                     /* tp_call */
+        (reprfunc)long_str,                    /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       long_doc,                               /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       long_new,                               /* tp_new */
 };
index bff79ed042df4076b90eac10855039f4b19ad005..56fbcc22fd9a05b6046effc5caa10c14cd54e905 100644 (file)
@@ -3,8 +3,6 @@
 
 #include "Python.h"
 
-#include "token.h"
-
 static PyCFunctionObject *free_list = NULL;
 
 PyObject *
@@ -69,6 +67,23 @@ meth_dealloc(PyCFunctionObject *m)
        free_list = m;
 }
 
+static PyObject *
+meth_get__doc__(PyCFunctionObject *m, void *closure)
+{
+       char *doc = m->m_ml->ml_doc;
+
+       if (doc != NULL)
+               return PyString_FromString(doc);
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+meth_get__name__(PyCFunctionObject *m, void *closure)
+{
+       return PyString_FromString(m->m_ml->ml_name);
+}
+
 static int
 meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
 {
@@ -79,39 +94,28 @@ meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
 }
 
 static PyObject *
-meth_getattr(PyCFunctionObject *m, char *name)
+meth_get__self__(PyCFunctionObject *m, void *closure)
 {
-       if (strcmp(name, "__name__") == 0) {
-               return PyString_FromString(m->m_ml->ml_name);
-       }
-       if (strcmp(name, "__doc__") == 0) {
-               char *doc = m->m_ml->ml_doc;
-               if (doc != NULL)
-                       return PyString_FromString(doc);
-               Py_INCREF(Py_None);
-               return Py_None;
-       }
-       if (strcmp(name, "__self__") == 0) {
-               PyObject *self;
-               if (PyEval_GetRestricted()) {
-                       PyErr_SetString(PyExc_RuntimeError,
-                        "method.__self__ not accessible in restricted mode");
-                       return NULL;
-               }
-               self = m->m_self;
-               if (self == NULL)
-                       self = Py_None;
-               Py_INCREF(self);
-               return self;
-       }
-       if (strcmp(name, "__members__") == 0) {
-               return Py_BuildValue("[sss]",
-                                    "__doc__", "__name__", "__self__");
+       PyObject *self;
+       if (PyEval_GetRestricted()) {
+               PyErr_SetString(PyExc_RuntimeError,
+                       "method.__self__ not accessible in restricted mode");
+               return NULL;
        }
-       PyErr_SetString(PyExc_AttributeError, name);
-       return NULL;
+       self = m->m_self;
+       if (self == NULL)
+               self = Py_None;
+       Py_INCREF(self);
+       return self;
 }
 
+static struct getsetlist meth_getsets [] = {
+       {"__doc__",  (getter)meth_get__doc__,  NULL, NULL},
+       {"__name__", (getter)meth_get__name__, NULL, NULL},
+       {"__self__", (getter)meth_get__self__, NULL, NULL},
+       {0}
+};
+
 static PyObject *
 meth_repr(PyCFunctionObject *m)
 {
@@ -159,6 +163,41 @@ meth_hash(PyCFunctionObject *a)
        return x;
 }
 
+static PyObject *
+meth_call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+       PyCFunctionObject* f = (PyCFunctionObject*)func;
+       PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+       PyObject *self = PyCFunction_GET_SELF(func);
+       int flags = PyCFunction_GET_FLAGS(func);
+
+       if (flags & METH_KEYWORDS) {
+               return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
+       }
+       if (kw != NULL && PyDict_Size(kw) != 0) {
+               PyErr_Format(PyExc_TypeError,
+                            "%.200s() takes no keyword arguments",
+                            f->m_ml->ml_name);
+               return NULL;
+       }
+       if (flags & METH_VARARGS) {
+               return (*meth)(self, arg);
+       }
+       if (!(flags & METH_VARARGS)) {
+               /* the really old style */
+               int size = PyTuple_GET_SIZE(arg);
+               if (size == 1)
+                       arg = PyTuple_GET_ITEM(arg, 0);
+               else if (size == 0)
+                       arg = NULL;
+               return (*meth)(self, arg);
+       }
+       /* should never get here ??? */
+       PyErr_BadInternalCall();
+       return NULL;
+}
+
+
 PyTypeObject PyCFunction_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
@@ -167,7 +206,7 @@ PyTypeObject PyCFunction_Type = {
        0,
        (destructor)meth_dealloc,               /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)meth_getattr,              /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        (cmpfunc)meth_compare,                  /* tp_compare */
        (reprfunc)meth_repr,                    /* tp_repr */
@@ -175,14 +214,24 @@ PyTypeObject PyCFunction_Type = {
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        (hashfunc)meth_hash,                    /* tp_hash */
-       0,                                      /* tp_call */
+       meth_call,                              /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
        0,                                      /* tp_doc */
        (traverseproc)meth_traverse,            /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       meth_getsets,                           /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
 
 /* List all methods in a chain -- helper for findmethodinchain */
index 7df5ce0b1ba5e940b97868f6be7109e9d0af416b..7faa3bbfd3e656a2de36bd95729f02ae884f0919 100644 (file)
@@ -2,12 +2,18 @@
 /* Module object implementation */
 
 #include "Python.h"
+#include "structmember.h"
 
 typedef struct {
        PyObject_HEAD
        PyObject *md_dict;
 } PyModuleObject;
 
+struct memberlist module_members[] = {
+       {"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
+       {0}
+};
+
 PyObject *
 PyModule_New(char *name)
 {
@@ -128,6 +134,15 @@ _PyModule_Clear(PyObject *m)
 
 /* Methods */
 
+static int
+module_init(PyModuleObject *m, PyObject *args, PyObject *kw)
+{
+       m->md_dict = PyDict_New();
+       if (m->md_dict == NULL)
+               return -1;
+       return 0;
+}
+
 static void
 module_dealloc(PyModuleObject *m)
 {
@@ -161,59 +176,6 @@ module_repr(PyModuleObject *m)
        return PyString_FromString(buf);
 }
 
-static PyObject *
-module_getattro(PyModuleObject *m, PyObject *name)
-{
-       PyObject *res;
-       char *sname = PyString_AsString(name);
-
-       if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
-               Py_INCREF(m->md_dict);
-               return m->md_dict;
-       }
-       res = PyDict_GetItem(m->md_dict, name);
-       if (res == NULL) {
-               char *modname = PyModule_GetName((PyObject *)m);
-               if (modname == NULL) {
-                       PyErr_Clear();
-                       modname = "?";
-               }
-               PyErr_Format(PyExc_AttributeError,
-                            "'%.50s' module has no attribute '%.400s'",
-                            modname, sname);
-       }
-       else
-               Py_INCREF(res);
-       return res;
-}
-
-static int
-module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
-{
-       char *sname = PyString_AsString(name);
-       if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
-               PyErr_SetString(PyExc_TypeError,
-                               "read-only special attribute");
-               return -1;
-       }
-       if (v == NULL) {
-               int rv = PyDict_DelItem(m->md_dict, name);
-               if (rv < 0) {
-                       char *modname = PyModule_GetName((PyObject *)m);
-                       if (modname == NULL) {
-                               PyErr_Clear();
-                               modname = "?";
-                       }
-                       PyErr_Format(PyExc_AttributeError,
-                                    "'%.50s' module has no attribute '%.400s'",
-                                    modname, sname);
-               }
-               return rv;
-       }
-       else
-               return PyDict_SetItem(m->md_dict, name, v);
-}
-
 /* We only need a traverse function, no clear function: If the module
    is in a cycle, md_dict will be cleared as well, which will break
    the cycle. */
@@ -229,24 +191,41 @@ PyTypeObject PyModule_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                                      /* ob_size */
        "module",                               /* tp_name */
-       sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
+       sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /* tp_size */
        0,                                      /* tp_itemsize */
-       (destructor)module_dealloc,             /* tp_dealloc */
+       (destructor)module_dealloc,             /* tp_dealloc */
        0,                                      /* tp_print */
-       0,                                      /* tp_getattr */
-       0,                                      /* tp_setattr */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
-       (reprfunc)module_repr,                  /* tp_repr */
+       (reprfunc)module_repr,                  /* tp_repr */
        0,                                      /* tp_as_number */
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       (getattrofunc)module_getattro,          /* tp_getattro */
-       (setattrofunc)module_setattro,          /* tp_setattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       PyObject_GenericSetAttr,                /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
        0,                                      /* tp_doc */
        (traverseproc)module_traverse,          /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       module_members,                         /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       offsetof(PyModuleObject, md_dict),      /* tp_dictoffset */
+       (initproc)module_init,                  /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       PyType_GenericNew,                      /* tp_new */
 };
index 87c8e1a801dc64bca7d1bf0cecf94b19d07d3c57..137752d841d087e14af637c771e849e779b1ce37 100644 (file)
@@ -32,7 +32,7 @@ dump_counts(void)
 
        for (tp = type_list; tp; tp = tp->tp_next)
                fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n",
-                       tp->tp_name, tp->tp_alloc, tp->tp_free,
+                       tp->tp_name, tp->tp_allocs, tp->tp_frees,
                        tp->tp_maxalloc);
        fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
                fast_tuple_allocs, tuple_zero_allocs);
@@ -53,8 +53,8 @@ get_counts(void)
        if (result == NULL)
                return NULL;
        for (tp = type_list; tp; tp = tp->tp_next) {
-               v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_alloc,
-                                 tp->tp_free, tp->tp_maxalloc);
+               v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_allocs,
+                                 tp->tp_frees, tp->tp_maxalloc);
                if (v == NULL) {
                        Py_DECREF(result);
                        return NULL;
@@ -72,16 +72,16 @@ get_counts(void)
 void
 inc_count(PyTypeObject *tp)
 {
-       if (tp->tp_alloc == 0) {
+       if (tp->tp_allocs == 0) {
                /* first time; insert in linked list */
                if (tp->tp_next != NULL) /* sanity check */
                        Py_FatalError("XXX inc_count sanity check");
                tp->tp_next = type_list;
                type_list = tp;
        }
-       tp->tp_alloc++;
-       if (tp->tp_alloc - tp->tp_free > tp->tp_maxalloc)
-               tp->tp_maxalloc = tp->tp_alloc - tp->tp_free;
+       tp->tp_allocs++;
+       if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc)
+               tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees;
 }
 #endif
 
@@ -93,10 +93,8 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
                                "NULL object passed to PyObject_Init");
                return op;
        }
-#ifdef WITH_CYCLE_GC
        if (PyType_IS_GC(tp))
                op = (PyObject *) PyObject_FROM_GC(op);
-#endif
        /* Any changes should be reflected in PyObject_INIT (objimpl.h) */
        op->ob_type = tp;
        _Py_NewReference(op);
@@ -111,10 +109,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, int size)
                                "NULL object passed to PyObject_InitVar");
                return op;
        }
-#ifdef WITH_CYCLE_GC
        if (PyType_IS_GC(tp))
                op = (PyVarObject *) PyObject_FROM_GC(op);
-#endif
        /* Any changes should be reflected in PyObject_INIT_VAR */
        op->ob_size = size;
        op->ob_type = tp;
@@ -129,10 +125,8 @@ _PyObject_New(PyTypeObject *tp)
        op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
        if (op == NULL)
                return PyErr_NoMemory();
-#ifdef WITH_CYCLE_GC
        if (PyType_IS_GC(tp))
                op = (PyObject *) PyObject_FROM_GC(op);
-#endif
        return PyObject_INIT(op, tp);
 }
 
@@ -143,21 +137,17 @@ _PyObject_NewVar(PyTypeObject *tp, int size)
        op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
        if (op == NULL)
                return (PyVarObject *)PyErr_NoMemory();
-#ifdef WITH_CYCLE_GC
        if (PyType_IS_GC(tp))
                op = (PyVarObject *) PyObject_FROM_GC(op);
-#endif
        return PyObject_INIT_VAR(op, tp, size);
 }
 
 void
 _PyObject_Del(PyObject *op)
 {
-#ifdef WITH_CYCLE_GC
        if (op && PyType_IS_GC(op->ob_type)) {
                op = (PyObject *) PyObject_AS_GC(op);
        }
-#endif
        PyObject_FREE(op);
 }
 
@@ -994,26 +984,16 @@ PyObject_Hash(PyObject *v)
 PyObject *
 PyObject_GetAttrString(PyObject *v, char *name)
 {
-       if (v->ob_type->tp_getattro != NULL) {
-               PyObject *w, *res;
-               w = PyString_InternFromString(name);
-               if (w == NULL)
-                       return NULL;
-               res = (*v->ob_type->tp_getattro)(v, w);
-               Py_XDECREF(w);
-               return res;
-       }
+       PyObject *w, *res;
 
-       if (v->ob_type->tp_getattr == NULL) {
-               PyErr_Format(PyExc_AttributeError,
-                            "'%.50s' object has no attribute '%.400s'",
-                            v->ob_type->tp_name,
-                            name);
-               return NULL;
-       }
-       else {
+       if (v->ob_type->tp_getattr != NULL)
                return (*v->ob_type->tp_getattr)(v, name);
-       }
+       w = PyString_InternFromString(name);
+       if (w == NULL)
+               return NULL;
+       res = PyObject_GetAttr(v, w);
+       Py_XDECREF(w);
+       return res;
 }
 
 int
@@ -1031,34 +1011,24 @@ PyObject_HasAttrString(PyObject *v, char *name)
 int
 PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
 {
-       if (v->ob_type->tp_setattro != NULL) {
-               PyObject *s;
-               int res;
-               s = PyString_InternFromString(name);
-               if (s == NULL)
-                       return -1;
-               res = (*v->ob_type->tp_setattro)(v, s, w);
-               Py_XDECREF(s);
-               return res;
-       }
+       PyObject *s;
+       int res;
 
-       if (v->ob_type->tp_setattr == NULL) {
-               if (v->ob_type->tp_getattr == NULL)
-                       PyErr_SetString(PyExc_TypeError,
-                                  "attribute-less object (assign or del)");
-               else
-                       PyErr_SetString(PyExc_TypeError,
-                                  "object has read-only attributes");
-               return -1;
-       }
-       else {
+       if (v->ob_type->tp_setattr != NULL)
                return (*v->ob_type->tp_setattr)(v, name, w);
-       }
+       s = PyString_InternFromString(name);
+       if (s == NULL)
+               return -1;
+       res = PyObject_SetAttr(v, s, w);
+       Py_XDECREF(s);
+       return res;
 }
 
 PyObject *
 PyObject_GetAttr(PyObject *v, PyObject *name)
 {
+       PyTypeObject *tp = v->ob_type;
+
        /* The Unicode to string conversion is done here because the
           existing tp_getattro slots expect a string object as name
           and we wouldn't want to break those. */
@@ -1067,16 +1037,19 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
                if (name == NULL)
                        return NULL;
        }
-
        if (!PyString_Check(name)) {
                PyErr_SetString(PyExc_TypeError,
                                "attribute name must be string");
                return NULL;
        }
-       if (v->ob_type->tp_getattro != NULL)
-               return (*v->ob_type->tp_getattro)(v, name);
-       else
-               return PyObject_GetAttrString(v, PyString_AS_STRING(name));
+       if (tp->tp_getattro != NULL)
+               return (*tp->tp_getattro)(v, name);
+       if (tp->tp_getattr != NULL)
+               return (*tp->tp_getattr)(v, PyString_AS_STRING(name));
+       PyErr_Format(PyExc_AttributeError,
+                    "'%.50s' object has no attribute '%.400s'",
+                    tp->tp_name, PyString_AS_STRING(name));
+       return NULL;
 }
 
 int
@@ -1094,6 +1067,7 @@ PyObject_HasAttr(PyObject *v, PyObject *name)
 int
 PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
 {
+       PyTypeObject *tp = v->ob_type;
        int err;
 
        /* The Unicode to string conversion is done here because the
@@ -1104,25 +1078,182 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
                if (name == NULL)
                        return -1;
        }
-       else
-               Py_INCREF(name);
-       
-       if (!PyString_Check(name)){
+       else if (!PyString_Check(name)){
                PyErr_SetString(PyExc_TypeError,
                                "attribute name must be string");
-               err = -1;
+               return -1;
        }
-       else {
-               PyString_InternInPlace(&name);
-               if (v->ob_type->tp_setattro != NULL)
-                       err = (*v->ob_type->tp_setattro)(v, name, value);
-               else
-                       err = PyObject_SetAttrString(v, 
-                                       PyString_AS_STRING(name), value);
+       else
+               Py_INCREF(name);
+
+       PyString_InternInPlace(&name);
+       if (tp->tp_setattro != NULL) {
+               err = (*tp->tp_setattro)(v, name, value);
+               Py_DECREF(name);
+               return err;
+       }
+       if (tp->tp_setattr != NULL) {
+               err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value);
+               Py_DECREF(name);
+               return err;
        }
-       
        Py_DECREF(name);
-       return err;
+       if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
+               PyErr_Format(PyExc_TypeError,
+                            "'%.100s' object has no attributes "
+                            "(%s .%.100s)",
+                            tp->tp_name,
+                            value==NULL ? "del" : "assign to",
+                            PyString_AS_STRING(name));
+       else
+               PyErr_Format(PyExc_TypeError,
+                            "'%.100s' object has only read-only attributes "
+                            "(%s .%.100s)",
+                            tp->tp_name,
+                            value==NULL ? "del" : "assign to",
+                            PyString_AS_STRING(name));
+       return -1;
+}
+
+/* Helper to get a pointer to an object's __dict__ slot, if any */
+
+PyObject **
+_PyObject_GetDictPtr(PyObject *obj)
+{
+#define PTRSIZE (sizeof(PyObject *))
+
+       long dictoffset;
+       PyTypeObject *tp = obj->ob_type;
+
+       if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS))
+               return NULL;
+       dictoffset = tp->tp_dictoffset;
+       if (dictoffset == 0)
+               return NULL;
+       if (dictoffset < 0) {
+               dictoffset += PyType_BASICSIZE(tp);
+               assert(dictoffset > 0); /* Sanity check */
+               if (tp->tp_itemsize > 0) {
+                       int n = ((PyVarObject *)obj)->ob_size;
+                       if (n > 0) {
+                               dictoffset += tp->tp_itemsize * n;
+                               /* Round up, if necessary */
+                               if (tp->tp_itemsize % PTRSIZE != 0) {
+                                       dictoffset += PTRSIZE - 1;
+                                       dictoffset /= PTRSIZE;
+                                       dictoffset *= PTRSIZE;
+                               }
+                       }
+               }
+       }
+       return (PyObject **) ((char *)obj + dictoffset);
+}
+
+/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
+
+PyObject *
+PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
+{
+       PyTypeObject *tp = obj->ob_type;
+       PyObject *descr;
+       descrgetfunc f;
+       PyObject **dictptr;
+
+       if (tp->tp_dict == NULL) {
+               if (PyType_InitDict(tp) < 0)
+                       return NULL;
+       }
+
+       descr = _PyType_Lookup(tp, name);
+       f = NULL;
+       if (descr != NULL) {
+               f = descr->ob_type->tp_descr_get;
+               if (f != NULL && PyDescr_IsData(descr))
+                       return f(descr, obj, (PyObject *)obj->ob_type);
+       }
+
+       dictptr = _PyObject_GetDictPtr(obj);
+       if (dictptr != NULL) {
+               PyObject *dict = *dictptr;
+               if (dict != NULL) {
+                       PyObject *res = PyDict_GetItem(dict, name);
+                       if (res != NULL) {
+                               Py_INCREF(res);
+                               return res;
+                       }
+               }
+       }
+
+       if (f != NULL)
+               return f(descr, obj, (PyObject *)obj->ob_type);
+
+       if (descr != NULL) {
+               Py_INCREF(descr);
+               return descr;
+       }
+
+       PyErr_Format(PyExc_AttributeError,
+                    "'%.50s' object has no attribute '%.400s'",
+                    tp->tp_name, PyString_AS_STRING(name));
+       return NULL;
+}
+
+int
+PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
+{
+       PyTypeObject *tp = obj->ob_type;
+       PyObject *descr;
+       descrsetfunc f;
+       PyObject **dictptr;
+
+       if (tp->tp_dict == NULL) {
+               if (PyType_InitDict(tp) < 0)
+                       return -1;
+       }
+
+       descr = _PyType_Lookup(tp, name);
+       f = NULL;
+       if (descr != NULL) {
+               f = descr->ob_type->tp_descr_set;
+               if (f != NULL && PyDescr_IsData(descr))
+                       return f(descr, obj, value);
+       }
+
+       dictptr = _PyObject_GetDictPtr(obj);
+       if (dictptr != NULL) {
+               PyObject *dict = *dictptr;
+               if (dict == NULL && value != NULL) {
+                       dict = PyDict_New();
+                       if (dict == NULL)
+                               return -1;
+                       *dictptr = dict;
+               }
+               if (dict != NULL) {
+                       int res;
+                       if (value == NULL)
+                               res = PyDict_DelItem(dict, name);
+                       else
+                               res = PyDict_SetItem(dict, name, value);
+                       if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
+                               PyErr_SetObject(PyExc_AttributeError, name);
+                       return res;
+               }
+       }
+
+       if (f != NULL)
+               return f(descr, obj, value);
+
+       if (descr == NULL) {
+               PyErr_Format(PyExc_AttributeError,
+                            "'%.50s' object has no attribute '%.400s'",
+                            tp->tp_name, PyString_AS_STRING(name));
+               return -1;
+       }
+
+       PyErr_Format(PyExc_AttributeError,
+                    "'%.50s' object attribute '%.400s' is read-only",
+                    tp->tp_name, PyString_AS_STRING(name));
+       return -1;
 }
 
 /* Test a value used as condition, e.g., in a for or if statement.
@@ -1218,12 +1349,6 @@ PyCallable_Check(PyObject *x)
 {
        if (x == NULL)
                return 0;
-       if (x->ob_type->tp_call != NULL ||
-           PyFunction_Check(x) ||
-           PyMethod_Check(x) ||
-           PyCFunction_Check(x) ||
-           PyClass_Check(x))
-               return 1;
        if (PyInstance_Check(x)) {
                PyObject *call = PyObject_GetAttrString(x, "__call__");
                if (call == NULL) {
@@ -1235,7 +1360,9 @@ PyCallable_Check(PyObject *x)
                Py_DECREF(call);
                return 1;
        }
-       return 0;
+       else {
+               return x->ob_type->tp_call != NULL;
+       }
 }
 
 
@@ -1365,7 +1492,7 @@ _Py_ForgetReference(register PyObject *op)
        op->_ob_prev->_ob_next = op->_ob_next;
        op->_ob_next = op->_ob_prev = NULL;
 #ifdef COUNT_ALLOCS
-       op->ob_type->tp_free++;
+       op->ob_type->tp_frees++;
 #endif
 }
 
index 1f446df2dd4c82cfcb0ff7160a240ec62896210c..9f155cf5998c9d892607a182cf69faaddcb0433b 100644 (file)
@@ -310,22 +310,34 @@ PyTypeObject PyRange_Type = {
        "xrange",               /* Name of this type */
        sizeof(rangeobject),    /* Basic object size */
        0,                      /* Item size for varobject */
-       (destructor)range_dealloc, /*tp_dealloc*/
-       0,                      /*tp_print*/
-       (getattrfunc)range_getattr, /*tp_getattr*/
-       0,                      /*tp_setattr*/
-       (cmpfunc)range_compare, /*tp_compare*/
-       (reprfunc)range_repr,   /*tp_repr*/
-       0,                      /*tp_as_number*/
-       &range_as_sequence,     /*tp_as_sequence*/
-       0,                      /*tp_as_mapping*/
-       0,                      /*tp_hash*/
-       0,                      /*tp_call*/
-       0,                      /*tp_str*/
-       0,                      /*tp_getattro*/
-       0,                      /*tp_setattro*/
-       0,                      /*tp_as_buffer*/
-       Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+       (destructor)range_dealloc,              /*tp_dealloc*/
+       0,                                      /*tp_print*/
+       (getattrfunc)range_getattr,             /*tp_getattr*/
+       0,                                      /*tp_setattr*/
+       (cmpfunc)range_compare,                 /*tp_compare*/
+       (reprfunc)range_repr,                   /*tp_repr*/
+       0,                                      /*tp_as_number*/
+       &range_as_sequence,                     /*tp_as_sequence*/
+       0,                                      /*tp_as_mapping*/
+       0,                                      /*tp_hash*/
+       0,                                      /*tp_call*/
+       0,                                      /*tp_str*/
+       PyObject_GenericGetAttr,                /*tp_getattro*/
+       0,                                      /*tp_setattro*/
+       0,                                      /*tp_as_buffer*/
+       Py_TPFLAGS_DEFAULT,                     /*tp_flags*/
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
 
 #undef WARN
index 6f7a6d818ba8c79712fd280a2ab2f35970538fad..8f52f9ec1722157a5d286a5ecd80814ec123f50e 100644 (file)
@@ -14,6 +14,7 @@ this type and there is exactly one in existence.
 */
 
 #include "Python.h"
+#include "structmember.h"
 
 static PyObject *
 ellipsis_repr(PyObject *op)
@@ -128,32 +129,12 @@ slice_repr(PySliceObject *r)
        return s;
 }
 
-
-static PyObject *slice_getattr(PySliceObject *self, char *name)
-{
-       PyObject *ret;
-  
-       ret = NULL;
-       if (strcmp(name, "start") == 0) {
-               ret = self->start;
-       }
-       else if (strcmp(name, "stop") == 0) {
-               ret = self->stop;
-       }
-       else if (strcmp(name, "step") == 0) {
-               ret = self->step;
-       }
-       else if (strcmp(name, "__members__") == 0) {
-               return Py_BuildValue("[sss]",
-                                    "start", "stop", "step");
-       }
-       else {
-               PyErr_SetString(PyExc_AttributeError, name);
-               return NULL;
-       }
-       Py_INCREF(ret);
-       return ret;
-}
+static struct memberlist slice_members[] = {
+       {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
+       {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
+       {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
+       {0}
+};
 
 static int
 slice_compare(PySliceObject *v, PySliceObject *w)
@@ -182,13 +163,32 @@ PyTypeObject PySlice_Type = {
        "slice",                /* Name of this type */
        sizeof(PySliceObject),  /* Basic object size */
        0,                      /* Item size for varobject */
-       (destructor)slice_dealloc, /*tp_dealloc*/
-       0,                      /*tp_print*/
-       (getattrfunc)slice_getattr, /*tp_getattr*/
-       0,                      /*tp_setattr*/
-       (cmpfunc)slice_compare, /*tp_compare*/
-       (reprfunc)slice_repr,   /*tp_repr*/
-       0,                      /*tp_as_number*/
-       0,                      /*tp_as_sequence*/
-       0,                      /*tp_as_mapping*/
+       (destructor)slice_dealloc,              /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       (cmpfunc)slice_compare,                 /* tp_compare */
+       (reprfunc)slice_repr,                   /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       slice_members,                          /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
index c7f5062a0fb1d191524cbf2838cdc4a35003f101..3d12588d2c6de2cde40b18f30979e0b450137225 100644 (file)
@@ -2522,41 +2522,65 @@ string_methods[] = {
 };
 
 static PyObject *
-string_getattr(PyStringObject *s, char *name)
+string_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-       return Py_FindMethod(string_methods, (PyObject*)s, name);
+       PyObject *x = NULL;
+       static char *kwlist[] = {"object", 0};
+
+       assert(type == &PyString_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str", kwlist, &x))
+               return NULL;
+       if (x == NULL)
+               return PyString_FromString("");
+       return PyObject_Str(x);
 }
 
+static char string_doc[] =
+"str(object) -> string\n\
+\n\
+Return a nice string representation of the object.\n\
+If the argument is a string, the return value is the same object.";
 
 PyTypeObject PyString_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
-       "string",
+       "str",
        sizeof(PyStringObject),
        sizeof(char),
-       (destructor)string_dealloc, /*tp_dealloc*/
-       (printfunc)string_print, /*tp_print*/
-       (getattrfunc)string_getattr,            /*tp_getattr*/
-       0,              /*tp_setattr*/
-       0,              /*tp_compare*/
-       (reprfunc)string_repr, /*tp_repr*/
-       0,              /*tp_as_number*/
-       &string_as_sequence,    /*tp_as_sequence*/
-       0,              /*tp_as_mapping*/
-       (hashfunc)string_hash, /*tp_hash*/
-       0,              /*tp_call*/
-       (reprfunc)string_str,   /*tp_str*/
-       0,              /*tp_getattro*/
-       0,              /*tp_setattro*/
-       &string_as_buffer,      /*tp_as_buffer*/
-       Py_TPFLAGS_DEFAULT,     /*tp_flags*/
-       0,              /*tp_doc*/
-       0,              /*tp_traverse*/
-       0,              /*tp_clear*/
-       (richcmpfunc)string_richcompare,        /*tp_richcompare*/
-       0,              /*tp_weaklistoffset*/
-       0,              /*tp_iter*/
-       0,              /*tp_iternext*/
+       (destructor)string_dealloc,             /* tp_dealloc */
+       (printfunc)string_print,                /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)string_repr,                  /* tp_repr */
+       0,                                      /* tp_as_number */
+       &string_as_sequence,                    /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)string_hash,                  /* tp_hash */
+       0,                                      /* tp_call */
+       (reprfunc)string_str,                   /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       &string_as_buffer,                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       string_doc,                             /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       (richcmpfunc)string_richcompare,        /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       string_methods,                         /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       string_new,                             /* tp_new */
 };
 
 void
index 538cc704d2098784ea4b476d63241c95935a0176..46f5714364b8b7b7dcb4d150b162373886830d01 100644 (file)
@@ -480,6 +480,28 @@ tuplerichcompare(PyObject *v, PyObject *w, int op)
        return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op);
 }
 
+static PyObject *
+tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *arg = NULL;
+       static char *kwlist[] = {"sequence", 0};
+
+       assert(type == &PyTuple_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
+               return NULL;
+
+       if (arg == NULL)
+               return PyTuple_New(0);
+       else
+               return PySequence_Tuple(arg);
+}
+
+static char tuple_doc[] =
+"tuple(sequence) -> list\n\
+\n\
+Return a tuple whose items are the same as those of the argument sequence.\n\
+If the argument is a tuple, the return value is the same object.";
+
 static PySequenceMethods tuple_as_sequence = {
        (inquiry)tuplelength,                   /* sq_length */
        (binaryfunc)tupleconcat,                /* sq_concat */
@@ -509,14 +531,28 @@ PyTypeObject PyTuple_Type = {
        (hashfunc)tuplehash,                    /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
-       0,                                      /* tp_doc */
+       tuple_doc,                              /* tp_doc */
        (traverseproc)tupletraverse,            /* tp_traverse */
        0,                                      /* tp_clear */
        tuplerichcompare,                       /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       0,                                      /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       tuple_new,                              /* tp_new */
 };
 
 /* The following function breaks the notion that tuples are immutable:
index ea3494eed2c9d3303a590e97d4942cc59191e14a..429680d148e212ea4490a01d43581371c3e51e4b 100644 (file)
@@ -2,27 +2,78 @@
 /* Type object implementation */
 
 #include "Python.h"
+#include "structmember.h"
 
-/* Type object implementation */
+staticforward int add_members(PyTypeObject *, struct memberlist *);
+
+static struct memberlist type_members[] = {
+       {"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
+       {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
+       {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
+       {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
+       {"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY},
+       {"__weaklistoffset__", T_LONG,
+        offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
+       {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
+       {"__dictoffset__", T_LONG,
+        offsetof(PyTypeObject, tp_dictoffset), READONLY},
+       {"__bases__", T_OBJECT, offsetof(PyTypeObject, tp_bases), READONLY},
+       {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
+       {0}
+};
+
+static PyObject *
+type_module(PyTypeObject *type, void *context)
+{
+       return PyString_FromString("__builtin__");
+}
 
 static PyObject *
-type_getattr(PyTypeObject *t, char *name)
+type_dict(PyTypeObject *type, void *context)
 {
-       if (strcmp(name, "__name__") == 0)
-               return PyString_FromString(t->tp_name);
-       if (strcmp(name, "__doc__") == 0) {
-               char *doc = t->tp_doc;
-               if (doc != NULL)
-                       return PyString_FromString(doc);
+       if (type->tp_dict == NULL) {
                Py_INCREF(Py_None);
                return Py_None;
        }
-       if (strcmp(name, "__members__") == 0)
-               return Py_BuildValue("[ss]", "__doc__", "__name__");
-       PyErr_SetString(PyExc_AttributeError, name);
-       return NULL;
+       if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+               Py_INCREF(type->tp_dict);
+               return type->tp_dict;
+       }
+       return PyDictProxy_New(type->tp_dict);
+}
+
+static PyObject *
+type_defined(PyTypeObject *type, void *context)
+{
+       if (type->tp_defined == NULL) {
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+               Py_INCREF(type->tp_defined);
+               return type->tp_defined;
+       }
+       return PyDictProxy_New(type->tp_defined);
+}
+
+static PyObject *
+type_dynamic(PyTypeObject *type, void *context)
+{
+       PyObject *res;
+
+       res = (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ? Py_True : Py_False;
+       Py_INCREF(res);
+       return res;
 }
 
+struct getsetlist type_getsets[] = {
+       {"__module__", (getter)type_module, NULL, NULL},
+       {"__dict__",  (getter)type_dict,  NULL, NULL},
+       {"__defined__",  (getter)type_defined,  NULL, NULL},
+       {"__dynamic__", (getter)type_dynamic, NULL, NULL},
+       {0}
+};
+
 static int
 type_compare(PyObject *v, PyObject *w)
 {
@@ -34,34 +85,2271 @@ type_compare(PyObject *v, PyObject *w)
 }
 
 static PyObject *
-type_repr(PyTypeObject *v)
+type_repr(PyTypeObject *type)
 {
        char buf[100];
-       sprintf(buf, "<type '%.80s'>", v->tp_name);
+       sprintf(buf, "<type '%.80s'>", type->tp_name);
        return PyString_FromString(buf);
 }
 
+static PyObject *
+type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *obj;
+
+       if (type->tp_new == NULL) {
+               PyErr_Format(PyExc_TypeError,
+                            "cannot create '%.100s' instances",
+                            type->tp_name);
+               return NULL;
+       }
+
+       obj = type->tp_new(type, args, NULL);
+       if (obj != NULL) {
+               type = obj->ob_type;
+               if (type->tp_init != NULL &&
+                   type->tp_init(obj, args, kwds) < 0) {
+                       Py_DECREF(obj);
+                       obj = NULL;
+               }
+       }
+       return obj;
+}
+
+PyObject *
+PyType_GenericAlloc(PyTypeObject *type, int nitems)
+{
+       int size;
+       void *mem;
+       PyObject *obj;
+
+       /* Inline PyObject_New() so we can zero the memory */
+       size = _PyObject_VAR_SIZE(type, nitems);
+       mem = PyObject_MALLOC(size);
+       if (mem == NULL)
+               return PyErr_NoMemory();
+       memset(mem, '\0', size);
+       if (PyType_IS_GC(type))
+               obj = PyObject_FROM_GC(mem);
+       else
+               obj = (PyObject *)mem;
+       if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+               Py_INCREF(type);
+       if (type->tp_itemsize == 0)
+               PyObject_INIT(obj, type);
+       else
+               (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
+       if (PyType_IS_GC(type))
+               PyObject_GC_Init(obj);
+       return obj;
+}
+
+PyObject *
+PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       return type->tp_alloc(type, 0);
+}
+
+/* Helper for subtyping */
+
+static void
+subtype_dealloc(PyObject *self)
+{
+       int dictoffset = self->ob_type->tp_dictoffset;
+       PyTypeObject *type, *base;
+       destructor f;
+
+       /* This exists so we can DECREF self->ob_type */
+
+       /* Find the nearest base with a different tp_dealloc */
+       type = self->ob_type;
+       base = type->tp_base;
+       while ((f = base->tp_dealloc) == subtype_dealloc) {
+               base = base->tp_base;
+               assert(base);
+       }
+
+       /* If we added a dict, DECREF it */
+       if (dictoffset && !base->tp_dictoffset) {
+               PyObject **dictptr = (PyObject **) ((char *)self + dictoffset);
+               PyObject *dict = *dictptr;
+               if (dict != NULL) {
+                       Py_DECREF(dict);
+                       *dictptr = NULL;
+               }
+       }
+
+       /* Finalize GC if the base doesn't do GC and we do */
+       if (PyType_IS_GC(type) && !PyType_IS_GC(base))
+               PyObject_GC_Fini(self);
+
+       /* Call the base tp_dealloc() */
+       assert(f);
+       f(self);
+
+       /* Can't reference self beyond this point */
+       if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+               Py_DECREF(type);
+       }
+}
+
+staticforward void override_slots(PyTypeObject *type, PyObject *dict);
+staticforward PyTypeObject *solid_base(PyTypeObject *type);
+
+typedef struct {
+       PyTypeObject type;
+       PyNumberMethods as_number;
+       PySequenceMethods as_sequence;
+       PyMappingMethods as_mapping;
+       PyBufferProcs as_buffer;
+       PyObject *name, *slots;
+       struct memberlist members[1];
+} etype;
+
+/* type test with subclassing support */
+
+int
+PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
+{
+       PyObject *mro;
+
+       mro = a->tp_mro;
+       if (mro != NULL) {
+               /* Deal with multiple inheritance without recursion
+                  by walking the MRO tuple */
+               int i, n;
+               assert(PyTuple_Check(mro));
+               n = PyTuple_GET_SIZE(mro);
+               for (i = 0; i < n; i++) {
+                       if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
+                               return 1;
+               }
+               return 0;
+       }
+       else {
+               /* a is not completely initilized yet; follow tp_base */
+               do {
+                       if (a == b)
+                               return 1;
+                       a = a->tp_base;
+               } while (a != NULL);
+               return b == &PyBaseObject_Type;
+       }
+}
+
+/* Method resolution order algorithm from "Putting Metaclasses to Work"
+   by Forman and Danforth (Addison-Wesley 1999). */
+
+static int
+conservative_merge(PyObject *left, PyObject *right)
+{
+       int left_size;
+       int right_size;
+       int i, j, r, ok;
+       PyObject *temp, *rr;
+
+       assert(PyList_Check(left));
+       assert(PyList_Check(right));
+
+  again:
+       left_size = PyList_GET_SIZE(left);
+       right_size = PyList_GET_SIZE(right);
+       for (i = 0; i < left_size; i++) {
+               for (j = 0; j < right_size; j++) {
+                       if (PyList_GET_ITEM(left, i) ==
+                           PyList_GET_ITEM(right, j)) {
+                               /* found a merge point */
+                               temp = PyList_New(0);
+                               if (temp == NULL)
+                                       return -1;
+                               for (r = 0; r < j; r++) {
+                                       rr = PyList_GET_ITEM(right, r);
+                                       ok = PySequence_Contains(left, rr);
+                                       if (ok < 0) {
+                                               Py_DECREF(temp);
+                                               return -1;
+                                       }
+                                       if (!ok) {
+                                               ok = PyList_Append(temp, rr);
+                                               if (ok < 0) {
+                                                       Py_DECREF(temp);
+                                                       return -1;
+                                               }
+                                       }
+                               }
+                               ok = PyList_SetSlice(left, i, i, temp);
+                               Py_DECREF(temp);
+                               if (ok < 0)
+                                       return -1;
+                               ok = PyList_SetSlice(right, 0, j+1, NULL);
+                               if (ok < 0)
+                                       return -1;
+                               goto again;
+                       }
+               }
+       }
+       return PyList_SetSlice(left, left_size, left_size, right);
+}
+
+static int
+serious_order_disagreements(PyObject *left, PyObject *right)
+{
+       return 0; /* XXX later -- for now, we cheat: "don't do that" */
+}
+
+static PyObject *
+mro_implementation(PyTypeObject *type)
+{
+       int i, n, ok;
+       PyObject *bases, *result;
+
+       bases = type->tp_bases;
+       n = PyTuple_GET_SIZE(bases);
+       result = Py_BuildValue("[O]", (PyObject *)type);
+       if (result == NULL)
+               return NULL;
+       for (i = 0; i < n; i++) {
+               PyTypeObject *base =
+                       (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
+               PyObject *parentMRO = PySequence_List(base->tp_mro);
+               if (parentMRO == NULL) {
+                       Py_DECREF(result);
+                       return NULL;
+               }
+               if (serious_order_disagreements(result, parentMRO)) {
+                       Py_DECREF(result);
+                       return NULL;
+               }
+               ok = conservative_merge(result, parentMRO);
+               Py_DECREF(parentMRO);
+               if (ok < 0) {
+                       Py_DECREF(result);
+                       return NULL;
+               }
+       }
+       return result;
+}
+
+static PyObject *
+mro_external(PyObject *self, PyObject *args)
+{
+       PyTypeObject *type = (PyTypeObject *)self;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+       return mro_implementation(type);
+}
+
+static int
+mro_internal(PyTypeObject *type)
+{
+       PyObject *mro, *result, *tuple;
+
+       if (type->ob_type == &PyType_Type) {
+               result = mro_implementation(type);
+       }
+       else {
+               mro = PyObject_GetAttrString((PyObject *)type, "mro");
+               if (mro == NULL)
+                       return -1;
+               result = PyObject_CallObject(mro, NULL);
+               Py_DECREF(mro);
+       }
+       if (result == NULL)
+               return -1;
+       tuple = PySequence_Tuple(result);
+       Py_DECREF(result);
+       type->tp_mro = tuple;
+       return 0;
+}
+
+
+/* Calculate the best base amongst multiple base classes.
+   This is the first one that's on the path to the "solid base". */
+
+static PyTypeObject *
+best_base(PyObject *bases)
+{
+       int i, n;
+       PyTypeObject *base, *winner, *candidate, *base_i;
+
+       assert(PyTuple_Check(bases));
+       n = PyTuple_GET_SIZE(bases);
+       assert(n > 0);
+       base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
+       winner = &PyBaseObject_Type;
+       for (i = 0; i < n; i++) {
+               base_i = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+               if (!PyType_Check((PyObject *)base_i)) {
+                       PyErr_SetString(
+                               PyExc_TypeError,
+                               "bases must be types");
+                       return NULL;
+               }
+               if (base_i->tp_dict == NULL) {
+                       if (PyType_InitDict(base_i) < 0)
+                               return NULL;
+               }
+               candidate = solid_base(base_i);
+               if (PyType_IsSubtype(winner, candidate))
+                       ;
+               else if (PyType_IsSubtype(candidate, winner)) {
+                       winner = candidate;
+                       base = base_i;
+               }
+               else {
+                       PyErr_SetString(
+                               PyExc_TypeError,
+                               "multiple bases have "
+                               "instance lay-out conflict");
+                       return NULL;
+               }
+       }
+       assert(base != NULL);
+       return base;
+}
+
+static int
+extra_ivars(PyTypeObject *type, PyTypeObject *base)
+{
+       int t_size = PyType_BASICSIZE(type);
+       int b_size = PyType_BASICSIZE(base);
+
+       assert(t_size >= b_size); /* type smaller than base! */
+       if (type->tp_itemsize || base->tp_itemsize) {
+               /* If itemsize is involved, stricter rules */
+               return t_size != b_size ||
+                       type->tp_itemsize != base->tp_itemsize;
+       }
+       if (t_size == b_size)
+               return 0;
+       if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 &&
+           type->tp_dictoffset == b_size &&
+           (size_t)t_size == b_size + sizeof(PyObject *))
+               return 0; /* "Forgive" adding a __dict__ only */
+       return 1;
+}
+
+static PyTypeObject *
+solid_base(PyTypeObject *type)
+{
+       PyTypeObject *base;
+
+       if (type->tp_base)
+               base = solid_base(type->tp_base);
+       else
+               base = &PyBaseObject_Type;
+       if (extra_ivars(type, base))
+               return type;
+       else
+               return base;
+}
+
+staticforward void object_dealloc(PyObject *);
+staticforward int object_init(PyObject *, PyObject *, PyObject *);
+
+static PyObject *
+type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+       PyObject *name, *bases, *dict;
+       static char *kwlist[] = {"name", "bases", "dict", 0};
+       PyObject *slots, *tmp;
+       PyTypeObject *type, *base, *tmptype;
+       etype *et;
+       struct memberlist *mp;
+       int i, nbases, nslots, slotoffset, dynamic;
+
+       if (metatype == &PyType_Type &&
+           PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
+           (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) {
+               /* type(x) -> x.__class__ */
+               PyObject *x = PyTuple_GET_ITEM(args, 0);
+               Py_INCREF(x->ob_type);
+               return (PyObject *) x->ob_type;
+       }
+
+       /* Check arguments */
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist,
+                                        &name,
+                                        &PyTuple_Type, &bases,
+                                        &PyDict_Type, &dict))
+               return NULL;
+
+       /* Determine the proper metatype to deal with this,
+          and check for metatype conflicts while we're at it.
+          Note that if some other metatype wins to contract,
+          it's possible that its instances are not types. */
+       nbases = PyTuple_GET_SIZE(bases);
+       for (i = 0; i < nbases; i++) {
+               tmp = PyTuple_GET_ITEM(bases, i);
+               tmptype = tmp->ob_type;
+               if (PyType_IsSubtype(metatype, tmptype))
+                       continue;
+               if (PyType_IsSubtype(tmptype, metatype)) {
+                       metatype = tmptype;
+                       continue;
+               }
+               PyErr_SetString(PyExc_TypeError,
+                               "metatype conflict among bases");
+               return NULL;
+       }
+       if (metatype->tp_new != type_new) /* Pass it to the winner */
+               return metatype->tp_new(metatype, args, kwds);
+
+       /* Adjust for empty tuple bases */
+       if (nbases == 0) {
+               bases = Py_BuildValue("(O)", &PyBaseObject_Type);
+               if (bases == NULL)
+                       return NULL;
+               nbases = 1;
+       }
+       else
+               Py_INCREF(bases);
+
+       /* XXX From here until type is allocated, "return NULL" leaks bases! */
+
+       /* Calculate best base, and check that all bases are type objects */
+       base = best_base(bases);
+       if (base == NULL)
+               return NULL;
+       if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
+               PyErr_Format(PyExc_TypeError,
+                            "type '%.100s' is not an acceptable base type",
+                            base->tp_name);
+               return NULL;
+       }
+
+       /* Should this be a dynamic class (i.e. modifiable __dict__)? */
+       tmp = PyDict_GetItemString(dict, "__dynamic__");
+       if (tmp != NULL) {
+               /* The class author has a preference */
+               dynamic = PyObject_IsTrue(tmp);
+               Py_DECREF(tmp);
+               if (dynamic < 0)
+                       return NULL;
+       }
+       else {
+               /* Make a new class dynamic if any of its bases is dynamic.
+                  This is not always the same as inheriting the __dynamic__
+                  class attribute! */
+               dynamic = 0;
+               for (i = 0; i < nbases; i++) {
+                       tmptype = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+                       if (tmptype->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+                               dynamic = 1;
+                               break;
+                       }
+               }
+       }
+
+       /* Check for a __slots__ sequence variable in dict, and count it */
+       slots = PyDict_GetItemString(dict, "__slots__");
+       nslots = 0;
+       if (slots != NULL) {
+               /* Make it into a tuple */
+               if (PyString_Check(slots))
+                       slots = Py_BuildValue("(O)", slots);
+               else
+                       slots = PySequence_Tuple(slots);
+               if (slots == NULL)
+                       return NULL;
+               nslots = PyTuple_GET_SIZE(slots);
+               for (i = 0; i < nslots; i++) {
+                       if (!PyString_Check(PyTuple_GET_ITEM(slots, i))) {
+                               PyErr_SetString(PyExc_TypeError,
+                               "__slots__ must be a sequence of strings");
+                               Py_DECREF(slots);
+                               return NULL;
+                       }
+               }
+       }
+       if (slots == NULL && base->tp_dictoffset == 0 &&
+           (base->tp_setattro == PyObject_GenericSetAttr ||
+            base->tp_setattro == NULL))
+               nslots = 1;
+
+       /* XXX From here until type is safely allocated,
+          "return NULL" may leak slots! */
+
+       /* Allocate the type object */
+       type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots);
+       if (type == NULL)
+               return NULL;
+
+       /* Keep name and slots alive in the extended type object */
+       et = (etype *)type;
+       Py_INCREF(name);
+       et->name = name;
+       et->slots = slots;
+
+       /* Initialize essential fields */
+       type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
+               Py_TPFLAGS_BASETYPE;
+       if (dynamic)
+               type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
+       type->tp_as_number = &et->as_number;
+       type->tp_as_sequence = &et->as_sequence;
+       type->tp_as_mapping = &et->as_mapping;
+       type->tp_as_buffer = &et->as_buffer;
+       type->tp_name = PyString_AS_STRING(name);
+
+       /* Set tp_base and tp_bases */
+       type->tp_bases = bases;
+       Py_INCREF(base);
+       type->tp_base = base;
+
+       /* Initialize tp_defined from passed-in dict */
+       type->tp_defined = dict = PyDict_Copy(dict);
+       if (dict == NULL) {
+               Py_DECREF(type);
+               return NULL;
+       }
+
+       /* Special-case __new__: if it's a plain function,
+          make it a static function */
+       tmp = PyDict_GetItemString(dict, "__new__");
+       if (tmp != NULL && PyFunction_Check(tmp)) {
+               tmp = PyStaticMethod_New(tmp);
+               if (tmp == NULL) {
+                       Py_DECREF(type);
+                       return NULL;
+               }
+               PyDict_SetItemString(dict, "__new__", tmp);
+               Py_DECREF(tmp);
+       }
+
+       /* Add descriptors for custom slots from __slots__, or for __dict__ */
+       mp = et->members;
+       slotoffset = PyType_BASICSIZE(base);
+       if (slots != NULL) {
+               for (i = 0; i < nslots; i++, mp++) {
+                       mp->name = PyString_AS_STRING(
+                               PyTuple_GET_ITEM(slots, i));
+                       mp->type = T_OBJECT;
+                       mp->offset = slotoffset;
+                       slotoffset += sizeof(PyObject *);
+               }
+       }
+       else if (nslots) {
+               type->tp_dictoffset = slotoffset;
+               mp->name = "__dict__";
+               mp->type = T_OBJECT;
+               mp->offset = slotoffset;
+               mp->readonly = 1;
+               slotoffset += sizeof(PyObject *);
+       }
+       type->tp_basicsize = slotoffset;
+       add_members(type, et->members);
+
+       /* Special case some slots */
+       if (type->tp_dictoffset != 0 || nslots > 0) {
+               if (base->tp_getattr == NULL && base->tp_getattro == NULL)
+                       type->tp_getattro = PyObject_GenericGetAttr;
+               if (base->tp_setattr == NULL && base->tp_setattro == NULL)
+                       type->tp_setattro = PyObject_GenericSetAttr;
+       }
+       type->tp_dealloc = subtype_dealloc;
+
+       /* Always override allocation strategy to use regular heap */
+       type->tp_alloc = PyType_GenericAlloc;
+       type->tp_free = _PyObject_Del;
+
+       /* Initialize the rest */
+       if (PyType_InitDict(type) < 0) {
+               Py_DECREF(type);
+               return NULL;
+       }
+
+       /* Override slots that deserve it */
+       override_slots(type, type->tp_defined);
+       return (PyObject *)type;
+}
+
+/* Internal API to look for a name through the MRO.
+   This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PyType_Lookup(PyTypeObject *type, PyObject *name)
+{
+       int i, n;
+       PyObject *mro, *res, *dict;
+
+       /* For static types, look in tp_dict */
+       if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)) {
+               dict = type->tp_dict;
+               assert(dict && PyDict_Check(dict));
+               return PyDict_GetItem(dict, name);
+       }
+
+       /* For dynamic types, look in tp_defined of types in MRO */
+       mro = type->tp_mro;
+       assert(PyTuple_Check(mro));
+       n = PyTuple_GET_SIZE(mro);
+       for (i = 0; i < n; i++) {
+               type = (PyTypeObject *) PyTuple_GET_ITEM(mro, i);
+               assert(PyType_Check(type));
+               dict = type->tp_defined;
+               assert(dict && PyDict_Check(dict));
+               res = PyDict_GetItem(dict, name);
+               if (res != NULL)
+                       return res;
+       }
+       return NULL;
+}
+
+/* This is similar to PyObject_GenericGetAttr(),
+   but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
+static PyObject *
+type_getattro(PyTypeObject *type, PyObject *name)
+{
+       PyTypeObject *metatype = type->ob_type;
+       PyObject *descr, *res;
+       descrgetfunc f;
+
+       /* Initialize this type (we'll assume the metatype is initialized) */
+       if (type->tp_dict == NULL) {
+               if (PyType_InitDict(type) < 0)
+                       return NULL;
+       }
+
+       /* Get a descriptor from the metatype */
+       descr = _PyType_Lookup(metatype, name);
+       f = NULL;
+       if (descr != NULL) {
+               f = descr->ob_type->tp_descr_get;
+               if (f != NULL && PyDescr_IsData(descr))
+                       return f(descr,
+                                (PyObject *)type, (PyObject *)metatype);
+       }
+
+       /* Look in tp_defined of this type and its bases */
+       res = _PyType_Lookup(type, name);
+       if (res != NULL) {
+               f = res->ob_type->tp_descr_get;
+               if (f != NULL)
+                       return f(res, (PyObject *)NULL, (PyObject *)type);
+               Py_INCREF(res);
+               return res;
+       }
+
+       /* Use the descriptor from the metatype */
+       if (f != NULL) {
+               res = f(descr, (PyObject *)type, (PyObject *)metatype);
+               return res;
+       }
+       if (descr != NULL) {
+               Py_INCREF(descr);
+               return descr;
+       }
+
+       /* Give up */
+       PyErr_Format(PyExc_AttributeError,
+                    "type object '%.50s' has no attribute '%.400s'",
+                    type->tp_name, PyString_AS_STRING(name));
+       return NULL;
+}
+
+static int
+type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
+{
+       if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)
+               return PyObject_GenericSetAttr((PyObject *)type, name, value);
+       PyErr_SetString(PyExc_TypeError, "can't set type attributes");
+       return -1;
+}
+
+static void
+type_dealloc(PyTypeObject *type)
+{
+       etype *et;
+
+       /* Assert this is a heap-allocated type object */
+       assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+       et = (etype *)type;
+       Py_XDECREF(type->tp_base);
+       Py_XDECREF(type->tp_dict);
+       Py_XDECREF(type->tp_bases);
+       Py_XDECREF(type->tp_mro);
+       Py_XDECREF(type->tp_defined);
+       /* XXX more? */
+       Py_XDECREF(et->name);
+       Py_XDECREF(et->slots);
+       type->ob_type->tp_free((PyObject *)type);
+}
+
+static PyMethodDef type_methods[] = {
+       {"mro", mro_external, METH_VARARGS,
+        "mro() -> list\nreturn a type's method resolution order"},
+       {0}
+};
+
+static char type_doc[] =
+"type(object) -> the object's type\n"
+"type(name, bases, dict) -> a new type";
+
 PyTypeObject PyType_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
-       0,                      /* Number of items for varobject */
-       "type",                 /* Name of this type */
-       sizeof(PyTypeObject),   /* Basic object size */
-       0,                      /* Item size for varobject */
-       0,                      /*tp_dealloc*/
-       0,                      /*tp_print*/
-       (getattrfunc)type_getattr, /*tp_getattr*/
-       0,                      /*tp_setattr*/
-       type_compare,           /*tp_compare*/
-       (reprfunc)type_repr,    /*tp_repr*/
-       0,                      /*tp_as_number*/
-       0,                      /*tp_as_sequence*/
-       0,                      /*tp_as_mapping*/
-       (hashfunc)_Py_HashPointer,      /*tp_hash*/
-       0,                      /*tp_call*/
-       0,                      /*tp_str*/
-       0,                      /*tp_xxx1*/
-       0,                      /*tp_xxx2*/
-       0,                      /*tp_xxx3*/
-       0,                      /*tp_xxx4*/
-       "Define the behavior of a particular type of object.",
+       0,                                      /* ob_size */
+       "type",                                 /* tp_name */
+       sizeof(etype),                          /* tp_basicsize */
+       sizeof(struct memberlist),              /* tp_itemsize */
+       (destructor)type_dealloc,               /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       type_compare,                           /* tp_compare */
+       (reprfunc)type_repr,                    /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       (hashfunc)_Py_HashPointer,              /* tp_hash */
+       (ternaryfunc)type_call,                 /* tp_call */
+       0,                                      /* tp_str */
+       (getattrofunc)type_getattro,            /* tp_getattro */
+       (setattrofunc)type_setattro,            /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       type_doc,                               /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       type_methods,                           /* tp_methods */
+       type_members,                           /* tp_members */
+       type_getsets,                           /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       offsetof(PyTypeObject, tp_dict),        /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       type_new,                               /* tp_new */
+};
+
+
+/* The base type of all types (eventually)... except itself. */
+
+static int
+object_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+       return 0;
+}
+
+static void
+object_dealloc(PyObject *self)
+{
+       self->ob_type->tp_free(self);
+}
+
+static void
+object_free(PyObject *self)
+{
+       PyObject_Del(self);
+}
+
+static struct memberlist object_members[] = {
+       {"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
+       {0}
+};
+
+PyTypeObject PyBaseObject_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                                      /* ob_size */
+       "object",                               /* tp_name */
+       sizeof(PyObject),                       /* tp_basicsize */
+       0,                                      /* tp_itemsize */
+       (destructor)object_dealloc,             /* tp_dealloc */
+       0,                                      /* tp_print */
+       0,                                      /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       0,                                      /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       PyObject_GenericGetAttr,                /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       "The most base type",                   /* tp_doc */
+       0,                                      /* tp_traverse */
+       0,                                      /* tp_clear */
+       0,                                      /* tp_richcompare */
+       0,                                      /* tp_weaklistoffset */
+       0,                                      /* tp_iter */
+       0,                                      /* tp_iternext */
+       0,                                      /* tp_methods */
+       object_members,                         /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       object_init,                            /* tp_init */
+       PyType_GenericAlloc,                    /* tp_alloc */
+       PyType_GenericNew,                      /* tp_new */
+       object_free,                            /* tp_free */
 };
+
+
+/* Initialize the __dict__ in a type object */
+
+static int
+add_methods(PyTypeObject *type, PyMethodDef *meth)
+{
+       PyObject *dict = type->tp_defined;
+
+       for (; meth->ml_name != NULL; meth++) {
+               PyObject *descr;
+               if (PyDict_GetItemString(dict, meth->ml_name))
+                       continue;
+               descr = PyDescr_NewMethod(type, meth);
+               if (descr == NULL)
+                       return -1;
+               if (PyDict_SetItemString(dict,meth->ml_name,descr) < 0)
+                       return -1;
+               Py_DECREF(descr);
+       }
+       return 0;
+}
+
+static int
+add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
+{
+       PyObject *dict = type->tp_defined;
+
+       for (; base->name != NULL; base++) {
+               PyObject *descr;
+               if (PyDict_GetItemString(dict, base->name))
+                       continue;
+               descr = PyDescr_NewWrapper(type, base, wrapped);
+               if (descr == NULL)
+                       return -1;
+               if (PyDict_SetItemString(dict, base->name, descr) < 0)
+                       return -1;
+               Py_DECREF(descr);
+       }
+       return 0;
+}
+
+static int
+add_staticmethodwrappers(PyTypeObject *type, struct wrapperbase *base,
+                       void *wrapped)
+{
+       PyObject *dict = type->tp_defined;
+       PyObject *sm;
+
+       for (; base->name != NULL; base++) {
+               PyObject *descr;
+               if (PyDict_GetItemString(dict, base->name))
+                       continue;
+               descr = PyDescr_NewWrapper(type->ob_type, base, wrapped);
+               if (descr == NULL)
+                       return -1;
+               sm = PyStaticMethod_New(descr);
+               Py_DECREF(descr);
+               if (sm == NULL)
+                       return -1;
+               if (PyDict_SetItemString(dict, base->name, sm) < 0)
+                       return -1;
+               Py_DECREF(sm);
+       }
+       return 0;
+}
+
+static int
+add_members(PyTypeObject *type, struct memberlist *memb)
+{
+       PyObject *dict = type->tp_defined;
+
+       for (; memb->name != NULL; memb++) {
+               PyObject *descr;
+               if (PyDict_GetItemString(dict, memb->name))
+                       continue;
+               descr = PyDescr_NewMember(type, memb);
+               if (descr == NULL)
+                       return -1;
+               if (PyDict_SetItemString(dict, memb->name, descr) < 0)
+                       return -1;
+               Py_DECREF(descr);
+       }
+       return 0;
+}
+
+static int
+add_getset(PyTypeObject *type, struct getsetlist *gsp)
+{
+       PyObject *dict = type->tp_defined;
+
+       for (; gsp->name != NULL; gsp++) {
+               PyObject *descr;
+               if (PyDict_GetItemString(dict, gsp->name))
+                       continue;
+               descr = PyDescr_NewGetSet(type, gsp);
+
+               if (descr == NULL)
+                       return -1;
+               if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+                       return -1;
+               Py_DECREF(descr);
+       }
+       return 0;
+}
+
+staticforward int add_operators(PyTypeObject *);
+
+static int
+inherit_slots(PyTypeObject *type, PyTypeObject *base)
+{
+       int oldsize, newsize;
+
+#undef COPYSLOT
+#undef COPYNUM
+#undef COPYSEQ
+#undef COPYMAP
+#define COPYSLOT(SLOT) \
+       if (!type->SLOT) type->SLOT = base->SLOT
+
+#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
+#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
+#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
+
+       if (type->tp_as_number == NULL)
+               type->tp_as_number = base->tp_as_number;
+       else if (base->tp_as_number) {
+               COPYNUM(nb_add);
+               COPYNUM(nb_subtract);
+               COPYNUM(nb_multiply);
+               COPYNUM(nb_divide);
+               COPYNUM(nb_remainder);
+               COPYNUM(nb_divmod);
+               COPYNUM(nb_power);
+               COPYNUM(nb_negative);
+               COPYNUM(nb_positive);
+               COPYNUM(nb_absolute);
+               COPYNUM(nb_nonzero);
+               COPYNUM(nb_invert);
+               COPYNUM(nb_lshift);
+               COPYNUM(nb_rshift);
+               COPYNUM(nb_and);
+               COPYNUM(nb_xor);
+               COPYNUM(nb_or);
+               COPYNUM(nb_coerce);
+               COPYNUM(nb_int);
+               COPYNUM(nb_long);
+               COPYNUM(nb_float);
+               COPYNUM(nb_oct);
+               COPYNUM(nb_hex);
+               COPYNUM(nb_inplace_add);
+               COPYNUM(nb_inplace_subtract);
+               COPYNUM(nb_inplace_multiply);
+               COPYNUM(nb_inplace_divide);
+               COPYNUM(nb_inplace_remainder);
+               COPYNUM(nb_inplace_power);
+               COPYNUM(nb_inplace_lshift);
+               COPYNUM(nb_inplace_rshift);
+               COPYNUM(nb_inplace_and);
+               COPYNUM(nb_inplace_xor);
+               COPYNUM(nb_inplace_or);
+       }
+
+       if (type->tp_as_sequence == NULL)
+               type->tp_as_sequence = base->tp_as_sequence;
+       else if (base->tp_as_sequence) {
+               COPYSEQ(sq_length);
+               COPYSEQ(sq_concat);
+               COPYSEQ(sq_repeat);
+               COPYSEQ(sq_item);
+               COPYSEQ(sq_slice);
+               COPYSEQ(sq_ass_item);
+               COPYSEQ(sq_ass_slice);
+               COPYSEQ(sq_contains);
+               COPYSEQ(sq_inplace_concat);
+               COPYSEQ(sq_inplace_repeat);
+       }
+
+       if (type->tp_as_mapping == NULL)
+               type->tp_as_mapping = base->tp_as_mapping;
+       else if (base->tp_as_mapping) {
+               COPYMAP(mp_length);
+               COPYMAP(mp_subscript);
+               COPYMAP(mp_ass_subscript);
+       }
+
+       /* Special flag magic */
+       if (!type->tp_as_buffer && base->tp_as_buffer) {
+               type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
+               type->tp_flags |=
+                       base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
+       }
+       if (!type->tp_as_sequence && base->tp_as_sequence) {
+               type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
+               type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
+       }
+       if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
+           (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
+               if ((!type->tp_as_number && base->tp_as_number) ||
+                   (!type->tp_as_sequence && base->tp_as_sequence)) {
+                       type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
+                       if (!type->tp_as_number && !type->tp_as_sequence) {
+                               type->tp_flags |= base->tp_flags &
+                                       Py_TPFLAGS_HAVE_INPLACEOPS;
+                       }
+               }
+               /* Wow */
+       }
+       if (!type->tp_as_number && base->tp_as_number) {
+               type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
+               type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
+       }
+
+       /* Copying basicsize is connected to the GC flags */
+       oldsize = PyType_BASICSIZE(base);
+       newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
+       if (!(type->tp_flags & Py_TPFLAGS_GC) &&
+           (base->tp_flags & Py_TPFLAGS_GC) &&
+           (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
+           (!type->tp_traverse && !type->tp_clear)) {
+               type->tp_flags |= Py_TPFLAGS_GC;
+               COPYSLOT(tp_traverse);
+               COPYSLOT(tp_clear);
+       }
+       PyType_SET_BASICSIZE(type, newsize);
+
+       COPYSLOT(tp_itemsize);
+       COPYSLOT(tp_dealloc);
+       COPYSLOT(tp_print);
+       if (type->tp_getattr == NULL && type->tp_getattro == NULL) {
+               type->tp_getattr = base->tp_getattr;
+               type->tp_getattro = base->tp_getattro;
+       }
+       if (type->tp_setattr == NULL && type->tp_setattro == NULL) {
+               type->tp_setattr = base->tp_setattr;
+               type->tp_setattro = base->tp_setattro;
+       }
+       /* tp_compare see tp_richcompare */
+       COPYSLOT(tp_repr);
+       COPYSLOT(tp_hash);
+       COPYSLOT(tp_call);
+       COPYSLOT(tp_str);
+       COPYSLOT(tp_as_buffer);
+       COPYSLOT(tp_flags);
+       if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
+               if (type->tp_compare == NULL && type->tp_richcompare == NULL) {
+                       type->tp_compare = base->tp_compare;
+                       type->tp_richcompare = base->tp_richcompare;
+               }
+       }
+       else {
+               COPYSLOT(tp_compare);
+       }
+       if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) {
+               COPYSLOT(tp_weaklistoffset);
+       }
+       if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) {
+               COPYSLOT(tp_iter);
+               COPYSLOT(tp_iternext);
+       }
+       if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+               COPYSLOT(tp_descr_get);
+               COPYSLOT(tp_descr_set);
+               COPYSLOT(tp_dictoffset);
+               COPYSLOT(tp_init);
+               COPYSLOT(tp_alloc);
+               COPYSLOT(tp_new);
+               COPYSLOT(tp_free);
+       }
+
+       return 0;
+}
+
+int
+PyType_InitDict(PyTypeObject *type)
+{
+       PyObject *dict, *bases, *x;
+       PyTypeObject *base;
+       int i, n;
+
+       if (type->tp_dict != NULL)
+               return 0; /* Already initialized */
+
+       /* Initialize tp_base (defaults to BaseObject unless that's us) */
+       base = type->tp_base;
+       if (base == NULL && type != &PyBaseObject_Type)
+               base = type->tp_base = &PyBaseObject_Type;
+
+       /* Initialize tp_bases */
+       bases = type->tp_bases;
+       if (bases == NULL) {
+               if (base == NULL)
+                       bases = PyTuple_New(0);
+               else
+                       bases = Py_BuildValue("(O)", base);
+               if (bases == NULL)
+                       return -1;
+               type->tp_bases = bases;
+       }
+
+       /* Initialize the base class */
+       if (base) {
+               if (PyType_InitDict(base) < 0)
+                       return -1;
+       }
+
+       /* Initialize tp_defined */
+       dict = type->tp_defined;
+       if (dict == NULL) {
+               dict = PyDict_New();
+               if (dict == NULL)
+                       return -1;
+               type->tp_defined = dict;
+       }
+
+       /* Add type-specific descriptors to tp_defined */
+       if (add_operators(type) < 0)
+               return -1;
+       if (type->tp_methods != NULL) {
+               if (add_methods(type, type->tp_methods) < 0)
+                       return -1;
+       }
+       if (type->tp_members != NULL) {
+               if (add_members(type, type->tp_members) < 0)
+                       return -1;
+       }
+       if (type->tp_getset != NULL) {
+               if (add_getset(type, type->tp_getset) < 0)
+                       return -1;
+       }
+
+       /* Temporarily make tp_dict the same object as tp_defined.
+          (This is needed to call mro(), and can stay this way for
+          dynamic types). */
+       Py_INCREF(type->tp_defined);
+       type->tp_dict = type->tp_defined;
+
+       /* Calculate method resolution order */
+       if (mro_internal(type) < 0) {
+               return -1;
+       }
+
+       /* Initialize tp_dict properly */
+       if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
+               /* For a static type, tp_dict is the consolidation
+                  of the tp_defined of its bases in MRO.  Earlier
+                  bases override later bases; since d.update() works
+                  the other way, we walk the MRO sequence backwards. */
+               Py_DECREF(type->tp_dict);
+               type->tp_dict = PyDict_New();
+               if (type->tp_dict == NULL)
+                       return -1;
+               bases = type->tp_mro;
+               assert(bases != NULL);
+               assert(PyTuple_Check(bases));
+               n = PyTuple_GET_SIZE(bases);
+               for (i = n; --i >= 0; ) {
+                       base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+                       assert(PyType_Check(base));
+                       x = base->tp_defined;
+                       if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
+                               return -1;
+               }
+       }
+
+       /* Inherit slots from direct base */
+       if (type->tp_base != NULL)
+               if (inherit_slots(type, type->tp_base) < 0)
+                       return -1;
+
+       return 0;
+}
+
+
+/* Generic wrappers for overloadable 'operators' such as __getitem__ */
+
+/* There's a wrapper *function* for each distinct function typedef used
+   for type object slots (e.g. binaryfunc, ternaryfunc, etc.).  There's a
+   wrapper *table* for each distinct operation (e.g. __len__, __add__).
+   Most tables have only one entry; the tables for binary operators have two
+   entries, one regular and one with reversed arguments. */
+
+static PyObject *
+wrap_inquiry(PyObject *self, PyObject *args, void *wrapped)
+{
+       inquiry func = (inquiry)wrapped;
+       int res;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+       res = (*func)(self);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_len[] = {
+       {"__len__", (wrapperfunc)wrap_inquiry, "x.__len__() <==> len(x)"},
+       {0}
+};
+
+static PyObject *
+wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       binaryfunc func = (binaryfunc)wrapped;
+       PyObject *other;
+
+       if (!PyArg_ParseTuple(args, "O", &other))
+               return NULL;
+       return (*func)(self, other);
+}
+
+static PyObject *
+wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
+{
+       binaryfunc func = (binaryfunc)wrapped;
+       PyObject *other;
+
+       if (!PyArg_ParseTuple(args, "O", &other))
+               return NULL;
+       return (*func)(other, self);
+}
+
+#undef BINARY
+#define BINARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+       {"__" #NAME "__", \
+        (wrapperfunc)wrap_binaryfunc, \
+        "x.__" #NAME "__(y) <==> " #OP}, \
+       {"__r" #NAME "__", \
+        (wrapperfunc)wrap_binaryfunc_r, \
+        "y.__r" #NAME "__(x) <==> " #OP}, \
+       {0} \
+}
+
+BINARY(add, "x+y");
+BINARY(sub, "x-y");
+BINARY(mul, "x*y");
+BINARY(div, "x/y");
+BINARY(mod, "x%y");
+BINARY(divmod, "divmod(x,y)");
+BINARY(lshift, "x<<y");
+BINARY(rshift, "x>>y");
+BINARY(and, "x&y");
+BINARY(xor, "x^y");
+BINARY(or, "x|y");
+
+static PyObject *
+wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       ternaryfunc func = (ternaryfunc)wrapped;
+       PyObject *other;
+       PyObject *third = Py_None;
+
+       /* Note: This wrapper only works for __pow__() */
+
+       if (!PyArg_ParseTuple(args, "O|O", &other, &third))
+               return NULL;
+       return (*func)(self, other, third);
+}
+
+#undef TERNARY
+#define TERNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+       {"__" #NAME "__", \
+        (wrapperfunc)wrap_ternaryfunc, \
+        "x.__" #NAME "__(y, z) <==> " #OP}, \
+       {"__r" #NAME "__", \
+        (wrapperfunc)wrap_ternaryfunc, \
+        "y.__r" #NAME "__(x, z) <==> " #OP}, \
+       {0} \
+}
+
+TERNARY(pow, "(x**y) % z");
+
+#undef UNARY
+#define UNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+       {"__" #NAME "__", \
+        (wrapperfunc)wrap_unaryfunc, \
+        "x.__" #NAME "__() <==> " #OP}, \
+       {0} \
+}
+
+static PyObject *
+wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       unaryfunc func = (unaryfunc)wrapped;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+       return (*func)(self);
+}
+
+UNARY(neg, "-x");
+UNARY(pos, "+x");
+UNARY(abs, "abs(x)");
+UNARY(nonzero, "x != 0");
+UNARY(invert, "~x");
+UNARY(int, "int(x)");
+UNARY(long, "long(x)");
+UNARY(float, "float(x)");
+UNARY(oct, "oct(x)");
+UNARY(hex, "hex(x)");
+
+#undef IBINARY
+#define IBINARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+       {"__" #NAME "__", \
+        (wrapperfunc)wrap_binaryfunc, \
+        "x.__" #NAME "__(y) <==> " #OP}, \
+       {0} \
+}
+
+IBINARY(iadd, "x+=y");
+IBINARY(isub, "x-=y");
+IBINARY(imul, "x*=y");
+IBINARY(idiv, "x/=y");
+IBINARY(imod, "x%=y");
+IBINARY(ilshift, "x<<=y");
+IBINARY(irshift, "x>>=y");
+IBINARY(iand, "x&=y");
+IBINARY(ixor, "x^=y");
+IBINARY(ior, "x|=y");
+
+#undef ITERNARY
+#define ITERNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+       {"__" #NAME "__", \
+        (wrapperfunc)wrap_ternaryfunc, \
+        "x.__" #NAME "__(y) <==> " #OP}, \
+       {0} \
+}
+
+ITERNARY(ipow, "x = (x**y) % z");
+
+static struct wrapperbase tab_getitem[] = {
+       {"__getitem__", (wrapperfunc)wrap_binaryfunc,
+        "x.__getitem__(y) <==> x[y]"},
+       {0}
+};
+
+static PyObject *
+wrap_intargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       intargfunc func = (intargfunc)wrapped;
+       int i;
+
+       if (!PyArg_ParseTuple(args, "i", &i))
+               return NULL;
+       return (*func)(self, i);
+}
+
+static struct wrapperbase tab_mul_int[] = {
+       {"__mul__", (wrapperfunc)wrap_intargfunc, "x.__mul__(n) <==> x*n"},
+       {"__rmul__", (wrapperfunc)wrap_intargfunc, "x.__rmul__(n) <==> n*x"},
+       {0}
+};
+
+static struct wrapperbase tab_concat[] = {
+       {"__add__", (wrapperfunc)wrap_binaryfunc, "x.__add__(y) <==> x+y"},
+       {0}
+};
+
+static struct wrapperbase tab_imul_int[] = {
+       {"__imul__", (wrapperfunc)wrap_intargfunc, "x.__imul__(n) <==> x*=n"},
+       {0}
+};
+
+static struct wrapperbase tab_getitem_int[] = {
+       {"__getitem__", (wrapperfunc)wrap_intargfunc,
+        "x.__getitem__(i) <==> x[i]"},
+       {0}
+};
+
+static PyObject *
+wrap_intintargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       intintargfunc func = (intintargfunc)wrapped;
+       int i, j;
+
+       if (!PyArg_ParseTuple(args, "ii", &i, &j))
+               return NULL;
+       return (*func)(self, i, j);
+}
+
+static struct wrapperbase tab_getslice[] = {
+       {"__getslice__", (wrapperfunc)wrap_intintargfunc,
+        "x.__getslice__(i, j) <==> x[i:j]"},
+       {0}
+};
+
+static PyObject *
+wrap_intobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+       intobjargproc func = (intobjargproc)wrapped;
+       int i, res;
+       PyObject *value;
+
+       if (!PyArg_ParseTuple(args, "iO", &i, &value))
+               return NULL;
+       res = (*func)(self, i, value);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_setitem_int[] = {
+       {"__setitem__", (wrapperfunc)wrap_intobjargproc,
+        "x.__setitem__(i, y) <==> x[i]=y"},
+       {0}
+};
+
+static PyObject *
+wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+       intintobjargproc func = (intintobjargproc)wrapped;
+       int i, j, res;
+       PyObject *value;
+
+       if (!PyArg_ParseTuple(args, "iiO", &i, &j, &value))
+               return NULL;
+       res = (*func)(self, i, j, value);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_setslice[] = {
+       {"__setslice__", (wrapperfunc)wrap_intintobjargproc,
+        "x.__setslice__(i, j, y) <==> x[i:j]=y"},
+       {0}
+};
+
+/* XXX objobjproc is a misnomer; should be objargpred */
+static PyObject *
+wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped)
+{
+       objobjproc func = (objobjproc)wrapped;
+       int res;
+       PyObject *value;
+
+       if (!PyArg_ParseTuple(args, "O", &value))
+               return NULL;
+       res = (*func)(self, value);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_contains[] = {
+       {"__contains__", (wrapperfunc)wrap_objobjproc,
+        "x.__contains__(y) <==> y in x"},
+       {0}
+};
+
+static PyObject *
+wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+       objobjargproc func = (objobjargproc)wrapped;
+       int res;
+       PyObject *key, *value;
+
+       if (!PyArg_ParseTuple(args, "OO", &key, &value))
+               return NULL;
+       res = (*func)(self, key, value);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_setitem[] = {
+       {"__setitem__", (wrapperfunc)wrap_objobjargproc,
+        "x.__setitem__(y, z) <==> x[y]=z"},
+       {0}
+};
+
+static PyObject *
+wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       cmpfunc func = (cmpfunc)wrapped;
+       int res;
+       PyObject *other;
+
+       if (!PyArg_ParseTuple(args, "O", &other))
+               return NULL;
+       res = (*func)(self, other);
+       if (PyErr_Occurred())
+               return NULL;
+       return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_cmp[] = {
+       {"__cmp__", (wrapperfunc)wrap_cmpfunc,
+        "x.__cmp__(y) <==> cmp(x,y)"},
+       {0}
+};
+
+static struct wrapperbase tab_repr[] = {
+       {"__repr__", (wrapperfunc)wrap_unaryfunc,
+        "x.__repr__() <==> repr(x)"},
+       {0}
+};
+
+static struct wrapperbase tab_getattr[] = {
+       {"__getattr__", (wrapperfunc)wrap_binaryfunc,
+        "x.__getattr__('name') <==> x.name"},
+       {0}
+};
+
+static PyObject *
+wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
+{
+       setattrofunc func = (setattrofunc)wrapped;
+       int res;
+       PyObject *name, *value;
+
+       if (!PyArg_ParseTuple(args, "OO", &name, &value))
+               return NULL;
+       res = (*func)(self, name, value);
+       if (res < 0)
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
+{
+       setattrofunc func = (setattrofunc)wrapped;
+       int res;
+       PyObject *name;
+
+       if (!PyArg_ParseTuple(args, "O", &name))
+               return NULL;
+       res = (*func)(self, name, NULL);
+       if (res < 0)
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_setattr[] = {
+       {"__setattr__", (wrapperfunc)wrap_setattr,
+        "x.__setattr__('name', value) <==> x.name = value"},
+       {"__delattr__", (wrapperfunc)wrap_delattr,
+        "x.__delattr__('name') <==> del x.name"},
+       {0}
+};
+
+static PyObject *
+wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       hashfunc func = (hashfunc)wrapped;
+       long res;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+       res = (*func)(self);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       return PyInt_FromLong(res);
+}
+
+static struct wrapperbase tab_hash[] = {
+       {"__hash__", (wrapperfunc)wrap_hashfunc,
+        "x.__hash__() <==> hash(x)"},
+       {0}
+};
+
+static PyObject *
+wrap_call(PyObject *self, PyObject *args, void *wrapped)
+{
+       ternaryfunc func = (ternaryfunc)wrapped;
+
+       /* XXX What about keyword arguments? */
+       return (*func)(self, args, NULL);
+}
+
+static struct wrapperbase tab_call[] = {
+       {"__call__", (wrapperfunc)wrap_call,
+        "x.__call__(...) <==> x(...)"},
+       {0}
+};
+
+static struct wrapperbase tab_str[] = {
+       {"__str__", (wrapperfunc)wrap_unaryfunc,
+        "x.__str__() <==> str(x)"},
+       {0}
+};
+
+static PyObject *
+wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op)
+{
+       richcmpfunc func = (richcmpfunc)wrapped;
+       PyObject *other;
+
+       if (!PyArg_ParseTuple(args, "O", &other))
+               return NULL;
+       return (*func)(self, other, op);
+}
+
+#undef RICHCMP_WRAPPER
+#define RICHCMP_WRAPPER(NAME, OP) \
+static PyObject * \
+richcmp_##NAME(PyObject *self, PyObject *args, void *wrapped) \
+{ \
+       return wrap_richcmpfunc(self, args, wrapped, OP); \
+}
+
+RICHCMP_WRAPPER(lt, Py_LT);
+RICHCMP_WRAPPER(le, Py_LE);
+RICHCMP_WRAPPER(eq, Py_EQ);
+RICHCMP_WRAPPER(ne, Py_NE);
+RICHCMP_WRAPPER(gt, Py_GT);
+RICHCMP_WRAPPER(ge, Py_GE);
+
+#undef RICHCMP_ENTRY
+#define RICHCMP_ENTRY(NAME, EXPR) \
+       {"__" #NAME "__", (wrapperfunc)richcmp_##NAME, \
+        "x.__" #NAME "__(y) <==> " EXPR}
+
+static struct wrapperbase tab_richcmp[] = {
+       RICHCMP_ENTRY(lt, "x<y"),
+       RICHCMP_ENTRY(le, "x<=y"),
+       RICHCMP_ENTRY(eq, "x==y"),
+       RICHCMP_ENTRY(ne, "x!=y"),
+       RICHCMP_ENTRY(gt, "x>y"),
+       RICHCMP_ENTRY(ge, "x>=y"),
+       {0}
+};
+
+static struct wrapperbase tab_iter[] = {
+       {"__iter__", (wrapperfunc)wrap_unaryfunc, "x.__iter__() <==> iter(x)"},
+       {0}
+};
+
+static PyObject *
+wrap_next(PyObject *self, PyObject *args, void *wrapped)
+{
+       unaryfunc func = (unaryfunc)wrapped;
+       PyObject *res;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+       res = (*func)(self);
+       if (res == NULL && !PyErr_Occurred())
+               PyErr_SetNone(PyExc_StopIteration);
+       return res;
+}
+
+static struct wrapperbase tab_next[] = {
+       {"next", (wrapperfunc)wrap_next,
+               "x.next() -> the next value, or raise StopIteration"},
+       {0}
+};
+
+static PyObject *
+wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
+{
+       descrgetfunc func = (descrgetfunc)wrapped;
+       PyObject *obj;
+       PyObject *type = NULL;
+
+       if (!PyArg_ParseTuple(args, "O|O", &obj, &type))
+               return NULL;
+       if (type == NULL)
+               type = (PyObject *)obj->ob_type;
+       return (*func)(self, obj, type);
+}
+
+static struct wrapperbase tab_descr_get[] = {
+       {"__get__", (wrapperfunc)wrap_descr_get,
+        "descr.__get__(obj, type) -> value"},
+       {0}
+};
+
+static PyObject *
+wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+       descrsetfunc func = (descrsetfunc)wrapped;
+       PyObject *obj, *value;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &obj, &value))
+               return NULL;
+       ret = (*func)(self, obj, value);
+       if (ret < 0)
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_descr_set[] = {
+       {"__set__", (wrapperfunc)wrap_descrsetfunc,
+        "descr.__set__(obj, value)"},
+       {0}
+};
+
+static PyObject *
+wrap_init(PyObject *self, PyObject *args, void *wrapped)
+{
+       initproc func = (initproc)wrapped;
+
+       /* XXX What about keyword arguments? */
+       if (func(self, args, NULL) < 0)
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static struct wrapperbase tab_init[] = {
+       {"__init__", (wrapperfunc)wrap_init,
+        "x.__init__(...) initializes x; "
+        "see x.__type__.__doc__ for signature"},
+       {0}
+};
+
+static PyObject *
+wrap_new(PyObject *type, PyObject *args, void *wrapped)
+{
+       newfunc new = (newfunc)wrapped;
+       return new((PyTypeObject *)type, args, NULL);
+}
+
+static struct wrapperbase tab_new[] = {
+       {"__new__", (wrapperfunc)wrap_new,
+        "T.__new__() -> an object with type T"},
+       {0}
+};
+
+static int
+add_operators(PyTypeObject *type)
+{
+       PySequenceMethods *sq;
+       PyMappingMethods *mp;
+       PyNumberMethods *nb;
+
+#undef ADD
+#define ADD(SLOT, TABLE) \
+               if (SLOT) { \
+                       if (add_wrappers(type, TABLE, (void *)(SLOT)) < 0) \
+                               return -1; \
+               }
+
+       if ((sq = type->tp_as_sequence) != NULL) {
+               ADD(sq->sq_length, tab_len);
+               ADD(sq->sq_concat, tab_concat);
+               ADD(sq->sq_repeat, tab_mul_int);
+               ADD(sq->sq_item, tab_getitem_int);
+               ADD(sq->sq_slice, tab_getslice);
+               ADD(sq->sq_ass_item, tab_setitem_int);
+               ADD(sq->sq_ass_slice, tab_setslice);
+               ADD(sq->sq_contains, tab_contains);
+               ADD(sq->sq_inplace_concat, tab_iadd);
+               ADD(sq->sq_inplace_repeat, tab_imul_int);
+       }
+
+       if ((mp = type->tp_as_mapping) != NULL) {
+               if (sq->sq_length == NULL)
+                       ADD(mp->mp_length, tab_len);
+               ADD(mp->mp_subscript, tab_getitem);
+               ADD(mp->mp_ass_subscript, tab_setitem);
+       }
+
+       /* We don't support "old-style numbers" because their binary
+          operators require that both arguments have the same type;
+          the wrappers here only work for new-style numbers. */
+       if ((type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
+           (nb = type->tp_as_number) != NULL) {
+               ADD(nb->nb_add, tab_add);
+               ADD(nb->nb_subtract, tab_sub);
+               ADD(nb->nb_multiply, tab_mul);
+               ADD(nb->nb_divide, tab_div);
+               ADD(nb->nb_remainder, tab_mod);
+               ADD(nb->nb_divmod, tab_divmod);
+               ADD(nb->nb_power, tab_pow);
+               ADD(nb->nb_negative, tab_neg);
+               ADD(nb->nb_positive, tab_pos);
+               ADD(nb->nb_absolute, tab_abs);
+               ADD(nb->nb_nonzero, tab_nonzero);
+               ADD(nb->nb_invert, tab_invert);
+               ADD(nb->nb_lshift, tab_lshift);
+               ADD(nb->nb_rshift, tab_rshift);
+               ADD(nb->nb_and, tab_and);
+               ADD(nb->nb_xor, tab_xor);
+               ADD(nb->nb_or, tab_or);
+               /* We don't support coerce() -- see above comment */
+               ADD(nb->nb_int, tab_int);
+               ADD(nb->nb_long, tab_long);
+               ADD(nb->nb_float, tab_float);
+               ADD(nb->nb_oct, tab_oct);
+               ADD(nb->nb_hex, tab_hex);
+               ADD(nb->nb_inplace_add, tab_iadd);
+               ADD(nb->nb_inplace_subtract, tab_isub);
+               ADD(nb->nb_inplace_multiply, tab_imul);
+               ADD(nb->nb_inplace_divide, tab_idiv);
+               ADD(nb->nb_inplace_remainder, tab_imod);
+               ADD(nb->nb_inplace_power, tab_ipow);
+               ADD(nb->nb_inplace_lshift, tab_ilshift);
+               ADD(nb->nb_inplace_rshift, tab_irshift);
+               ADD(nb->nb_inplace_and, tab_iand);
+               ADD(nb->nb_inplace_xor, tab_ixor);
+               ADD(nb->nb_inplace_or, tab_ior);
+       }
+
+       ADD(type->tp_getattro, tab_getattr);
+       ADD(type->tp_setattro, tab_setattr);
+       ADD(type->tp_compare, tab_cmp);
+       ADD(type->tp_repr, tab_repr);
+       ADD(type->tp_hash, tab_hash);
+       ADD(type->tp_call, tab_call);
+       ADD(type->tp_str, tab_str);
+       ADD(type->tp_richcompare, tab_richcmp);
+       ADD(type->tp_iter, tab_iter);
+       ADD(type->tp_iternext, tab_next);
+       ADD(type->tp_descr_get, tab_descr_get);
+       ADD(type->tp_descr_set, tab_descr_set);
+       ADD(type->tp_init, tab_init);
+
+       if (type->tp_new != NULL)
+               add_staticmethodwrappers(type, tab_new,
+                                        (void *)(type->tp_new));
+
+       return 0;
+}
+
+/* Slot wrappers that call the corresponding __foo__ slot */
+
+#define SLOT0(SLOTNAME, OPNAME) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self) \
+{ \
+       return PyObject_CallMethod(self, "__" #OPNAME "__", ""); \
+}
+
+#define SLOT1(SLOTNAME, OPNAME, ARG1TYPE, ARGCODES) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self, ARG1TYPE arg1) \
+{ \
+       return PyObject_CallMethod(self, "__" #OPNAME "__", #ARGCODES, arg1); \
+}
+
+#define SLOT2(SLOTNAME, OPNAME, ARG1TYPE, ARG2TYPE, ARGCODES) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \
+{ \
+       return PyObject_CallMethod(self, "__" #OPNAME "__", \
+               #ARGCODES, arg1, arg2); \
+}
+
+static int
+slot_sq_length(PyObject *self)
+{
+       PyObject *res = PyObject_CallMethod(self, "__len__", "");
+
+       if (res == NULL)
+               return -1;
+       return (int)PyInt_AsLong(res);
+}
+
+SLOT1(sq_concat, add, PyObject *, O);
+SLOT1(sq_repeat, mul, int, i);
+SLOT1(sq_item, getitem, int, i);
+SLOT2(sq_slice, getslice, int, int, ii);
+
+static int
+slot_sq_ass_item(PyObject *self, int index, PyObject *value)
+{
+       PyObject *res;
+
+       if (value == NULL)
+               res = PyObject_CallMethod(self, "__delitem__", "i", index);
+       else
+               res = PyObject_CallMethod(self, "__setitem__",
+                                         "iO", index, value);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+static int
+slot_sq_ass_slice(PyObject *self, int i, int j, PyObject *value)
+{
+       PyObject *res;
+
+       if (value == NULL)
+               res = PyObject_CallMethod(self, "__delslice__", "ii", i, j);
+       else
+               res = PyObject_CallMethod(self, "__setslice__",
+                                         "iiO", i, j, value);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+static int
+slot_sq_contains(PyObject *self, PyObject *value)
+{
+       PyObject *res = PyObject_CallMethod(self, "__contains__", "O", value);
+       int r;
+
+       if (res == NULL)
+               return -1;
+       r = PyInt_AsLong(res);
+       Py_DECREF(res);
+       return r;
+}
+
+SLOT1(sq_inplace_concat, iadd, PyObject *, O);
+SLOT1(sq_inplace_repeat, imul, int, i);
+
+#define slot_mp_length slot_sq_length
+
+SLOT1(mp_subscript, getitem, PyObject *, O);
+
+static int
+slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
+{
+       PyObject *res;
+
+       if (value == NULL)
+               res = PyObject_CallMethod(self, "__delitem__", "O", key);
+       else
+               res = PyObject_CallMethod(self, "__setitem__",
+                                         "OO", key, value);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+/* XXX the numerical slots should call the reverse operators too;
+   but how do they know their type? */
+SLOT1(nb_add, add, PyObject *, O);
+SLOT1(nb_subtract, sub, PyObject *, O);
+SLOT1(nb_multiply, mul, PyObject *, O);
+SLOT1(nb_divide, div, PyObject *, O);
+SLOT1(nb_remainder, mod, PyObject *, O);
+SLOT1(nb_divmod, divmod, PyObject *, O);
+SLOT2(nb_power, pow, PyObject *, PyObject *, OO);
+SLOT0(nb_negative, neg);
+SLOT0(nb_positive, pos);
+SLOT0(nb_absolute, abs);
+
+static int
+slot_nb_nonzero(PyObject *self)
+{
+       PyObject *res = PyObject_CallMethod(self, "__nonzero__", "");
+
+       if (res == NULL)
+               return -1;
+       return (int)PyInt_AsLong(res);
+}
+
+SLOT0(nb_invert, invert);
+SLOT1(nb_lshift, lshift, PyObject *, O);
+SLOT1(nb_rshift, rshift, PyObject *, O);
+SLOT1(nb_and, and, PyObject *, O);
+SLOT1(nb_xor, xor, PyObject *, O);
+SLOT1(nb_or, or, PyObject *, O);
+/* Not coerce() */
+SLOT0(nb_int, int);
+SLOT0(nb_long, long);
+SLOT0(nb_float, float);
+SLOT0(nb_oct, oct);
+SLOT0(nb_hex, hex);
+SLOT1(nb_inplace_add, iadd, PyObject *, O);
+SLOT1(nb_inplace_subtract, isub, PyObject *, O);
+SLOT1(nb_inplace_multiply, imul, PyObject *, O);
+SLOT1(nb_inplace_divide, idiv, PyObject *, O);
+SLOT1(nb_inplace_remainder, imod, PyObject *, O);
+SLOT2(nb_inplace_power, ipow, PyObject *, PyObject *, OO);
+SLOT1(nb_inplace_lshift, ilshift, PyObject *, O);
+SLOT1(nb_inplace_rshift, irshift, PyObject *, O);
+SLOT1(nb_inplace_and, iand, PyObject *, O);
+SLOT1(nb_inplace_xor, ixor, PyObject *, O);
+SLOT1(nb_inplace_or, ior, PyObject *, O);
+
+static int
+slot_tp_compare(PyObject *self, PyObject *other)
+{
+       PyObject *res = PyObject_CallMethod(self, "__cmp__", "O", other);
+       long r;
+
+       if (res == NULL)
+               return -1;
+       r = PyInt_AsLong(res);
+       Py_DECREF(res);
+       return (int)r;
+}
+
+SLOT0(tp_repr, repr);
+
+static long
+slot_tp_hash(PyObject *self)
+{
+       PyObject *res = PyObject_CallMethod(self, "__hash__", "");
+       long h;
+
+       if (res == NULL)
+               return -1;
+       h = PyInt_AsLong(res);
+       if (h == -1 && !PyErr_Occurred())
+               h = -2;
+       return h;
+}
+
+static PyObject *
+slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
+{
+       PyObject *meth = PyObject_GetAttrString(self, "__call__");
+       PyObject *res;
+
+       if (meth == NULL)
+               return NULL;
+       res = PyObject_Call(meth, args, kwds);
+       Py_DECREF(meth);
+       return res;
+}
+
+SLOT0(tp_str, str);
+
+static PyObject *
+slot_tp_getattro(PyObject *self, PyObject *name)
+{
+       PyTypeObject *tp = self->ob_type;
+       PyObject *dict = NULL;
+       PyObject *getattr;
+
+       if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
+               dict = tp->tp_dict;
+       if (dict == NULL) {
+               PyErr_Format(PyExc_SystemError,
+                            "'%.100s' type object has no __dict__???",
+                            tp->tp_name);
+               return NULL;
+       }
+       getattr = PyDict_GetItemString(dict, "__getattr__");
+       if (getattr == NULL) {
+               PyErr_SetString(PyExc_AttributeError, "__getattr__");
+               return NULL;
+       }
+       return PyObject_CallFunction(getattr, "OO", self, name);
+}
+
+static int
+slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
+{
+       PyObject *res;
+
+       if (value == NULL)
+               res = PyObject_CallMethod(self, "__delattr__", "O", name);
+       else
+               res = PyObject_CallMethod(self, "__setattr__",
+                                         "OO", name, value);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+/* Map rich comparison operators to their __xx__ namesakes */
+static char *name_op[] = {
+       "__lt__",
+       "__le__",
+       "__eq__",
+       "__ne__",
+       "__gt__",
+       "__ge__",
+};
+
+static PyObject *
+slot_tp_richcompare(PyObject *self, PyObject *other, int op)
+{
+       PyObject *meth = PyObject_GetAttrString(self, name_op[op]);
+       PyObject *res;
+
+       if (meth == NULL)
+               return NULL;
+       res = PyObject_CallFunction(meth, "O", other);
+       Py_DECREF(meth);
+       return res;
+}
+
+SLOT0(tp_iter, iter);
+
+static PyObject *
+slot_tp_iternext(PyObject *self)
+{
+       return PyObject_CallMethod(self, "next", "");
+}
+
+SLOT2(tp_descr_get, get, PyObject *, PyObject *, OO);
+
+static int
+slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)
+{
+       PyObject *res = PyObject_CallMethod(self, "__set__",
+                                           "OO", target, value);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+static int
+slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+       PyObject *meth = PyObject_GetAttrString(self, "__init__");
+       PyObject *res;
+
+       if (meth == NULL)
+               return -1;
+       res = PyObject_Call(meth, args, kwds);
+       Py_DECREF(meth);
+       if (res == NULL)
+               return -1;
+       Py_DECREF(res);
+       return 0;
+}
+
+static PyObject *
+slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *func = PyObject_GetAttrString((PyObject *)type, "__new__");
+       PyObject *newargs, *x;
+       int i, n;
+
+       if (func == NULL)
+               return NULL;
+       assert(PyTuple_Check(args));
+       n = PyTuple_GET_SIZE(args);
+       newargs = PyTuple_New(n+1);
+       if (newargs == NULL)
+               return NULL;
+       Py_INCREF(type);
+       PyTuple_SET_ITEM(newargs, 0, (PyObject *)type);
+       for (i = 0; i < n; i++) {
+               x = PyTuple_GET_ITEM(args, i);
+               Py_INCREF(x);
+               PyTuple_SET_ITEM(newargs, i+1, x);
+       }
+       x = PyObject_Call(func, newargs, kwds);
+       Py_DECREF(func);
+       return x;
+}
+
+static void
+override_slots(PyTypeObject *type, PyObject *dict)
+{
+       PySequenceMethods *sq = type->tp_as_sequence;
+       PyMappingMethods *mp = type->tp_as_mapping;
+       PyNumberMethods *nb = type->tp_as_number;
+
+#define SQSLOT(OPNAME, SLOTNAME) \
+       if (PyDict_GetItemString(dict, OPNAME)) { \
+               sq->SLOTNAME = slot_##SLOTNAME; \
+       }
+
+#define MPSLOT(OPNAME, SLOTNAME) \
+       if (PyDict_GetItemString(dict, OPNAME)) { \
+               mp->SLOTNAME = slot_##SLOTNAME; \
+       }
+
+#define NBSLOT(OPNAME, SLOTNAME) \
+       if (PyDict_GetItemString(dict, OPNAME)) { \
+               nb->SLOTNAME = slot_##SLOTNAME; \
+       }
+
+#define TPSLOT(OPNAME, SLOTNAME) \
+       if (PyDict_GetItemString(dict, OPNAME)) { \
+               type->SLOTNAME = slot_##SLOTNAME; \
+       }
+
+       SQSLOT("__len__", sq_length);
+       SQSLOT("__add__", sq_concat);
+       SQSLOT("__mul__", sq_repeat);
+       SQSLOT("__getitem__", sq_item);
+       SQSLOT("__getslice__", sq_slice);
+       SQSLOT("__setitem__", sq_ass_item);
+       SQSLOT("__delitem__", sq_ass_item);
+       SQSLOT("__setslice__", sq_ass_slice);
+       SQSLOT("__delslice__", sq_ass_slice);
+       SQSLOT("__contains__", sq_contains);
+       SQSLOT("__iadd__", sq_inplace_concat);
+       SQSLOT("__imul__", sq_inplace_repeat);
+
+       MPSLOT("__len__", mp_length);
+       MPSLOT("__getitem__", mp_subscript);
+       MPSLOT("__setitem__", mp_ass_subscript);
+       MPSLOT("__delitem__", mp_ass_subscript);
+
+       NBSLOT("__add__", nb_add);
+       NBSLOT("__sub__", nb_subtract);
+       NBSLOT("__mul__", nb_multiply);
+       NBSLOT("__div__", nb_divide);
+       NBSLOT("__mod__", nb_remainder);
+       NBSLOT("__divmod__", nb_divmod);
+       NBSLOT("__pow__", nb_power);
+       NBSLOT("__neg__", nb_negative);
+       NBSLOT("__pos__", nb_positive);
+       NBSLOT("__abs__", nb_absolute);
+       NBSLOT("__nonzero__", nb_nonzero);
+       NBSLOT("__invert__", nb_invert);
+       NBSLOT("__lshift__", nb_lshift);
+       NBSLOT("__rshift__", nb_rshift);
+       NBSLOT("__and__", nb_and);
+       NBSLOT("__xor__", nb_xor);
+       NBSLOT("__or__", nb_or);
+       /* Not coerce() */
+       NBSLOT("__int__", nb_int);
+       NBSLOT("__long__", nb_long);
+       NBSLOT("__float__", nb_float);
+       NBSLOT("__oct__", nb_oct);
+       NBSLOT("__hex__", nb_hex);
+       NBSLOT("__iadd__", nb_inplace_add);
+       NBSLOT("__isub__", nb_inplace_subtract);
+       NBSLOT("__imul__", nb_inplace_multiply);
+       NBSLOT("__idiv__", nb_inplace_divide);
+       NBSLOT("__imod__", nb_inplace_remainder);
+       NBSLOT("__ipow__", nb_inplace_power);
+       NBSLOT("__ilshift__", nb_inplace_lshift);
+       NBSLOT("__irshift__", nb_inplace_rshift);
+       NBSLOT("__iand__", nb_inplace_and);
+       NBSLOT("__ixor__", nb_inplace_xor);
+       NBSLOT("__ior__", nb_inplace_or);
+
+       if (PyDict_GetItemString(dict, "__str__") ||
+           PyDict_GetItemString(dict, "__repr__"))
+               type->tp_print = NULL;
+
+       TPSLOT("__cmp__", tp_compare);
+       TPSLOT("__repr__", tp_repr);
+       TPSLOT("__hash__", tp_hash);
+       TPSLOT("__call__", tp_call);
+       TPSLOT("__str__", tp_str);
+       TPSLOT("__getattr__", tp_getattro);
+       TPSLOT("__setattr__", tp_setattro);
+       TPSLOT("__lt__", tp_richcompare);
+       TPSLOT("__le__", tp_richcompare);
+       TPSLOT("__eq__", tp_richcompare);
+       TPSLOT("__ne__", tp_richcompare);
+       TPSLOT("__gt__", tp_richcompare);
+       TPSLOT("__ge__", tp_richcompare);
+       TPSLOT("__iter__", tp_iter);
+       TPSLOT("next", tp_iternext);
+       TPSLOT("__get__", tp_descr_get);
+       TPSLOT("__set__", tp_descr_set);
+       TPSLOT("__init__", tp_init);
+       TPSLOT("__new__", tp_new);
+}
index 4bdff5a314e77296de2a1ed82ead029c66a0525f..1319c7c52ad3ab13dc6659de5ee605e34f1ff36a 100644 (file)
@@ -4667,12 +4667,6 @@ static PyMethodDef unicode_methods[] = {
     {NULL, NULL}
 };
 
-static PyObject * 
-unicode_getattr(PyUnicodeObject *self, char *name)
-{
-    return Py_FindMethod(unicode_methods, (PyObject*) self, name);
-}
-
 static PySequenceMethods unicode_as_sequence = {
     (inquiry) unicode_length,          /* sq_length */
     (binaryfunc) PyUnicode_Concat,     /* sq_concat */
@@ -5346,6 +5340,30 @@ static PyBufferProcs unicode_as_buffer = {
     (getcharbufferproc) unicode_buffer_getcharbuf,
 };
 
+static PyObject *
+unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+        PyObject *x = NULL;
+       static char *kwlist[] = {"string", "encoding", "errors", 0};
+       char *encoding = NULL;
+       char *errors = NULL;
+
+       assert(type == &PyUnicode_Type);
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:unicode",
+                                         kwlist, &x, &encoding, &errors))
+           return NULL;
+       if (x == NULL)
+               return (PyObject *)_PyUnicode_New(0);
+       return PyUnicode_FromEncodedObject(x, encoding, errors);
+}
+
+static char unicode_doc[] =
+"unicode(string [, encoding[, errors]]) -> object\n\
+\n\
+Create a new Unicode object from the given encoded string.\n\
+encoding defaults to the current default string encoding and \n\
+errors, defining the error handling, to 'strict'.";
+
 PyTypeObject PyUnicode_Type = {
     PyObject_HEAD_INIT(&PyType_Type)
     0,                                         /* ob_size */
@@ -5355,7 +5373,7 @@ PyTypeObject PyUnicode_Type = {
     /* Slots */
     (destructor)_PyUnicode_Free,       /* tp_dealloc */
     0,                                         /* tp_print */
-    (getattrfunc)unicode_getattr,      /* tp_getattr */
+    0,                                 /* tp_getattr */
     0,                                         /* tp_setattr */
     (cmpfunc) unicode_compare,                 /* tp_compare */
     (reprfunc) unicode_repr,           /* tp_repr */
@@ -5365,10 +5383,28 @@ PyTypeObject PyUnicode_Type = {
     (hashfunc) unicode_hash,           /* tp_hash*/
     0,                                         /* tp_call*/
     (reprfunc) unicode_str,            /* tp_str */
-    (getattrofunc) NULL,               /* tp_getattro */
-    (setattrofunc) NULL,               /* tp_setattro */
+    PyObject_GenericGetAttr,           /* tp_getattro */
+    0,                                 /* tp_setattro */
     &unicode_as_buffer,                        /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT,                        /* tp_flags */
+    unicode_doc,                       /* tp_doc */
+    0,                                 /* tp_traverse */
+    0,                                 /* tp_clear */
+    0,                                 /* tp_richcompare */
+    0,                                 /* tp_weaklistoffset */
+    0,                                 /* tp_iter */
+    0,                                 /* tp_iternext */
+    unicode_methods,                   /* tp_methods */
+    0,                                 /* tp_members */
+    0,                                 /* tp_getset */
+    0,                                 /* tp_base */
+    0,                                 /* tp_dict */
+    0,                                 /* tp_descr_get */
+    0,                                 /* tp_descr_set */
+    0,                                 /* tp_dictoffset */
+    0,                                 /* tp_init */
+    0,                                 /* tp_alloc */
+    unicode_new,                       /* tp_new */
 };
 
 /* Initialize the Unicode implementation */
index 2044688009bd21b180492f8c22a891e7aae8552e..df9b89abbe2a0e6bdc135db97313348d1f65843f 100644 (file)
@@ -44,6 +44,7 @@ extern void init_locale(void);
 extern void init_codecs(void);
 extern void initxreadlines(void);
 extern void init_weakref(void);
+extern void initxxsubtype(void);
 
 /* XXX tim: what's the purpose of ADDMODULE MARKER? */
 /* -- ADDMODULE MARKER 1 -- */
@@ -98,6 +99,8 @@ struct _inittab _PyImport_Inittab[] = {
        {"xreadlines", initxreadlines},
        {"_weakref", init_weakref},
 
+       {"xxsubtype", initxxsubtype},
+
 /* XXX tim: what's the purpose of ADDMODULE MARKER? */
 /* -- ADDMODULE MARKER 2 -- */
 
index 83e801627962213de85563b061a9362cf69cc978..4995caed4ee34c8eb1f068103ed2a43c015672e2 100644 (file)
@@ -495,6 +495,21 @@ SOURCE=..\Modules\cStringIO.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\Objects\descrobject.c\r
+\r
+!IF  "$(CFG)" == "pythoncore - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Release"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\Objects\dictobject.c\r
 \r
 !IF  "$(CFG)" == "pythoncore - Win32 Release"\r
@@ -1737,6 +1752,21 @@ SOURCE=..\Modules\xreadlinesmodule.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\Modules\xxsubtype.c\r
+\r
+!IF  "$(CFG)" == "pythoncore - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Release"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\Modules\yuvconvert.c\r
 \r
 !IF  "$(CFG)" == "pythoncore - Win32 Release"\r
diff --git a/PLAN.txt b/PLAN.txt
new file mode 100644 (file)
index 0000000..1ab384c
--- /dev/null
+++ b/PLAN.txt
@@ -0,0 +1,431 @@
+Project: core implementation
+****************************
+
+Tasks:
+
+Do binary operators properly.  nb_add should try to call self.__add__
+and other.__radd__.  I think I'll exclude base types that define any
+binary operator without setting the CHECKTYPES flag.
+
+Fix comparisons.  There's some nasty stuff here: when two types are
+not the same, and they're not instances, the fallback code doesn't
+account for the possibility that they might be subtypes of a common
+base type that defines a comparison.
+
+Fix subtype_dealloc().  This currently searches through the list of
+base types until it finds a type whose tp_dealloc is not
+subtype_dealloc.  I think this is not safe.  I think the alloc/dealloc
+policy needs to be rethought.  *** There's an idea here that I haven't
+worked out yet: just as object creation now has separate API's tp_new,
+tp_alloc, and tp_init, destruction has tp_dealloc and tp_free.  (Maybe
+tp_fini should be added to correspond to tp_init?)  Something
+could/should be done with this. ***
+
+Clean up isinstance(), issubclass() and their C equivalents.  There
+are a bunch of different APIs here and not all of them do the right
+thing yet.  There should be fewer APIs and their implementation should
+be simpler.  The old "abstract subclass" test should probably
+disappear (if we want to root out ExtensionClass).  *** I think I've
+done 90% of this by creating PyType_IsSubtype() and using it
+appropriately.  For now, the old "abstract subclass" test is still
+there, and there may be some places where PyObject_IsSubclass() is
+called where PyType_IsSubtype() would be more appropriate. ***
+
+Check for conflicts between base classes.  I fear that the rules used
+to decide whether multiple bases have conflicting instance variables
+aren't strict enough.  I think that sometimes two different classes
+adding __dict__ may be incompatible after all.
+
+Check for order conflicts.  Suppose there are two base classes X and
+Y.  Suppose class B derives from X and Y, and class C from Y and X (in
+that order).  Now suppose class D derives from B and C.  In which
+order should the base classes X and Y be searched?  This is an order
+conflict, and should be disallowed; currently the test for this is not
+implemented.
+
+Clean up the GC interface.  Currently, tp_basicsize includes the GC
+head size iff tp_flags includes the GC flag bit.  This makes object
+size math a pain (e.g. to see if two object types have the same
+instance size, you can't just compare the tp_basicsize fields -- you
+have to conditionally subtract the GC head size).  Neil has a patch
+that improves the API in this area, but it's backwards incompatible.
+(http://sf.net/tracker/?func=detail&aid=421893&group_id=5470&atid=305470)
+I think I know of a way to fix the incompatibility (by switching to a
+different flag bit).  *** Tim proposed a better idea: macros to access
+tp_basicsize while hiding the nastiness.  This is done now, so I think
+the rest of this task needn't be done. ***
+
+Make the __dict__ of types declared with Python class statements
+writable -- only statically declared types must have an immutable
+dict, because they're shared between interpreter instances.  Possibly
+trap writes to the __dict__ to update the corresponding tp_<slot> if
+an __<slot>__ name is affected.  *** Done as part of the next task. ***
+
+It should be an option (maybe a different metaclass, maybe a flag) to
+*not* merge __dict__ with all the bases, but instead search the
+__dict__ (or __introduced__?) of all bases in __mro__ order.  (This is
+needed anyway to unify classes completely.)  *** Partly done.
+Inheritance of slots from bases is still icky: (1) MRO is not always
+respected when inheriting slots; (2) dynamic classes can't add slot
+implementations in Python after creation (e.g., setting C.__hash__
+doesn't set the tp_hash slot).  ***
+
+Universal base class (object).  How can we make the object class
+subclassable and define simple default methods for everything without
+having these inherited by built-in types that don't want these
+defaults?  *** Done, really. ***
+
+Add error checking to the MRO calculation.  *** Done. ***
+
+Make __new__ overridable through a Python class method (!).  Make more
+of the sub-algorithms of type construction available as methods.  ***
+After I implemented class methods, I found that in order to be able
+to make an upcall to Base.__new__() and have it create an instance of
+your class (rather than a Base instance), you can't use class methods
+-- you must use static methods.  So I've implemented those too.  I've
+hooked up __new__ in the right places, so the first part of this is
+now done.  I've also exported the MRO calculation and made it
+overridable, as metamethod mro().  I believe that closes this topic
+for now.  I expect that some warts will only be really debugged when
+we try to use this for some, eh, interesting types such as tuples. ***
+
+More -- I'm sure new issues will crop up as we go.
+
+
+Project: loose ends and follow-through
+**************************************
+
+Tasks:
+
+Make more (most?) built-in types act as their own factory functions.
+
+Make more (most?) built-in types subtypable -- with or without
+overridable allocation.  *** This includes descriptors!  It should be
+possible to write descriptors in Python, so metaclasses can do clever
+things with them. ***
+
+Exceptions should be types.  This changes the rules, since now almost
+anything can be raised (as maybe it should).  Or should we strive for
+enforcement of the convention that all exceptions should be derived
+from Exception?  String exceptions will be another hassle, to be
+deprecated and eventually ruled out.
+
+Standardize a module containing names for all built-in types, and
+standardize on names.  E.g. should the official name of the string
+type be 'str', 'string', or 'StringType'?
+
+Create a hierarchy of types, so that e.g. int and long are both
+subtypes of an abstract base type integer, which is itself a subtype
+of number, etc.  A lot of thinking can go into this!
+
+*** NEW TASK??? ***
+Implement "signature" objects.  These are alluded to in PEP 252 but
+not yet specified.  Supposedly they provide an easily usable API to
+find out about function/method arguments.  Building these for Python
+functions is simple.  Building these for built-in functions will
+require a change to the PyMethodDef structure, so that a type can
+provide signature information for its C methods.  (This would also
+help in supporting keyword arguments for C methods with less work than
+PyArg_ParseTupleAndKeywords() currently requires.)  But should we do
+this?  It's additional work and not required for any of the other
+parts.
+
+
+Project: making classes use the new machinery
+*********************************************
+
+Tasks:
+
+Try to get rid of all code in classobject.c by deferring to the new
+mechanisms.  How far can we get without breaking backwards
+compatibility?  This is underspecified because I haven't thought much
+about it yet.  Can we lose the use of PyInstance_Check() everywhere?
+I would hope so!
+
+
+Project: backwards compatibility
+********************************
+
+Tasks:
+
+Make sure all code checks the proper tp_flags bit before accessing
+type object fields.
+
+Identify areas of incompatibility with Python 2.1.  Design solutions.
+Implement and test.
+
+Some specific areas: a fair amount of code probably depends on
+specific types having __members__ and/or __methods__ attributes.
+These are currently not present (conformant to PEP 252, which proposes
+to drop them) but we may have to add them back.  This can be done in a
+generic way with not too much effort.  Tim adds:  Perhaps that dir(object)
+rarely returns anything but [] now is a consequence of this.  I'm very
+used to doing, e.g., dir([]) or dir("") in an interactive shell to jog my
+memory; also one of the reasons test_generators failed.
+
+Another area: going all the way with classes and instances means that
+type(x) == types.InstanceType won't work any more to detect instances.
+Should there be a mode where this still works?  Maybe this should be
+the default mode, with a warning, and an explicit way to get the new
+way to work?  (Instead of a __future__ statement, I'm thinking of a
+module global __metaclass__ which would provide the default metaclass
+for baseless class statements.)
+
+
+Project: testing
+****************
+
+Tasks:
+
+Identify new functionality that needs testing.  Conceive unit tests
+for all new functionality.  Conceive stress tests for critical
+features.  Run the tests.  Fix bugs.  Repeat until satisfied.
+
+Note: this may interact with the branch integration task.
+
+
+Project: integration with main branch
+*************************************
+
+Tasks:
+
+Merge changes in the HEAD branch into the descr-branch.  Then merge
+the descr-branch back into the HEAD branch.
+
+The longer we wait, the more effort this will be -- the descr-branch
+forked off quite a long time ago, and there are changes everywhere in
+the HEAD branch (e.g. the dict object has been radically rewritten).
+
+On the other hand, if we do this too early, we'll have to do it again
+later.
+
+Note from Tim:  We should never again wait until literally 100s of files
+are out of synch.  I don't care how often I need to do this, provided only
+that it's a tractable task each time.  Once per week sounds like a good
+idea.  As is, even the trunk change to rangeobject.c created more than its
+proper share of merge headaches, because it confused all the other reasons
+include file merges were getting conflicts (the more changes there are, the
+worse diff does; indeed, I came up with the ndiff algorithm in the 80s
+precisely because the source-control diff program Cray used at the time
+produced minimal but *senseless* diffs, thus creating artificial conflicts;
+paying unbounded attention to context does a much better job of putting
+changes where they make semantic sense too; but we're stuck with Unix diff
+here, and it isn't robust in this sense; if we don't keep its job simple,
+it will make my job hell).
+
+Done:
+To undo or rename before final merge:  Modules/spam.c has worked its
+way into the branch Unix and Windows builds (pythoncore.dsp and
+PC/config.c); also imported by test_descr.py.  How about renaming to
+xxsubtype.c (whatever) now?
+
+
+Project: performance tuning
+***************************
+
+Tasks:
+
+Pick or create a general performance benchmark for Python.  Benchmark
+the new system vs. the old system.  Profile the new system.  Improve
+hotspots.  Repeat until satisfied.
+
+Note: this may interact with the branch integration task.
+
+
+Project: documentation
+**********************
+
+Tasks:
+
+Update PEP 252 (descriptors).  Describe more of the prototype
+implementation
+
+Update PEP 253 (subtyping).  Complicated architectural wrangling with
+metaclasses.  There is an interaction between implementation and
+description.
+
+Write PEP 254 (unification of classes).  This should discuss what
+changes for ordinary classes, and how we can make it more b/w
+compatible.
+
+Other documentation.  There needs to be user documentation,
+eventually.
+
+
+Project: community interaction
+******************************
+
+Tasks:
+
+Once the PEPs are written, solicit community feedback, and formulate
+responses to the feedback.  Give the community enough time to think
+over this complicated proposal.  Provide the community with a
+prototype implementation to test.  Try to do this *before* casting
+everything in stone!
+
+MERGE BEGIN ****************************************************************
+Merge details (this section is Tim's scratchpad, but should help a lot if
+he dies of frustration while wrestling with CVS <0.9 wink>).
+----------------------------------------------------------------------------
+2001-08-01  Merging descr-branch back into trunk.
+
+Tagged trunk about 22:05:
+    cvs tag date2001-08-01 python
+
+Merged trunk delta into branch:
+    cvs -q -z3 up -j date2001-07-30 -j date2001-08-01 descr
+
+No conflicts (! first time ever!) ... but problems with pythoncore.dsp.
+Resolved.
+
+Rebuilt from scratch; ran all tests; checked into branch about 22:40.
+
+Merged descr-branch back into trunk:
+    cvs -q -z3 up -j descr-branch python
+
+34 conflicts.  Hmm!  OK, looks like every file in the project with an
+embedded RCS Id is "a conflict".  Others make no sense, e.g., a dozen
+conflicts in dictobject.c, sometimes enclosing identical(!) blobs of
+source code.  And CVS remains utterly baffled by Python type object decls.
+Every line of ceval.c's generator code si in conflict blocks ... OK,
+there's no pattern or sense here, I'll just deal with it.
+
+Conflicts resolved; rebuilt from scratch; test_weakref fails.
+----------------------------------------------------------------------------
+2001-07-30
+
+Doing this again while the expat and Windows installer changes are still
+fresh on my mind.
+
+Tagged trunk about 23:50 EDT on the 29th:
+    cvs tag date2001-07-30 python
+
+Merged trunk delta into branch:
+
+    cvs -q -z3 up -j date2001-07-28 -j date2001-07-30 descr
+
+2 conflicts, resolved.
+----------------------------------------------------------------------------
+2001-07-28
+
+Tagged trunk about 00:31 EDT:
+    cvs tag date2001-07-28 python
+
+Merged trunk delta into branch:
+    cvs -q -z3 up -j date2001-07-21 -j date2001-07-28 descr
+
+4 conflicts, all RCS Ids.  Resolved.
+----------------------------------------------------------------------------
+2001-07-21
+
+Tagged trunk about 01:00 EDT:
+    cvs tag date2001-07-21 python
+
+Merged trunk delta into branch:
+    cvs -q -z3 up -j date2001-07-17b -j date2001-07-21 descr
+
+4 conflicts, mostly RCS Id thingies.  Resolved.
+
+Legit failure in new test_repr, because repr.py dispatches on the exact
+string returned by type(x).  type(1L) and type('s') differ in descr-branch
+now, and repr.py didn't realize that, falling back to the "unknown type"
+case for longs and strings.  Repaired descr-branch repr.py.
+----------------------------------------------------------------------------
+2001-07-19
+
+Removed the r22a1-branch tag (see next entry).  Turns out Guido did add a
+r22a1 tag, so the r22a1-branch tag served no point anymore.
+----------------------------------------------------------------------------
+2001-07-18  2.2a1 releaase
+
+Immediately after the merge just below, I tagged descr-branch via
+
+    cvs tag r22a1-branch descr
+
+Guido may or may not want to add another tag here (? maybe he wants to do
+some more Unix fiddling first).
+----------------------------------------------------------------------------
+2001-07-17  building 2.2a1 release, from descr-branch
+
+Tagged trunk about 22:00 EDT, like so:
+    cvs tag date2001-07-17b python
+
+Merged trunk delta into branch via:
+    cvs -q -z3 up -j date2001-07-17a -j date2001-07-17b descr
+----------------------------------------------------------------------------
+2001-07-17
+
+Tagged trunk about 00:05 EDT, like so:
+    cvs tag date2001-07-17a python
+
+Merged trunk delta into branch via:
+    cvs -q -z3 up -j date2001-07-16 -j date2001-07-17a descr
+----------------------------------------------------------------------------
+2001-07-16
+
+Tagged trunk about 15:20 EDT, like so:
+    cvs tag date2001-07-16 python
+
+Guido then added all the other dist/ directories to descr-branch from that
+trunk tag.
+
+Tim then merged trunk delta into the branch via:
+    cvs -q -z3 up -j date2001-07-15 -j date2001-07-16 descr
+----------------------------------------------------------------------------
+2001-07-15
+
+Tagged trunk about 15:44 EDT, like so:
+    cvs tag date2001-07-15 python
+
+Merged trunk delta into branch via:
+    cvs -q -z3 up -j date2001-07-13 -j date2001-07-15 descr
+
+Four files with conflicts, all artificial RCS Id & Revision thingies.
+Resolved and committed.
+----------------------------------------------------------------------------
+2001-07-13
+
+Tagged trunk about 22:13 EDT, like so:
+    cvs tag date2001-07-13 python
+
+Merged trunk delta into branch via:
+    cvs -q -z3 up -j date2001-07-06 -j date2001-07-13 descr
+
+Six(!) files with conflicts, mostly related to NeilS's generator gc patches.
+Unsure why, but CVS seems always to think there are conflicts whenever a
+line in a type object decl gets changed, and the conflict marking seems
+maximally confused in these cases.  Anyway, since I reviewed those patches
+on the trunk, good thing I'm merging them, and darned glad it's still fresh
+on my mind.
+
+Resolved the conflicts, and committed the changes in a few hours total.
+----------------------------------------------------------------------------
+2001-07-07
+
+Merge of trunk tag date2001-07-06 into descr-branch, via
+    cvs -q -z3 up -j date2001-07-06 mergedescr
+was committed on 2001-07-07.
+
+Merge issues:
+
+(all resolved -- GvR)
+----------------------------------------------------------------------------
+2001-07-06
+
+Tagged trunk a bit after midnight, like so:
+
+C:\Code>cvs tag date2001-07-06 python
+cvs server: Tagging python
+cvs server: Tagging python/dist
+cvs server: Tagging python/dist/src
+T python/dist/src/.cvsignore
+T python/dist/src/LICENSE
+T python/dist/src/Makefile.pre.in
+T python/dist/src/README
+... [& about 3000 lines more] ...
+
+This is the first trunk snapshot to be merged into the descr-branch.
+Gave it a date instead of a goofy name because there's going to be more
+than one of these, and at least it's obvious which of two ISO dates comes
+earlier.  These tags should go away after all merging is complete.
+MERGE END ******************************************************************
index ec55928cccc1efb17be3a5f2208330f348b7b7e8..ec3c5fc0a046650392b307e7767a20967449fccb 100644 (file)
@@ -131,26 +131,6 @@ start of the object (or at the specified offset). The slice will\n\
 extend to the end of the target object (or with the specified size).";
 
 
-static PyObject *
-builtin_unicode(PyObject *self, PyObject *args)
-{
-        PyObject *v;
-       char *encoding = NULL;
-       char *errors = NULL;
-
-       if ( !PyArg_ParseTuple(args, "O|ss:unicode", &v, &encoding, &errors) )
-           return NULL;
-       return PyUnicode_FromEncodedObject(v, encoding, errors);
-}
-
-static char unicode_doc[] =
-"unicode(string [, encoding[, errors]]) -> object\n\
-\n\
-Create a new Unicode object from the given encoded string.\n\
-encoding defaults to the current default string encoding and \n\
-errors, defining the error handling, to 'strict'.";
-
-
 static PyObject *
 builtin_callable(PyObject *self, PyObject *args)
 {
@@ -435,257 +415,6 @@ The mode must be 'exec' to compile a module, 'single' to compile a\n\
 single (interactive) statement, or 'eval' to compile an expression.";
 
 
-#ifndef WITHOUT_COMPLEX
-
-static PyObject *
-complex_from_string(PyObject *v)
-{
-       extern double strtod(const char *, char **);
-       const char *s, *start;
-       char *end;
-       double x=0.0, y=0.0, z;
-       int got_re=0, got_im=0, done=0;
-       int digit_or_dot;
-       int sw_error=0;
-       int sign;
-       char buffer[256]; /* For errors */
-       char s_buffer[256];
-       int len;
-
-       if (PyString_Check(v)) {
-               s = PyString_AS_STRING(v);
-               len = PyString_GET_SIZE(v);
-       }
-       else if (PyUnicode_Check(v)) {
-               if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
-                       PyErr_SetString(PyExc_ValueError,
-                                "complex() literal too large to convert");
-                       return NULL;
-               }
-               if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
-                                           PyUnicode_GET_SIZE(v),
-                                           s_buffer,
-                                           NULL))
-                       return NULL;
-               s = s_buffer;
-               len = (int)strlen(s);
-       }
-       else if (PyObject_AsCharBuffer(v, &s, &len)) {
-               PyErr_SetString(PyExc_TypeError,
-                               "complex() arg is not a string");
-               return NULL;
-       }
-
-       /* position on first nonblank */
-       start = s;
-       while (*s && isspace(Py_CHARMASK(*s)))
-               s++;
-       if (s[0] == '\0') {
-               PyErr_SetString(PyExc_ValueError,
-                               "complex() arg is an empty string");
-               return NULL;
-       }
-
-       z = -1.0;
-       sign = 1;
-       do {
-
-               switch (*s) {
-
-               case '\0':
-                       if (s-start != len) {
-                               PyErr_SetString(
-                                       PyExc_ValueError,
-                                       "complex() arg contains a null byte");
-                               return NULL;
-                       }
-                       if(!done) sw_error=1;
-                       break;
-
-               case '-':
-                       sign = -1;
-                               /* Fallthrough */
-               case '+':
-                       if (done)  sw_error=1;
-                       s++;
-                       if  (  *s=='\0'||*s=='+'||*s=='-'  ||
-                              isspace(Py_CHARMASK(*s))  )  sw_error=1;
-                       break;
-
-               case 'J':
-               case 'j':
-                       if (got_im || done) {
-                               sw_error = 1;
-                               break;
-                       }
-                       if  (z<0.0) {
-                               y=sign;
-                       }
-                       else{
-                               y=sign*z;
-                       }
-                       got_im=1;
-                       s++;
-                       if  (*s!='+' && *s!='-' )
-                               done=1;
-                       break;
-
-               default:
-                       if (isspace(Py_CHARMASK(*s))) {
-                               while (*s && isspace(Py_CHARMASK(*s)))
-                                       s++;
-                               if (s[0] != '\0')
-                                       sw_error=1;
-                               else
-                                       done = 1;
-                               break;
-                       }
-                       digit_or_dot =
-                               (*s=='.' || isdigit(Py_CHARMASK(*s)));
-                       if  (done||!digit_or_dot) {
-                               sw_error=1;
-                               break;
-                       }
-                       errno = 0;
-                       PyFPE_START_PROTECT("strtod", return 0)
-                               z = strtod(s, &end) ;
-                       PyFPE_END_PROTECT(z)
-                               if (errno != 0) {
-                                       sprintf(buffer,
-                                         "float() out of range: %.150s", s);
-                                       PyErr_SetString(
-                                               PyExc_ValueError,
-                                               buffer);
-                                       return NULL;
-                               }
-                       s=end;
-                       if  (*s=='J' || *s=='j') {
-
-                               break;
-                       }
-                       if  (got_re) {
-                               sw_error=1;
-                               break;
-                       }
-
-                               /* accept a real part */
-                       x=sign*z;
-                       got_re=1;
-                       if  (got_im)  done=1;
-                       z = -1.0;
-                       sign = 1;
-                       break;
-
-               }  /* end of switch  */
-
-       } while (*s!='\0' && !sw_error);
-
-       if (sw_error) {
-               PyErr_SetString(PyExc_ValueError,
-                               "complex() arg is a malformed string");
-               return NULL;
-       }
-
-       return PyComplex_FromDoubles(x,y);
-}
-
-static PyObject *
-builtin_complex(PyObject *self, PyObject *args)
-{
-       PyObject *r, *i, *tmp;
-       PyNumberMethods *nbr, *nbi = NULL;
-       Py_complex cr, ci;
-       int own_r = 0;
-
-       i = NULL;
-       if (!PyArg_ParseTuple(args, "O|O:complex", &r, &i))
-               return NULL;
-       if (PyString_Check(r) || PyUnicode_Check(r))
-               return complex_from_string(r);
-       if ((nbr = r->ob_type->tp_as_number) == NULL ||
-           nbr->nb_float == NULL ||
-           (i != NULL &&
-            ((nbi = i->ob_type->tp_as_number) == NULL ||
-             nbi->nb_float == NULL))) {
-               PyErr_SetString(PyExc_TypeError,
-                          "complex() arg can't be converted to complex");
-               return NULL;
-       }
-       /* XXX Hack to support classes with __complex__ method */
-       if (PyInstance_Check(r)) {
-               static PyObject *complexstr;
-               PyObject *f;
-               if (complexstr == NULL) {
-                       complexstr = PyString_InternFromString("__complex__");
-                       if (complexstr == NULL)
-                               return NULL;
-               }
-               f = PyObject_GetAttr(r, complexstr);
-               if (f == NULL)
-                       PyErr_Clear();
-               else {
-                       PyObject *args = Py_BuildValue("()");
-                       if (args == NULL)
-                               return NULL;
-                       r = PyEval_CallObject(f, args);
-                       Py_DECREF(args);
-                       Py_DECREF(f);
-                       if (r == NULL)
-                               return NULL;
-                       own_r = 1;
-               }
-       }
-       if (PyComplex_Check(r)) {
-               cr = ((PyComplexObject*)r)->cval;
-               if (own_r) {
-                       Py_DECREF(r);
-               }
-       }
-       else {
-               tmp = PyNumber_Float(r);
-               if (own_r) {
-                       Py_DECREF(r);
-               }
-               if (tmp == NULL)
-                       return NULL;
-               if (!PyFloat_Check(tmp)) {
-                       PyErr_SetString(PyExc_TypeError,
-                                       "float(r) didn't return a float");
-                       Py_DECREF(tmp);
-                       return NULL;
-               }
-               cr.real = PyFloat_AsDouble(tmp);
-               Py_DECREF(tmp);
-               cr.imag = 0.0;
-       }
-       if (i == NULL) {
-               ci.real = 0.0;
-               ci.imag = 0.0;
-       }
-       else if (PyComplex_Check(i))
-               ci = ((PyComplexObject*)i)->cval;
-       else {
-               tmp = (*nbi->nb_float)(i);
-               if (tmp == NULL)
-                       return NULL;
-               ci.real = PyFloat_AsDouble(tmp);
-               Py_DECREF(tmp);
-               ci.imag = 0.;
-       }
-       cr.real -= ci.imag;
-       cr.imag += ci.real;
-       return PyComplex_FromCComplex(cr);
-}
-
-static char complex_doc[] =
-"complex(real[, imag]) -> complex number\n\
-\n\
-Create a complex number from a real part and an optional imaginary part.\n\
-This is equivalent to (real + imag*1j) where imag defaults to 0.";
-
-
-#endif
-
 static PyObject *
 builtin_dir(PyObject *self, PyObject *args)
 {
@@ -1060,8 +789,8 @@ builtin_map(PyObject *self, PyObject *args)
                }
                if (curlen < 0)
                        curlen = 8;  /* arbitrary */
-               if (curlen > len)
-                       len = curlen;
+                       if (curlen > len)
+                               len = curlen;
        }
 
        /* Get space for the result list. */
@@ -1300,91 +1029,6 @@ Return the string itself or the previously interned string object with the\n\
 same value.";
 
 
-static PyObject *
-builtin_int(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-       int base = -909;                     /* unlikely! */
-
-       if (!PyArg_ParseTuple(args, "O|i:int", &v, &base))
-               return NULL;
-       if (base == -909)
-               return PyNumber_Int(v);
-       else if (PyString_Check(v))
-               return PyInt_FromString(PyString_AS_STRING(v), NULL, base);
-       else if (PyUnicode_Check(v))
-               return PyInt_FromUnicode(PyUnicode_AS_UNICODE(v),
-                                        PyUnicode_GET_SIZE(v),
-                                        base);
-       else {
-               PyErr_SetString(PyExc_TypeError,
-                               "int() can't convert non-string with explicit base");
-               return NULL;
-       }
-}
-
-static char int_doc[] =
-"int(x[, base]) -> integer\n\
-\n\
-Convert a string or number to an integer, if possible.  A floating point\n\
-argument will be truncated towards zero (this does not include a string\n\
-representation of a floating point number!)  When converting a string, use\n\
-the optional base.  It is an error to supply a base when converting a\n\
-non-string.";
-
-
-static PyObject *
-builtin_long(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-       int base = -909;                     /* unlikely! */
-
-       if (!PyArg_ParseTuple(args, "O|i:long", &v, &base))
-               return NULL;
-       if (base == -909)
-               return PyNumber_Long(v);
-       else if (PyString_Check(v))
-               return PyLong_FromString(PyString_AS_STRING(v), NULL, base);
-       else if (PyUnicode_Check(v))
-               return PyLong_FromUnicode(PyUnicode_AS_UNICODE(v),
-                                         PyUnicode_GET_SIZE(v),
-                                         base);
-       else {
-               PyErr_SetString(PyExc_TypeError,
-                               "long() can't convert non-string with explicit base");
-               return NULL;
-       }
-}
-
-static char long_doc[] =
-"long(x) -> long integer\n\
-long(x, base) -> long integer\n\
-\n\
-Convert a string or number to a long integer, if possible.  A floating\n\
-point argument will be truncated towards zero (this does not include a\n\
-string representation of a floating point number!)  When converting a\n\
-string, use the given base.  It is an error to supply a base when\n\
-converting a non-string.";
-
-
-static PyObject *
-builtin_float(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-
-       if (!PyArg_ParseTuple(args, "O:float", &v))
-               return NULL;
-       if (PyString_Check(v))
-               return PyFloat_FromString(v, NULL);
-       return PyNumber_Float(v);
-}
-
-static char float_doc[] =
-"float(x) -> floating point number\n\
-\n\
-Convert a string or number to a floating point number, if possible.";
-
-
 static PyObject *
 builtin_iter(PyObject *self, PyObject *args)
 {
@@ -1431,22 +1075,6 @@ static char len_doc[] =
 Return the number of items of a sequence or mapping.";
 
 
-static PyObject *
-builtin_list(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-
-       if (!PyArg_ParseTuple(args, "O:list", &v))
-               return NULL;
-       return PySequence_List(v);
-}
-
-static char list_doc[] =
-"list(sequence) -> list\n\
-\n\
-Return a new list whose items are the same as those of the argument sequence.";
-
-
 static PyObject *
 builtin_slice(PyObject *self, PyObject *args)
 {
@@ -2032,58 +1660,6 @@ Round a number to a given precision in decimal digits (default 0 digits).\n\
 This always returns a floating point number.  Precision may be negative.";
 
 
-static PyObject *
-builtin_str(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-
-       if (!PyArg_ParseTuple(args, "O:str", &v))
-               return NULL;
-       return PyObject_Str(v);
-}
-
-static char str_doc[] =
-"str(object) -> string\n\
-\n\
-Return a nice string representation of the object.\n\
-If the argument is a string, the return value is the same object.";
-
-
-static PyObject *
-builtin_tuple(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-
-       if (!PyArg_ParseTuple(args, "O:tuple", &v))
-               return NULL;
-       return PySequence_Tuple(v);
-}
-
-static char tuple_doc[] =
-"tuple(sequence) -> list\n\
-\n\
-Return a tuple whose items are the same as those of the argument sequence.\n\
-If the argument is a tuple, the return value is the same object.";
-
-
-static PyObject *
-builtin_type(PyObject *self, PyObject *args)
-{
-       PyObject *v;
-
-       if (!PyArg_ParseTuple(args, "O:type", &v))
-               return NULL;
-       v = (PyObject *)v->ob_type;
-       Py_INCREF(v);
-       return v;
-}
-
-static char type_doc[] =
-"type(object) -> type object\n\
-\n\
-Return the type of the object.";
-
-
 static PyObject *
 builtin_vars(PyObject *self, PyObject *args)
 {
@@ -2255,16 +1831,12 @@ static PyMethodDef builtin_methods[] = {
        {"cmp",         builtin_cmp, 1, cmp_doc},
        {"coerce",      builtin_coerce, 1, coerce_doc},
        {"compile",     builtin_compile, 1, compile_doc},
-#ifndef WITHOUT_COMPLEX
-       {"complex",     builtin_complex, 1, complex_doc},
-#endif
        {"delattr",     builtin_delattr, 1, delattr_doc},
        {"dir",         builtin_dir, 1, dir_doc},
        {"divmod",      builtin_divmod, 1, divmod_doc},
        {"eval",        builtin_eval, 1, eval_doc},
        {"execfile",    builtin_execfile, 1, execfile_doc},
        {"filter",      builtin_filter, 1, filter_doc},
-       {"float",       builtin_float, 1, float_doc},
        {"getattr",     builtin_getattr, 1, getattr_doc},
        {"globals",     builtin_globals, 1, globals_doc},
        {"hasattr",     builtin_hasattr, 1, hasattr_doc},
@@ -2273,14 +1845,11 @@ static PyMethodDef builtin_methods[] = {
        {"id",          builtin_id, 1, id_doc},
        {"input",       builtin_input, 1, input_doc},
        {"intern",      builtin_intern, 1, intern_doc},
-       {"int",         builtin_int, 1, int_doc},
        {"isinstance",  builtin_isinstance, 1, isinstance_doc},
        {"issubclass",  builtin_issubclass, 1, issubclass_doc},
        {"iter",        builtin_iter, 1, iter_doc},
        {"len",         builtin_len, 1, len_doc},
-       {"list",        builtin_list, 1, list_doc},
        {"locals",      builtin_locals, 1, locals_doc},
-       {"long",        builtin_long, 1, long_doc},
        {"map",         builtin_map, 1, map_doc},
        {"max",         builtin_max, 1, max_doc},
        {"min",         builtin_min, 1, min_doc},
@@ -2296,10 +1865,6 @@ static PyMethodDef builtin_methods[] = {
        {"round",       builtin_round, 1, round_doc},
        {"setattr",     builtin_setattr, 1, setattr_doc},
        {"slice",       builtin_slice, 1, slice_doc},
-       {"str",         builtin_str, 1, str_doc},
-       {"tuple",       builtin_tuple, 1, tuple_doc},
-       {"type",        builtin_type, 1, type_doc},
-       {"unicode",     builtin_unicode, 1, unicode_doc},
        {"unichr",      builtin_unichr, 1, unichr_doc},
        {"vars",        builtin_vars, 1, vars_doc},
        {"xrange",      builtin_xrange, 1, xrange_doc},
@@ -2329,6 +1894,42 @@ _PyBuiltin_Init(void)
        if (PyDict_SetItemString(dict, "NotImplemented",
                                 Py_NotImplemented) < 0)
                return NULL;
+       if (PyDict_SetItemString(dict, "classmethod",
+                                (PyObject *) &PyClassMethod_Type) < 0)
+               return NULL;
+#ifndef WITHOUT_COMPLEX
+       if (PyDict_SetItemString(dict, "complex",
+                                (PyObject *) &PyComplex_Type) < 0)
+               return NULL;
+#endif
+       if (PyDict_SetItemString(dict, "dictionary",
+                                (PyObject *) &PyDict_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "float",
+                                (PyObject *) &PyFloat_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "int", (PyObject *) &PyInt_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "list", (PyObject *) &PyList_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "long", (PyObject *) &PyLong_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "object",
+                                (PyObject *) &PyBaseObject_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "staticmethod",
+                                (PyObject *) &PyStaticMethod_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "str", (PyObject *) &PyString_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "tuple",
+                                (PyObject *) &PyTuple_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "type", (PyObject *) &PyType_Type) < 0)
+               return NULL;
+       if (PyDict_SetItemString(dict, "unicode",
+                                (PyObject *) &PyUnicode_Type) < 0)
+               return NULL;
        debug = PyInt_FromLong(Py_OptimizeFlag == 0);
        if (PyDict_SetItemString(dict, "__debug__", debug) < 0) {
                Py_XDECREF(debug);
index e614e17fc16eb5c8879b7a386802a3f7fe33e414..e6da9ebe1c3c663976417b71d7272e7368a91d2b 100644 (file)
@@ -13,6 +13,7 @@
 #include "frameobject.h"
 #include "eval.h"
 #include "opcode.h"
+#include "structmember.h"
 
 #ifdef macintosh
 #include "macglue.h"
 typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
 
 /* Forward declarations */
-
-static PyObject *eval_code2(PyCodeObject *,
-                           PyObject *, PyObject *,
-                           PyObject **, int,
-                           PyObject **, int,
-                           PyObject **, int,
-                           PyObject *);
-
 static PyObject *eval_frame(PyFrameObject *);
-static char *get_func_name(PyObject *);
-static char *get_func_desc(PyObject *);
 static PyObject *call_object(PyObject *, PyObject *, PyObject *);
 static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
 static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
@@ -98,7 +89,6 @@ static long dxp[256];
 #endif
 #endif
 
-
 staticforward PyTypeObject gentype;
 
 typedef struct {
@@ -211,24 +201,11 @@ static struct PyMethodDef gen_methods[] = {
        {NULL,          NULL}   /* Sentinel */
 };
 
-static PyObject *
-gen_getattr(genobject *gen, char *name)
-{
-       PyObject *result;
-
-       if (strcmp(name, "gi_frame") == 0) {
-               result = (PyObject *)gen->gi_frame;
-               assert(result != NULL);
-               Py_INCREF(result);
-       }
-       else if (strcmp(name, "gi_running") == 0)
-               result = (PyObject *)PyInt_FromLong((long)gen->gi_running);
-       else if (strcmp(name, "__members__") == 0)
-               result = Py_BuildValue("[ss]", "gi_frame", "gi_running");
-       else
-               result = Py_FindMethod(gen_methods, (PyObject *)gen, name);
-       return result;
-}
+static struct memberlist gen_memberlist[] = {
+       {"gi_frame",    T_OBJECT, offsetof(genobject, gi_frame),        RO},
+       {"gi_running",  T_INT,    offsetof(genobject, gi_running),      RO},
+       {NULL}  /* Sentinel */
+};
 
 statichere PyTypeObject gentype = {
        PyObject_HEAD_INIT(&PyType_Type)
@@ -239,7 +216,7 @@ statichere PyTypeObject gentype = {
        /* methods */
        (destructor)gen_dealloc,                /* tp_dealloc */
        0,                                      /* tp_print */
-       (getattrfunc)gen_getattr,               /* tp_getattr */
+       0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
@@ -249,7 +226,7 @@ statichere PyTypeObject gentype = {
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
        0,                                      /* tp_str */
-       0,                                      /* tp_getattro */
+       PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,     /* tp_flags */
@@ -260,6 +237,11 @@ statichere PyTypeObject gentype = {
        0,                                      /* tp_weaklistoffset */
        (getiterfunc)gen_getiter,               /* tp_iter */
        (iternextfunc)gen_iternext,             /* tp_iternext */
+       gen_methods,                            /* tp_methods */
+       gen_memberlist,                         /* tp_members */
+       0,                                      /* tp_getset */
+       0,                                      /* tp_base */
+       0,                                      /* tp_dict */
 };
 
 
@@ -505,7 +487,7 @@ static int unpack_iterable(PyObject *, int, PyObject **);
 PyObject *
 PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
 {
-       return eval_code2(co,
+       return PyEval_EvalCodeEx(co,
                          globals, locals,
                          (PyObject **)NULL, 0,
                          (PyObject **)NULL, 0,
@@ -516,7 +498,7 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
 
 /* Interpreter main loop */
 
-PyObject *
+static PyObject *
 eval_frame(PyFrameObject *f)
 {
 #ifdef DXPAIRS
@@ -965,7 +947,7 @@ eval_frame(PyFrameObject *f)
                case BINARY_SUBSCR:
                        w = POP();
                        v = POP();
-                       if (PyList_Check(v) && PyInt_Check(w)) {
+                       if (v->ob_type == &PyList_Type && PyInt_Check(w)) {
                                /* INLINE: list[int] */
                                long i = PyInt_AsLong(w);
                                if (i < 0)
@@ -2273,8 +2255,8 @@ eval_frame(PyFrameObject *f)
        return retval;
 }
 
-static PyObject *
-eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
+PyObject *
+PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
           PyObject **args, int argcount, PyObject **kws, int kwcount,
           PyObject **defs, int defcount, PyObject *closure)
 {
@@ -2973,13 +2955,13 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
                return NULL;
        }
 
-       result = call_object(func, arg, kw);
+       result = PyObject_Call(func, arg, kw);
        Py_DECREF(arg);
        return result;
 }
 
 /* How often is each kind of object called?  The answer depends on the
-   program.  An instrumented call_object() was used to run the Python
+   program.  An instrumented PyObject_Call() was used to run the Python
    regression test suite.  The results were:
    4200000 PyCFunctions
     390000 fast_function() calls
@@ -2992,11 +2974,11 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
     most common, but not by such a large margin.
 */
 
-static char *
-get_func_name(PyObject *func)
+char *
+PyEval_GetFuncName(PyObject *func)
 {
        if (PyMethod_Check(func))
-               return get_func_name(PyMethod_GET_FUNCTION(func));
+               return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func));
        else if (PyFunction_Check(func))
                return PyString_AsString(((PyFunctionObject*)func)->func_name);
        else if (PyCFunction_Check(func))
@@ -3011,8 +2993,8 @@ get_func_name(PyObject *func)
        }
 }
 
-static char *
-get_func_desc(PyObject *func)
+char *
+PyEval_GetFuncDesc(PyObject *func)
 {
        if (PyMethod_Check(func))
                return "()";
@@ -3136,7 +3118,8 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
                        PyErr_Format(PyExc_TypeError,
                                     "unbound method %s%s must be "
                                     "called with instance as first argument",
-                                    get_func_name(func), get_func_desc(func));
+                                    PyEval_GetFuncName(func),
+                                    PyEval_GetFuncDesc(func));
                        return NULL;
                }
                Py_INCREF(arg);
@@ -3199,7 +3182,7 @@ call_eval_code2(PyObject *func, PyObject *arg, PyObject *kw)
                nk = 0;
        }
 
-       result = eval_code2(
+       result = PyEval_EvalCodeEx(
                (PyCodeObject *)PyFunction_GET_CODE(func),
                PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
                &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
@@ -3255,7 +3238,7 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
                d = &PyTuple_GET_ITEM(argdefs, 0);
                nd = ((PyTupleObject *)argdefs)->ob_size;
        }
-       return eval_code2((PyCodeObject *)co, globals,
+       return PyEval_EvalCodeEx((PyCodeObject *)co, globals,
                          (PyObject *)NULL, (*pp_stack)-n, na,
                          (*pp_stack)-2*nk, nk, d, nd,
                          closure);
@@ -3282,8 +3265,8 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
                         PyErr_Format(PyExc_TypeError,
                                      "%.200s%s got multiple values "
                                      "for keyword argument '%.200s'",
-                                    get_func_name(func),
-                                    get_func_desc(func),
+                                    PyEval_GetFuncName(func),
+                                    PyEval_GetFuncDesc(func),
                                     PyString_AsString(key));
                        Py_DECREF(key);
                        Py_DECREF(value);
@@ -3356,7 +3339,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
        callargs = load_args(pp_stack, na);
        if (callargs == NULL)
                goto call_fail;
-       result = call_object(func, callargs, kwdict);
+       result = PyObject_Call(func, callargs, kwdict);
  call_fail:
        Py_XDECREF(callargs);
        Py_XDECREF(kwdict);
@@ -3378,8 +3361,8 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
                        PyErr_Format(PyExc_TypeError,
                                     "%s%s argument after ** "
                                     "must be a dictionary",
-                                    get_func_name(func),
-                                    get_func_desc(func));
+                                    PyEval_GetFuncName(func),
+                                    PyEval_GetFuncDesc(func));
                        goto ext_call_fail;
                }
        }
@@ -3393,8 +3376,8 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
                                        PyErr_Format(PyExc_TypeError,
                                                     "%s%s argument after * "
                                                     "must be a sequence",
-                                                    get_func_name(func),
-                                                    get_func_desc(func));
+                                                    PyEval_GetFuncName(func),
+                                                    PyEval_GetFuncDesc(func));
                                }
                                goto ext_call_fail;
                        }
@@ -3411,7 +3394,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
        callargs = update_star_args(na, nstar, stararg, pp_stack);
        if (callargs == NULL)
                goto ext_call_fail;
-       result = call_object(func, callargs, kwdict);
+       result = PyObject_Call(func, callargs, kwdict);
       ext_call_fail:
        Py_XDECREF(callargs);
        Py_XDECREF(kwdict);
@@ -3632,63 +3615,25 @@ import_all_from(PyObject *locals, PyObject *v)
 static PyObject *
 build_class(PyObject *methods, PyObject *bases, PyObject *name)
 {
-       int i, n;
-       if (!PyTuple_Check(bases)) {
-               PyErr_SetString(PyExc_SystemError,
-                               "build_class with non-tuple bases");
-               return NULL;
-       }
-       if (!PyDict_Check(methods)) {
-               PyErr_SetString(PyExc_SystemError,
-                               "build_class with non-dictionary");
-               return NULL;
-       }
-       if (!PyString_Check(name)) {
-               PyErr_SetString(PyExc_SystemError,
-                               "build_class with non-string name");
-               return NULL;
-       }
-       n = PyTuple_Size(bases);
-       for (i = 0; i < n; i++) {
-               PyObject *base = PyTuple_GET_ITEM(bases, i);
-               if (!PyClass_Check(base)) {
-                       /* Call the base's *type*, if it is callable.
-                          This code is a hook for Donald Beaudry's
-                          and Jim Fulton's type extensions.  In
-                          unextended Python it will never be triggered
-                          since its types are not callable.
-                          Ditto: call the bases's *class*, if it has
-                          one.  This makes the same thing possible
-                          without writing C code.  A true meta-object
-                          protocol! */
-                       PyObject *basetype = (PyObject *)base->ob_type;
-                       PyObject *callable = NULL;
-                       if (PyCallable_Check(basetype))
-                               callable = basetype;
-                       else
-                               callable = PyObject_GetAttrString(
-                                       base, "__class__");
-                       if (callable) {
-                               PyObject *args;
-                               PyObject *newclass = NULL;
-                               args = Py_BuildValue(
-                                       "(OOO)", name, bases, methods);
-                               if (args != NULL) {
-                                       newclass = PyEval_CallObject(
-                                               callable, args);
-                                       Py_DECREF(args);
-                               }
-                               if (callable != basetype) {
-                                       Py_DECREF(callable);
-                               }
-                               return newclass;
-                       }
-                       PyErr_SetString(PyExc_TypeError,
-                               "base is not a class object");
-                       return NULL;
+       PyObject *metaclass = NULL;
+
+       if (PyDict_Check(methods))
+               metaclass = PyDict_GetItemString(methods, "__metaclass__");
+
+       if (metaclass == NULL) {
+               if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0)
+                       metaclass = (PyObject *)
+                               PyTuple_GET_ITEM(bases, 0)->ob_type;
+               else {
+                       PyObject *g = PyEval_GetGlobals();
+                       if (g != NULL && PyDict_Check(g))
+                               metaclass = PyDict_GetItemString(
+                                       g, "__metaclass__");
+                       if (metaclass == NULL)
+                               metaclass = (PyObject *) &PyClass_Type;
                }
        }
-       return PyClass_New(bases, methods, name);
+       return PyObject_CallFunction(metaclass, "OOO", name, bases, methods);
 }
 
 static int
index 214d8e5e623bd5aa3fd709c10d289b6fdf44edfc..6fb52ca6c080abfc81a86f6c381bd418ad501f05 100644 (file)
@@ -1056,23 +1056,36 @@ static struct {
 \f
 
 DL_EXPORT(void)
-init_exceptions(void)
+_PyExc_Init(void)
 {
     char *modulename = "exceptions";
     int modnamesz = strlen(modulename);
     int i;
-
-    PyObject *me = Py_InitModule(modulename, functions);
-    PyObject *mydict = PyModule_GetDict(me);
-    PyObject *bltinmod = PyImport_ImportModule("__builtin__");
-    PyObject *bdict = PyModule_GetDict(bltinmod);
-    PyObject *doc = PyString_FromString(module__doc__);
-    PyObject *args;
-
-    PyDict_SetItemString(mydict, "__doc__", doc);
+    PyObject *me, *mydict, *bltinmod, *bdict, *doc, *args;
+
+    me = Py_InitModule(modulename, functions);
+    if (me == NULL)
+       goto err;
+    mydict = PyModule_GetDict(me);
+    if (mydict == NULL)
+       goto err;
+    bltinmod = PyImport_ImportModule("__builtin__");
+    if (bltinmod == NULL)
+       goto err;
+    bdict = PyModule_GetDict(bltinmod);
+    if (bdict == NULL)
+       goto err;
+    doc = PyString_FromString(module__doc__);
+    if (doc == NULL)
+       goto err;
+
+    i = PyDict_SetItemString(mydict, "__doc__", doc);
     Py_DECREF(doc);
-    if (PyErr_Occurred())
+    if (i < 0) {
+ err:
        Py_FatalError("exceptions bootstrapping error.");
+       return;
+    }
 
     /* This is the base class of all exceptions, so make it first. */
     if (make_Exception(modulename) ||
@@ -1139,7 +1152,7 @@ init_exceptions(void)
 
 
 DL_EXPORT(void)
-fini_exceptions(void)
+_PyExc_Fini(void)
 {
     int i;
 
index 82524f654dd928bd45a9fdb3046dff70641c4dfc..a2106de370dfbbd8387dfd2f6aeb2c6e04d2483d 100644 (file)
@@ -43,7 +43,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
 /* XXX Perhaps the magic number should be frozen and a version field
    added to the .pyc file header? */
 /* New way to come up with the magic number: (YEAR-1995), MONTH, DAY */
-#define MAGIC (60420 | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (60717 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 /* Magic word as global; note that _PyImport_Init() can change the
    value of this global to accommodate for alterations of how the
@@ -1968,8 +1968,11 @@ PyImport_Import(PyObject *module_name)
        }
 
        /* Get the __import__ function from the builtins */
-       if (PyDict_Check(builtins))
+       if (PyDict_Check(builtins)) {
                import = PyObject_GetItem(builtins, import_str);
+               if (import == NULL)
+                       PyErr_SetObject(PyExc_KeyError, import_str);
+       }
        else
                import = PyObject_GetAttr(builtins, import_str);
        if (import == NULL)
index c74b0623bb5e1a9b81c9bff92404b9fe01c74c6c..e6162305f477decc5a571b882b70822ff88cc2f2 100644 (file)
@@ -115,6 +115,9 @@ Py_Initialize(void)
                Py_FatalError("Py_Initialize: can't make first thread");
        (void) PyThreadState_Swap(tstate);
 
+       if (PyType_InitDict(&PyType_Type) < 0)
+               Py_FatalError("Py_Initialize: can't initialize 'type'");
+
        interp->modules = PyDict_New();
        if (interp->modules == NULL)
                Py_FatalError("Py_Initialize: can't make modules dictionary");
@@ -144,7 +147,7 @@ Py_Initialize(void)
        _PyImport_Init();
 
        /* initialize builtin exceptions */
-       init_exceptions();
+       _PyExc_Init();
 
        /* phase 2 of builtins */
        _PyImport_FixupExtension("__builtin__", "__builtin__");
@@ -238,7 +241,7 @@ Py_Finalize(void)
           below has been checked to make sure no exceptions are ever
           raised.
        */
-       fini_exceptions();
+       _PyExc_Fini();
 
        /* Delete current thread */
        PyInterpreterState_Clear(interp);
@@ -1345,7 +1348,7 @@ _Py_AskYesNo(char *prompt)
 {
        char buf[256];
        
-       printf("%s [ny] ", prompt);
+       fprintf(stderr, "%s [ny] ", prompt);
        if (fgets(buf, sizeof buf, stdin) == NULL)
                return 0;
        return buf[0] == 'y' || buf[0] == 'Y';