Merge of descr-branch back into trunk.
diff --git a/Include/Python.h b/Include/Python.h
index f9c33d4..9757a70 100644
--- a/Include/Python.h
+++ b/Include/Python.h
@@ -89,6 +89,7 @@
 #include "sliceobject.h"
 #include "cellobject.h"
 #include "iterobject.h"
+#include "descrobject.h"
 
 #include "codecs.h"
 #include "pyerrors.h"
diff --git a/Include/abstract.h b/Include/abstract.h
index 9082edb..799438e 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -294,6 +294,17 @@
        */
 
 
+
+     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);
diff --git a/Include/ceval.h b/Include/ceval.h
index 0fc5cba..ae4d858 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -45,6 +45,9 @@
 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
diff --git a/Include/classobject.h b/Include/classobject.h
index 3b25c74..3bd535e 100644
--- a/Include/classobject.h
+++ b/Include/classobject.h
@@ -47,10 +47,6 @@
 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
index 0000000..b6fc521
--- /dev/null
+++ b/Include/descrobject.h
@@ -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 *);
diff --git a/Include/dictobject.h b/Include/dictobject.h
index 4f5f94a..abc8ed5 100644
--- a/Include/dictobject.h
+++ b/Include/dictobject.h
@@ -7,9 +7,83 @@
 
 /* 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_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);
diff --git a/Include/eval.h b/Include/eval.h
index 2a45009..f9334a7 100644
--- a/Include/eval.h
+++ b/Include/eval.h
@@ -9,6 +9,14 @@
 
 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
diff --git a/Include/funcobject.h b/Include/funcobject.h
index 8cedeb7..6b1e389 100644
--- a/Include/funcobject.h
+++ b/Include/funcobject.h
@@ -42,6 +42,13 @@
 #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
diff --git a/Include/listobject.h b/Include/listobject.h
index 73ac724..af1368c 100644
--- a/Include/listobject.h
+++ b/Include/listobject.h
@@ -26,7 +26,7 @@
 
 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 *);
diff --git a/Include/modsupport.h b/Include/modsupport.h
index 4a40499..8ef343c 100644
--- a/Include/modsupport.h
+++ b/Include/modsupport.h
@@ -22,8 +22,8 @@
 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 @@
    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
 
diff --git a/Include/object.h b/Include/object.h
index 0765748..d81d4c2 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -202,6 +202,11 @@
 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 @@
 	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(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 @@
 /* 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 @@
                              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 @@
 
 #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*/
diff --git a/Include/objimpl.h b/Include/objimpl.h
index 4aa38d5..18cece8 100644
--- a/Include/objimpl.h
+++ b/Include/objimpl.h
@@ -236,7 +236,13 @@
 #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 @@
 /* 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 */
diff --git a/Include/patchlevel.h b/Include/patchlevel.h
index dddc28f..85ffacb 100644
--- a/Include/patchlevel.h
+++ b/Include/patchlevel.h
@@ -23,13 +23,13 @@
 #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 >= ... */
diff --git a/Include/pythonrun.h b/Include/pythonrun.h
index 6e9821b..7d947df 100644
--- a/Include/pythonrun.h
+++ b/Include/pythonrun.h
@@ -92,10 +92,10 @@
 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);
diff --git a/Lib/pickle.py b/Lib/pickle.py
index f6cbea8..c92dac2 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -504,6 +504,7 @@
     dispatch[ClassType] = save_global
     dispatch[FunctionType] = save_global
     dispatch[BuiltinFunctionType] = save_global
+    dispatch[TypeType] = save_global
 
 
 def _keep_alive(x, memo):
diff --git a/Lib/repr.py b/Lib/repr.py
index c2d3ed5..f9cfcf6 100644
--- a/Lib/repr.py
+++ b/Lib/repr.py
@@ -62,7 +62,7 @@
             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 @@
             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
index 0000000..92f79d5
--- /dev/null
+++ b/Lib/test/test_descr.py
@@ -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"
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 2a174c3..72a70ec 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -380,10 +380,16 @@
 >>> 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 @@
 >>> 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()
diff --git a/Lib/types.py b/Lib/types.py
index 95600a3..d60ee56d 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -7,7 +7,8 @@
 import sys
 
 NoneType = type(None)
-TypeType = type(NoneType)
+TypeType = type
+ObjectType = object
 
 IntType = type(0)
 LongType = type(0L)
@@ -22,8 +23,8 @@
 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 @@
 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
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 9fbf29d..ff22ef3 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -237,6 +237,7 @@
 		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 @@
 		Include/tupleobject.h \
 		Include/listobject.h \
 		Include/iterobject.h \
+		Include/descrobject.h \
 		Include/dictobject.h \
 		Include/methodobject.h \
 		Include/moduleobject.h \
diff --git a/Misc/NEWS b/Misc/NEWS
index db4fbde..d93ab86 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,17 @@
 
 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
diff --git a/Modules/Setup.dist b/Modules/Setup.dist
index 9114414..e9c2a94 100644
--- a/Modules/Setup.dist
+++ b/Modules/Setup.dist
@@ -464,3 +464,5 @@
 # Example -- included for reference only:
 # xx xxmodule.c
 
+# Another example -- the 'xxsubtype' module shows C-level subtyping in action
+xxsubtype xxsubtype.c
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
index e3cc58d..b27339f 100644
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -1869,6 +1869,10 @@
                 res = save_tuple(self, args);
                 goto finally;
             }
+	    if (type == &PyType_Type) {
+		res = save_global(self, args, NULL);
+		goto finally;
+	    }
             break;
 
         case 'l':
diff --git a/Modules/config.c.in b/Modules/config.c.in
index 5a5878f..0d5e8b0 100644
--- a/Modules/config.c.in
+++ b/Modules/config.c.in
@@ -37,7 +37,7 @@
 	{"__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
index 0000000..60d8c7d
--- /dev/null
+++ b/Modules/xxsubtype.c
@@ -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;
+}
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 63fe7d5..a0f075f 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1589,6 +1589,24 @@
 }
 
 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, ...)
 {
 	va_list va;
@@ -1746,7 +1764,7 @@
 		}
 	}
 	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) {
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c
index 1a17ec5..4c213ce 100644
--- a/Objects/bufferobject.c
+++ b/Objects/bufferobject.c
@@ -537,21 +537,21 @@
 	"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 */
 };
diff --git a/Objects/cellobject.c b/Objects/cellobject.c
index 66fc8d1..9a36776 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -106,7 +106,7 @@
 	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 */
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 06f6714..c4b1d8e 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -36,12 +36,12 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 #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 @@
 	_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 @@
 {
 	register PyObject *v;
 	PyClassObject *class;
+	descrgetfunc f;
+
 	class = NULL;
 	v = PyDict_GetItem(inst->in_dict, name);
 	if (v == NULL) {
@@ -628,17 +665,20 @@
 	}
 	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 @@
 	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 @@
 	&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 @@
 	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 @@
 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);
+	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;
 	}
-	else {
-		funcname = PyObject_GetAttrString(func,"__name__");
-		if (funcname == NULL)
-			PyErr_Clear();
+	else
+		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;
 	}
-	if (funcname != NULL && PyString_Check(funcname))
-		fname = PyString_AS_STRING(funcname);
 	else
-		fname = "?";
-	if (fclassname != NULL && PyString_Check(fclassname))
-		fcname = PyString_AsString(fclassname);
-	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 @@
 	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 @@
 	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 */
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 34dbab0..9a66c0c 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -8,6 +8,7 @@
 #ifndef WITHOUT_COMPLEX
 
 #include "Python.h"
+#include "structmember.h"
 
 /* Precisions used by repr() and str(), respectively.
 
@@ -182,6 +183,17 @@
 
 }
 
+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 @@
 	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 @@
 	{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)
+complex_subtype_from_string(PyTypeObject *type, PyObject *v)
 {
-	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);
+	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 @@
 	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 @@
 	(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
index 0000000..40629f6
--- /dev/null
+++ b/Objects/descrobject.c
@@ -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;
+}
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index c17664e..ce4c578 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -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 @@
 /* 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 @@
 }
 #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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	 */
 	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 @@
 		 */
 		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 @@
 }
 
 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 @@
 	}
 	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 @@
 			 * 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 @@
 	{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)
 {
@@ -1732,6 +1683,26 @@
 };
 
 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)
 {
 	return dictiter_new(dict, select_key);
@@ -1745,7 +1716,7 @@
 	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 @@
 	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 @@
 	{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 @@
 	/* 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 @@
 	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 @@
 	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 */
 };
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 18d15e1..e192e8b 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -1273,29 +1273,15 @@
 };
 
 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 @@
 	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. */
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d1ce092..df88736 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -636,6 +636,26 @@
 }
 
 
+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 @@
 	"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
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 0801b93..d327616 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -15,7 +15,6 @@
 	{"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 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 @@
 	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 @@
 	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 *
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 09c6cb8..311bcde 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -3,6 +3,7 @@
 
 #include "Python.h"
 #include "compile.h"
+#include "eval.h"
 #include "structmember.h"
 
 PyObject *
@@ -141,9 +142,8 @@
 };
 
 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 @@
 		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 @@
 		}
 	}
 
-	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 @@
 	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;
+}
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 282da20..e5106c5 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -742,6 +742,41 @@
 	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 @@
 	"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
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index c4f4e61..e062c8a 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -96,12 +96,6 @@
 	{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 @@
 	/* 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 @@
 	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 @@
 	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 */
 };
 
 /* -------------------------------------- */
@@ -198,12 +199,6 @@
 };
 
 static PyObject *
-calliter_getattr(calliterobject *it, char *name)
-{
-	return Py_FindMethod(calliter_methods, (PyObject *)it, name);
-}
-
-static PyObject *
 calliter_iternext(calliterobject *it)
 {
 	PyObject *result = PyObject_CallObject(it->it_callable, NULL);
@@ -228,7 +223,7 @@
 	/* 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 @@
 	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 @@
 	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 */
 };
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 7166ced..b77cc0a 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -523,6 +523,10 @@
 			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 @@
 {
 	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 @@
 	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 @@
 	{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 @@
 	(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 @@
 	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 @@
 	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 @@
 	{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 @@
 	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 @@
 	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! */
 };
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 71bd1ce..28c3e57 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -2031,6 +2031,43 @@
 	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 @@
 
 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 */
 };
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index bff79ed..56fbcc2 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -3,8 +3,6 @@
 
 #include "Python.h"
 
-#include "token.h"
-
 static PyCFunctionObject *free_list = NULL;
 
 PyObject *
@@ -69,6 +67,23 @@
 	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 @@
 }
 
 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);
+	PyObject *self;
+	if (PyEval_GetRestricted()) {
+		PyErr_SetString(PyExc_RuntimeError,
+			"method.__self__ not accessible in restricted mode");
+		return NULL;
 	}
-	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__");
-	}
-	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 @@
 	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 @@
 	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 @@
 	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 */
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 7df5ce0..7faa3bb 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -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 @@
 
 /* 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 @@
 	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 @@
 	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 */
 };
diff --git a/Objects/object.c b/Objects/object.c
index 87c8e1a..137752d 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -32,7 +32,7 @@
 
 	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 @@
 	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 @@
 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 @@
 				"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 @@
 				"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 @@
 	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 @@
 	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 *
 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 @@
 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 @@
 		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 @@
 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 @@
 		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 @@
 {
 	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 @@
 		Py_DECREF(call);
 		return 1;
 	}
-	return 0;
+	else {
+		return x->ob_type->tp_call != NULL;
+	}
 }
 
 
@@ -1365,7 +1492,7 @@
 	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
 }
 
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index 1f446df..9f155cf 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -310,22 +310,34 @@
 	"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
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 6f7a6d8..8f52f9e 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -14,6 +14,7 @@
 */
 
 #include "Python.h"
+#include "structmember.h"
 
 static PyObject *
 ellipsis_repr(PyObject *op)
@@ -128,32 +129,12 @@
 	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 @@
 	"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 */
 };
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index c7f5062..3d12588 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -2522,41 +2522,65 @@
 };
 
 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
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 538cc70..46f5714 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -480,6 +480,28 @@
 	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 @@
 	(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:
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ea3494e..429680d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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_getattr(PyTypeObject *t, char *name)
+type_module(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);
+	return PyString_FromString("__builtin__");
+}
+
+static PyObject *
+type_dict(PyTypeObject *type, void *context)
+{
+	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 @@
 }
 
 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);
+}
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 4bdff5a..1319c7c 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -4667,12 +4667,6 @@
     {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 @@
     (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 @@
     /* 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 @@
     (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 */
diff --git a/PC/config.c b/PC/config.c
index 2044688..df9b89a 100644
--- a/PC/config.c
+++ b/PC/config.c
@@ -44,6 +44,7 @@
 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 @@
 	{"xreadlines", initxreadlines},
 	{"_weakref", init_weakref},
 
+	{"xxsubtype", initxxsubtype},
+
 /* XXX tim: what's the purpose of ADDMODULE MARKER? */
 /* -- ADDMODULE MARKER 2 -- */
 
diff --git a/PCbuild/pythoncore.dsp b/PCbuild/pythoncore.dsp
index 83e8016..4995cae 100644
--- a/PCbuild/pythoncore.dsp
+++ b/PCbuild/pythoncore.dsp
@@ -495,6 +495,21 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\Objects\descrobject.c

+

+!IF  "$(CFG)" == "pythoncore - Win32 Release"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Debug"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Debug"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Release"

+

+!ENDIF 

+

+# End Source File

+# Begin Source File

+

 SOURCE=..\Objects\dictobject.c

 

 !IF  "$(CFG)" == "pythoncore - Win32 Release"

@@ -1737,6 +1752,21 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\Modules\xxsubtype.c

+

+!IF  "$(CFG)" == "pythoncore - Win32 Release"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Debug"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Debug"

+

+!ELSEIF  "$(CFG)" == "pythoncore - Win32 Alpha Release"

+

+!ENDIF 

+

+# End Source File

+# Begin Source File

+

 SOURCE=..\Modules\yuvconvert.c

 

 !IF  "$(CFG)" == "pythoncore - Win32 Release"

diff --git a/PLAN.txt b/PLAN.txt
new file mode 100644
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 ******************************************************************
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index ec55928..ec3c5fc 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -132,26 +132,6 @@
 
 
 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)
 {
 	PyObject *v;
@@ -435,257 +415,6 @@
 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 @@
 		}
 		if (curlen < 0)
 			curlen = 8;  /* arbitrary */
-		if (curlen > len)
-			len = curlen;
+			if (curlen > len)
+				len = curlen;
 	}
 
 	/* Get space for the result list. */
@@ -1301,91 +1030,6 @@
 
 
 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)
 {
 	PyObject *v, *w = NULL;
@@ -1432,22 +1076,6 @@
 
 
 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)
 {
 	PyObject *start, *stop, *step;
@@ -2033,58 +1661,6 @@
 
 
 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)
 {
 	PyObject *v = NULL;
@@ -2255,16 +1831,12 @@
 	{"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 @@
 	{"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 @@
 	{"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 @@
 	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);
diff --git a/Python/ceval.c b/Python/ceval.c
index e614e17..e6da9eb 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -13,6 +13,7 @@
 #include "frameobject.h"
 #include "eval.h"
 #include "opcode.h"
+#include "structmember.h"
 
 #ifdef macintosh
 #include "macglue.h"
@@ -32,17 +33,7 @@
 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 @@
 #endif
 #endif
 
-
 staticforward PyTypeObject gentype;
 
 typedef struct {
@@ -211,24 +201,11 @@
 	{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 @@
 	/* 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 @@
 	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 @@
 	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 @@
 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 @@
 
 /* Interpreter main loop */
 
-PyObject *
+static PyObject *
 eval_frame(PyFrameObject *f)
 {
 #ifdef DXPAIRS
@@ -965,7 +947,7 @@
 		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 @@
 	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 @@
 		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 @@
     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 @@
 	}
 }
 
-static char *
-get_func_desc(PyObject *func)
+char *
+PyEval_GetFuncDesc(PyObject *func)
 {
 	if (PyMethod_Check(func))
 		return "()";
@@ -3136,7 +3118,8 @@
 			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 @@
 		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 @@
 		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 @@
                         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 @@
 	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 @@
 			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 @@
 					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 @@
 	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 @@
 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
diff --git a/Python/exceptions.c b/Python/exceptions.c
index 214d8e5..6fb52ca 100644
--- a/Python/exceptions.c
+++ b/Python/exceptions.c
@@ -1056,23 +1056,36 @@
 
 
 DL_EXPORT(void)
-init_exceptions(void)
+_PyExc_Init(void)
 {
     char *modulename = "exceptions";
     int modnamesz = strlen(modulename);
     int i;
+    PyObject *me, *mydict, *bltinmod, *bdict, *doc, *args;
 
-    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;
+    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;
 
-    PyDict_SetItemString(mydict, "__doc__", doc);
+    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 @@
 
 
 DL_EXPORT(void)
-fini_exceptions(void)
+_PyExc_Fini(void)
 {
     int i;
 
diff --git a/Python/import.c b/Python/import.c
index 82524f6..a2106de 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -43,7 +43,7 @@
 /* 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 @@
 	}
 
 	/* 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)
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index c74b062..e616230 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -115,6 +115,9 @@
 		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 @@
 	_PyImport_Init();
 
 	/* initialize builtin exceptions */
-	init_exceptions();
+	_PyExc_Init();
 
 	/* phase 2 of builtins */
 	_PyImport_FixupExtension("__builtin__", "__builtin__");
@@ -238,7 +241,7 @@
 	   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 @@
 {
 	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';