#include "sliceobject.h"
#include "cellobject.h"
#include "iterobject.h"
+#include "descrobject.h"
#include "codecs.h"
#include "pyerrors.h"
*/
+
+ 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);
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
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) \
--- /dev/null
+/* 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 *);
/* 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);
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);
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
#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
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 *);
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
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
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
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);
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 *);
/* 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 | \
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)
#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*/
#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 */
/* 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 */
#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 >= ... */
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);
dispatch[ClassType] = save_global
dispatch[FunctionType] = save_global
dispatch[BuiltinFunctionType] = save_global
+ dispatch[TypeType] = save_global
def _keep_alive(x, memo):
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)
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)
--- /dev/null
+# 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"
>>> 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
>>> 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()
import sys
NoneType = type(None)
-TypeType = type(NoneType)
+TypeType = type
+ObjectType = object
IntType = type(0)
LongType = type(0L)
BufferType = type(buffer(''))
TupleType = type(())
-ListType = type([])
-DictType = DictionaryType = type({})
+ListType = list
+DictType = DictionaryType = dictionary
def _f(): pass
FunctionType = type(_f)
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
Objects/classobject.o \
Objects/cobject.o \
Objects/complexobject.o \
+ Objects/descrobject.o \
Objects/fileobject.o \
Objects/floatobject.o \
Objects/frameobject.o \
Include/tupleobject.h \
Include/listobject.h \
Include/iterobject.h \
+ Include/descrobject.h \
Include/dictobject.h \
Include/methodobject.h \
Include/moduleobject.h \
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
# Example -- included for reference only:
# xx xxmodule.c
+# Another example -- the 'xxsubtype' module shows C-level subtyping in action
+xxsubtype xxsubtype.c
res = save_tuple(self, args);
goto finally;
}
+ if (type == &PyType_Type) {
+ res = save_global(self, args, NULL);
+ goto finally;
+ }
break;
case 'l':
{"__main__", NULL},
{"__builtin__", NULL},
{"sys", NULL},
- {"exceptions", init_exceptions},
+ {"exceptions", NULL},
/* Sentinel */
{0, 0}
--- /dev/null
+#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;
+}
return r;
}
+PyObject *
+PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
+{
+ ternaryfunc call;
+
+ if ((call = func->ob_type->tp_call) != NULL) {
+ PyObject *result = (*call)(func, arg, kw);
+ if (result == NULL && !PyErr_Occurred())
+ PyErr_SetString(
+ PyExc_SystemError,
+ "NULL result without error in PyObject_Call");
+ return result;
+ }
+ PyErr_Format(PyExc_TypeError, "object is not callable: %s",
+ PyString_AS_STRING(PyObject_Repr(func)));
+ return NULL;
+}
+
PyObject *
PyObject_CallFunction(PyObject *callable, char *format, ...)
{
}
}
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) {
"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 */
};
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 */
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;
}
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;
}
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
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()) {
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;
}
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 */
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
/* 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 */
#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 */
}
_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;
{
register PyObject *v;
PyClassObject *class;
+ descrgetfunc f;
+
class = NULL;
v = PyDict_GetItem(inst->in_dict, name);
if (v == NULL) {
}
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);
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 */
&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 */
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)
static PyObject *
instancemethod_repr(PyMethodObject *a)
{
- char buf[240];
- PyInstanceObject *self = (PyInstanceObject *)(a->im_self);
+ char buffer[240];
+ PyObject *self = a->im_self;
PyObject *func = a->im_func;
- PyClassObject *class = (PyClassObject *)(a->im_class);
- PyObject *fclassname, *iclassname, *funcname;
- char *fcname, *icname, *fname;
- fclassname = class->cl_name;
- if (PyFunction_Check(func)) {
- funcname = ((PyFunctionObject *)func)->func_name;
- Py_INCREF(funcname);
- }
- else {
- funcname = PyObject_GetAttrString(func,"__name__");
- if (funcname == NULL)
- PyErr_Clear();
+ PyObject *klass = a->im_class;
+ PyObject *funcname = NULL, *klassname = NULL, *result = NULL;
+ char *sfuncname = "?", *sklassname = "?";
+
+ funcname = PyObject_GetAttrString(func, "__name__");
+ if (funcname == NULL)
+ PyErr_Clear();
+ else if (!PyString_Check(funcname)) {
+ Py_DECREF(funcname);
+ funcname = NULL;
}
- if (funcname != NULL && PyString_Check(funcname))
- fname = PyString_AS_STRING(funcname);
else
- fname = "?";
- if (fclassname != NULL && PyString_Check(fclassname))
- fcname = PyString_AsString(fclassname);
+ sfuncname = PyString_AS_STRING(funcname);
+ klassname = PyObject_GetAttrString(klass, "__name__");
+ if (klassname == NULL)
+ PyErr_Clear();
+ else if (!PyString_Check(klassname)) {
+ Py_DECREF(klassname);
+ klassname = NULL;
+ }
else
- fcname = "?";
+ sklassname = PyString_AS_STRING(klassname);
if (self == NULL)
- sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
+ sprintf(buffer, "<unbound method %.100s.%.100s>",
+ sklassname, sfuncname);
else {
- iclassname = self->in_class->cl_name;
- if (iclassname != NULL && PyString_Check(iclassname))
- icname = PyString_AsString(iclassname);
- else
- icname = "?";
- sprintf(buf, "<method %.60s.%.60s of %.60s instance at %p>",
- fcname, fname, icname, self);
+ /* XXX Shouldn't use repr() here! */
+ PyObject *selfrepr = PyObject_Repr(self);
+ if (selfrepr == NULL)
+ goto fail;
+ if (!PyString_Check(selfrepr)) {
+ Py_DECREF(selfrepr);
+ goto fail;
+ }
+ sprintf(buffer, "<bound method %.60s.%.60s of %.60s>",
+ sklassname, sfuncname, PyString_AS_STRING(selfrepr));
+ Py_DECREF(selfrepr);
}
+ result = PyString_FromString(buffer);
+ fail:
Py_XDECREF(funcname);
- return PyString_FromString(buf);
+ Py_XDECREF(klassname);
+ return result;
}
static long
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,
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 */
#ifndef WITHOUT_COMPLEX
#include "Python.h"
+#include "structmember.h"
/* Precisions used by repr() and str(), respectively.
}
+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)
{
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)
{
{NULL, NULL} /* sentinel */
};
+static struct memberlist complex_members[] = {
+ {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
+ {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
+ {0},
+};
static PyObject *
-complex_getattr(PyComplexObject *self, char *name)
-{
- if (strcmp(name, "real") == 0)
- return (PyObject *)PyFloat_FromDouble(self->cval.real);
- else if (strcmp(name, "imag") == 0)
- return (PyObject *)PyFloat_FromDouble(self->cval.imag);
- else if (strcmp(name, "__members__") == 0)
- return Py_BuildValue("[ss]", "imag", "real");
- return Py_FindMethod(complex_methods, (PyObject *)self, name);
+complex_subtype_from_string(PyTypeObject *type, PyObject *v)
+{
+ extern double strtod(const char *, char **);
+ const char *s, *start;
+ char *end;
+ double x=0.0, y=0.0, z;
+ int got_re=0, got_im=0, done=0;
+ int digit_or_dot;
+ int sw_error=0;
+ int sign;
+ char buffer[256]; /* For errors */
+ char s_buffer[256];
+ int len;
+
+ if (PyString_Check(v)) {
+ s = PyString_AS_STRING(v);
+ len = PyString_GET_SIZE(v);
+ }
+ else if (PyUnicode_Check(v)) {
+ if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
+ PyErr_SetString(PyExc_ValueError,
+ "complex() literal too large to convert");
+ return NULL;
+ }
+ if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
+ PyUnicode_GET_SIZE(v),
+ s_buffer,
+ NULL))
+ return NULL;
+ s = s_buffer;
+ len = (int)strlen(s);
+ }
+ else if (PyObject_AsCharBuffer(v, &s, &len)) {
+ PyErr_SetString(PyExc_TypeError,
+ "complex() arg is not a string");
+ return NULL;
+ }
+
+ /* position on first nonblank */
+ start = s;
+ while (*s && isspace(Py_CHARMASK(*s)))
+ s++;
+ if (s[0] == '\0') {
+ PyErr_SetString(PyExc_ValueError,
+ "complex() arg is an empty string");
+ return NULL;
+ }
+
+ z = -1.0;
+ sign = 1;
+ do {
+
+ switch (*s) {
+
+ case '\0':
+ if (s-start != len) {
+ PyErr_SetString(
+ PyExc_ValueError,
+ "complex() arg contains a null byte");
+ return NULL;
+ }
+ if(!done) sw_error=1;
+ break;
+
+ case '-':
+ sign = -1;
+ /* Fallthrough */
+ case '+':
+ if (done) sw_error=1;
+ s++;
+ if ( *s=='\0'||*s=='+'||*s=='-' ||
+ isspace(Py_CHARMASK(*s)) ) sw_error=1;
+ break;
+
+ case 'J':
+ case 'j':
+ if (got_im || done) {
+ sw_error = 1;
+ break;
+ }
+ if (z<0.0) {
+ y=sign;
+ }
+ else{
+ y=sign*z;
+ }
+ got_im=1;
+ s++;
+ if (*s!='+' && *s!='-' )
+ done=1;
+ break;
+
+ default:
+ if (isspace(Py_CHARMASK(*s))) {
+ while (*s && isspace(Py_CHARMASK(*s)))
+ s++;
+ if (s[0] != '\0')
+ sw_error=1;
+ else
+ done = 1;
+ break;
+ }
+ digit_or_dot =
+ (*s=='.' || isdigit(Py_CHARMASK(*s)));
+ if (done||!digit_or_dot) {
+ sw_error=1;
+ break;
+ }
+ errno = 0;
+ PyFPE_START_PROTECT("strtod", return 0)
+ z = strtod(s, &end) ;
+ PyFPE_END_PROTECT(z)
+ if (errno != 0) {
+ sprintf(buffer,
+ "float() out of range: %.150s", s);
+ PyErr_SetString(
+ PyExc_ValueError,
+ buffer);
+ return NULL;
+ }
+ s=end;
+ if (*s=='J' || *s=='j') {
+
+ break;
+ }
+ if (got_re) {
+ sw_error=1;
+ break;
+ }
+
+ /* accept a real part */
+ x=sign*z;
+ got_re=1;
+ if (got_im) done=1;
+ z = -1.0;
+ sign = 1;
+ break;
+
+ } /* end of switch */
+
+ } while (*s!='\0' && !sw_error);
+
+ if (sw_error) {
+ PyErr_SetString(PyExc_ValueError,
+ "complex() arg is a malformed string");
+ return NULL;
+ }
+
+ return complex_subtype_from_doubles(type, x, y);
+}
+
+static PyObject *
+complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *r, *i, *tmp;
+ PyNumberMethods *nbr, *nbi = NULL;
+ Py_complex cr, ci;
+ int own_r = 0;
+ static char *kwlist[] = {"real", "imag", 0};
+
+ r = Py_False;
+ i = NULL;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist,
+ &r, &i))
+ return NULL;
+ if (PyString_Check(r) || PyUnicode_Check(r))
+ return complex_subtype_from_string(type, r);
+ if ((nbr = r->ob_type->tp_as_number) == NULL ||
+ nbr->nb_float == NULL ||
+ (i != NULL &&
+ ((nbi = i->ob_type->tp_as_number) == NULL ||
+ nbi->nb_float == NULL))) {
+ PyErr_SetString(PyExc_TypeError,
+ "complex() arg can't be converted to complex");
+ return NULL;
+ }
+ /* XXX Hack to support classes with __complex__ method */
+ if (PyInstance_Check(r)) {
+ static PyObject *complexstr;
+ PyObject *f;
+ if (complexstr == NULL) {
+ complexstr = PyString_InternFromString("__complex__");
+ if (complexstr == NULL)
+ return NULL;
+ }
+ f = PyObject_GetAttr(r, complexstr);
+ if (f == NULL)
+ PyErr_Clear();
+ else {
+ PyObject *args = Py_BuildValue("()");
+ if (args == NULL)
+ return NULL;
+ r = PyEval_CallObject(f, args);
+ Py_DECREF(args);
+ Py_DECREF(f);
+ if (r == NULL)
+ return NULL;
+ own_r = 1;
+ }
+ }
+ if (PyComplex_Check(r)) {
+ cr = ((PyComplexObject*)r)->cval;
+ if (own_r) {
+ Py_DECREF(r);
+ }
+ }
+ else {
+ tmp = PyNumber_Float(r);
+ if (own_r) {
+ Py_DECREF(r);
+ }
+ if (tmp == NULL)
+ return NULL;
+ if (!PyFloat_Check(tmp)) {
+ PyErr_SetString(PyExc_TypeError,
+ "float(r) didn't return a float");
+ Py_DECREF(tmp);
+ return NULL;
+ }
+ cr.real = PyFloat_AsDouble(tmp);
+ Py_DECREF(tmp);
+ cr.imag = 0.0;
+ }
+ if (i == NULL) {
+ ci.real = 0.0;
+ ci.imag = 0.0;
+ }
+ else if (PyComplex_Check(i))
+ ci = ((PyComplexObject*)i)->cval;
+ else {
+ tmp = (*nbi->nb_float)(i);
+ if (tmp == NULL)
+ return NULL;
+ ci.real = PyFloat_AsDouble(tmp);
+ Py_DECREF(tmp);
+ ci.imag = 0.;
+ }
+ cr.real -= ci.imag;
+ cr.imag += ci.real;
+ return complex_subtype_from_c_complex(type, cr);
}
+static char complex_doc[] =
+"complex(real[, imag]) -> complex number\n\
+\n\
+Create a complex number from a real part and an optional imaginary part.\n\
+This is equivalent to (real + imag*1j) where imag defaults to 0.";
+
static PyNumberMethods complex_as_number = {
(binaryfunc)complex_add, /* nb_add */
(binaryfunc)complex_sub, /* nb_subtract */
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 */
(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
--- /dev/null
+/* 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;
+}
#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
/* 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);
}
#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 *
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;
{
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;
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)
;
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) {
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
*/
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.
*/
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 */
}
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", ¶m))
- 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];
}
else {
/* Do it the generic, slower way */
- PyObject *keys = PyMapping_Keys(param);
+ PyObject *keys = PyMapping_Keys(b);
PyObject *iter;
PyObject *key, *value;
int status;
* 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 *
{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)
{
0, /* sq_inplace_repeat */
};
+static PyObject *
+dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *self;
+
+ assert(type != NULL && type->tp_alloc != NULL);
+ self = type->tp_alloc(type, 0);
+ if (self != NULL) {
+ PyDictObject *d = (PyDictObject *)self;
+ /* It's guaranteed that tp->alloc zeroed out the struct. */
+ assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0);
+ INIT_NONZERO_DICT_SLOTS(d);
+ d->ma_lookup = lookdict_string;
+#ifdef SHOW_CONVERSION_COUNTS
+ ++created;
+#endif
+ }
+ return self;
+}
+
static PyObject *
dict_iter(dictobject *dict)
{
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 */
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 */
{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;
/* 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 */
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_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 */
};
};
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)
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. */
}
+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*/
"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
{"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},
};
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
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 */
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 *
#include "Python.h"
#include "compile.h"
+#include "eval.h"
#include "structmember.h"
PyObject *
};
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()) {
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()) {
}
}
- 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
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;
+}
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*/
"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
{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 */
/* 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 */
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_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 */
};
/* -------------------------------------- */
{NULL, NULL} /* sentinel */
};
-static PyObject *
-calliter_getattr(calliterobject *it, char *name)
-{
- return Py_FindMethod(calliter_methods, (PyObject *)it, name);
-}
-
static PyObject *
calliter_iternext(calliterobject *it)
{
/* 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 */
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_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 */
};
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
}
{
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);
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[] =
{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 */
(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,
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 */
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 */
};
{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)
{
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 */
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! */
};
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*/
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 */
};
#include "Python.h"
-#include "token.h"
-
static PyCFunctionObject *free_list = NULL;
PyObject *
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)
{
}
static PyObject *
-meth_getattr(PyCFunctionObject *m, char *name)
+meth_get__self__(PyCFunctionObject *m, void *closure)
{
- if (strcmp(name, "__name__") == 0) {
- return PyString_FromString(m->m_ml->ml_name);
- }
- if (strcmp(name, "__doc__") == 0) {
- char *doc = m->m_ml->ml_doc;
- if (doc != NULL)
- return PyString_FromString(doc);
- Py_INCREF(Py_None);
- return Py_None;
- }
- if (strcmp(name, "__self__") == 0) {
- PyObject *self;
- if (PyEval_GetRestricted()) {
- PyErr_SetString(PyExc_RuntimeError,
- "method.__self__ not accessible in restricted mode");
- return NULL;
- }
- self = m->m_self;
- if (self == NULL)
- self = Py_None;
- Py_INCREF(self);
- return self;
- }
- if (strcmp(name, "__members__") == 0) {
- return Py_BuildValue("[sss]",
- "__doc__", "__name__", "__self__");
+ PyObject *self;
+ if (PyEval_GetRestricted()) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "method.__self__ not accessible in restricted mode");
+ return NULL;
}
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
+ self = m->m_self;
+ if (self == NULL)
+ self = Py_None;
+ Py_INCREF(self);
+ return self;
}
+static struct getsetlist meth_getsets [] = {
+ {"__doc__", (getter)meth_get__doc__, NULL, NULL},
+ {"__name__", (getter)meth_get__name__, NULL, NULL},
+ {"__self__", (getter)meth_get__self__, NULL, NULL},
+ {0}
+};
+
static PyObject *
meth_repr(PyCFunctionObject *m)
{
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,
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 */
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 */
/* 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)
{
/* 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)
{
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. */
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 */
};
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);
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;
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
"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);
"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;
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);
}
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);
}
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
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. */
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
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
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.
{
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) {
Py_DECREF(call);
return 1;
}
- return 0;
+ else {
+ return x->ob_type->tp_call != NULL;
+ }
}
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
}
"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
*/
#include "Python.h"
+#include "structmember.h"
static PyObject *
ellipsis_repr(PyObject *op)
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)
"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 */
};
};
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
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 */
(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:
/* Type object implementation */
#include "Python.h"
+#include "structmember.h"
-/* Type object implementation */
+staticforward int add_members(PyTypeObject *, struct memberlist *);
+
+static struct memberlist type_members[] = {
+ {"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
+ {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
+ {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
+ {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
+ {"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY},
+ {"__weaklistoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
+ {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
+ {"__dictoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_dictoffset), READONLY},
+ {"__bases__", T_OBJECT, offsetof(PyTypeObject, tp_bases), READONLY},
+ {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
+ {0}
+};
+
+static PyObject *
+type_module(PyTypeObject *type, void *context)
+{
+ return PyString_FromString("__builtin__");
+}
static PyObject *
-type_getattr(PyTypeObject *t, char *name)
+type_dict(PyTypeObject *type, void *context)
{
- if (strcmp(name, "__name__") == 0)
- return PyString_FromString(t->tp_name);
- if (strcmp(name, "__doc__") == 0) {
- char *doc = t->tp_doc;
- if (doc != NULL)
- return PyString_FromString(doc);
+ if (type->tp_dict == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
- if (strcmp(name, "__members__") == 0)
- return Py_BuildValue("[ss]", "__doc__", "__name__");
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_dict);
+ return type->tp_dict;
+ }
+ return PyDictProxy_New(type->tp_dict);
+}
+
+static PyObject *
+type_defined(PyTypeObject *type, void *context)
+{
+ if (type->tp_defined == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_defined);
+ return type->tp_defined;
+ }
+ return PyDictProxy_New(type->tp_defined);
+}
+
+static PyObject *
+type_dynamic(PyTypeObject *type, void *context)
+{
+ PyObject *res;
+
+ res = (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ? Py_True : Py_False;
+ Py_INCREF(res);
+ return res;
}
+struct getsetlist type_getsets[] = {
+ {"__module__", (getter)type_module, NULL, NULL},
+ {"__dict__", (getter)type_dict, NULL, NULL},
+ {"__defined__", (getter)type_defined, NULL, NULL},
+ {"__dynamic__", (getter)type_dynamic, NULL, NULL},
+ {0}
+};
+
static int
type_compare(PyObject *v, PyObject *w)
{
}
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);
+}
{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 */
(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 */
/* 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 */
(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 */
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 -- */
{"xreadlines", initxreadlines},
{"_weakref", init_weakref},
+ {"xxsubtype", initxxsubtype},
+
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
/* -- ADDMODULE MARKER 2 -- */
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\Objects\descrobject.c\r
+\r
+!IF "$(CFG)" == "pythoncore - Win32 Release"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Debug"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Debug"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Release"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\Objects\dictobject.c\r
\r
!IF "$(CFG)" == "pythoncore - Win32 Release"\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\Modules\xxsubtype.c\r
+\r
+!IF "$(CFG)" == "pythoncore - Win32 Release"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Debug"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Debug"\r
+\r
+!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Release"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\Modules\yuvconvert.c\r
\r
!IF "$(CFG)" == "pythoncore - Win32 Release"\r
--- /dev/null
+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 ******************************************************************
extend to the end of the target object (or with the specified size).";
-static PyObject *
-builtin_unicode(PyObject *self, PyObject *args)
-{
- PyObject *v;
- char *encoding = NULL;
- char *errors = NULL;
-
- if ( !PyArg_ParseTuple(args, "O|ss:unicode", &v, &encoding, &errors) )
- return NULL;
- return PyUnicode_FromEncodedObject(v, encoding, errors);
-}
-
-static char unicode_doc[] =
-"unicode(string [, encoding[, errors]]) -> object\n\
-\n\
-Create a new Unicode object from the given encoded string.\n\
-encoding defaults to the current default string encoding and \n\
-errors, defining the error handling, to 'strict'.";
-
-
static PyObject *
builtin_callable(PyObject *self, PyObject *args)
{
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)
{
}
if (curlen < 0)
curlen = 8; /* arbitrary */
- if (curlen > len)
- len = curlen;
+ if (curlen > len)
+ len = curlen;
}
/* Get space for the result list. */
same value.";
-static PyObject *
-builtin_int(PyObject *self, PyObject *args)
-{
- PyObject *v;
- int base = -909; /* unlikely! */
-
- if (!PyArg_ParseTuple(args, "O|i:int", &v, &base))
- return NULL;
- if (base == -909)
- return PyNumber_Int(v);
- else if (PyString_Check(v))
- return PyInt_FromString(PyString_AS_STRING(v), NULL, base);
- else if (PyUnicode_Check(v))
- return PyInt_FromUnicode(PyUnicode_AS_UNICODE(v),
- PyUnicode_GET_SIZE(v),
- base);
- else {
- PyErr_SetString(PyExc_TypeError,
- "int() can't convert non-string with explicit base");
- return NULL;
- }
-}
-
-static char int_doc[] =
-"int(x[, base]) -> integer\n\
-\n\
-Convert a string or number to an integer, if possible. A floating point\n\
-argument will be truncated towards zero (this does not include a string\n\
-representation of a floating point number!) When converting a string, use\n\
-the optional base. It is an error to supply a base when converting a\n\
-non-string.";
-
-
-static PyObject *
-builtin_long(PyObject *self, PyObject *args)
-{
- PyObject *v;
- int base = -909; /* unlikely! */
-
- if (!PyArg_ParseTuple(args, "O|i:long", &v, &base))
- return NULL;
- if (base == -909)
- return PyNumber_Long(v);
- else if (PyString_Check(v))
- return PyLong_FromString(PyString_AS_STRING(v), NULL, base);
- else if (PyUnicode_Check(v))
- return PyLong_FromUnicode(PyUnicode_AS_UNICODE(v),
- PyUnicode_GET_SIZE(v),
- base);
- else {
- PyErr_SetString(PyExc_TypeError,
- "long() can't convert non-string with explicit base");
- return NULL;
- }
-}
-
-static char long_doc[] =
-"long(x) -> long integer\n\
-long(x, base) -> long integer\n\
-\n\
-Convert a string or number to a long integer, if possible. A floating\n\
-point argument will be truncated towards zero (this does not include a\n\
-string representation of a floating point number!) When converting a\n\
-string, use the given base. It is an error to supply a base when\n\
-converting a non-string.";
-
-
-static PyObject *
-builtin_float(PyObject *self, PyObject *args)
-{
- PyObject *v;
-
- if (!PyArg_ParseTuple(args, "O:float", &v))
- return NULL;
- if (PyString_Check(v))
- return PyFloat_FromString(v, NULL);
- return PyNumber_Float(v);
-}
-
-static char float_doc[] =
-"float(x) -> floating point number\n\
-\n\
-Convert a string or number to a floating point number, if possible.";
-
-
static PyObject *
builtin_iter(PyObject *self, PyObject *args)
{
Return the number of items of a sequence or mapping.";
-static PyObject *
-builtin_list(PyObject *self, PyObject *args)
-{
- PyObject *v;
-
- if (!PyArg_ParseTuple(args, "O:list", &v))
- return NULL;
- return PySequence_List(v);
-}
-
-static char list_doc[] =
-"list(sequence) -> list\n\
-\n\
-Return a new list whose items are the same as those of the argument sequence.";
-
-
static PyObject *
builtin_slice(PyObject *self, PyObject *args)
{
This always returns a floating point number. Precision may be negative.";
-static PyObject *
-builtin_str(PyObject *self, PyObject *args)
-{
- PyObject *v;
-
- if (!PyArg_ParseTuple(args, "O:str", &v))
- return NULL;
- return PyObject_Str(v);
-}
-
-static char str_doc[] =
-"str(object) -> string\n\
-\n\
-Return a nice string representation of the object.\n\
-If the argument is a string, the return value is the same object.";
-
-
-static PyObject *
-builtin_tuple(PyObject *self, PyObject *args)
-{
- PyObject *v;
-
- if (!PyArg_ParseTuple(args, "O:tuple", &v))
- return NULL;
- return PySequence_Tuple(v);
-}
-
-static char tuple_doc[] =
-"tuple(sequence) -> list\n\
-\n\
-Return a tuple whose items are the same as those of the argument sequence.\n\
-If the argument is a tuple, the return value is the same object.";
-
-
-static PyObject *
-builtin_type(PyObject *self, PyObject *args)
-{
- PyObject *v;
-
- if (!PyArg_ParseTuple(args, "O:type", &v))
- return NULL;
- v = (PyObject *)v->ob_type;
- Py_INCREF(v);
- return v;
-}
-
-static char type_doc[] =
-"type(object) -> type object\n\
-\n\
-Return the type of the object.";
-
-
static PyObject *
builtin_vars(PyObject *self, PyObject *args)
{
{"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},
{"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},
{"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},
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);
#include "frameobject.h"
#include "eval.h"
#include "opcode.h"
+#include "structmember.h"
#ifdef macintosh
#include "macglue.h"
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
/* Forward declarations */
-
-static PyObject *eval_code2(PyCodeObject *,
- PyObject *, PyObject *,
- PyObject **, int,
- PyObject **, int,
- PyObject **, int,
- PyObject *);
-
static PyObject *eval_frame(PyFrameObject *);
-static char *get_func_name(PyObject *);
-static char *get_func_desc(PyObject *);
static PyObject *call_object(PyObject *, PyObject *, PyObject *);
static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
#endif
#endif
-
staticforward PyTypeObject gentype;
typedef struct {
{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)
/* 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 */
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_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 */
};
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,
/* Interpreter main loop */
-PyObject *
+static PyObject *
eval_frame(PyFrameObject *f)
{
#ifdef DXPAIRS
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)
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)
{
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
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))
}
}
-static char *
-get_func_desc(PyObject *func)
+char *
+PyEval_GetFuncDesc(PyObject *func)
{
if (PyMethod_Check(func))
return "()";
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);
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),
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);
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);
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);
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;
}
}
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;
}
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);
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
\f
DL_EXPORT(void)
-init_exceptions(void)
+_PyExc_Init(void)
{
char *modulename = "exceptions";
int modnamesz = strlen(modulename);
int i;
-
- PyObject *me = Py_InitModule(modulename, functions);
- PyObject *mydict = PyModule_GetDict(me);
- PyObject *bltinmod = PyImport_ImportModule("__builtin__");
- PyObject *bdict = PyModule_GetDict(bltinmod);
- PyObject *doc = PyString_FromString(module__doc__);
- PyObject *args;
-
- PyDict_SetItemString(mydict, "__doc__", doc);
+ PyObject *me, *mydict, *bltinmod, *bdict, *doc, *args;
+
+ me = Py_InitModule(modulename, functions);
+ if (me == NULL)
+ goto err;
+ mydict = PyModule_GetDict(me);
+ if (mydict == NULL)
+ goto err;
+ bltinmod = PyImport_ImportModule("__builtin__");
+ if (bltinmod == NULL)
+ goto err;
+ bdict = PyModule_GetDict(bltinmod);
+ if (bdict == NULL)
+ goto err;
+ doc = PyString_FromString(module__doc__);
+ if (doc == NULL)
+ goto err;
+
+ i = PyDict_SetItemString(mydict, "__doc__", doc);
Py_DECREF(doc);
- if (PyErr_Occurred())
+ if (i < 0) {
+ err:
Py_FatalError("exceptions bootstrapping error.");
+ return;
+ }
/* This is the base class of all exceptions, so make it first. */
if (make_Exception(modulename) ||
DL_EXPORT(void)
-fini_exceptions(void)
+_PyExc_Fini(void)
{
int i;
/* 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
}
/* 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)
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");
_PyImport_Init();
/* initialize builtin exceptions */
- init_exceptions();
+ _PyExc_Init();
/* phase 2 of builtins */
_PyImport_FixupExtension("__builtin__", "__builtin__");
below has been checked to make sure no exceptions are ever
raised.
*/
- fini_exceptions();
+ _PyExc_Fini();
/* Delete current thread */
PyInterpreterState_Clear(interp);
{
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';