Merge of descr-branch back into trunk.

This commit is contained in:
Tim Peters 2001-08-02 04:15:00 +00:00
parent 52d55a3926
commit 6d6c1a35e0
57 changed files with 6923 additions and 1309 deletions

View File

@ -89,6 +89,7 @@
#include "sliceobject.h"
#include "cellobject.h"
#include "iterobject.h"
#include "descrobject.h"
#include "codecs.h"
#include "pyerrors.h"

View File

@ -294,6 +294,17 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
*/
DL_IMPORT(PyObject *) PyObject_Call(PyObject *callable_object,
PyObject *args, PyObject *kw);
/*
Call a callable Python object, callable_object, with
arguments and keywords arguments. The 'args' argument can not be
NULL, but the 'kw' argument can be NULL.
*/
DL_IMPORT(PyObject *) PyObject_CallObject(PyObject *callable_object,
PyObject *args);

View File

@ -45,6 +45,9 @@ DL_IMPORT(int) Py_MakePendingCalls(void);
DL_IMPORT(void) Py_SetRecursionLimit(int);
DL_IMPORT(int) Py_GetRecursionLimit(void);
DL_IMPORT(char *) PyEval_GetFuncName(PyObject *);
DL_IMPORT(char *) PyEval_GetFuncDesc(PyObject *);
/* Interface for threads.
A module that plans to do a blocking system call (or something else

View File

@ -47,10 +47,6 @@ extern DL_IMPORT(PyObject *) PyInstance_New(PyObject *, PyObject *,
extern DL_IMPORT(PyObject *) PyInstance_NewRaw(PyObject *, PyObject *);
extern DL_IMPORT(PyObject *) PyMethod_New(PyObject *, PyObject *, PyObject *);
extern DL_IMPORT(PyObject *) PyMethod_Function(PyObject *);
extern DL_IMPORT(PyObject *) PyMethod_Self(PyObject *);
extern DL_IMPORT(PyObject *) PyMethod_Class(PyObject *);
/* Macros for direct access to these values. Type checks are *not*
done, so use with care. */
#define PyMethod_GET_FUNCTION(meth) \

32
Include/descrobject.h Normal file
View File

@ -0,0 +1,32 @@
/* XXX getter, setter, getsetlist and wrapperbase need 'Py'-prefixed names */
typedef PyObject *(*getter)(PyObject *, void *);
typedef int (*setter)(PyObject *, PyObject *, void *);
struct getsetlist {
char *name;
getter get;
setter set;
void *closure;
};
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
void *wrapped);
struct wrapperbase {
char *name;
wrapperfunc wrapper;
char *doc;
};
extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
struct memberlist *);
extern DL_IMPORT(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
struct getsetlist *);
extern DL_IMPORT(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
struct wrapperbase *, void *);
extern DL_IMPORT(int) PyDescr_IsData(PyObject *);
extern DL_IMPORT(PyObject *) PyDictProxy_New(PyObject *);
extern DL_IMPORT(PyObject *) PyWrapper_New(PyObject *, PyObject *);

View File

@ -7,9 +7,83 @@ extern "C" {
/* Dictionary object type -- mapping from hashable object to object */
/*
There are three kinds of slots in the table:
1. Unused. me_key == me_value == NULL
Does not hold an active (key, value) pair now and never did. Unused can
transition to Active upon key insertion. This is the only case in which
me_key is NULL, and is each slot's initial state.
2. Active. me_key != NULL and me_key != dummy and me_value != NULL
Holds an active (key, value) pair. Active can transition to Dummy upon
key deletion. This is the only case in which me_value != NULL.
3. Dummy. me_key == dummy and me_value == NULL
Previously held an active (key, value) pair, but that was deleted and an
active pair has not yet overwritten the slot. Dummy can transition to
Active upon key insertion. Dummy slots cannot be made Unused again
(cannot have me_key set to NULL), else the probe sequence in case of
collision would have no way to know they were once active.
Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to
hold a search finger. The me_hash field of Unused or Dummy slots has no
meaning otherwise.
*/
/* PyDict_MINSIZE is the minimum size of a dictionary. This many slots are
* allocated directly in the dict object (in the ma_smalltable member).
* It must be a power of 2, and at least 4. 8 allows dicts with no more
* than 5 active entries to live in ma_smalltable (and so avoid an
* additional malloc); instrumentation suggested this suffices for the
* majority of dicts (consisting mostly of usually-small instance dicts and
* usually-small dicts created to pass keyword arguments).
*/
#define PyDict_MINSIZE 8
typedef struct {
long me_hash; /* cached hash code of me_key */
PyObject *me_key;
PyObject *me_value;
#ifdef USE_CACHE_ALIGNED
long aligner;
#endif
} PyDictEntry;
/*
To ensure the lookup algorithm terminates, there must be at least one Unused
slot (NULL key) in the table.
The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
values == the number of Active items).
To avoid slowing down lookups on a near-full table, we resize the table when
it's two-thirds full.
*/
typedef struct _dictobject PyDictObject;
struct _dictobject {
PyObject_HEAD
int ma_fill; /* # Active + # Dummy */
int ma_used; /* # Active */
/* The table contains ma_mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
int ma_mask;
/* ma_table points to ma_smalltable for small tables, else to
* additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and
* setitem calls.
*/
PyDictEntry *ma_table;
PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash);
PyDictEntry ma_smalltable[PyDict_MINSIZE];
};
extern DL_IMPORT(PyTypeObject) PyDict_Type;
#define PyDict_Check(op) ((op)->ob_type == &PyDict_Type)
#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type)
extern DL_IMPORT(PyObject *) PyDict_New(void);
extern DL_IMPORT(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
@ -23,6 +97,7 @@ extern DL_IMPORT(PyObject *) PyDict_Values(PyObject *mp);
extern DL_IMPORT(PyObject *) PyDict_Items(PyObject *mp);
extern DL_IMPORT(int) PyDict_Size(PyObject *mp);
extern DL_IMPORT(PyObject *) PyDict_Copy(PyObject *mp);
extern DL_IMPORT(int) PyDict_Update(PyObject *mp, PyObject *other);
extern DL_IMPORT(PyObject *) PyDict_GetItemString(PyObject *dp, char *key);

View File

@ -9,6 +9,14 @@ extern "C" {
DL_IMPORT(PyObject *) PyEval_EvalCode(PyCodeObject *, PyObject *, PyObject *);
DL_IMPORT(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
PyObject *globals,
PyObject *locals,
PyObject **args, int argc,
PyObject **kwds, int kwdc,
PyObject **defs, int defc,
PyObject *closure);
#ifdef __cplusplus
}
#endif

View File

@ -42,6 +42,13 @@ extern DL_IMPORT(int) PyFunction_SetClosure(PyObject *, PyObject *);
#define PyFunction_GET_CLOSURE(func) \
(((PyFunctionObject *)func) -> func_closure)
/* The classmethod and staticmethod types lives here, too */
extern DL_IMPORT(PyTypeObject) PyClassMethod_Type;
extern DL_IMPORT(PyTypeObject) PyStaticMethod_Type;
extern DL_IMPORT(PyObject *) PyClassMethod_New(PyObject *);
extern DL_IMPORT(PyObject *) PyStaticMethod_New(PyObject *);
#ifdef __cplusplus
}
#endif

View File

@ -26,7 +26,7 @@ typedef struct {
extern DL_IMPORT(PyTypeObject) PyList_Type;
#define PyList_Check(op) ((op)->ob_type == &PyList_Type)
#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type)
extern DL_IMPORT(PyObject *) PyList_New(int size);
extern DL_IMPORT(int) PyList_Size(PyObject *);

View File

@ -22,8 +22,8 @@ extern DL_IMPORT(int) PyModule_AddObject(PyObject *, char *, PyObject *);
extern DL_IMPORT(int) PyModule_AddIntConstant(PyObject *, char *, long);
extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
#define PYTHON_API_VERSION 1010
#define PYTHON_API_STRING "1010"
#define PYTHON_API_VERSION 1011
#define PYTHON_API_STRING "1011"
/* The API version is maintained (independently from the Python version)
so we can detect mismatches between the interpreter and dynamically
loaded modules. These are diagnosed by an error message but
@ -37,6 +37,8 @@ extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
Please add a line or two to the top of this log for each API
version change:
17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side
25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and
PyFrame_New(); Python 2.1a2

View File

@ -202,6 +202,11 @@ typedef long (*hashfunc)(PyObject *);
typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
typedef PyObject *(*getiterfunc) (PyObject *);
typedef PyObject *(*iternextfunc) (PyObject *);
typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
typedef PyObject *(*allocfunc)(struct _typeobject *, int);
typedef struct _typeobject {
PyObject_VAR_HEAD
@ -255,18 +260,48 @@ typedef struct _typeobject {
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods;
struct memberlist *tp_members;
struct getsetlist *tp_getset;
struct _typeobject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
long tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
destructor tp_free; /* Low-level free-memory routine */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_defined;
#ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */
int tp_alloc;
int tp_free;
int tp_allocs;
int tp_frees;
int tp_maxalloc;
struct _typeobject *tp_next;
#endif
} PyTypeObject;
extern DL_IMPORT(PyTypeObject) PyType_Type; /* The type of type objects */
#define PyType_Check(op) ((op)->ob_type == &PyType_Type)
/* Generic type check */
extern DL_IMPORT(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *);
#define PyObject_TypeCheck(ob, tp) \
((ob)->ob_type == (tp) || PyType_IsSubtype((ob)->ob_type, (tp)))
extern DL_IMPORT(PyTypeObject) PyType_Type; /* Metatype */
extern DL_IMPORT(PyTypeObject) PyBaseObject_Type; /* Most base object type */
#define PyType_Check(op) PyObject_TypeCheck(op, &PyType_Type)
extern DL_IMPORT(int) PyType_InitDict(PyTypeObject *);
extern DL_IMPORT(PyObject *) PyType_GenericAlloc(PyTypeObject *, int);
extern DL_IMPORT(PyObject *) PyType_GenericNew(PyTypeObject *,
PyObject *, PyObject *);
extern DL_IMPORT(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
/* Generic operations on objects */
extern DL_IMPORT(int) PyObject_Print(PyObject *, FILE *, int);
@ -283,6 +318,10 @@ extern DL_IMPORT(int) PyObject_HasAttrString(PyObject *, char *);
extern DL_IMPORT(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
extern DL_IMPORT(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
extern DL_IMPORT(int) PyObject_HasAttr(PyObject *, PyObject *);
extern DL_IMPORT(PyObject **) _PyObject_GetDictPtr(PyObject *);
extern DL_IMPORT(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
extern DL_IMPORT(int) PyObject_GenericSetAttr(PyObject *,
PyObject *, PyObject *);
extern DL_IMPORT(long) PyObject_Hash(PyObject *);
extern DL_IMPORT(int) PyObject_IsTrue(PyObject *);
extern DL_IMPORT(int) PyObject_Not(PyObject *);
@ -357,6 +396,18 @@ given type object has a specified feature.
/* tp_iter is defined */
#define Py_TPFLAGS_HAVE_ITER (1L<<7)
/* Experimental stuff for healing the type/class split */
#define Py_TPFLAGS_HAVE_CLASS (1L<<8)
/* Set if the type object is dynamically allocated */
#define Py_TPFLAGS_HEAPTYPE (1L<<9)
/* Set if the type allows subclassing */
#define Py_TPFLAGS_BASETYPE (1L<<10)
/* Set if the type's __dict__ may change */
#define Py_TPFLAGS_DYNAMICTYPE (1L<<11)
#define Py_TPFLAGS_DEFAULT ( \
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@ -364,6 +415,7 @@ given type object has a specified feature.
Py_TPFLAGS_HAVE_RICHCOMPARE | \
Py_TPFLAGS_HAVE_WEAKREFS | \
Py_TPFLAGS_HAVE_ITER | \
Py_TPFLAGS_HAVE_CLASS | \
0)
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
@ -412,8 +464,8 @@ extern DL_IMPORT(void) _Py_ResetReferences(void);
#ifndef Py_TRACE_REFS
#ifdef COUNT_ALLOCS
#define _Py_Dealloc(op) ((op)->ob_type->tp_free++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
#define _Py_ForgetReference(op) ((op)->ob_type->tp_free++)
#define _Py_Dealloc(op) ((op)->ob_type->tp_frees++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
#define _Py_ForgetReference(op) ((op)->ob_type->tp_frees++)
#else /* !COUNT_ALLOCS */
#define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op))
#define _Py_ForgetReference(op) /*empty*/

View File

@ -236,7 +236,13 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
#define PyObject_GC_Fini(op)
#define PyObject_AS_GC(op) (op)
#define PyObject_FROM_GC(op) (op)
#define PyType_IS_GC(t) 0
#define PyObject_IS_GC(o) 0
#define PyObject_AS_GC(o) (o)
#define PyObject_FROM_GC(o) (o)
#define PyType_BASICSIZE(t) ((t)->tp_basicsize)
#define PyType_SET_BASICSIZE(t, s) ((t)->tp_basicsize = (s))
#else
/* Add the object into the container set */
@ -269,6 +275,13 @@ typedef struct _gc_head {
/* Get the object given the PyGC_Head */
#define PyObject_FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
/* Calculate tp_basicsize excluding PyGC_HEAD_SIZE if applicable */
#define PyType_BASICSIZE(t) (!PyType_IS_GC(t) ? (t)->tp_basicsize : \
(t)->tp_basicsize - PyGC_HEAD_SIZE)
#define PyType_SET_BASICSIZE(t, s) (!PyType_IS_GC(t) ? \
((t)->tp_basicsize = (s)) : \
((t)->tp_basicsize = (s) + PyGC_HEAD_SIZE))
extern DL_IMPORT(void) _PyGC_Dump(PyGC_Head *);
#endif /* WITH_CYCLE_GC */

View File

@ -23,13 +23,13 @@
#define PY_MINOR_VERSION 2
#define PY_MICRO_VERSION 0
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
#define PY_RELEASE_SERIAL 0
#define PY_RELEASE_SERIAL 1
/* Version as a string */
#define PY_VERSION "2.2a0"
#define PY_VERSION "2.2a1"
/* Historic */
#define PATCHLEVEL "2.2a0"
#define PATCHLEVEL "2.2a1"
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */

View File

@ -92,10 +92,10 @@ DL_IMPORT(const char *) Py_GetBuildInfo(void);
DL_IMPORT(PyObject *) _PyBuiltin_Init(void);
DL_IMPORT(PyObject *) _PySys_Init(void);
DL_IMPORT(void) _PyImport_Init(void);
DL_IMPORT(void) init_exceptions(void);
DL_IMPORT(void) _PyExc_Init(void);
/* Various internal finalizers */
DL_IMPORT(void) fini_exceptions(void);
DL_IMPORT(void) _PyExc_Fini(void);
DL_IMPORT(void) _PyImport_Fini(void);
DL_IMPORT(void) PyMethod_Fini(void);
DL_IMPORT(void) PyFrame_Fini(void);

View File

@ -504,6 +504,7 @@ class Pickler:
dispatch[ClassType] = save_global
dispatch[FunctionType] = save_global
dispatch[BuiltinFunctionType] = save_global
dispatch[TypeType] = save_global
def _keep_alive(x, memo):

View File

@ -62,7 +62,7 @@ class Repr:
s = s + ': ' + self.repr1(x[key], level-1)
if n > self.maxdict: s = s + ', ...'
return '{' + s + '}'
def repr_string(self, x, level):
def repr_str(self, x, level):
s = `x[:self.maxstring]`
if len(s) > self.maxstring:
i = max(0, (self.maxstring-3)/2)
@ -70,7 +70,7 @@ class Repr:
s = `x[:i] + x[len(x)-j:]`
s = s[:i] + '...' + s[len(s)-j:]
return s
def repr_long_int(self, x, level):
def repr_long(self, x, level):
s = `x` # XXX Hope this isn't too slow...
if len(s) > self.maxlong:
i = max(0, (self.maxlong-3)/2)

829
Lib/test/test_descr.py Normal file
View File

@ -0,0 +1,829 @@
# Test descriptor-related enhancements
from test_support import verify, verbose
from copy import deepcopy
def testunop(a, res, expr="len(a)", meth="__len__"):
if verbose: print "checking", expr
dict = {'a': a}
verify(eval(expr, dict) == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
verify(m(a) == res)
bm = getattr(a, meth)
verify(bm() == res)
def testbinop(a, b, res, expr="a+b", meth="__add__"):
if verbose: print "checking", expr
dict = {'a': a, 'b': b}
verify(eval(expr, dict) == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
verify(m(a, b) == res)
bm = getattr(a, meth)
verify(bm(b) == res)
def testternop(a, b, c, res, expr="a[b:c]", meth="__getslice__"):
if verbose: print "checking", expr
dict = {'a': a, 'b': b, 'c': c}
verify(eval(expr, dict) == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
verify(m(a, b, c) == res)
bm = getattr(a, meth)
verify(bm(b, c) == res)
def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"):
if verbose: print "checking", stmt
dict = {'a': deepcopy(a), 'b': b}
exec stmt in dict
verify(dict['a'] == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
dict['a'] = deepcopy(a)
m(dict['a'], b)
verify(dict['a'] == res)
dict['a'] = deepcopy(a)
bm = getattr(dict['a'], meth)
bm(b)
verify(dict['a'] == res)
def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"):
if verbose: print "checking", stmt
dict = {'a': deepcopy(a), 'b': b, 'c': c}
exec stmt in dict
verify(dict['a'] == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
dict['a'] = deepcopy(a)
m(dict['a'], b, c)
verify(dict['a'] == res)
dict['a'] = deepcopy(a)
bm = getattr(dict['a'], meth)
bm(b, c)
verify(dict['a'] == res)
def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
if verbose: print "checking", stmt
dict = {'a': deepcopy(a), 'b': b, 'c': c, 'd': d}
exec stmt in dict
verify(dict['a'] == res)
t = type(a)
m = getattr(t, meth)
verify(m == t.__dict__[meth])
dict['a'] = deepcopy(a)
m(dict['a'], b, c, d)
verify(dict['a'] == res)
dict['a'] = deepcopy(a)
bm = getattr(dict['a'], meth)
bm(b, c, d)
verify(dict['a'] == res)
def lists():
if verbose: print "Testing list operations..."
testbinop([1], [2], [1,2], "a+b", "__add__")
testbinop([1,2,3], 2, 1, "b in a", "__contains__")
testbinop([1,2,3], 4, 0, "b in a", "__contains__")
testbinop([1,2,3], 1, 2, "a[b]", "__getitem__")
testternop([1,2,3], 0, 2, [1,2], "a[b:c]", "__getslice__")
testsetop([1], [2], [1,2], "a+=b", "__iadd__")
testsetop([1,2], 3, [1,2,1,2,1,2], "a*=b", "__imul__")
testunop([1,2,3], 3, "len(a)", "__len__")
testbinop([1,2], 3, [1,2,1,2,1,2], "a*b", "__mul__")
testbinop([1,2], 3, [1,2,1,2,1,2], "b*a", "__rmul__")
testset2op([1,2], 1, 3, [1,3], "a[b]=c", "__setitem__")
testset3op([1,2,3,4], 1, 3, [5,6], [1,5,6,4], "a[b:c]=d", "__setslice__")
def dicts():
if verbose: print "Testing dict operations..."
testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__")
testbinop({1:2,3:4}, 1, 1, "b in a", "__contains__")
testbinop({1:2,3:4}, 2, 0, "b in a", "__contains__")
testbinop({1:2,3:4}, 1, 2, "a[b]", "__getitem__")
d = {1:2,3:4}
l1 = []
for i in d.keys(): l1.append(i)
l = []
for i in iter(d): l.append(i)
verify(l == l1)
l = []
for i in d.__iter__(): l.append(i)
verify(l == l1)
l = []
for i in dictionary.__iter__(d): l.append(i)
verify(l == l1)
d = {1:2, 3:4}
testunop(d, 2, "len(a)", "__len__")
verify(eval(repr(d), {}) == d)
verify(eval(d.__repr__(), {}) == d)
testset2op({1:2,3:4}, 2, 3, {1:2,2:3,3:4}, "a[b]=c", "__setitem__")
binops = {
'add': '+',
'sub': '-',
'mul': '*',
'div': '/',
'mod': '%',
'divmod': 'divmod',
'pow': '**',
'lshift': '<<',
'rshift': '>>',
'and': '&',
'xor': '^',
'or': '|',
'cmp': 'cmp',
'lt': '<',
'le': '<=',
'eq': '==',
'ne': '!=',
'gt': '>',
'ge': '>=',
}
for name, expr in binops.items():
if expr.islower():
expr = expr + "(a, b)"
else:
expr = 'a %s b' % expr
binops[name] = expr
unops = {
'pos': '+',
'neg': '-',
'abs': 'abs',
'invert': '~',
'int': 'int',
'long': 'long',
'float': 'float',
'oct': 'oct',
'hex': 'hex',
}
for name, expr in unops.items():
if expr.islower():
expr = expr + "(a)"
else:
expr = '%s a' % expr
unops[name] = expr
def numops(a, b, skip=[]):
dict = {'a': a, 'b': b}
for name, expr in binops.items():
if name not in skip:
name = "__%s__" % name
if hasattr(a, name):
res = eval(expr, dict)
testbinop(a, b, res, expr, name)
for name, expr in unops.items():
name = "__%s__" % name
if hasattr(a, name):
res = eval(expr, dict)
testunop(a, res, expr, name)
def ints():
if verbose: print "Testing int operations..."
numops(100, 3)
def longs():
if verbose: print "Testing long operations..."
numops(100L, 3L)
def floats():
if verbose: print "Testing float operations..."
numops(100.0, 3.0)
def complexes():
if verbose: print "Testing complex operations..."
numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge'])
class Number(complex):
__slots__ = ['prec']
def __init__(self, *args, **kwds):
self.prec = kwds.get('prec', 12)
def __repr__(self):
prec = self.prec
if self.imag == 0.0:
return "%.*g" % (prec, self.real)
if self.real == 0.0:
return "%.*gj" % (prec, self.imag)
return "(%.*g+%.*gj)" % (prec, self.real, prec, self.imag)
__str__ = __repr__
a = Number(3.14, prec=6)
verify(`a` == "3.14")
verify(a.prec == 6)
def spamlists():
if verbose: print "Testing spamlist operations..."
import copy, xxsubtype as spam
def spamlist(l, memo=None):
import xxsubtype as spam
return spam.spamlist(l)
# This is an ugly hack:
copy._deepcopy_dispatch[spam.spamlist] = spamlist
testbinop(spamlist([1]), spamlist([2]), spamlist([1,2]), "a+b", "__add__")
testbinop(spamlist([1,2,3]), 2, 1, "b in a", "__contains__")
testbinop(spamlist([1,2,3]), 4, 0, "b in a", "__contains__")
testbinop(spamlist([1,2,3]), 1, 2, "a[b]", "__getitem__")
testternop(spamlist([1,2,3]), 0, 2, spamlist([1,2]),
"a[b:c]", "__getslice__")
testsetop(spamlist([1]), spamlist([2]), spamlist([1,2]),
"a+=b", "__iadd__")
testsetop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*=b", "__imul__")
testunop(spamlist([1,2,3]), 3, "len(a)", "__len__")
testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*b", "__mul__")
testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "b*a", "__rmul__")
testset2op(spamlist([1,2]), 1, 3, spamlist([1,3]), "a[b]=c", "__setitem__")
testset3op(spamlist([1,2,3,4]), 1, 3, spamlist([5,6]),
spamlist([1,5,6,4]), "a[b:c]=d", "__setslice__")
# Test subclassing
class C(spam.spamlist):
def foo(self): return 1
a = C()
verify(a == [])
verify(a.foo() == 1)
a.append(100)
verify(a == [100])
verify(a.getstate() == 0)
a.setstate(42)
verify(a.getstate() == 42)
def spamdicts():
if verbose: print "Testing spamdict operations..."
import copy, xxsubtype as spam
def spamdict(d, memo=None):
import xxsubtype as spam
sd = spam.spamdict()
for k, v in d.items(): sd[k] = v
return sd
# This is an ugly hack:
copy._deepcopy_dispatch[spam.spamdict] = spamdict
testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__")
testbinop(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__")
testbinop(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__")
testbinop(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__")
d = spamdict({1:2,3:4})
l1 = []
for i in d.keys(): l1.append(i)
l = []
for i in iter(d): l.append(i)
verify(l == l1)
l = []
for i in d.__iter__(): l.append(i)
verify(l == l1)
l = []
for i in type(spamdict({})).__iter__(d): l.append(i)
verify(l == l1)
straightd = {1:2, 3:4}
spamd = spamdict(straightd)
testunop(spamd, 2, "len(a)", "__len__")
testunop(spamd, repr(straightd), "repr(a)", "__repr__")
testset2op(spamdict({1:2,3:4}), 2, 3, spamdict({1:2,2:3,3:4}),
"a[b]=c", "__setitem__")
# Test subclassing
class C(spam.spamdict):
def foo(self): return 1
a = C()
verify(a.items() == [])
verify(a.foo() == 1)
a['foo'] = 'bar'
verify(a.items() == [('foo', 'bar')])
verify(a.getstate() == 0)
a.setstate(100)
verify(a.getstate() == 100)
def pydicts():
if verbose: print "Testing Python subclass of dict..."
verify(issubclass(dictionary, dictionary))
verify(isinstance({}, dictionary))
d = dictionary()
verify(d == {})
verify(d.__class__ is dictionary)
verify(isinstance(d, dictionary))
class C(dictionary):
state = -1
def __init__(self, *a, **kw):
if a:
assert len(a) == 1
self.state = a[0]
if kw:
for k, v in kw.items(): self[v] = k
def __getitem__(self, key):
return self.get(key, 0)
def __setitem__(self, key, value):
assert isinstance(key, type(0))
dictionary.__setitem__(self, key, value)
def setstate(self, state):
self.state = state
def getstate(self):
return self.state
verify(issubclass(C, dictionary))
a1 = C(12)
verify(a1.state == 12)
a2 = C(foo=1, bar=2)
verify(a2[1] == 'foo' and a2[2] == 'bar')
a = C()
verify(a.state == -1)
verify(a.getstate() == -1)
a.setstate(0)
verify(a.state == 0)
verify(a.getstate() == 0)
a.setstate(10)
verify(a.state == 10)
verify(a.getstate() == 10)
verify(a[42] == 0)
a[42] = 24
verify(a[42] == 24)
if verbose: print "pydict stress test ..."
N = 50
for i in range(N):
a[i] = C()
for j in range(N):
a[i][j] = i*j
for i in range(N):
for j in range(N):
verify(a[i][j] == i*j)
def pylists():
if verbose: print "Testing Python subclass of list..."
class C(list):
def __getitem__(self, i):
return list.__getitem__(self, i) + 100
def __getslice__(self, i, j):
return (i, j)
a = C()
a.extend([0,1,2])
verify(a[0] == 100)
verify(a[1] == 101)
verify(a[2] == 102)
verify(a[100:200] == (100,200))
def metaclass():
if verbose: print "Testing __metaclass__..."
global C
class C:
__metaclass__ = type
def __init__(self):
self.__state = 0
def getstate(self):
return self.__state
def setstate(self, state):
self.__state = state
a = C()
verify(a.getstate() == 0)
a.setstate(10)
verify(a.getstate() == 10)
class D:
class __metaclass__(type):
def myself(cls): return cls
verify(D.myself() == D)
import sys
MT = type(sys)
def pymods():
if verbose: print "Testing Python subclass of module..."
global log
log = []
class MM(MT):
def __init__(self):
MT.__init__(self)
def __getattr__(self, name):
log.append(("getattr", name))
return MT.__getattr__(self, name)
def __setattr__(self, name, value):
log.append(("setattr", name, value))
MT.__setattr__(self, name, value)
def __delattr__(self, name):
log.append(("delattr", name))
MT.__delattr__(self, name)
a = MM()
a.foo = 12
x = a.foo
del a.foo
verify(log == [('getattr', '__init__'),
('getattr', '__setattr__'),
("setattr", "foo", 12),
("getattr", "foo"),
('getattr', '__delattr__'),
("delattr", "foo")], log)
def multi():
if verbose: print "Testing multiple inheritance..."
global C
class C(object):
def __init__(self):
self.__state = 0
def getstate(self):
return self.__state
def setstate(self, state):
self.__state = state
a = C()
verify(a.getstate() == 0)
a.setstate(10)
verify(a.getstate() == 10)
class D(dictionary, C):
def __init__(self):
type({}).__init__(self)
C.__init__(self)
d = D()
verify(d.keys() == [])
d["hello"] = "world"
verify(d.items() == [("hello", "world")])
verify(d["hello"] == "world")
verify(d.getstate() == 0)
d.setstate(10)
verify(d.getstate() == 10)
verify(D.__mro__ == (D, dictionary, C, object))
def diamond():
if verbose: print "Testing multiple inheritance special cases..."
class A(object):
def spam(self): return "A"
verify(A().spam() == "A")
class B(A):
def boo(self): return "B"
def spam(self): return "B"
verify(B().spam() == "B")
verify(B().boo() == "B")
class C(A):
def boo(self): return "C"
verify(C().spam() == "A")
verify(C().boo() == "C")
class D(B, C): pass
verify(D().spam() == "B")
verify(D().boo() == "B")
verify(D.__mro__ == (D, B, C, A, object))
class E(C, B): pass
verify(E().spam() == "B")
verify(E().boo() == "C")
verify(E.__mro__ == (E, C, B, A, object))
class F(D, E): pass
verify(F().spam() == "B")
verify(F().boo() == "B")
verify(F.__mro__ == (F, D, E, B, C, A, object))
class G(E, D): pass
verify(G().spam() == "B")
verify(G().boo() == "C")
verify(G.__mro__ == (G, E, D, C, B, A, object))
def objects():
if verbose: print "Testing object class..."
a = object()
verify(a.__class__ == object == type(a))
b = object()
verify(a is not b)
verify(not hasattr(a, "foo"))
try:
a.foo = 12
except TypeError:
pass
else:
verify(0, "object() should not allow setting a foo attribute")
verify(not hasattr(object(), "__dict__"))
class Cdict(object):
pass
x = Cdict()
verify(x.__dict__ is None)
x.foo = 1
verify(x.foo == 1)
verify(x.__dict__ == {'foo': 1})
def slots():
if verbose: print "Testing __slots__..."
class C0(object):
__slots__ = []
x = C0()
verify(not hasattr(x, "__dict__"))
verify(not hasattr(x, "foo"))
class C1(object):
__slots__ = ['a']
x = C1()
verify(not hasattr(x, "__dict__"))
verify(x.a == None)
x.a = 1
verify(x.a == 1)
del x.a
verify(x.a == None)
class C3(object):
__slots__ = ['a', 'b', 'c']
x = C3()
verify(not hasattr(x, "__dict__"))
verify(x.a is None)
verify(x.b is None)
verify(x.c is None)
x.a = 1
x.b = 2
x.c = 3
verify(x.a == 1)
verify(x.b == 2)
verify(x.c == 3)
def dynamics():
if verbose: print "Testing __dynamic__..."
verify(object.__dynamic__ == 0)
verify(list.__dynamic__ == 0)
class S1:
__metaclass__ = type
verify(S1.__dynamic__ == 0)
class S(object):
pass
verify(C.__dynamic__ == 0)
class D(object):
__dynamic__ = 1
verify(D.__dynamic__ == 1)
class E(D, S):
pass
verify(E.__dynamic__ == 1)
class F(S, D):
pass
verify(F.__dynamic__ == 1)
try:
S.foo = 1
except (AttributeError, TypeError):
pass
else:
verify(0, "assignment to a static class attribute should be illegal")
D.foo = 1
verify(D.foo == 1)
# Test that dynamic attributes are inherited
verify(E.foo == 1)
verify(F.foo == 1)
class SS(D):
__dynamic__ = 0
verify(SS.__dynamic__ == 0)
verify(SS.foo == 1)
try:
SS.foo = 1
except (AttributeError, TypeError):
pass
else:
verify(0, "assignment to SS.foo should be illegal")
def errors():
if verbose: print "Testing errors..."
try:
class C(list, dictionary):
pass
except TypeError:
pass
else:
verify(0, "inheritance from both list and dict should be illegal")
try:
class C(object, None):
pass
except TypeError:
pass
else:
verify(0, "inheritance from non-type should be illegal")
class Classic:
pass
try:
class C(object, Classic):
pass
except TypeError:
pass
else:
verify(0, "inheritance from object and Classic should be illegal")
try:
class C(int):
pass
except TypeError:
pass
else:
verify(0, "inheritance from int should be illegal")
try:
class C(object):
__slots__ = 1
except TypeError:
pass
else:
verify(0, "__slots__ = 1 should be illegal")
try:
class C(object):
__slots__ = [1]
except TypeError:
pass
else:
verify(0, "__slots__ = [1] should be illegal")
def classmethods():
if verbose: print "Testing class methods..."
class C(object):
def foo(*a): return a
goo = classmethod(foo)
c = C()
verify(C.goo(1) == (C, 1))
verify(c.goo(1) == (C, 1))
verify(c.foo(1) == (c, 1))
class D(C):
pass
d = D()
verify(D.goo(1) == (D, 1))
verify(d.goo(1) == (D, 1))
verify(d.foo(1) == (d, 1))
verify(D.foo(d, 1) == (d, 1))
def staticmethods():
if verbose: print "Testing static methods..."
class C(object):
def foo(*a): return a
goo = staticmethod(foo)
c = C()
verify(C.goo(1) == (1,))
verify(c.goo(1) == (1,))
verify(c.foo(1) == (c, 1,))
class D(C):
pass
d = D()
verify(D.goo(1) == (1,))
verify(d.goo(1) == (1,))
verify(d.foo(1) == (d, 1))
verify(D.foo(d, 1) == (d, 1))
def classic():
if verbose: print "Testing classic classes..."
class C:
def foo(*a): return a
goo = classmethod(foo)
c = C()
verify(C.goo(1) == (C, 1))
verify(c.goo(1) == (C, 1))
verify(c.foo(1) == (c, 1))
class D(C):
pass
d = D()
verify(D.goo(1) == (D, 1))
verify(d.goo(1) == (D, 1))
verify(d.foo(1) == (d, 1))
verify(D.foo(d, 1) == (d, 1))
def compattr():
if verbose: print "Testing computed attributes..."
class C(object):
class computed_attribute(object):
def __init__(self, get, set=None):
self.__get = get
self.__set = set
def __get__(self, obj, type=None):
return self.__get(obj)
def __set__(self, obj, value):
return self.__set(obj, value)
def __init__(self):
self.__x = 0
def __get_x(self):
x = self.__x
self.__x = x+1
return x
def __set_x(self, x):
self.__x = x
x = computed_attribute(__get_x, __set_x)
a = C()
verify(a.x == 0)
verify(a.x == 1)
a.x = 10
verify(a.x == 10)
verify(a.x == 11)
def newslot():
if verbose: print "Testing __new__ slot override..."
class C(list):
def __new__(cls):
self = list.__new__(cls)
self.foo = 1
return self
def __init__(self):
self.foo = self.foo + 2
a = C()
verify(a.foo == 3)
verify(a.__class__ is C)
class D(C):
pass
b = D()
verify(b.foo == 3)
verify(b.__class__ is D)
class PerverseMetaType(type):
def mro(cls):
L = type.mro(cls)
L.reverse()
return L
def altmro():
if verbose: print "Testing mro() and overriding it..."
class A(object):
def f(self): return "A"
class B(A):
pass
class C(A):
def f(self): return "C"
class D(B, C):
pass
verify(D.mro() == [D, B, C, A, object] == list(D.__mro__))
verify(D().f() == "C")
class X(A,B,C,D):
__metaclass__ = PerverseMetaType
verify(X.__mro__ == (object, A, C, B, D, X))
verify(X().f() == "A")
def overloading():
if verbose: print "testing operator overloading..."
class B(object):
"Intermediate class because object doesn't have a __setattr__"
class C(B):
def __getattr__(self, name):
if name == "foo":
return ("getattr", name)
else:
return B.__getattr__(self, name)
def __setattr__(self, name, value):
if name == "foo":
self.setattr = (name, value)
else:
return B.__setattr__(self, name, value)
def __delattr__(self, name):
if name == "foo":
self.delattr = name
else:
return B.__delattr__(self, name)
def __getitem__(self, key):
return ("getitem", key)
def __setitem__(self, key, value):
self.setitem = (key, value)
def __delitem__(self, key):
self.delitem = key
def __getslice__(self, i, j):
return ("getslice", i, j)
def __setslice__(self, i, j, value):
self.setslice = (i, j, value)
def __delslice__(self, i, j):
self.delslice = (i, j)
a = C()
verify(a.foo == ("getattr", "foo"))
a.foo = 12
verify(a.setattr == ("foo", 12))
del a.foo
verify(a.delattr == "foo")
verify(a[12] == ("getitem", 12))
a[12] = 21
verify(a.setitem == (12, 21))
del a[12]
verify(a.delitem == 12)
verify(a[0:10] == ("getslice", 0, 10))
a[0:10] = "foo"
verify(a.setslice == (0, 10, "foo"))
del a[0:10]
verify(a.delslice == (0, 10))
def all():
lists()
dicts()
ints()
longs()
floats()
complexes()
spamlists()
spamdicts()
pydicts()
pylists()
metaclass()
pymods()
multi()
diamond()
objects()
slots()
dynamics()
errors()
classmethods()
staticmethods()
classic()
compattr()
newslot()
altmro()
overloading()
all()
if verbose: print "All OK"

View File

@ -380,10 +380,16 @@ From the Iterators list, about the types of these things.
>>> i = g()
>>> type(i)
<type 'generator'>
XXX dir(object) *generally* doesn't return useful stuff in descr-branch.
>>> dir(i)
[]
Was hoping to see this instead:
['gi_frame', 'gi_running', 'next']
>>> print i.next.__doc__
next() -- get the next value, or raise StopIteration
x.next() -> the next value, or raise StopIteration
>>> iter(i) is i
1
>>> import types
@ -399,7 +405,7 @@ And more, added later.
>>> i.gi_running = 42
Traceback (most recent call last):
...
TypeError: object has read-only attributes
TypeError: 'generator' object has only read-only attributes (assign to .gi_running)
>>> def g():
... yield me.gi_running
>>> me = g()

View File

@ -7,7 +7,8 @@ from __future__ import generators
import sys
NoneType = type(None)
TypeType = type(NoneType)
TypeType = type
ObjectType = object
IntType = type(0)
LongType = type(0L)
@ -22,8 +23,8 @@ UnicodeType = type(u'')
BufferType = type(buffer(''))
TupleType = type(())
ListType = type([])
DictType = DictionaryType = type({})
ListType = list
DictType = DictionaryType = dictionary
def _f(): pass
FunctionType = type(_f)
@ -71,4 +72,9 @@ except TypeError:
SliceType = type(slice(0))
EllipsisType = type(Ellipsis)
DictIterType = type(iter({}))
SequenceIterType = type(iter([]))
FunctionIterType = type(iter(lambda: 0, 0))
DictProxyType = type(TypeType.__dict__)
del sys, _f, _C, _x # Not for export

View File

@ -237,6 +237,7 @@ OBJECT_OBJS= \
Objects/classobject.o \
Objects/cobject.o \
Objects/complexobject.o \
Objects/descrobject.o \
Objects/fileobject.o \
Objects/floatobject.o \
Objects/frameobject.o \
@ -438,6 +439,7 @@ PYTHON_HEADERS= \
Include/tupleobject.h \
Include/listobject.h \
Include/iterobject.h \
Include/descrobject.h \
Include/dictobject.h \
Include/methodobject.h \
Include/moduleobject.h \

View File

@ -44,6 +44,17 @@ What's New in Python 2.2a1?
Core
- TENTATIVELY, a large amount of code implementing much of what's
described in PEP 252 (Making Types Look More Like Classes) and PEP
253 (Subtyping Built-in Types) was added. This will be released
with Python 2.2a1. Documentation will be provided separately
through http://www.python.org/2.2/. The purpose of releasing this
with Python 2.2a1 is to test backwards compatibility. It is
possible, though not likely, that a decision is made not to release
this code as part of 2.2 final, if any serious backwards
incompapatibilities are found during alpha testing that cannot be
repaired.
- Generators were added; this is a new way to create an iterator (see
below) using what looks like a simple function containing one or
more 'yield' statements. See PEP 255. Since this adds a new

View File

@ -464,3 +464,5 @@ GLHACK=-Dclear=__GLclear
# Example -- included for reference only:
# xx xxmodule.c
# Another example -- the 'xxsubtype' module shows C-level subtyping in action
xxsubtype xxsubtype.c

View File

@ -1869,6 +1869,10 @@ save(Picklerobject *self, PyObject *args, int pers_save) {
res = save_tuple(self, args);
goto finally;
}
if (type == &PyType_Type) {
res = save_global(self, args, NULL);
goto finally;
}
break;
case 'l':

View File

@ -37,7 +37,7 @@ struct _inittab _PyImport_Inittab[] = {
{"__main__", NULL},
{"__builtin__", NULL},
{"sys", NULL},
{"exceptions", init_exceptions},
{"exceptions", NULL},
/* Sentinel */
{0, 0}

233
Modules/xxsubtype.c Normal file
View File

@ -0,0 +1,233 @@
#include "Python.h"
/* Examples showing how to subtype the builtin list and dict types from C. */
/* spamlist -- a list subtype */
typedef struct {
PyListObject list;
int state;
} spamlistobject;
static PyObject *
spamlist_getstate(spamlistobject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":getstate"))
return NULL;
return PyInt_FromLong(self->state);
}
static PyObject *
spamlist_setstate(spamlistobject *self, PyObject *args)
{
int state;
if (!PyArg_ParseTuple(args, "i:setstate", &state))
return NULL;
self->state = state;
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef spamlist_methods[] = {
{"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
"getstate() -> state"},
{"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
"setstate(state)"},
{NULL, NULL},
};
staticforward PyTypeObject spamlist_type;
static int
spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
{
if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject spamlist_type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"spamlist",
sizeof(spamlistobject),
0,
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
spamlist_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyList_Type, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)spamlist_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
/* spamdict -- a dict subtype */
typedef struct {
PyDictObject dict;
int state;
} spamdictobject;
static PyObject *
spamdict_getstate(spamdictobject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":getstate"))
return NULL;
return PyInt_FromLong(self->state);
}
static PyObject *
spamdict_setstate(spamdictobject *self, PyObject *args)
{
int state;
if (!PyArg_ParseTuple(args, "i:setstate", &state))
return NULL;
self->state = state;
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef spamdict_methods[] = {
{"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
"getstate() -> state"},
{"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
"setstate(state)"},
{NULL, NULL},
};
staticforward PyTypeObject spamdict_type;
static int
spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
{
if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject spamdict_type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"spamdict",
sizeof(spamdictobject),
0,
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
spamdict_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyDict_Type, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)spamdict_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
PyObject *
spam_bench(PyObject *self, PyObject *args)
{
PyObject *obj, *name, *res;
int n = 1000;
time_t t0, t1;
if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n))
return NULL;
t0 = clock();
while (--n >= 0) {
res = PyObject_GetAttr(obj, name);
if (res == NULL)
return NULL;
Py_DECREF(res);
}
t1 = clock();
return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
}
static PyMethodDef xxsubtype_functions[] = {
{"bench", spam_bench, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
DL_EXPORT(void)
initxxsubtype(void)
{
PyObject *m, *d;
m = Py_InitModule("xxsubtype", xxsubtype_functions);
if (m == NULL)
return;
if (PyType_InitDict(&spamlist_type) < 0)
return;
if (PyType_InitDict(&spamdict_type) < 0)
return;
d = PyModule_GetDict(m);
if (d == NULL)
return;
Py_INCREF(&spamlist_type);
if (PyDict_SetItemString(d, "spamlist",
(PyObject *) &spamlist_type) < 0)
return;
Py_INCREF(&spamdict_type);
if (PyDict_SetItemString(d, "spamdict",
(PyObject *) &spamdict_type) < 0)
return;
}

View File

@ -1588,6 +1588,24 @@ PyObject_CallObject(PyObject *o, PyObject *a)
return r;
}
PyObject *
PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
{
ternaryfunc call;
if ((call = func->ob_type->tp_call) != NULL) {
PyObject *result = (*call)(func, arg, kw);
if (result == NULL && !PyErr_Occurred())
PyErr_SetString(
PyExc_SystemError,
"NULL result without error in PyObject_Call");
return result;
}
PyErr_Format(PyExc_TypeError, "object is not callable: %s",
PyString_AS_STRING(PyObject_Repr(func)));
return NULL;
}
PyObject *
PyObject_CallFunction(PyObject *callable, char *format, ...)
{
@ -1746,7 +1764,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
}
}
else if (PyType_Check(cls)) {
retval = ((PyObject *)(inst->ob_type) == cls);
retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
}
else if (!PyInstance_Check(inst)) {
if (__class__ == NULL) {

View File

@ -537,21 +537,21 @@ PyTypeObject PyBuffer_Type = {
"buffer",
sizeof(PyBufferObject),
0,
(destructor)buffer_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)buffer_compare, /*tp_compare*/
(reprfunc)buffer_repr, /*tp_repr*/
0, /*tp_as_number*/
&buffer_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)buffer_hash, /*tp_hash*/
0, /*tp_call*/
(reprfunc)buffer_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
&buffer_as_buffer, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
(destructor)buffer_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)buffer_compare, /* tp_compare */
(reprfunc)buffer_repr, /* tp_repr */
0, /* tp_as_number */
&buffer_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)buffer_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)buffer_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&buffer_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
};

View File

@ -106,7 +106,7 @@ PyTypeObject PyCell_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */

View File

@ -36,12 +36,12 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
return NULL;
}
if (name == NULL || !PyString_Check(name)) {
PyErr_SetString(PyExc_SystemError,
PyErr_SetString(PyExc_TypeError,
"PyClass_New: name must be a string");
return NULL;
}
if (dict == NULL || !PyDict_Check(dict)) {
PyErr_SetString(PyExc_SystemError,
PyErr_SetString(PyExc_TypeError,
"PyClass_New: dict must be a dictionary");
return NULL;
}
@ -67,14 +67,14 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
else {
int i;
if (!PyTuple_Check(bases)) {
PyErr_SetString(PyExc_SystemError,
PyErr_SetString(PyExc_TypeError,
"PyClass_New: bases must be a tuple");
return NULL;
}
i = PyTuple_Size(bases);
while (--i >= 0) {
if (!PyClass_Check(PyTuple_GetItem(bases, i))) {
PyErr_SetString(PyExc_SystemError,
PyErr_SetString(PyExc_TypeError,
"PyClass_New: base must be a class");
return NULL;
}
@ -106,6 +106,18 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
return (PyObject *) op;
}
static PyObject *
class_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *name, *bases, *dict;
static char *kwlist[] = {"name", "bases", "dict", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist,
&name, &bases, &dict))
return NULL;
return PyClass_New(bases, dict, name);
}
/* Class methods */
static void
@ -149,6 +161,8 @@ class_getattr(register PyClassObject *op, PyObject *name)
register PyObject *v;
register char *sname = PyString_AsString(name);
PyClassObject *class;
descrgetfunc f;
if (sname[0] == '_' && sname[1] == '_') {
if (strcmp(sname, "__dict__") == 0) {
if (PyEval_GetRestricted()) {
@ -186,6 +200,11 @@ class_getattr(register PyClassObject *op, PyObject *name)
Py_DECREF(v);
v = w;
}
f = v->ob_type->tp_descr_get;
if (f == NULL)
Py_INCREF(v);
else
v = f(v, (PyObject *)NULL, (PyObject *)op);
return v;
}
@ -396,7 +415,7 @@ PyTypeObject PyClass_Type = {
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
PyInstance_New, /* tp_call */
(reprfunc)class_str, /* tp_str */
(getattrofunc)class_getattr, /* tp_getattro */
(setattrofunc)class_setattr, /* tp_setattro */
@ -404,6 +423,22 @@ PyTypeObject PyClass_Type = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)class_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
class_new, /* tp_new */
};
int
@ -531,7 +566,7 @@ instance_dealloc(register PyInstanceObject *inst)
/* compensate for boost in _Py_NewReference; note that
* _Py_RefTotal was also boosted; we'll knock that down later.
*/
inst->ob_type->tp_alloc--;
inst->ob_type->tp_allocs--;
#endif
#else /* !Py_TRACE_REFS */
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
@ -564,7 +599,7 @@ instance_dealloc(register PyInstanceObject *inst)
#endif
if (--inst->ob_refcnt > 0) {
#ifdef COUNT_ALLOCS
inst->ob_type->tp_free--;
inst->ob_type->tp_frees--;
#endif
return; /* __del__ added a reference; don't delete now */
}
@ -572,7 +607,7 @@ instance_dealloc(register PyInstanceObject *inst)
_Py_ForgetReference((PyObject *)inst);
#ifdef COUNT_ALLOCS
/* compensate for increment in _Py_ForgetReference */
inst->ob_type->tp_free--;
inst->ob_type->tp_frees--;
#endif
#ifndef WITH_CYCLE_GC
inst->ob_type = NULL;
@ -619,6 +654,8 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
{
register PyObject *v;
PyClassObject *class;
descrgetfunc f;
class = NULL;
v = PyDict_GetItem(inst->in_dict, name);
if (v == NULL) {
@ -628,17 +665,20 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
}
Py_INCREF(v);
if (class != NULL) {
if (PyFunction_Check(v)) {
PyObject *w = PyMethod_New(v, (PyObject *)inst,
(PyObject *)class);
f = v->ob_type->tp_descr_get;
if (f != NULL) {
PyObject *w = f(v, (PyObject *)inst,
(PyObject *)(inst->in_class));
Py_DECREF(v);
v = w;
}
else if (PyMethod_Check(v)) {
PyObject *im_class = PyMethod_Class(v);
/* XXX This should be a tp_descr_get slot of
PyMethodObjects */
PyObject *im_class = PyMethod_GET_CLASS(v);
/* Only if classes are compatible */
if (PyClass_IsSubclass((PyObject *)class, im_class)) {
PyObject *im_func = PyMethod_Function(v);
PyObject *im_func = PyMethod_GET_FUNCTION(v);
PyObject *w = PyMethod_New(im_func,
(PyObject *)inst, im_class);
Py_DECREF(v);
@ -1814,6 +1854,23 @@ instance_iternext(PyInstanceObject *self)
return NULL;
}
static PyObject *
instance_call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
if (call == NULL) {
PyInstanceObject *inst = (PyInstanceObject*) func;
PyErr_Clear();
PyErr_Format(PyExc_AttributeError,
"%.200s instance has no __call__ method",
PyString_AsString(inst->in_class->cl_name));
return NULL;
}
res = PyObject_Call(call, arg, kw);
Py_DECREF(call);
return res;
}
static PyNumberMethods instance_as_number = {
(binaryfunc)instance_add, /* nb_add */
@ -1868,7 +1925,7 @@ PyTypeObject PyInstance_Type = {
&instance_as_sequence, /* tp_as_sequence */
&instance_as_mapping, /* tp_as_mapping */
(hashfunc)instance_hash, /* tp_hash */
0, /* tp_call */
instance_call, /* tp_call */
(reprfunc)instance_str, /* tp_str */
(getattrofunc)instance_getattr, /* tp_getattro */
(setattrofunc)instance_setattr, /* tp_setattro */
@ -1921,36 +1978,6 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
return (PyObject *)im;
}
PyObject *
PyMethod_Function(register PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_func;
}
PyObject *
PyMethod_Self(register PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_self;
}
PyObject *
PyMethod_Class(register PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_class;
}
/* Class method methods */
#define OFF(x) offsetof(PyMethodObject, x)
@ -2028,43 +2055,52 @@ instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
static PyObject *
instancemethod_repr(PyMethodObject *a)
{
char buf[240];
PyInstanceObject *self = (PyInstanceObject *)(a->im_self);
char buffer[240];
PyObject *self = a->im_self;
PyObject *func = a->im_func;
PyClassObject *class = (PyClassObject *)(a->im_class);
PyObject *fclassname, *iclassname, *funcname;
char *fcname, *icname, *fname;
fclassname = class->cl_name;
if (PyFunction_Check(func)) {
funcname = ((PyFunctionObject *)func)->func_name;
Py_INCREF(funcname);
PyObject *klass = a->im_class;
PyObject *funcname = NULL, *klassname = NULL, *result = NULL;
char *sfuncname = "?", *sklassname = "?";
funcname = PyObject_GetAttrString(func, "__name__");
if (funcname == NULL)
PyErr_Clear();
else if (!PyString_Check(funcname)) {
Py_DECREF(funcname);
funcname = NULL;
}
else {
funcname = PyObject_GetAttrString(func,"__name__");
if (funcname == NULL)
PyErr_Clear();
else
sfuncname = PyString_AS_STRING(funcname);
klassname = PyObject_GetAttrString(klass, "__name__");
if (klassname == NULL)
PyErr_Clear();
else if (!PyString_Check(klassname)) {
Py_DECREF(klassname);
klassname = NULL;
}
if (funcname != NULL && PyString_Check(funcname))
fname = PyString_AS_STRING(funcname);
else
fname = "?";
if (fclassname != NULL && PyString_Check(fclassname))
fcname = PyString_AsString(fclassname);
else
fcname = "?";
sklassname = PyString_AS_STRING(klassname);
if (self == NULL)
sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
sprintf(buffer, "<unbound method %.100s.%.100s>",
sklassname, sfuncname);
else {
iclassname = self->in_class->cl_name;
if (iclassname != NULL && PyString_Check(iclassname))
icname = PyString_AsString(iclassname);
else
icname = "?";
sprintf(buf, "<method %.60s.%.60s of %.60s instance at %p>",
fcname, fname, icname, self);
/* XXX Shouldn't use repr() here! */
PyObject *selfrepr = PyObject_Repr(self);
if (selfrepr == NULL)
goto fail;
if (!PyString_Check(selfrepr)) {
Py_DECREF(selfrepr);
goto fail;
}
sprintf(buffer, "<bound method %.60s.%.60s of %.60s>",
sklassname, sfuncname, PyString_AS_STRING(selfrepr));
Py_DECREF(selfrepr);
}
result = PyString_FromString(buffer);
fail:
Py_XDECREF(funcname);
return PyString_FromString(buf);
Py_XDECREF(klassname);
return result;
}
static long
@ -2105,6 +2141,57 @@ instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg)
return 0;
}
static PyObject *
instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyObject *self = PyMethod_GET_SELF(func);
PyObject *class = PyMethod_GET_CLASS(func);
PyObject *result;
func = PyMethod_GET_FUNCTION(func);
if (self == NULL) {
/* Unbound methods must be called with an instance of
the class (or a derived class) as first argument */
int ok;
if (PyTuple_Size(arg) >= 1)
self = PyTuple_GET_ITEM(arg, 0);
if (self == NULL)
ok = 0;
else {
ok = PyObject_IsInstance(self, class);
if (ok < 0)
return NULL;
}
if (!ok) {
PyErr_Format(PyExc_TypeError,
"unbound method %s%s must be "
"called with instance as first argument",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func));
return NULL;
}
Py_INCREF(arg);
}
else {
int argcount = PyTuple_Size(arg);
PyObject *newarg = PyTuple_New(argcount + 1);
int i;
if (newarg == NULL)
return NULL;
Py_INCREF(self);
PyTuple_SET_ITEM(newarg, 0, self);
for (i = 0; i < argcount; i++) {
PyObject *v = PyTuple_GET_ITEM(arg, i);
Py_XINCREF(v);
PyTuple_SET_ITEM(newarg, i+1, v);
}
arg = newarg;
}
result = PyObject_Call((PyObject *)func, arg, kw);
Py_DECREF(arg);
return result;
}
PyTypeObject PyMethod_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
@ -2121,7 +2208,7 @@ PyTypeObject PyMethod_Type = {
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)instancemethod_hash, /* tp_hash */
0, /* tp_call */
instancemethod_call, /* tp_call */
0, /* tp_str */
(getattrofunc)instancemethod_getattro, /* tp_getattro */
(setattrofunc)instancemethod_setattro, /* tp_setattro */

View File

@ -8,6 +8,7 @@
#ifndef WITHOUT_COMPLEX
#include "Python.h"
#include "structmember.h"
/* Precisions used by repr() and str(), respectively.
@ -182,6 +183,17 @@ c_powi(Py_complex x, long n)
}
static PyObject *
complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
{
PyObject *op;
op = PyType_GenericAlloc(type, 0);
if (op != NULL)
((PyComplexObject *)op)->cval = cval;
return op;
}
PyObject *
PyComplex_FromCComplex(Py_complex cval)
{
@ -196,6 +208,15 @@ PyComplex_FromCComplex(Py_complex cval)
return (PyObject *) op;
}
static PyObject *
complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
{
Py_complex c;
c.real = real;
c.imag = imag;
return complex_subtype_from_c_complex(type, c);
}
PyObject *
PyComplex_FromDoubles(double real, double imag)
{
@ -559,19 +580,261 @@ static PyMethodDef complex_methods[] = {
{NULL, NULL} /* sentinel */
};
static struct memberlist complex_members[] = {
{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
{0},
};
static PyObject *
complex_getattr(PyComplexObject *self, char *name)
complex_subtype_from_string(PyTypeObject *type, PyObject *v)
{
if (strcmp(name, "real") == 0)
return (PyObject *)PyFloat_FromDouble(self->cval.real);
else if (strcmp(name, "imag") == 0)
return (PyObject *)PyFloat_FromDouble(self->cval.imag);
else if (strcmp(name, "__members__") == 0)
return Py_BuildValue("[ss]", "imag", "real");
return Py_FindMethod(complex_methods, (PyObject *)self, name);
extern double strtod(const char *, char **);
const char *s, *start;
char *end;
double x=0.0, y=0.0, z;
int got_re=0, got_im=0, done=0;
int digit_or_dot;
int sw_error=0;
int sign;
char buffer[256]; /* For errors */
char s_buffer[256];
int len;
if (PyString_Check(v)) {
s = PyString_AS_STRING(v);
len = PyString_GET_SIZE(v);
}
else if (PyUnicode_Check(v)) {
if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
PyErr_SetString(PyExc_ValueError,
"complex() literal too large to convert");
return NULL;
}
if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v),
s_buffer,
NULL))
return NULL;
s = s_buffer;
len = (int)strlen(s);
}
else if (PyObject_AsCharBuffer(v, &s, &len)) {
PyErr_SetString(PyExc_TypeError,
"complex() arg is not a string");
return NULL;
}
/* position on first nonblank */
start = s;
while (*s && isspace(Py_CHARMASK(*s)))
s++;
if (s[0] == '\0') {
PyErr_SetString(PyExc_ValueError,
"complex() arg is an empty string");
return NULL;
}
z = -1.0;
sign = 1;
do {
switch (*s) {
case '\0':
if (s-start != len) {
PyErr_SetString(
PyExc_ValueError,
"complex() arg contains a null byte");
return NULL;
}
if(!done) sw_error=1;
break;
case '-':
sign = -1;
/* Fallthrough */
case '+':
if (done) sw_error=1;
s++;
if ( *s=='\0'||*s=='+'||*s=='-' ||
isspace(Py_CHARMASK(*s)) ) sw_error=1;
break;
case 'J':
case 'j':
if (got_im || done) {
sw_error = 1;
break;
}
if (z<0.0) {
y=sign;
}
else{
y=sign*z;
}
got_im=1;
s++;
if (*s!='+' && *s!='-' )
done=1;
break;
default:
if (isspace(Py_CHARMASK(*s))) {
while (*s && isspace(Py_CHARMASK(*s)))
s++;
if (s[0] != '\0')
sw_error=1;
else
done = 1;
break;
}
digit_or_dot =
(*s=='.' || isdigit(Py_CHARMASK(*s)));
if (done||!digit_or_dot) {
sw_error=1;
break;
}
errno = 0;
PyFPE_START_PROTECT("strtod", return 0)
z = strtod(s, &end) ;
PyFPE_END_PROTECT(z)
if (errno != 0) {
sprintf(buffer,
"float() out of range: %.150s", s);
PyErr_SetString(
PyExc_ValueError,
buffer);
return NULL;
}
s=end;
if (*s=='J' || *s=='j') {
break;
}
if (got_re) {
sw_error=1;
break;
}
/* accept a real part */
x=sign*z;
got_re=1;
if (got_im) done=1;
z = -1.0;
sign = 1;
break;
} /* end of switch */
} while (*s!='\0' && !sw_error);
if (sw_error) {
PyErr_SetString(PyExc_ValueError,
"complex() arg is a malformed string");
return NULL;
}
return complex_subtype_from_doubles(type, x, y);
}
static PyObject *
complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *r, *i, *tmp;
PyNumberMethods *nbr, *nbi = NULL;
Py_complex cr, ci;
int own_r = 0;
static char *kwlist[] = {"real", "imag", 0};
r = Py_False;
i = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist,
&r, &i))
return NULL;
if (PyString_Check(r) || PyUnicode_Check(r))
return complex_subtype_from_string(type, r);
if ((nbr = r->ob_type->tp_as_number) == NULL ||
nbr->nb_float == NULL ||
(i != NULL &&
((nbi = i->ob_type->tp_as_number) == NULL ||
nbi->nb_float == NULL))) {
PyErr_SetString(PyExc_TypeError,
"complex() arg can't be converted to complex");
return NULL;
}
/* XXX Hack to support classes with __complex__ method */
if (PyInstance_Check(r)) {
static PyObject *complexstr;
PyObject *f;
if (complexstr == NULL) {
complexstr = PyString_InternFromString("__complex__");
if (complexstr == NULL)
return NULL;
}
f = PyObject_GetAttr(r, complexstr);
if (f == NULL)
PyErr_Clear();
else {
PyObject *args = Py_BuildValue("()");
if (args == NULL)
return NULL;
r = PyEval_CallObject(f, args);
Py_DECREF(args);
Py_DECREF(f);
if (r == NULL)
return NULL;
own_r = 1;
}
}
if (PyComplex_Check(r)) {
cr = ((PyComplexObject*)r)->cval;
if (own_r) {
Py_DECREF(r);
}
}
else {
tmp = PyNumber_Float(r);
if (own_r) {
Py_DECREF(r);
}
if (tmp == NULL)
return NULL;
if (!PyFloat_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"float(r) didn't return a float");
Py_DECREF(tmp);
return NULL;
}
cr.real = PyFloat_AsDouble(tmp);
Py_DECREF(tmp);
cr.imag = 0.0;
}
if (i == NULL) {
ci.real = 0.0;
ci.imag = 0.0;
}
else if (PyComplex_Check(i))
ci = ((PyComplexObject*)i)->cval;
else {
tmp = (*nbi->nb_float)(i);
if (tmp == NULL)
return NULL;
ci.real = PyFloat_AsDouble(tmp);
Py_DECREF(tmp);
ci.imag = 0.;
}
cr.real -= ci.imag;
cr.imag += ci.real;
return complex_subtype_from_c_complex(type, cr);
}
static char complex_doc[] =
"complex(real[, imag]) -> complex number\n\
\n\
Create a complex number from a real part and an optional imaginary part.\n\
This is equivalent to (real + imag*1j) where imag defaults to 0.";
static PyNumberMethods complex_as_number = {
(binaryfunc)complex_add, /* nb_add */
(binaryfunc)complex_sub, /* nb_subtract */
@ -606,7 +869,7 @@ PyTypeObject PyComplex_Type = {
0,
(destructor)complex_dealloc, /* tp_dealloc */
(printfunc)complex_print, /* tp_print */
(getattrfunc)complex_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)complex_repr, /* tp_repr */
@ -616,14 +879,28 @@ PyTypeObject PyComplex_Type = {
(hashfunc)complex_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)complex_str, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
complex_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
complex_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
complex_methods, /* tp_methods */
complex_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
complex_new, /* tp_new */
};
#endif

854
Objects/descrobject.c Normal file
View File

@ -0,0 +1,854 @@
/* Descriptors -- a new, flexible way to describe attributes */
#include "Python.h"
#include "structmember.h" /* Why is this not included in Python.h? */
/* Various kinds of descriptor objects */
#define COMMON \
PyObject_HEAD \
PyTypeObject *d_type; \
PyObject *d_name
typedef struct {
COMMON;
} PyDescrObject;
typedef struct {
COMMON;
PyMethodDef *d_method;
} PyMethodDescrObject;
typedef struct {
COMMON;
struct memberlist *d_member;
} PyMemberDescrObject;
typedef struct {
COMMON;
struct getsetlist *d_getset;
} PyGetSetDescrObject;
typedef struct {
COMMON;
struct wrapperbase *d_base;
void *d_wrapped; /* This can be any function pointer */
} PyWrapperDescrObject;
static void
descr_dealloc(PyDescrObject *descr)
{
Py_XDECREF(descr->d_type);
Py_XDECREF(descr->d_name);
PyObject_DEL(descr);
}
static char *
descr_name(PyDescrObject *descr)
{
if (descr->d_name != NULL && PyString_Check(descr->d_name))
return PyString_AS_STRING(descr->d_name);
else
return "?";
}
static PyObject *
descr_repr(PyDescrObject *descr, char *format)
{
char buffer[500];
sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name);
return PyString_FromString(buffer);
}
static PyObject *
method_repr(PyMethodDescrObject *descr)
{
return descr_repr((PyDescrObject *)descr,
"<method '%.300s' of '%.100s' objects>");
}
static PyObject *
member_repr(PyMemberDescrObject *descr)
{
return descr_repr((PyDescrObject *)descr,
"<member '%.300s' of '%.100s' objects>");
}
static PyObject *
getset_repr(PyGetSetDescrObject *descr)
{
return descr_repr((PyDescrObject *)descr,
"<attribute '%.300s' of '%.100s' objects>");
}
static PyObject *
wrapper_repr(PyWrapperDescrObject *descr)
{
return descr_repr((PyDescrObject *)descr,
"<slot wrapper '%.300s' of '%.100s' objects>");
}
static int
descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
PyObject **pres)
{
if (obj == NULL || obj == Py_None) {
Py_INCREF(descr);
*pres = (PyObject *)descr;
return 1;
}
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.200s' for '%.100s' objects "
"doesn't apply to '%.100s' object",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name,
obj->ob_type->tp_name);
*pres = NULL;
return 1;
}
return 0;
}
static PyObject *
method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
{
PyObject *res;
if (descr_check((PyDescrObject *)descr, obj, type, &res))
return res;
return PyCFunction_New(descr->d_method, obj);
}
static PyObject *
member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
{
PyObject *res;
if (descr_check((PyDescrObject *)descr, obj, type, &res))
return res;
return PyMember_Get((char *)obj, descr->d_member,
descr->d_member->name);
}
static PyObject *
getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
{
PyObject *res;
if (descr_check((PyDescrObject *)descr, obj, type, &res))
return res;
if (descr->d_getset->get != NULL)
return descr->d_getset->get(obj, descr->d_getset->closure);
PyErr_Format(PyExc_TypeError,
"attribute '%300s' of '%.100s' objects is not readable",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name);
return NULL;
}
static PyObject *
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
{
PyObject *res;
if (descr_check((PyDescrObject *)descr, obj, type, &res))
return res;
return PyWrapper_New((PyObject *)descr, obj);
}
static int
descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
int *pres)
{
assert(obj != NULL);
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.200s' for '%.100s' objects "
"doesn't apply to '%.100s' object",
descr_name(descr),
descr->d_type->tp_name,
obj->ob_type->tp_name);
*pres = -1;
return 1;
}
return 0;
}
static int
member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
{
int res;
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
return res;
return PyMember_Set((char *)obj, descr->d_member,
descr->d_member->name, value);
}
static int
getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
{
int res;
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
return res;
if (descr->d_getset->set != NULL)
return descr->d_getset->set(obj, value,
descr->d_getset->closure);
PyErr_Format(PyExc_TypeError,
"attribute '%300s' of '%.100s' objects is not writable",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name);
return -1;
}
static PyObject *
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
{
int argc;
PyObject *self, *func, *result;
/* Make sure that the first argument is acceptable as 'self' */
assert(PyTuple_Check(args));
argc = PyTuple_GET_SIZE(args);
if (argc < 1) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.300s' of '%.100s' "
"object needs an argument",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name);
return NULL;
}
self = PyTuple_GET_ITEM(args, 0);
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.200s' "
"requires a '%.100s' object "
"but received a '%.100s'",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name,
self->ob_type->tp_name);
return NULL;
}
func = PyCFunction_New(descr->d_method, self);
if (func == NULL)
return NULL;
args = PyTuple_GetSlice(args, 1, argc);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObjectWithKeywords(func, args, kwds);
Py_DECREF(args);
Py_DECREF(func);
return result;
}
static PyObject *
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
{
int argc;
PyObject *self, *func, *result;
/* Make sure that the first argument is acceptable as 'self' */
assert(PyTuple_Check(args));
argc = PyTuple_GET_SIZE(args);
if (argc < 1) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.300s' of '%.100s' "
"object needs an argument",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name);
return NULL;
}
self = PyTuple_GET_ITEM(args, 0);
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.200s' "
"requires a '%.100s' object "
"but received a '%.100s'",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name,
self->ob_type->tp_name);
return NULL;
}
func = PyWrapper_New((PyObject *)descr, self);
if (func == NULL)
return NULL;
args = PyTuple_GetSlice(args, 1, argc);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObjectWithKeywords(func, args, kwds);
Py_DECREF(args);
Py_DECREF(func);
return result;
}
static PyObject *
member_get_doc(PyMethodDescrObject *descr, void *closure)
{
if (descr->d_method->ml_doc == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
return PyString_FromString(descr->d_method->ml_doc);
}
static struct memberlist descr_members[] = {
{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
{0}
};
static struct getsetlist member_getset[] = {
{"__doc__", (getter)member_get_doc},
{0}
};
static PyObject *
wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
{
if (descr->d_base->doc == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
return PyString_FromString(descr->d_base->doc);
}
static struct getsetlist wrapper_getset[] = {
{"__doc__", (getter)wrapper_get_doc},
{0}
};
static PyTypeObject PyMethodDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"method_descriptor",
sizeof(PyMethodDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)method_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)methoddescr_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_members, /* tp_members */
member_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
(descrgetfunc)method_get, /* tp_descr_get */
0, /* tp_descr_set */
};
static PyTypeObject PyMemberDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"member_descriptor",
sizeof(PyMemberDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)member_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
(descrgetfunc)member_get, /* tp_descr_get */
(descrsetfunc)member_set, /* tp_descr_set */
};
static PyTypeObject PyGetSetDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"getset_descriptor",
sizeof(PyGetSetDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)getset_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
(descrgetfunc)getset_get, /* tp_descr_get */
(descrsetfunc)getset_set, /* tp_descr_set */
};
static PyTypeObject PyWrapperDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"wrapper_descriptor",
sizeof(PyWrapperDescrObject),
0,
(destructor)descr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)wrapper_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)wrapperdescr_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_members, /* tp_members */
wrapper_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
(descrgetfunc)wrapper_get, /* tp_descr_get */
0, /* tp_descr_set */
};
static PyDescrObject *
descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
{
PyDescrObject *descr;
descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
if (descr != NULL) {
Py_XINCREF(type);
descr->d_type = type;
descr->d_name = PyString_InternFromString(name);
if (descr->d_name == NULL) {
Py_DECREF(descr);
descr = NULL;
}
}
return descr;
}
PyObject *
PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
{
PyMethodDescrObject *descr;
descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
type, method->ml_name);
if (descr != NULL)
descr->d_method = method;
return (PyObject *)descr;
}
PyObject *
PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
{
PyMemberDescrObject *descr;
descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
type, member->name);
if (descr != NULL)
descr->d_member = member;
return (PyObject *)descr;
}
PyObject *
PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
{
PyGetSetDescrObject *descr;
descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
type, getset->name);
if (descr != NULL)
descr->d_getset = getset;
return (PyObject *)descr;
}
PyObject *
PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
{
PyWrapperDescrObject *descr;
descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
type, base->name);
if (descr != NULL) {
descr->d_base = base;
descr->d_wrapped = wrapped;
}
return (PyObject *)descr;
}
int
PyDescr_IsData(PyObject *d)
{
return d->ob_type->tp_descr_set != NULL;
}
/* --- Readonly proxy for dictionaries (actually any mapping) --- */
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
typedef struct {
PyObject_HEAD
PyObject *dict;
} proxyobject;
static int
proxy_len(proxyobject *pp)
{
return PyObject_Size(pp->dict);
}
static PyObject *
proxy_getitem(proxyobject *pp, PyObject *key)
{
return PyObject_GetItem(pp->dict, key);
}
static PyMappingMethods proxy_as_mapping = {
(inquiry)proxy_len, /* mp_length */
(binaryfunc)proxy_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
static int
proxy_contains(proxyobject *pp, PyObject *key)
{
return PySequence_Contains(pp->dict, key);
}
static PySequenceMethods proxy_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)proxy_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyObject *
proxy_has_key(proxyobject *pp, PyObject *args)
{
PyObject *key;
if (!PyArg_ParseTuple(args, "O:has_key", &key))
return NULL;
return PyInt_FromLong(PySequence_Contains(pp->dict, key));
}
static PyObject *
proxy_get(proxyobject *pp, PyObject *args)
{
PyObject *key, *def = Py_None;
if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
return NULL;
return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
}
static PyObject *
proxy_keys(proxyobject *pp, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":keys"))
return NULL;
return PyMapping_Keys(pp->dict);
}
static PyObject *
proxy_values(proxyobject *pp, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":values"))
return NULL;
return PyMapping_Values(pp->dict);
}
static PyObject *
proxy_items(proxyobject *pp, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":items"))
return NULL;
return PyMapping_Items(pp->dict);
}
static PyObject *
proxy_copy(proxyobject *pp, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":copy"))
return NULL;
return PyObject_CallMethod(pp->dict, "copy", NULL);
}
static PyMethodDef proxy_methods[] = {
{"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"},
{"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
{"keys", (PyCFunction)proxy_keys, METH_VARARGS, "XXX"},
{"values", (PyCFunction)proxy_values, METH_VARARGS, "XXX"},
{"items", (PyCFunction)proxy_items, METH_VARARGS, "XXX"},
{"copy", (PyCFunction)proxy_copy, METH_VARARGS, "XXX"},
{0}
};
static void
proxy_dealloc(proxyobject *pp)
{
Py_DECREF(pp->dict);
PyObject_DEL(pp);
}
static PyObject *
proxy_getiter(proxyobject *pp)
{
return PyObject_GetIter(pp->dict);
}
PyObject *
proxy_str(proxyobject *pp)
{
return PyObject_Str(pp->dict);
}
PyTypeObject proxytype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"dict-proxy", /* tp_name */
sizeof(proxyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)proxy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
&proxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
(reprfunc)proxy_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)proxy_getiter, /* tp_iter */
0, /* tp_iternext */
proxy_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};
PyObject *
PyDictProxy_New(PyObject *dict)
{
proxyobject *pp;
pp = PyObject_NEW(proxyobject, &proxytype);
if (pp != NULL) {
Py_INCREF(dict);
pp->dict = dict;
}
return (PyObject *)pp;
}
/* --- Wrapper object for "slot" methods --- */
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
typedef struct {
PyObject_HEAD
PyWrapperDescrObject *descr;
PyObject *self;
} wrapperobject;
static void
wrapper_dealloc(wrapperobject *wp)
{
Py_XDECREF(wp->descr);
Py_XDECREF(wp->self);
PyObject_DEL(wp);
}
static PyMethodDef wrapper_methods[] = {
{0}
};
static PyObject *
wrapper_name(wrapperobject *wp)
{
char *s = wp->descr->d_base->name;
return PyString_FromString(s);
}
static PyObject *
wrapper_doc(wrapperobject *wp)
{
char *s = wp->descr->d_base->doc;
if (s == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
else {
return PyString_FromString(s);
}
}
static struct getsetlist wrapper_getsets[] = {
{"__name__", (getter)wrapper_name},
{"__doc__", (getter)wrapper_doc},
{0}
};
static PyObject *
wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
{
wrapperfunc wrapper = wp->descr->d_base->wrapper;
PyObject *self = wp->self;
return (*wrapper)(self, args, wp->descr->d_wrapped);
}
PyTypeObject wrappertype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"method-wrapper", /* tp_name */
sizeof(wrapperobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)wrapper_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)wrapper_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
wrapper_methods, /* tp_methods */
0, /* tp_members */
wrapper_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};
PyObject *
PyWrapper_New(PyObject *d, PyObject *self)
{
wrapperobject *wp;
PyWrapperDescrObject *descr;
assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
descr = (PyWrapperDescrObject *)d;
assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
wp = PyObject_NEW(wrapperobject, &wrappertype);
if (wp != NULL) {
Py_INCREF(descr);
wp->descr = descr;
Py_INCREF(self);
wp->self = self;
}
return (PyObject *)wp;
}

View File

@ -3,15 +3,8 @@
#include "Python.h"
/* MINSIZE is the minimum size of a dictionary. This many slots are
* allocated directly in the dict object (in the ma_smalltable member).
* It must be a power of 2, and at least 4. 8 allows dicts with no more than
* 5 active entries to live in ma_smalltable (and so avoid an additional
* malloc); instrumentation suggested this suffices for the majority of
* dicts (consisting mostly of usually-small instance dicts and usually-small
* dicts created to pass keyword arguments).
*/
#define MINSIZE 8
typedef PyDictEntry dictentry;
typedef PyDictObject dictobject;
/* Define this out if you don't want conversion statistics on exit. */
#undef SHOW_CONVERSION_COUNTS
@ -116,69 +109,6 @@ equally good collision statistics, needed less code & used less memory.
/* Object used as dummy key to fill deleted entries */
static PyObject *dummy; /* Initialized by first call to newdictobject() */
/*
There are three kinds of slots in the table:
1. Unused. me_key == me_value == NULL
Does not hold an active (key, value) pair now and never did. Unused can
transition to Active upon key insertion. This is the only case in which
me_key is NULL, and is each slot's initial state.
2. Active. me_key != NULL and me_key != dummy and me_value != NULL
Holds an active (key, value) pair. Active can transition to Dummy upon
key deletion. This is the only case in which me_value != NULL.
3. Dummy. me_key == dummy and me_value == NULL
Previously held an active (key, value) pair, but that was deleted and an
active pair has not yet overwritten the slot. Dummy can transition to
Active upon key insertion. Dummy slots cannot be made Unused again
(cannot have me_key set to NULL), else the probe sequence in case of
collision would have no way to know they were once active.
Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to
hold a search finger. The me_hash field of Unused or Dummy slots has no
meaning otherwise.
*/
typedef struct {
long me_hash; /* cached hash code of me_key */
PyObject *me_key;
PyObject *me_value;
#ifdef USE_CACHE_ALIGNED
long aligner;
#endif
} dictentry;
/*
To ensure the lookup algorithm terminates, there must be at least one Unused
slot (NULL key) in the table.
The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
values == the number of Active items).
To avoid slowing down lookups on a near-full table, we resize the table when
it's two-thirds full.
*/
typedef struct dictobject dictobject;
struct dictobject {
PyObject_HEAD
int ma_fill; /* # Active + # Dummy */
int ma_used; /* # Active */
/* The table contains ma_mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
int ma_mask;
/* ma_table points to ma_smalltable for small tables, else to
* additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and
* setitem calls.
*/
dictentry *ma_table;
dictentry *(*ma_lookup)(dictobject *mp, PyObject *key, long hash);
dictentry ma_smalltable[MINSIZE];
};
/* forward declarations */
static dictentry *
lookdict_string(dictobject *mp, PyObject *key, long hash);
@ -196,12 +126,24 @@ show_counts(void)
}
#endif
/* Set dictobject* mp to empty but w/ MINSIZE slots, using ma_smalltable. */
#define empty_to_minsize(mp) do { \
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
/* Initialization macros.
There are two ways to create a dict: PyDict_New() is the main C API
function, and the tp_new slot maps to dict_new(). In the latter case we
can save a little time over what PyDict_New does because it's guaranteed
that the PyDictObject struct is already zeroed out.
Everyone except dict_new() should use EMPTY_TO_MINSIZE (unless they have
an excellent reason not to).
*/
#define INIT_NONZERO_DICT_SLOTS(mp) do { \
(mp)->ma_table = (mp)->ma_smalltable; \
(mp)->ma_mask = MINSIZE - 1; \
(mp)->ma_mask = PyDict_MINSIZE - 1; \
} while(0)
#define EMPTY_TO_MINSIZE(mp) do { \
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
(mp)->ma_used = (mp)->ma_fill = 0; \
INIT_NONZERO_DICT_SLOTS(mp); \
} while(0)
PyObject *
@ -219,7 +161,7 @@ PyDict_New(void)
mp = PyObject_NEW(dictobject, &PyDict_Type);
if (mp == NULL)
return NULL;
empty_to_minsize(mp);
EMPTY_TO_MINSIZE(mp);
mp->ma_lookup = lookdict_string;
#ifdef SHOW_CONVERSION_COUNTS
++created;
@ -418,7 +360,10 @@ insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
{
PyObject *old_value;
register dictentry *ep;
ep = (mp->ma_lookup)(mp, key, hash);
typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long);
assert(mp->ma_lookup != NULL);
ep = mp->ma_lookup(mp, key, hash);
if (ep->me_value != NULL) {
old_value = ep->me_value;
ep->me_value = value;
@ -449,12 +394,12 @@ dictresize(dictobject *mp, int minused)
dictentry *oldtable, *newtable, *ep;
int i;
int is_oldtable_malloced;
dictentry small_copy[MINSIZE];
dictentry small_copy[PyDict_MINSIZE];
assert(minused >= 0);
/* Find the smallest table size > minused. */
for (newsize = MINSIZE;
for (newsize = PyDict_MINSIZE;
newsize <= minused && newsize > 0;
newsize <<= 1)
;
@ -468,7 +413,7 @@ dictresize(dictobject *mp, int minused)
assert(oldtable != NULL);
is_oldtable_malloced = oldtable != mp->ma_smalltable;
if (newsize == MINSIZE) {
if (newsize == PyDict_MINSIZE) {
/* A large table is shrinking, or we can't get any smaller. */
newtable = mp->ma_smalltable;
if (newtable == oldtable) {
@ -649,7 +594,7 @@ PyDict_Clear(PyObject *op)
dictentry *ep, *table;
int table_is_malloced;
int fill;
dictentry small_copy[MINSIZE];
dictentry small_copy[PyDict_MINSIZE];
#ifdef Py_DEBUG
int i, n;
#endif
@ -674,7 +619,7 @@ PyDict_Clear(PyObject *op)
*/
fill = mp->ma_fill;
if (table_is_malloced)
empty_to_minsize(mp);
EMPTY_TO_MINSIZE(mp);
else if (fill > 0) {
/* It's a small table with something that needs to be cleared.
@ -683,7 +628,7 @@ PyDict_Clear(PyObject *op)
*/
memcpy(small_copy, table, sizeof(small_copy));
table = small_copy;
empty_to_minsize(mp);
EMPTY_TO_MINSIZE(mp);
}
/* else it's a small table that's already empty */
@ -1042,32 +987,47 @@ dict_items(register dictobject *mp, PyObject *args)
}
static PyObject *
dict_update(register dictobject *mp, PyObject *args)
dict_update(PyObject *mp, PyObject *args)
{
PyObject *other;
if (!PyArg_ParseTuple(args, "O:update", &other))
return NULL;
if (PyDict_Update(mp, other) < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
int
PyDict_Update(PyObject *a, PyObject *b)
{
register PyDictObject *mp, *other;
register int i;
dictobject *other;
dictentry *entry;
PyObject *param;
/* We accept for the argument either a concrete dictionary object,
* or an abstract "mapping" object. For the former, we can do
* things quite efficiently. For the latter, we only require that
* PyMapping_Keys() and PyObject_GetItem() be supported.
*/
if (!PyArg_ParseTuple(args, "O:update", &param))
return NULL;
if (PyDict_Check(param)) {
other = (dictobject*)param;
if (a == NULL || !PyDict_Check(a) || b == NULL) {
PyErr_BadInternalCall();
return -1;
}
mp = (dictobject*)a;
if (PyDict_Check(b)) {
other = (dictobject*)b;
if (other == mp || other->ma_used == 0)
/* a.update(a) or a.update({}); nothing to do */
goto done;
return 0;
/* Do one big resize at the start, rather than
* incrementally resizing as we insert new items. Expect
* that there will be no (or few) overlapping keys.
*/
if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
return NULL;
return -1;
}
for (i = 0; i <= other->ma_mask; i++) {
entry = &other->ma_table[i];
@ -1081,7 +1041,7 @@ dict_update(register dictobject *mp, PyObject *args)
}
else {
/* Do it the generic, slower way */
PyObject *keys = PyMapping_Keys(param);
PyObject *keys = PyMapping_Keys(b);
PyObject *iter;
PyObject *key, *value;
int status;
@ -1092,37 +1052,34 @@ dict_update(register dictobject *mp, PyObject *args)
* AttributeError to percolate up. Might as well
* do the same for any other error.
*/
return NULL;
return -1;
iter = PyObject_GetIter(keys);
Py_DECREF(keys);
if (iter == NULL)
return NULL;
return -1;
for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
value = PyObject_GetItem(param, key);
value = PyObject_GetItem(b, key);
if (value == NULL) {
Py_DECREF(iter);
Py_DECREF(key);
return NULL;
return -1;
}
status = PyDict_SetItem((PyObject*)mp, key, value);
Py_DECREF(key);
Py_DECREF(value);
if (status < 0) {
Py_DECREF(iter);
return NULL;
return -1;
}
}
Py_DECREF(iter);
if (PyErr_Occurred())
/* Iterator completed, via error */
return NULL;
return -1;
}
done:
Py_INCREF(Py_None);
return Py_None;
return 0;
}
static PyObject *
@ -1694,12 +1651,6 @@ static PyMethodDef mapp_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
dict_getattr(dictobject *mp, char *name)
{
return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
}
static int
dict_contains(dictobject *mp, PyObject *key)
{
@ -1731,6 +1682,26 @@ static PySequenceMethods dict_as_sequence = {
0, /* sq_inplace_repeat */
};
static PyObject *
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *self;
assert(type != NULL && type->tp_alloc != NULL);
self = type->tp_alloc(type, 0);
if (self != NULL) {
PyDictObject *d = (PyDictObject *)self;
/* It's guaranteed that tp->alloc zeroed out the struct. */
assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0);
INIT_NONZERO_DICT_SLOTS(d);
d->ma_lookup = lookdict_string;
#ifdef SHOW_CONVERSION_COUNTS
++created;
#endif
}
return self;
}
static PyObject *
dict_iter(dictobject *dict)
{
@ -1745,7 +1716,7 @@ PyTypeObject PyDict_Type = {
0,
(destructor)dict_dealloc, /* tp_dealloc */
(printfunc)dict_print, /* tp_print */
(getattrfunc)dict_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)dict_compare, /* tp_compare */
(reprfunc)dict_repr, /* tp_repr */
@ -1755,17 +1726,29 @@ PyTypeObject PyDict_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
"dictionary type", /* tp_doc */
(traverseproc)dict_traverse, /* tp_traverse */
(inquiry)dict_tp_clear, /* tp_clear */
dict_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)dict_iter, /* tp_iter */
0, /* tp_iternext */
mapp_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
dict_new, /* tp_new */
};
/* For backward compatibility with old dictionary interface */
@ -1873,12 +1856,6 @@ static PyMethodDef dictiter_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
dictiter_getattr(dictiterobject *di, char *name)
{
return Py_FindMethod(dictiter_methods, (PyObject *)di, name);
}
static PyObject *dictiter_iternext(dictiterobject *di)
{
PyObject *key, *value;
@ -1903,7 +1880,7 @@ PyTypeObject PyDictIter_Type = {
/* methods */
(destructor)dictiter_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)dictiter_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
@ -1913,7 +1890,7 @@ PyTypeObject PyDictIter_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
@ -1924,4 +1901,11 @@ PyTypeObject PyDictIter_Type = {
0, /* tp_weaklistoffset */
(getiterfunc)dictiter_getiter, /* tp_iter */
(iternextfunc)dictiter_iternext, /* tp_iternext */
dictiter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};

View File

@ -1273,29 +1273,15 @@ static struct memberlist file_memberlist[] = {
};
static PyObject *
file_getattr(PyFileObject *f, char *name)
get_closed(PyFileObject *f, void *closure)
{
PyObject *res;
res = Py_FindMethod(file_methods, (PyObject *)f, name);
if (res != NULL)
return res;
PyErr_Clear();
if (strcmp(name, "closed") == 0)
return PyInt_FromLong((long)(f->f_fp == 0));
return PyMember_Get((char *)f, file_memberlist, name);
return PyInt_FromLong((long)(f->f_fp == 0));
}
static int
file_setattr(PyFileObject *f, char *name, PyObject *v)
{
if (v == NULL) {
PyErr_SetString(PyExc_AttributeError,
"can't delete file attributes");
return -1;
}
return PyMember_Set((char *)f, file_memberlist, name, v);
}
static struct getsetlist file_getsetlist[] = {
{"closed", (getter)get_closed, NULL, NULL},
{0},
};
static PyObject *
file_getiter(PyObject *f)
@ -1311,27 +1297,32 @@ PyTypeObject PyFile_Type = {
0,
(destructor)file_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)file_getattr, /* tp_getattr */
(setattrfunc)file_setattr, /* tp_setattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)file_repr, /* tp_repr */
(reprfunc)file_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
file_getiter, /* tp_iter */
0, /* tp_iternext */
file_methods, /* tp_methods */
file_memberlist, /* tp_members */
file_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
/* Interface for the 'soft space' between print items. */

View File

@ -636,6 +636,26 @@ float_float(PyObject *v)
}
static PyObject *
float_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *x = Py_False; /* Integer zero */
static char *kwlist[] = {"x", 0};
assert(type == &PyFloat_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x))
return NULL;
if (PyString_Check(x))
return PyFloat_FromString(x, NULL);
return PyNumber_Float(x);
}
static char float_doc[] =
"float(x) -> floating point number\n\
\n\
Convert a string or number to a floating point number, if possible.";
static PyNumberMethods float_as_number = {
(binaryfunc)float_add, /*nb_add*/
(binaryfunc)float_sub, /*nb_subtract*/
@ -679,22 +699,40 @@ PyTypeObject PyFloat_Type = {
"float",
sizeof(PyFloatObject),
0,
(destructor)float_dealloc, /*tp_dealloc*/
(printfunc)float_print, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)float_compare, /*tp_compare*/
(reprfunc)float_repr, /*tp_repr*/
&float_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)float_hash, /*tp_hash*/
0, /*tp_call*/
(reprfunc)float_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
(destructor)float_dealloc, /* tp_dealloc */
(printfunc)float_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)float_compare, /* tp_compare */
(reprfunc)float_repr, /* tp_repr */
&float_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)float_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)float_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
float_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
float_new, /* tp_new */
};
void

View File

@ -15,7 +15,6 @@ static struct memberlist frame_memberlist[] = {
{"f_code", T_OBJECT, OFF(f_code), RO},
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},
{"f_globals", T_OBJECT, OFF(f_globals), RO},
{"f_locals", T_OBJECT, OFF(f_locals), RO},
{"f_lasti", T_INT, OFF(f_lasti), RO},
{"f_lineno", T_INT, OFF(f_lineno), RO},
{"f_restricted",T_INT, OFF(f_restricted),RO},
@ -27,18 +26,17 @@ static struct memberlist frame_memberlist[] = {
};
static PyObject *
frame_getattr(PyFrameObject *f, char *name)
frame_getlocals(PyFrameObject *f, void *closure)
{
if (strcmp(name, "f_locals") == 0)
PyFrame_FastToLocals(f);
return PyMember_Get((char *)f, frame_memberlist, name);
PyFrame_FastToLocals(f);
Py_INCREF(f->f_locals);
return f->f_locals;
}
static int
frame_setattr(PyFrameObject *f, char *name, PyObject *value)
{
return PyMember_Set((char *)f, frame_memberlist, name, value);
}
static struct getsetlist frame_getsetlist[] = {
{"f_locals", (getter)frame_getlocals, NULL, NULL},
{0}
};
/* Stack frames are allocated and deallocated at a considerable rate.
In an attempt to improve the speed of function calls, we maintain a
@ -177,8 +175,8 @@ PyTypeObject PyFrame_Type = {
0,
(destructor)frame_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)frame_getattr, /* tp_getattr */
(setattrfunc)frame_setattr, /* tp_setattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
@ -187,13 +185,22 @@ PyTypeObject PyFrame_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)frame_traverse, /* tp_traverse */
(inquiry)frame_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
frame_memberlist, /* tp_members */
frame_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
PyFrameObject *

View File

@ -3,6 +3,7 @@
#include "Python.h"
#include "compile.h"
#include "eval.h"
#include "structmember.h"
PyObject *
@ -141,9 +142,8 @@ static struct memberlist func_memberlist[] = {
};
static PyObject *
func_getattro(PyFunctionObject *op, PyObject *name)
func_getattro(PyObject *op, PyObject *name)
{
PyObject *rtn;
char *sname = PyString_AsString(name);
if (sname[0] != '_' && PyEval_GetRestricted()) {
@ -152,25 +152,12 @@ func_getattro(PyFunctionObject *op, PyObject *name)
return NULL;
}
/* no API for PyMember_HasAttr() */
rtn = PyMember_Get((char *)op, func_memberlist, sname);
if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
if (op->func_dict != NULL) {
rtn = PyDict_GetItem(op->func_dict, name);
Py_XINCREF(rtn);
}
if (rtn == NULL)
PyErr_SetObject(PyExc_AttributeError, name);
}
return rtn;
return PyObject_GenericGetAttr(op, name);
}
static int
func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
func_setattro(PyObject *op, PyObject *name, PyObject *value)
{
int rtn;
char *sname = PyString_AsString(name);
if (PyEval_GetRestricted()) {
@ -216,31 +203,7 @@ func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
}
}
rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
if (op->func_dict == NULL) {
/* don't create the dict if we're deleting an
* attribute. In that case, we know we'll get an
* AttributeError.
*/
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError, sname);
return -1;
}
op->func_dict = PyDict_New();
if (op->func_dict == NULL)
return -1;
}
if (value == NULL)
rtn = PyDict_DelItem(op->func_dict, name);
else
rtn = PyDict_SetItem(op->func_dict, name, value);
/* transform KeyError into AttributeError */
if (rtn < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetString(PyExc_AttributeError, sname);
}
return rtn;
return PyObject_GenericSetAttr(op, name, value);
}
static void
@ -314,31 +277,324 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
return 0;
}
static PyObject *
function_call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyObject *result;
PyObject *argdefs;
PyObject **d, **k;
int nk, nd;
argdefs = PyFunction_GET_DEFAULTS(func);
if (argdefs != NULL && PyTuple_Check(argdefs)) {
d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0);
nd = PyTuple_Size(argdefs);
}
else {
d = NULL;
nd = 0;
}
if (kw != NULL && PyDict_Check(kw)) {
int pos, i;
nk = PyDict_Size(kw);
k = PyMem_NEW(PyObject *, 2*nk);
if (k == NULL) {
PyErr_NoMemory();
Py_DECREF(arg);
return NULL;
}
pos = i = 0;
while (PyDict_Next(kw, &pos, &k[i], &k[i+1]))
i += 2;
nk = i/2;
/* XXX This is broken if the caller deletes dict items! */
}
else {
k = NULL;
nk = 0;
}
result = PyEval_EvalCodeEx(
(PyCodeObject *)PyFunction_GET_CODE(func),
PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
k, nk, d, nd,
PyFunction_GET_CLOSURE(func));
if (k != NULL)
PyMem_DEL(k);
return result;
}
/* Bind a function to an object */
static PyObject *
func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
{
if (obj == Py_None)
obj = NULL;
return PyMethod_New(func, obj, type);
}
PyTypeObject PyFunction_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"function",
sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
0,
(destructor)func_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)func_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
(getattrofunc)func_getattro, /* tp_getattro */
(setattrofunc)func_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)func_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
(destructor)func_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)func_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
function_call, /* tp_call */
0, /* tp_str */
func_getattro, /* tp_getattro */
func_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)func_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
func_memberlist, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
func_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */
};
/* Class method object */
/* A class method receives the class as implicit first argument,
just like an instance method receives the instance.
To declare a class method, use this idiom:
class C:
def f(cls, arg1, arg2, ...): ...
f = classmethod(f)
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()); the instance is ignored except for its class.
If a class method is called for a derived class, the derived class
object is passed as the implied first argument.
Class methods are different than C++ or Java static methods.
If you want those, see static methods below.
*/
typedef struct {
PyObject_HEAD
PyObject *cm_callable;
} classmethod;
static void
cm_dealloc(classmethod *cm)
{
Py_XDECREF(cm->cm_callable);
PyObject_DEL(cm);
}
static PyObject *
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
{
classmethod *cm = (classmethod *)self;
if (cm->cm_callable == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"uninitialized classmethod object");
return NULL;
}
return PyMethod_New(cm->cm_callable,
type, (PyObject *)(type->ob_type));
}
static int
cm_init(PyObject *self, PyObject *args, PyObject *kwds)
{
classmethod *cm = (classmethod *)self;
PyObject *callable;
if (!PyArg_ParseTuple(args, "O:callable", &callable))
return -1;
Py_INCREF(callable);
cm->cm_callable = callable;
return 0;
}
PyTypeObject PyClassMethod_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"classmethod",
sizeof(classmethod),
0,
(destructor)cm_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
cm_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
cm_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
PyObject *
PyClassMethod_New(PyObject *callable)
{
classmethod *cm = (classmethod *)
PyType_GenericAlloc(&PyClassMethod_Type, 0);
if (cm != NULL) {
Py_INCREF(callable);
cm->cm_callable = callable;
}
return (PyObject *)cm;
}
/* Static method object */
/* A static method does not receive an implicit first argument.
To declare a static method, use this idiom:
class C:
def f(arg1, arg2, ...): ...
f = staticmethod(f)
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()); the instance is ignored except for its class.
Static methods in Python are similar to those found in Java or C++.
For a more advanced concept, see class methods above.
*/
typedef struct {
PyObject_HEAD
PyObject *sm_callable;
} staticmethod;
static void
sm_dealloc(staticmethod *sm)
{
Py_XDECREF(sm->sm_callable);
PyObject_DEL(sm);
}
static PyObject *
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
{
staticmethod *sm = (staticmethod *)self;
if (sm->sm_callable == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"uninitialized staticmethod object");
return NULL;
}
Py_INCREF(sm->sm_callable);
return sm->sm_callable;
}
static int
sm_init(PyObject *self, PyObject *args, PyObject *kwds)
{
staticmethod *sm = (staticmethod *)self;
PyObject *callable;
if (!PyArg_ParseTuple(args, "O:callable", &callable))
return -1;
Py_INCREF(callable);
sm->sm_callable = callable;
return 0;
}
PyTypeObject PyStaticMethod_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"staticmethod",
sizeof(staticmethod),
0,
(destructor)sm_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
sm_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
sm_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
PyObject *
PyStaticMethod_New(PyObject *callable)
{
staticmethod *sm = (staticmethod *)
PyType_GenericAlloc(&PyStaticMethod_Type, 0);
if (sm != NULL) {
Py_INCREF(callable);
sm->sm_callable = callable;
}
return (PyObject *)sm;
}

View File

@ -742,6 +742,41 @@ int_hex(PyIntObject *v)
return PyString_FromString(buf);
}
static PyObject *
int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *x = NULL;
int base = -909;
static char *kwlist[] = {"x", "base", 0};
assert(type == &PyInt_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,
&x, &base))
return NULL;
if (x == NULL)
return PyInt_FromLong(0L);
if (base == -909)
return PyNumber_Int(x);
if (PyString_Check(x))
return PyInt_FromString(PyString_AS_STRING(x), NULL, base);
if (PyUnicode_Check(x))
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x),
PyUnicode_GET_SIZE(x),
base);
PyErr_SetString(PyExc_TypeError,
"int() can't convert non-string with explicit base");
return NULL;
}
static char int_doc[] =
"int(x[, base]) -> integer\n\
\n\
Convert a string or number to an integer, if possible. A floating point\n\
argument will be truncated towards zero (this does not include a string\n\
representation of a floating point number!) When converting a string, use\n\
the optional base. It is an error to supply a base when converting a\n\
non-string.";
static PyNumberMethods int_as_number = {
(binaryfunc)int_add, /*nb_add*/
(binaryfunc)int_sub, /*nb_subtract*/
@ -785,22 +820,40 @@ PyTypeObject PyInt_Type = {
"int",
sizeof(PyIntObject),
0,
(destructor)int_dealloc, /*tp_dealloc*/
(printfunc)int_print, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)int_compare, /*tp_compare*/
(reprfunc)int_repr, /*tp_repr*/
&int_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)int_hash, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
(destructor)int_dealloc, /* tp_dealloc */
(printfunc)int_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */
(reprfunc)int_repr, /* tp_repr */
&int_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)int_hash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
int_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
int_new, /* tp_new */
};
void

View File

@ -96,12 +96,6 @@ static PyMethodDef iter_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
iter_getattr(seqiterobject *it, char *name)
{
return Py_FindMethod(iter_methods, (PyObject *)it, name);
}
PyTypeObject PySeqIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
@ -111,7 +105,7 @@ PyTypeObject PySeqIter_Type = {
/* methods */
(destructor)iter_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)iter_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
@ -121,7 +115,7 @@ PyTypeObject PySeqIter_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
@ -132,6 +126,13 @@ PyTypeObject PySeqIter_Type = {
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
(iternextfunc)iter_iternext, /* tp_iternext */
iter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};
/* -------------------------------------- */
@ -197,12 +198,6 @@ static PyMethodDef calliter_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
calliter_getattr(calliterobject *it, char *name)
{
return Py_FindMethod(calliter_methods, (PyObject *)it, name);
}
static PyObject *
calliter_iternext(calliterobject *it)
{
@ -228,7 +223,7 @@ PyTypeObject PyCallIter_Type = {
/* methods */
(destructor)calliter_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)calliter_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
@ -238,7 +233,7 @@ PyTypeObject PyCallIter_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
@ -249,4 +244,11 @@ PyTypeObject PyCallIter_Type = {
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
(iternextfunc)calliter_iternext, /* tp_iternext */
calliter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};

View File

@ -523,6 +523,10 @@ list_ass_slice(PyListObject *a, int ilow, int ihigh, PyObject *v)
Py_XDECREF(*p);
PyMem_DEL(recycle);
}
if (a->ob_size == 0 && a->ob_item != NULL) {
PyMem_FREE(a->ob_item);
a->ob_item = NULL;
}
return 0;
#undef b
}
@ -1289,16 +1293,18 @@ listsort(PyListObject *self, PyObject *args)
{
int err;
PyObject *compare = NULL;
PyTypeObject *savetype;
if (args != NULL) {
if (!PyArg_ParseTuple(args, "|O:sort", &compare))
return NULL;
}
savetype = self->ob_type;
self->ob_type = &immutable_list_type;
err = samplesortslice(self->ob_item,
self->ob_item + self->ob_size,
compare);
self->ob_type = &PyList_Type;
self->ob_type = savetype;
if (err < 0)
return NULL;
Py_INCREF(Py_None);
@ -1541,6 +1547,100 @@ list_richcompare(PyObject *v, PyObject *w, int op)
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
}
/* Adapted from newer code by Tim */
static int
list_fill(PyListObject *result, PyObject *v)
{
PyObject *it; /* iter(v) */
int n; /* guess for result list size */
int i;
n = result->ob_size;
/* Special-case list(a_list), for speed. */
if (PyList_Check(v)) {
if (v == (PyObject *)result)
return 0; /* source is destination, we're done */
return list_ass_slice(result, 0, n, v);
}
/* Empty previous contents */
if (n != 0) {
if (list_ass_slice(result, 0, n, (PyObject *)NULL) != 0)
return -1;
}
/* Get iterator. There may be some low-level efficiency to be gained
* by caching the tp_iternext slot instead of using PyIter_Next()
* later, but premature optimization is the root etc.
*/
it = PyObject_GetIter(v);
if (it == NULL)
return -1;
/* Guess a result list size. */
n = -1; /* unknown */
if (PySequence_Check(v) &&
v->ob_type->tp_as_sequence->sq_length) {
n = PySequence_Size(v);
if (n < 0)
PyErr_Clear();
}
if (n < 0)
n = 8; /* arbitrary */
NRESIZE(result->ob_item, PyObject*, n);
if (result->ob_item == NULL)
goto error;
for (i = 0; i < n; i++)
result->ob_item[i] = NULL;
result->ob_size = n;
/* Run iterator to exhaustion. */
for (i = 0; ; i++) {
PyObject *item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto error;
break;
}
if (i < n)
PyList_SET_ITEM(result, i, item); /* steals ref */
else {
int status = ins1(result, result->ob_size, item);
Py_DECREF(item); /* append creates a new ref */
if (status < 0)
goto error;
}
}
/* Cut back result list if initial guess was too large. */
if (i < n && result != NULL) {
if (list_ass_slice(result, i, n, (PyObject *)NULL) != 0)
goto error;
}
Py_DECREF(it);
return 0;
error:
Py_DECREF(it);
return -1;
}
static int
list_init(PyListObject *self, PyObject *args, PyObject *kw)
{
PyObject *arg = NULL;
static char *kwlist[] = {"sequence", 0};
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
return -1;
if (arg != NULL)
return list_fill(self, arg);
if (self->ob_size > 0)
return list_ass_slice(self, 0, self->ob_size, (PyObject*)NULL);
return 0;
}
static char append_doc[] =
"L.append(object) -- append object to end";
static char extend_doc[] =
@ -1573,12 +1673,6 @@ static PyMethodDef list_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
list_getattr(PyListObject *f, char *name)
{
return Py_FindMethod(list_methods, (PyObject *)f, name);
}
static PySequenceMethods list_as_sequence = {
(inquiry)list_length, /* sq_length */
(binaryfunc)list_concat, /* sq_concat */
@ -1592,6 +1686,10 @@ static PySequenceMethods list_as_sequence = {
(intargfunc)list_inplace_repeat, /* sq_inplace_repeat */
};
static char list_doc[] =
"list() -> new list\n"
"list(sequence) -> new list initialized from sequence's items";
PyTypeObject PyList_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
@ -1600,7 +1698,7 @@ PyTypeObject PyList_Type = {
0,
(destructor)list_dealloc, /* tp_dealloc */
(printfunc)list_print, /* tp_print */
(getattrfunc)list_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)list_repr, /* tp_repr */
@ -1610,14 +1708,29 @@ PyTypeObject PyList_Type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
list_doc, /* tp_doc */
(traverseproc)list_traverse, /* tp_traverse */
(inquiry)list_clear, /* tp_clear */
list_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
list_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)list_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
@ -1646,12 +1759,6 @@ static PyMethodDef immutable_list_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyObject *
immutable_list_getattr(PyListObject *f, char *name)
{
return Py_FindMethod(immutable_list_methods, (PyObject *)f, name);
}
static int
immutable_list_ass(void)
{
@ -1678,7 +1785,7 @@ static PyTypeObject immutable_list_type = {
0,
0, /* Cannot happen */ /* tp_dealloc */
(printfunc)list_print, /* tp_print */
(getattrfunc)immutable_list_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* Won't be called */ /* tp_compare */
(reprfunc)list_repr, /* tp_repr */
@ -1688,13 +1795,24 @@ static PyTypeObject immutable_list_type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
list_doc, /* tp_doc */
(traverseproc)list_traverse, /* tp_traverse */
0, /* tp_clear */
list_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
immutable_list_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_init */
/* NOTE: This is *not* the standard list_type struct! */
};

View File

@ -2031,6 +2031,43 @@ long_hex(PyObject *v)
return long_format(v, 16, 1);
}
static PyObject *
long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *x = NULL;
int base = -909; /* unlikely! */
static char *kwlist[] = {"x", "base", 0};
assert(type == &PyLong_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist,
&x, &base))
return NULL;
if (x == NULL)
return PyLong_FromLong(0L);
if (base == -909)
return PyNumber_Long(x);
else if (PyString_Check(x))
return PyLong_FromString(PyString_AS_STRING(x), NULL, base);
else if (PyUnicode_Check(x))
return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x),
PyUnicode_GET_SIZE(x),
base);
else {
PyErr_SetString(PyExc_TypeError,
"long() can't convert non-string with explicit base");
return NULL;
}
}
static char long_doc[] =
"long(x[, base]) -> integer\n\
\n\
Convert a string or number to a long integer, if possible. A floating\n\
point argument will be truncated towards zero (this does not include a\n\
string representation of a floating point number!) When converting a\n\
string, use the optional base. It is an error to supply a base when\n\
converting a non-string.";
static PyNumberMethods long_as_number = {
(binaryfunc) long_add, /*nb_add*/
(binaryfunc) long_sub, /*nb_subtract*/
@ -2070,24 +2107,42 @@ static PyNumberMethods long_as_number = {
PyTypeObject PyLong_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"long int",
sizeof(PyLongObject) - sizeof(digit),
sizeof(digit),
(destructor)long_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)long_compare, /*tp_compare*/
(reprfunc)long_repr, /*tp_repr*/
&long_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)long_hash, /*tp_hash*/
0, /*tp_call*/
(reprfunc)long_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
0, /* ob_size */
"long", /* tp_name */
sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */
sizeof(digit), /* tp_itemsize */
(destructor)long_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)long_compare, /* tp_compare */
(reprfunc)long_repr, /* tp_repr */
&long_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)long_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)long_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
long_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
long_new, /* tp_new */
};

View File

@ -3,8 +3,6 @@
#include "Python.h"
#include "token.h"
static PyCFunctionObject *free_list = NULL;
PyObject *
@ -69,6 +67,23 @@ meth_dealloc(PyCFunctionObject *m)
free_list = m;
}
static PyObject *
meth_get__doc__(PyCFunctionObject *m, void *closure)
{
char *doc = m->m_ml->ml_doc;
if (doc != NULL)
return PyString_FromString(doc);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
meth_get__name__(PyCFunctionObject *m, void *closure)
{
return PyString_FromString(m->m_ml->ml_name);
}
static int
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
{
@ -79,39 +94,28 @@ meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
}
static PyObject *
meth_getattr(PyCFunctionObject *m, char *name)
meth_get__self__(PyCFunctionObject *m, void *closure)
{
if (strcmp(name, "__name__") == 0) {
return PyString_FromString(m->m_ml->ml_name);
PyObject *self;
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"method.__self__ not accessible in restricted mode");
return NULL;
}
if (strcmp(name, "__doc__") == 0) {
char *doc = m->m_ml->ml_doc;
if (doc != NULL)
return PyString_FromString(doc);
Py_INCREF(Py_None);
return Py_None;
}
if (strcmp(name, "__self__") == 0) {
PyObject *self;
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"method.__self__ not accessible in restricted mode");
return NULL;
}
self = m->m_self;
if (self == NULL)
self = Py_None;
Py_INCREF(self);
return self;
}
if (strcmp(name, "__members__") == 0) {
return Py_BuildValue("[sss]",
"__doc__", "__name__", "__self__");
}
PyErr_SetString(PyExc_AttributeError, name);
return NULL;
self = m->m_self;
if (self == NULL)
self = Py_None;
Py_INCREF(self);
return self;
}
static struct getsetlist meth_getsets [] = {
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
{"__name__", (getter)meth_get__name__, NULL, NULL},
{"__self__", (getter)meth_get__self__, NULL, NULL},
{0}
};
static PyObject *
meth_repr(PyCFunctionObject *m)
{
@ -159,6 +163,41 @@ meth_hash(PyCFunctionObject *a)
return x;
}
static PyObject *
meth_call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyCFunctionObject* f = (PyCFunctionObject*)func;
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
int flags = PyCFunction_GET_FLAGS(func);
if (flags & METH_KEYWORDS) {
return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
}
if (kw != NULL && PyDict_Size(kw) != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no keyword arguments",
f->m_ml->ml_name);
return NULL;
}
if (flags & METH_VARARGS) {
return (*meth)(self, arg);
}
if (!(flags & METH_VARARGS)) {
/* the really old style */
int size = PyTuple_GET_SIZE(arg);
if (size == 1)
arg = PyTuple_GET_ITEM(arg, 0);
else if (size == 0)
arg = NULL;
return (*meth)(self, arg);
}
/* should never get here ??? */
PyErr_BadInternalCall();
return NULL;
}
PyTypeObject PyCFunction_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
@ -167,7 +206,7 @@ PyTypeObject PyCFunction_Type = {
0,
(destructor)meth_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)meth_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)meth_compare, /* tp_compare */
(reprfunc)meth_repr, /* tp_repr */
@ -175,14 +214,24 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)meth_hash, /* tp_hash */
0, /* tp_call */
meth_call, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
meth_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
/* List all methods in a chain -- helper for findmethodinchain */

View File

@ -2,12 +2,18 @@
/* Module object implementation */
#include "Python.h"
#include "structmember.h"
typedef struct {
PyObject_HEAD
PyObject *md_dict;
} PyModuleObject;
struct memberlist module_members[] = {
{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
{0}
};
PyObject *
PyModule_New(char *name)
{
@ -128,6 +134,15 @@ _PyModule_Clear(PyObject *m)
/* Methods */
static int
module_init(PyModuleObject *m, PyObject *args, PyObject *kw)
{
m->md_dict = PyDict_New();
if (m->md_dict == NULL)
return -1;
return 0;
}
static void
module_dealloc(PyModuleObject *m)
{
@ -161,59 +176,6 @@ module_repr(PyModuleObject *m)
return PyString_FromString(buf);
}
static PyObject *
module_getattro(PyModuleObject *m, PyObject *name)
{
PyObject *res;
char *sname = PyString_AsString(name);
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
Py_INCREF(m->md_dict);
return m->md_dict;
}
res = PyDict_GetItem(m->md_dict, name);
if (res == NULL) {
char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) {
PyErr_Clear();
modname = "?";
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' module has no attribute '%.400s'",
modname, sname);
}
else
Py_INCREF(res);
return res;
}
static int
module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
{
char *sname = PyString_AsString(name);
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
PyErr_SetString(PyExc_TypeError,
"read-only special attribute");
return -1;
}
if (v == NULL) {
int rv = PyDict_DelItem(m->md_dict, name);
if (rv < 0) {
char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) {
PyErr_Clear();
modname = "?";
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' module has no attribute '%.400s'",
modname, sname);
}
return rv;
}
else
return PyDict_SetItem(m->md_dict, name, v);
}
/* We only need a traverse function, no clear function: If the module
is in a cycle, md_dict will be cleared as well, which will break
the cycle. */
@ -229,24 +191,41 @@ PyTypeObject PyModule_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"module", /* tp_name */
sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /* tp_size */
0, /* tp_itemsize */
(destructor)module_dealloc, /* tp_dealloc */
(destructor)module_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)module_repr, /* tp_repr */
(reprfunc)module_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
(getattrofunc)module_getattro, /* tp_getattro */
(setattrofunc)module_setattro, /* tp_setattro */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
(traverseproc)module_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
module_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyModuleObject, md_dict), /* tp_dictoffset */
(initproc)module_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};

View File

@ -32,7 +32,7 @@ dump_counts(void)
for (tp = type_list; tp; tp = tp->tp_next)
fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n",
tp->tp_name, tp->tp_alloc, tp->tp_free,
tp->tp_name, tp->tp_allocs, tp->tp_frees,
tp->tp_maxalloc);
fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
fast_tuple_allocs, tuple_zero_allocs);
@ -53,8 +53,8 @@ get_counts(void)
if (result == NULL)
return NULL;
for (tp = type_list; tp; tp = tp->tp_next) {
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_alloc,
tp->tp_free, tp->tp_maxalloc);
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_allocs,
tp->tp_frees, tp->tp_maxalloc);
if (v == NULL) {
Py_DECREF(result);
return NULL;
@ -72,16 +72,16 @@ get_counts(void)
void
inc_count(PyTypeObject *tp)
{
if (tp->tp_alloc == 0) {
if (tp->tp_allocs == 0) {
/* first time; insert in linked list */
if (tp->tp_next != NULL) /* sanity check */
Py_FatalError("XXX inc_count sanity check");
tp->tp_next = type_list;
type_list = tp;
}
tp->tp_alloc++;
if (tp->tp_alloc - tp->tp_free > tp->tp_maxalloc)
tp->tp_maxalloc = tp->tp_alloc - tp->tp_free;
tp->tp_allocs++;
if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc)
tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees;
}
#endif
@ -93,10 +93,8 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
"NULL object passed to PyObject_Init");
return op;
}
#ifdef WITH_CYCLE_GC
if (PyType_IS_GC(tp))
op = (PyObject *) PyObject_FROM_GC(op);
#endif
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
op->ob_type = tp;
_Py_NewReference(op);
@ -111,10 +109,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, int size)
"NULL object passed to PyObject_InitVar");
return op;
}
#ifdef WITH_CYCLE_GC
if (PyType_IS_GC(tp))
op = (PyVarObject *) PyObject_FROM_GC(op);
#endif
/* Any changes should be reflected in PyObject_INIT_VAR */
op->ob_size = size;
op->ob_type = tp;
@ -129,10 +125,8 @@ _PyObject_New(PyTypeObject *tp)
op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
if (op == NULL)
return PyErr_NoMemory();
#ifdef WITH_CYCLE_GC
if (PyType_IS_GC(tp))
op = (PyObject *) PyObject_FROM_GC(op);
#endif
return PyObject_INIT(op, tp);
}
@ -143,21 +137,17 @@ _PyObject_NewVar(PyTypeObject *tp, int size)
op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
if (op == NULL)
return (PyVarObject *)PyErr_NoMemory();
#ifdef WITH_CYCLE_GC
if (PyType_IS_GC(tp))
op = (PyVarObject *) PyObject_FROM_GC(op);
#endif
return PyObject_INIT_VAR(op, tp, size);
}
void
_PyObject_Del(PyObject *op)
{
#ifdef WITH_CYCLE_GC
if (op && PyType_IS_GC(op->ob_type)) {
op = (PyObject *) PyObject_AS_GC(op);
}
#endif
PyObject_FREE(op);
}
@ -994,26 +984,16 @@ PyObject_Hash(PyObject *v)
PyObject *
PyObject_GetAttrString(PyObject *v, char *name)
{
if (v->ob_type->tp_getattro != NULL) {
PyObject *w, *res;
w = PyString_InternFromString(name);
if (w == NULL)
return NULL;
res = (*v->ob_type->tp_getattro)(v, w);
Py_XDECREF(w);
return res;
}
PyObject *w, *res;
if (v->ob_type->tp_getattr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
v->ob_type->tp_name,
name);
return NULL;
}
else {
if (v->ob_type->tp_getattr != NULL)
return (*v->ob_type->tp_getattr)(v, name);
}
w = PyString_InternFromString(name);
if (w == NULL)
return NULL;
res = PyObject_GetAttr(v, w);
Py_XDECREF(w);
return res;
}
int
@ -1031,34 +1011,24 @@ PyObject_HasAttrString(PyObject *v, char *name)
int
PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
{
if (v->ob_type->tp_setattro != NULL) {
PyObject *s;
int res;
s = PyString_InternFromString(name);
if (s == NULL)
return -1;
res = (*v->ob_type->tp_setattro)(v, s, w);
Py_XDECREF(s);
return res;
}
PyObject *s;
int res;
if (v->ob_type->tp_setattr == NULL) {
if (v->ob_type->tp_getattr == NULL)
PyErr_SetString(PyExc_TypeError,
"attribute-less object (assign or del)");
else
PyErr_SetString(PyExc_TypeError,
"object has read-only attributes");
return -1;
}
else {
if (v->ob_type->tp_setattr != NULL)
return (*v->ob_type->tp_setattr)(v, name, w);
}
s = PyString_InternFromString(name);
if (s == NULL)
return -1;
res = PyObject_SetAttr(v, s, w);
Py_XDECREF(s);
return res;
}
PyObject *
PyObject_GetAttr(PyObject *v, PyObject *name)
{
PyTypeObject *tp = v->ob_type;
/* The Unicode to string conversion is done here because the
existing tp_getattro slots expect a string object as name
and we wouldn't want to break those. */
@ -1067,16 +1037,19 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
if (name == NULL)
return NULL;
}
if (!PyString_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"attribute name must be string");
return NULL;
}
if (v->ob_type->tp_getattro != NULL)
return (*v->ob_type->tp_getattro)(v, name);
else
return PyObject_GetAttrString(v, PyString_AS_STRING(name));
if (tp->tp_getattro != NULL)
return (*tp->tp_getattro)(v, name);
if (tp->tp_getattr != NULL)
return (*tp->tp_getattr)(v, PyString_AS_STRING(name));
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name));
return NULL;
}
int
@ -1094,6 +1067,7 @@ PyObject_HasAttr(PyObject *v, PyObject *name)
int
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
{
PyTypeObject *tp = v->ob_type;
int err;
/* The Unicode to string conversion is done here because the
@ -1104,25 +1078,182 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
if (name == NULL)
return -1;
}
else
Py_INCREF(name);
if (!PyString_Check(name)){
else if (!PyString_Check(name)){
PyErr_SetString(PyExc_TypeError,
"attribute name must be string");
err = -1;
return -1;
}
else {
PyString_InternInPlace(&name);
if (v->ob_type->tp_setattro != NULL)
err = (*v->ob_type->tp_setattro)(v, name, value);
else
err = PyObject_SetAttrString(v,
PyString_AS_STRING(name), value);
else
Py_INCREF(name);
PyString_InternInPlace(&name);
if (tp->tp_setattro != NULL) {
err = (*tp->tp_setattro)(v, name, value);
Py_DECREF(name);
return err;
}
if (tp->tp_setattr != NULL) {
err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value);
Py_DECREF(name);
return err;
}
Py_DECREF(name);
return err;
if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
PyErr_Format(PyExc_TypeError,
"'%.100s' object has no attributes "
"(%s .%.100s)",
tp->tp_name,
value==NULL ? "del" : "assign to",
PyString_AS_STRING(name));
else
PyErr_Format(PyExc_TypeError,
"'%.100s' object has only read-only attributes "
"(%s .%.100s)",
tp->tp_name,
value==NULL ? "del" : "assign to",
PyString_AS_STRING(name));
return -1;
}
/* Helper to get a pointer to an object's __dict__ slot, if any */
PyObject **
_PyObject_GetDictPtr(PyObject *obj)
{
#define PTRSIZE (sizeof(PyObject *))
long dictoffset;
PyTypeObject *tp = obj->ob_type;
if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS))
return NULL;
dictoffset = tp->tp_dictoffset;
if (dictoffset == 0)
return NULL;
if (dictoffset < 0) {
dictoffset += PyType_BASICSIZE(tp);
assert(dictoffset > 0); /* Sanity check */
if (tp->tp_itemsize > 0) {
int n = ((PyVarObject *)obj)->ob_size;
if (n > 0) {
dictoffset += tp->tp_itemsize * n;
/* Round up, if necessary */
if (tp->tp_itemsize % PTRSIZE != 0) {
dictoffset += PTRSIZE - 1;
dictoffset /= PTRSIZE;
dictoffset *= PTRSIZE;
}
}
}
}
return (PyObject **) ((char *)obj + dictoffset);
}
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
PyObject *
PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
{
PyTypeObject *tp = obj->ob_type;
PyObject *descr;
descrgetfunc f;
PyObject **dictptr;
if (tp->tp_dict == NULL) {
if (PyType_InitDict(tp) < 0)
return NULL;
}
descr = _PyType_Lookup(tp, name);
f = NULL;
if (descr != NULL) {
f = descr->ob_type->tp_descr_get;
if (f != NULL && PyDescr_IsData(descr))
return f(descr, obj, (PyObject *)obj->ob_type);
}
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
if (dict != NULL) {
PyObject *res = PyDict_GetItem(dict, name);
if (res != NULL) {
Py_INCREF(res);
return res;
}
}
}
if (f != NULL)
return f(descr, obj, (PyObject *)obj->ob_type);
if (descr != NULL) {
Py_INCREF(descr);
return descr;
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name));
return NULL;
}
int
PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
{
PyTypeObject *tp = obj->ob_type;
PyObject *descr;
descrsetfunc f;
PyObject **dictptr;
if (tp->tp_dict == NULL) {
if (PyType_InitDict(tp) < 0)
return -1;
}
descr = _PyType_Lookup(tp, name);
f = NULL;
if (descr != NULL) {
f = descr->ob_type->tp_descr_set;
if (f != NULL && PyDescr_IsData(descr))
return f(descr, obj, value);
}
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
if (dict == NULL && value != NULL) {
dict = PyDict_New();
if (dict == NULL)
return -1;
*dictptr = dict;
}
if (dict != NULL) {
int res;
if (value == NULL)
res = PyDict_DelItem(dict, name);
else
res = PyDict_SetItem(dict, name, value);
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetObject(PyExc_AttributeError, name);
return res;
}
}
if (f != NULL)
return f(descr, obj, value);
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name));
return -1;
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' object attribute '%.400s' is read-only",
tp->tp_name, PyString_AS_STRING(name));
return -1;
}
/* Test a value used as condition, e.g., in a for or if statement.
@ -1218,12 +1349,6 @@ PyCallable_Check(PyObject *x)
{
if (x == NULL)
return 0;
if (x->ob_type->tp_call != NULL ||
PyFunction_Check(x) ||
PyMethod_Check(x) ||
PyCFunction_Check(x) ||
PyClass_Check(x))
return 1;
if (PyInstance_Check(x)) {
PyObject *call = PyObject_GetAttrString(x, "__call__");
if (call == NULL) {
@ -1235,7 +1360,9 @@ PyCallable_Check(PyObject *x)
Py_DECREF(call);
return 1;
}
return 0;
else {
return x->ob_type->tp_call != NULL;
}
}
@ -1365,7 +1492,7 @@ _Py_ForgetReference(register PyObject *op)
op->_ob_prev->_ob_next = op->_ob_next;
op->_ob_next = op->_ob_prev = NULL;
#ifdef COUNT_ALLOCS
op->ob_type->tp_free++;
op->ob_type->tp_frees++;
#endif
}

View File

@ -310,22 +310,34 @@ PyTypeObject PyRange_Type = {
"xrange", /* Name of this type */
sizeof(rangeobject), /* Basic object size */
0, /* Item size for varobject */
(destructor)range_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)range_getattr, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)range_compare, /*tp_compare*/
(reprfunc)range_repr, /*tp_repr*/
0, /*tp_as_number*/
&range_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
(destructor)range_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)range_getattr, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)range_compare, /*tp_compare*/
(reprfunc)range_repr, /*tp_repr*/
0, /*tp_as_number*/
&range_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
PyObject_GenericGetAttr, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
#undef WARN

View File

@ -14,6 +14,7 @@ this type and there is exactly one in existence.
*/
#include "Python.h"
#include "structmember.h"
static PyObject *
ellipsis_repr(PyObject *op)
@ -128,32 +129,12 @@ slice_repr(PySliceObject *r)
return s;
}
static PyObject *slice_getattr(PySliceObject *self, char *name)
{
PyObject *ret;
ret = NULL;
if (strcmp(name, "start") == 0) {
ret = self->start;
}
else if (strcmp(name, "stop") == 0) {
ret = self->stop;
}
else if (strcmp(name, "step") == 0) {
ret = self->step;
}
else if (strcmp(name, "__members__") == 0) {
return Py_BuildValue("[sss]",
"start", "stop", "step");
}
else {
PyErr_SetString(PyExc_AttributeError, name);
return NULL;
}
Py_INCREF(ret);
return ret;
}
static struct memberlist slice_members[] = {
{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
{0}
};
static int
slice_compare(PySliceObject *v, PySliceObject *w)
@ -182,13 +163,32 @@ PyTypeObject PySlice_Type = {
"slice", /* Name of this type */
sizeof(PySliceObject), /* Basic object size */
0, /* Item size for varobject */
(destructor)slice_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)slice_getattr, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)slice_compare, /*tp_compare*/
(reprfunc)slice_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(destructor)slice_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)slice_compare, /* tp_compare */
(reprfunc)slice_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
slice_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};

View File

@ -2522,41 +2522,65 @@ string_methods[] = {
};
static PyObject *
string_getattr(PyStringObject *s, char *name)
string_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return Py_FindMethod(string_methods, (PyObject*)s, name);
PyObject *x = NULL;
static char *kwlist[] = {"object", 0};
assert(type == &PyString_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str", kwlist, &x))
return NULL;
if (x == NULL)
return PyString_FromString("");
return PyObject_Str(x);
}
static char string_doc[] =
"str(object) -> string\n\
\n\
Return a nice string representation of the object.\n\
If the argument is a string, the return value is the same object.";
PyTypeObject PyString_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"string",
"str",
sizeof(PyStringObject),
sizeof(char),
(destructor)string_dealloc, /*tp_dealloc*/
(printfunc)string_print, /*tp_print*/
(getattrfunc)string_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)string_repr, /*tp_repr*/
0, /*tp_as_number*/
&string_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)string_hash, /*tp_hash*/
0, /*tp_call*/
(reprfunc)string_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
&string_as_buffer, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
(richcmpfunc)string_richcompare, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
(destructor)string_dealloc, /* tp_dealloc */
(printfunc)string_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)string_repr, /* tp_repr */
0, /* tp_as_number */
&string_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)string_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)string_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&string_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
string_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)string_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
string_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
string_new, /* tp_new */
};
void

View File

@ -480,6 +480,28 @@ tuplerichcompare(PyObject *v, PyObject *w, int op)
return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op);
}
static PyObject *
tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
static char *kwlist[] = {"sequence", 0};
assert(type == &PyTuple_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
return NULL;
if (arg == NULL)
return PyTuple_New(0);
else
return PySequence_Tuple(arg);
}
static char tuple_doc[] =
"tuple(sequence) -> list\n\
\n\
Return a tuple whose items are the same as those of the argument sequence.\n\
If the argument is a tuple, the return value is the same object.";
static PySequenceMethods tuple_as_sequence = {
(inquiry)tuplelength, /* sq_length */
(binaryfunc)tupleconcat, /* sq_concat */
@ -509,14 +531,28 @@ PyTypeObject PyTuple_Type = {
(hashfunc)tuplehash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
tuple_doc, /* tp_doc */
(traverseproc)tupletraverse, /* tp_traverse */
0, /* tp_clear */
tuplerichcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
tuple_new, /* tp_new */
};
/* The following function breaks the notion that tuples are immutable:

File diff suppressed because it is too large Load Diff

View File

@ -4667,12 +4667,6 @@ static PyMethodDef unicode_methods[] = {
{NULL, NULL}
};
static PyObject *
unicode_getattr(PyUnicodeObject *self, char *name)
{
return Py_FindMethod(unicode_methods, (PyObject*) self, name);
}
static PySequenceMethods unicode_as_sequence = {
(inquiry) unicode_length, /* sq_length */
(binaryfunc) PyUnicode_Concat, /* sq_concat */
@ -5346,6 +5340,30 @@ static PyBufferProcs unicode_as_buffer = {
(getcharbufferproc) unicode_buffer_getcharbuf,
};
static PyObject *
unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *x = NULL;
static char *kwlist[] = {"string", "encoding", "errors", 0};
char *encoding = NULL;
char *errors = NULL;
assert(type == &PyUnicode_Type);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:unicode",
kwlist, &x, &encoding, &errors))
return NULL;
if (x == NULL)
return (PyObject *)_PyUnicode_New(0);
return PyUnicode_FromEncodedObject(x, encoding, errors);
}
static char unicode_doc[] =
"unicode(string [, encoding[, errors]]) -> object\n\
\n\
Create a new Unicode object from the given encoded string.\n\
encoding defaults to the current default string encoding and \n\
errors, defining the error handling, to 'strict'.";
PyTypeObject PyUnicode_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
@ -5355,7 +5373,7 @@ PyTypeObject PyUnicode_Type = {
/* Slots */
(destructor)_PyUnicode_Free, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)unicode_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc) unicode_compare, /* tp_compare */
(reprfunc) unicode_repr, /* tp_repr */
@ -5365,10 +5383,28 @@ PyTypeObject PyUnicode_Type = {
(hashfunc) unicode_hash, /* tp_hash*/
0, /* tp_call*/
(reprfunc) unicode_str, /* tp_str */
(getattrofunc) NULL, /* tp_getattro */
(setattrofunc) NULL, /* tp_setattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&unicode_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
unicode_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
unicode_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
unicode_new, /* tp_new */
};
/* Initialize the Unicode implementation */

View File

@ -44,6 +44,7 @@ extern void init_locale(void);
extern void init_codecs(void);
extern void initxreadlines(void);
extern void init_weakref(void);
extern void initxxsubtype(void);
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
/* -- ADDMODULE MARKER 1 -- */
@ -98,6 +99,8 @@ struct _inittab _PyImport_Inittab[] = {
{"xreadlines", initxreadlines},
{"_weakref", init_weakref},
{"xxsubtype", initxxsubtype},
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
/* -- ADDMODULE MARKER 2 -- */

View File

@ -495,6 +495,21 @@ SOURCE=..\Modules\cStringIO.c
# End Source File
# Begin Source File
SOURCE=..\Objects\descrobject.c
!IF "$(CFG)" == "pythoncore - Win32 Release"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Debug"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Debug"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Release"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\Objects\dictobject.c
!IF "$(CFG)" == "pythoncore - Win32 Release"
@ -1737,6 +1752,21 @@ SOURCE=..\Modules\xreadlinesmodule.c
# End Source File
# Begin Source File
SOURCE=..\Modules\xxsubtype.c
!IF "$(CFG)" == "pythoncore - Win32 Release"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Debug"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Debug"
!ELSEIF "$(CFG)" == "pythoncore - Win32 Alpha Release"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\Modules\yuvconvert.c
!IF "$(CFG)" == "pythoncore - Win32 Release"

431
PLAN.txt Normal file
View File

@ -0,0 +1,431 @@
Project: core implementation
****************************
Tasks:
Do binary operators properly. nb_add should try to call self.__add__
and other.__radd__. I think I'll exclude base types that define any
binary operator without setting the CHECKTYPES flag.
Fix comparisons. There's some nasty stuff here: when two types are
not the same, and they're not instances, the fallback code doesn't
account for the possibility that they might be subtypes of a common
base type that defines a comparison.
Fix subtype_dealloc(). This currently searches through the list of
base types until it finds a type whose tp_dealloc is not
subtype_dealloc. I think this is not safe. I think the alloc/dealloc
policy needs to be rethought. *** There's an idea here that I haven't
worked out yet: just as object creation now has separate API's tp_new,
tp_alloc, and tp_init, destruction has tp_dealloc and tp_free. (Maybe
tp_fini should be added to correspond to tp_init?) Something
could/should be done with this. ***
Clean up isinstance(), issubclass() and their C equivalents. There
are a bunch of different APIs here and not all of them do the right
thing yet. There should be fewer APIs and their implementation should
be simpler. The old "abstract subclass" test should probably
disappear (if we want to root out ExtensionClass). *** I think I've
done 90% of this by creating PyType_IsSubtype() and using it
appropriately. For now, the old "abstract subclass" test is still
there, and there may be some places where PyObject_IsSubclass() is
called where PyType_IsSubtype() would be more appropriate. ***
Check for conflicts between base classes. I fear that the rules used
to decide whether multiple bases have conflicting instance variables
aren't strict enough. I think that sometimes two different classes
adding __dict__ may be incompatible after all.
Check for order conflicts. Suppose there are two base classes X and
Y. Suppose class B derives from X and Y, and class C from Y and X (in
that order). Now suppose class D derives from B and C. In which
order should the base classes X and Y be searched? This is an order
conflict, and should be disallowed; currently the test for this is not
implemented.
Clean up the GC interface. Currently, tp_basicsize includes the GC
head size iff tp_flags includes the GC flag bit. This makes object
size math a pain (e.g. to see if two object types have the same
instance size, you can't just compare the tp_basicsize fields -- you
have to conditionally subtract the GC head size). Neil has a patch
that improves the API in this area, but it's backwards incompatible.
(http://sf.net/tracker/?func=detail&aid=421893&group_id=5470&atid=305470)
I think I know of a way to fix the incompatibility (by switching to a
different flag bit). *** Tim proposed a better idea: macros to access
tp_basicsize while hiding the nastiness. This is done now, so I think
the rest of this task needn't be done. ***
Make the __dict__ of types declared with Python class statements
writable -- only statically declared types must have an immutable
dict, because they're shared between interpreter instances. Possibly
trap writes to the __dict__ to update the corresponding tp_<slot> if
an __<slot>__ name is affected. *** Done as part of the next task. ***
It should be an option (maybe a different metaclass, maybe a flag) to
*not* merge __dict__ with all the bases, but instead search the
__dict__ (or __introduced__?) of all bases in __mro__ order. (This is
needed anyway to unify classes completely.) *** Partly done.
Inheritance of slots from bases is still icky: (1) MRO is not always
respected when inheriting slots; (2) dynamic classes can't add slot
implementations in Python after creation (e.g., setting C.__hash__
doesn't set the tp_hash slot). ***
Universal base class (object). How can we make the object class
subclassable and define simple default methods for everything without
having these inherited by built-in types that don't want these
defaults? *** Done, really. ***
Add error checking to the MRO calculation. *** Done. ***
Make __new__ overridable through a Python class method (!). Make more
of the sub-algorithms of type construction available as methods. ***
After I implemented class methods, I found that in order to be able
to make an upcall to Base.__new__() and have it create an instance of
your class (rather than a Base instance), you can't use class methods
-- you must use static methods. So I've implemented those too. I've
hooked up __new__ in the right places, so the first part of this is
now done. I've also exported the MRO calculation and made it
overridable, as metamethod mro(). I believe that closes this topic
for now. I expect that some warts will only be really debugged when
we try to use this for some, eh, interesting types such as tuples. ***
More -- I'm sure new issues will crop up as we go.
Project: loose ends and follow-through
**************************************
Tasks:
Make more (most?) built-in types act as their own factory functions.
Make more (most?) built-in types subtypable -- with or without
overridable allocation. *** This includes descriptors! It should be
possible to write descriptors in Python, so metaclasses can do clever
things with them. ***
Exceptions should be types. This changes the rules, since now almost
anything can be raised (as maybe it should). Or should we strive for
enforcement of the convention that all exceptions should be derived
from Exception? String exceptions will be another hassle, to be
deprecated and eventually ruled out.
Standardize a module containing names for all built-in types, and
standardize on names. E.g. should the official name of the string
type be 'str', 'string', or 'StringType'?
Create a hierarchy of types, so that e.g. int and long are both
subtypes of an abstract base type integer, which is itself a subtype
of number, etc. A lot of thinking can go into this!
*** NEW TASK??? ***
Implement "signature" objects. These are alluded to in PEP 252 but
not yet specified. Supposedly they provide an easily usable API to
find out about function/method arguments. Building these for Python
functions is simple. Building these for built-in functions will
require a change to the PyMethodDef structure, so that a type can
provide signature information for its C methods. (This would also
help in supporting keyword arguments for C methods with less work than
PyArg_ParseTupleAndKeywords() currently requires.) But should we do
this? It's additional work and not required for any of the other
parts.
Project: making classes use the new machinery
*********************************************
Tasks:
Try to get rid of all code in classobject.c by deferring to the new
mechanisms. How far can we get without breaking backwards
compatibility? This is underspecified because I haven't thought much
about it yet. Can we lose the use of PyInstance_Check() everywhere?
I would hope so!
Project: backwards compatibility
********************************
Tasks:
Make sure all code checks the proper tp_flags bit before accessing
type object fields.
Identify areas of incompatibility with Python 2.1. Design solutions.
Implement and test.
Some specific areas: a fair amount of code probably depends on
specific types having __members__ and/or __methods__ attributes.
These are currently not present (conformant to PEP 252, which proposes
to drop them) but we may have to add them back. This can be done in a
generic way with not too much effort. Tim adds: Perhaps that dir(object)
rarely returns anything but [] now is a consequence of this. I'm very
used to doing, e.g., dir([]) or dir("") in an interactive shell to jog my
memory; also one of the reasons test_generators failed.
Another area: going all the way with classes and instances means that
type(x) == types.InstanceType won't work any more to detect instances.
Should there be a mode where this still works? Maybe this should be
the default mode, with a warning, and an explicit way to get the new
way to work? (Instead of a __future__ statement, I'm thinking of a
module global __metaclass__ which would provide the default metaclass
for baseless class statements.)
Project: testing
****************
Tasks:
Identify new functionality that needs testing. Conceive unit tests
for all new functionality. Conceive stress tests for critical
features. Run the tests. Fix bugs. Repeat until satisfied.
Note: this may interact with the branch integration task.
Project: integration with main branch
*************************************
Tasks:
Merge changes in the HEAD branch into the descr-branch. Then merge
the descr-branch back into the HEAD branch.
The longer we wait, the more effort this will be -- the descr-branch
forked off quite a long time ago, and there are changes everywhere in
the HEAD branch (e.g. the dict object has been radically rewritten).
On the other hand, if we do this too early, we'll have to do it again
later.
Note from Tim: We should never again wait until literally 100s of files
are out of synch. I don't care how often I need to do this, provided only
that it's a tractable task each time. Once per week sounds like a good
idea. As is, even the trunk change to rangeobject.c created more than its
proper share of merge headaches, because it confused all the other reasons
include file merges were getting conflicts (the more changes there are, the
worse diff does; indeed, I came up with the ndiff algorithm in the 80s
precisely because the source-control diff program Cray used at the time
produced minimal but *senseless* diffs, thus creating artificial conflicts;
paying unbounded attention to context does a much better job of putting
changes where they make semantic sense too; but we're stuck with Unix diff
here, and it isn't robust in this sense; if we don't keep its job simple,
it will make my job hell).
Done:
To undo or rename before final merge: Modules/spam.c has worked its
way into the branch Unix and Windows builds (pythoncore.dsp and
PC/config.c); also imported by test_descr.py. How about renaming to
xxsubtype.c (whatever) now?
Project: performance tuning
***************************
Tasks:
Pick or create a general performance benchmark for Python. Benchmark
the new system vs. the old system. Profile the new system. Improve
hotspots. Repeat until satisfied.
Note: this may interact with the branch integration task.
Project: documentation
**********************
Tasks:
Update PEP 252 (descriptors). Describe more of the prototype
implementation
Update PEP 253 (subtyping). Complicated architectural wrangling with
metaclasses. There is an interaction between implementation and
description.
Write PEP 254 (unification of classes). This should discuss what
changes for ordinary classes, and how we can make it more b/w
compatible.
Other documentation. There needs to be user documentation,
eventually.
Project: community interaction
******************************
Tasks:
Once the PEPs are written, solicit community feedback, and formulate
responses to the feedback. Give the community enough time to think
over this complicated proposal. Provide the community with a
prototype implementation to test. Try to do this *before* casting
everything in stone!
MERGE BEGIN ****************************************************************
Merge details (this section is Tim's scratchpad, but should help a lot if
he dies of frustration while wrestling with CVS <0.9 wink>).
----------------------------------------------------------------------------
2001-08-01 Merging descr-branch back into trunk.
Tagged trunk about 22:05:
cvs tag date2001-08-01 python
Merged trunk delta into branch:
cvs -q -z3 up -j date2001-07-30 -j date2001-08-01 descr
No conflicts (! first time ever!) ... but problems with pythoncore.dsp.
Resolved.
Rebuilt from scratch; ran all tests; checked into branch about 22:40.
Merged descr-branch back into trunk:
cvs -q -z3 up -j descr-branch python
34 conflicts. Hmm! OK, looks like every file in the project with an
embedded RCS Id is "a conflict". Others make no sense, e.g., a dozen
conflicts in dictobject.c, sometimes enclosing identical(!) blobs of
source code. And CVS remains utterly baffled by Python type object decls.
Every line of ceval.c's generator code si in conflict blocks ... OK,
there's no pattern or sense here, I'll just deal with it.
Conflicts resolved; rebuilt from scratch; test_weakref fails.
----------------------------------------------------------------------------
2001-07-30
Doing this again while the expat and Windows installer changes are still
fresh on my mind.
Tagged trunk about 23:50 EDT on the 29th:
cvs tag date2001-07-30 python
Merged trunk delta into branch:
cvs -q -z3 up -j date2001-07-28 -j date2001-07-30 descr
2 conflicts, resolved.
----------------------------------------------------------------------------
2001-07-28
Tagged trunk about 00:31 EDT:
cvs tag date2001-07-28 python
Merged trunk delta into branch:
cvs -q -z3 up -j date2001-07-21 -j date2001-07-28 descr
4 conflicts, all RCS Ids. Resolved.
----------------------------------------------------------------------------
2001-07-21
Tagged trunk about 01:00 EDT:
cvs tag date2001-07-21 python
Merged trunk delta into branch:
cvs -q -z3 up -j date2001-07-17b -j date2001-07-21 descr
4 conflicts, mostly RCS Id thingies. Resolved.
Legit failure in new test_repr, because repr.py dispatches on the exact
string returned by type(x). type(1L) and type('s') differ in descr-branch
now, and repr.py didn't realize that, falling back to the "unknown type"
case for longs and strings. Repaired descr-branch repr.py.
----------------------------------------------------------------------------
2001-07-19
Removed the r22a1-branch tag (see next entry). Turns out Guido did add a
r22a1 tag, so the r22a1-branch tag served no point anymore.
----------------------------------------------------------------------------
2001-07-18 2.2a1 releaase
Immediately after the merge just below, I tagged descr-branch via
cvs tag r22a1-branch descr
Guido may or may not want to add another tag here (? maybe he wants to do
some more Unix fiddling first).
----------------------------------------------------------------------------
2001-07-17 building 2.2a1 release, from descr-branch
Tagged trunk about 22:00 EDT, like so:
cvs tag date2001-07-17b python
Merged trunk delta into branch via:
cvs -q -z3 up -j date2001-07-17a -j date2001-07-17b descr
----------------------------------------------------------------------------
2001-07-17
Tagged trunk about 00:05 EDT, like so:
cvs tag date2001-07-17a python
Merged trunk delta into branch via:
cvs -q -z3 up -j date2001-07-16 -j date2001-07-17a descr
----------------------------------------------------------------------------
2001-07-16
Tagged trunk about 15:20 EDT, like so:
cvs tag date2001-07-16 python
Guido then added all the other dist/ directories to descr-branch from that
trunk tag.
Tim then merged trunk delta into the branch via:
cvs -q -z3 up -j date2001-07-15 -j date2001-07-16 descr
----------------------------------------------------------------------------
2001-07-15
Tagged trunk about 15:44 EDT, like so:
cvs tag date2001-07-15 python
Merged trunk delta into branch via:
cvs -q -z3 up -j date2001-07-13 -j date2001-07-15 descr
Four files with conflicts, all artificial RCS Id & Revision thingies.
Resolved and committed.
----------------------------------------------------------------------------
2001-07-13
Tagged trunk about 22:13 EDT, like so:
cvs tag date2001-07-13 python
Merged trunk delta into branch via:
cvs -q -z3 up -j date2001-07-06 -j date2001-07-13 descr
Six(!) files with conflicts, mostly related to NeilS's generator gc patches.
Unsure why, but CVS seems always to think there are conflicts whenever a
line in a type object decl gets changed, and the conflict marking seems
maximally confused in these cases. Anyway, since I reviewed those patches
on the trunk, good thing I'm merging them, and darned glad it's still fresh
on my mind.
Resolved the conflicts, and committed the changes in a few hours total.
----------------------------------------------------------------------------
2001-07-07
Merge of trunk tag date2001-07-06 into descr-branch, via
cvs -q -z3 up -j date2001-07-06 mergedescr
was committed on 2001-07-07.
Merge issues:
(all resolved -- GvR)
----------------------------------------------------------------------------
2001-07-06
Tagged trunk a bit after midnight, like so:
C:\Code>cvs tag date2001-07-06 python
cvs server: Tagging python
cvs server: Tagging python/dist
cvs server: Tagging python/dist/src
T python/dist/src/.cvsignore
T python/dist/src/LICENSE
T python/dist/src/Makefile.pre.in
T python/dist/src/README
... [& about 3000 lines more] ...
This is the first trunk snapshot to be merged into the descr-branch.
Gave it a date instead of a goofy name because there's going to be more
than one of these, and at least it's obvious which of two ISO dates comes
earlier. These tags should go away after all merging is complete.
MERGE END ******************************************************************

View File

@ -131,26 +131,6 @@ start of the object (or at the specified offset). The slice will\n\
extend to the end of the target object (or with the specified size).";
static PyObject *
builtin_unicode(PyObject *self, PyObject *args)
{
PyObject *v;
char *encoding = NULL;
char *errors = NULL;
if ( !PyArg_ParseTuple(args, "O|ss:unicode", &v, &encoding, &errors) )
return NULL;
return PyUnicode_FromEncodedObject(v, encoding, errors);
}
static char unicode_doc[] =
"unicode(string [, encoding[, errors]]) -> object\n\
\n\
Create a new Unicode object from the given encoded string.\n\
encoding defaults to the current default string encoding and \n\
errors, defining the error handling, to 'strict'.";
static PyObject *
builtin_callable(PyObject *self, PyObject *args)
{
@ -435,257 +415,6 @@ The mode must be 'exec' to compile a module, 'single' to compile a\n\
single (interactive) statement, or 'eval' to compile an expression.";
#ifndef WITHOUT_COMPLEX
static PyObject *
complex_from_string(PyObject *v)
{
extern double strtod(const char *, char **);
const char *s, *start;
char *end;
double x=0.0, y=0.0, z;
int got_re=0, got_im=0, done=0;
int digit_or_dot;
int sw_error=0;
int sign;
char buffer[256]; /* For errors */
char s_buffer[256];
int len;
if (PyString_Check(v)) {
s = PyString_AS_STRING(v);
len = PyString_GET_SIZE(v);
}
else if (PyUnicode_Check(v)) {
if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
PyErr_SetString(PyExc_ValueError,
"complex() literal too large to convert");
return NULL;
}
if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v),
s_buffer,
NULL))
return NULL;
s = s_buffer;
len = (int)strlen(s);
}
else if (PyObject_AsCharBuffer(v, &s, &len)) {
PyErr_SetString(PyExc_TypeError,
"complex() arg is not a string");
return NULL;
}
/* position on first nonblank */
start = s;
while (*s && isspace(Py_CHARMASK(*s)))
s++;
if (s[0] == '\0') {
PyErr_SetString(PyExc_ValueError,
"complex() arg is an empty string");
return NULL;
}
z = -1.0;
sign = 1;
do {
switch (*s) {
case '\0':
if (s-start != len) {
PyErr_SetString(
PyExc_ValueError,
"complex() arg contains a null byte");
return NULL;
}
if(!done) sw_error=1;
break;
case '-':
sign = -1;
/* Fallthrough */
case '+':
if (done) sw_error=1;
s++;
if ( *s=='\0'||*s=='+'||*s=='-' ||
isspace(Py_CHARMASK(*s)) ) sw_error=1;
break;
case 'J':
case 'j':
if (got_im || done) {
sw_error = 1;
break;
}
if (z<0.0) {
y=sign;
}
else{
y=sign*z;
}
got_im=1;
s++;
if (*s!='+' && *s!='-' )
done=1;
break;
default:
if (isspace(Py_CHARMASK(*s))) {
while (*s && isspace(Py_CHARMASK(*s)))
s++;
if (s[0] != '\0')
sw_error=1;
else
done = 1;
break;
}
digit_or_dot =
(*s=='.' || isdigit(Py_CHARMASK(*s)));
if (done||!digit_or_dot) {
sw_error=1;
break;
}
errno = 0;
PyFPE_START_PROTECT("strtod", return 0)
z = strtod(s, &end) ;
PyFPE_END_PROTECT(z)
if (errno != 0) {
sprintf(buffer,
"float() out of range: %.150s", s);
PyErr_SetString(
PyExc_ValueError,
buffer);
return NULL;
}
s=end;
if (*s=='J' || *s=='j') {
break;
}
if (got_re) {
sw_error=1;
break;
}
/* accept a real part */
x=sign*z;
got_re=1;
if (got_im) done=1;
z = -1.0;
sign = 1;
break;
} /* end of switch */
} while (*s!='\0' && !sw_error);
if (sw_error) {
PyErr_SetString(PyExc_ValueError,
"complex() arg is a malformed string");
return NULL;
}
return PyComplex_FromDoubles(x,y);
}
static PyObject *
builtin_complex(PyObject *self, PyObject *args)
{
PyObject *r, *i, *tmp;
PyNumberMethods *nbr, *nbi = NULL;
Py_complex cr, ci;
int own_r = 0;
i = NULL;
if (!PyArg_ParseTuple(args, "O|O:complex", &r, &i))
return NULL;
if (PyString_Check(r) || PyUnicode_Check(r))
return complex_from_string(r);
if ((nbr = r->ob_type->tp_as_number) == NULL ||
nbr->nb_float == NULL ||
(i != NULL &&
((nbi = i->ob_type->tp_as_number) == NULL ||
nbi->nb_float == NULL))) {
PyErr_SetString(PyExc_TypeError,
"complex() arg can't be converted to complex");
return NULL;
}
/* XXX Hack to support classes with __complex__ method */
if (PyInstance_Check(r)) {
static PyObject *complexstr;
PyObject *f;
if (complexstr == NULL) {
complexstr = PyString_InternFromString("__complex__");
if (complexstr == NULL)
return NULL;
}
f = PyObject_GetAttr(r, complexstr);
if (f == NULL)
PyErr_Clear();
else {
PyObject *args = Py_BuildValue("()");
if (args == NULL)
return NULL;
r = PyEval_CallObject(f, args);
Py_DECREF(args);
Py_DECREF(f);
if (r == NULL)
return NULL;
own_r = 1;
}
}
if (PyComplex_Check(r)) {
cr = ((PyComplexObject*)r)->cval;
if (own_r) {
Py_DECREF(r);
}
}
else {
tmp = PyNumber_Float(r);
if (own_r) {
Py_DECREF(r);
}
if (tmp == NULL)
return NULL;
if (!PyFloat_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"float(r) didn't return a float");
Py_DECREF(tmp);
return NULL;
}
cr.real = PyFloat_AsDouble(tmp);
Py_DECREF(tmp);
cr.imag = 0.0;
}
if (i == NULL) {
ci.real = 0.0;
ci.imag = 0.0;
}
else if (PyComplex_Check(i))
ci = ((PyComplexObject*)i)->cval;
else {
tmp = (*nbi->nb_float)(i);
if (tmp == NULL)
return NULL;
ci.real = PyFloat_AsDouble(tmp);
Py_DECREF(tmp);
ci.imag = 0.;
}
cr.real -= ci.imag;
cr.imag += ci.real;
return PyComplex_FromCComplex(cr);
}
static char complex_doc[] =
"complex(real[, imag]) -> complex number\n\
\n\
Create a complex number from a real part and an optional imaginary part.\n\
This is equivalent to (real + imag*1j) where imag defaults to 0.";
#endif
static PyObject *
builtin_dir(PyObject *self, PyObject *args)
{
@ -1060,8 +789,8 @@ builtin_map(PyObject *self, PyObject *args)
}
if (curlen < 0)
curlen = 8; /* arbitrary */
if (curlen > len)
len = curlen;
if (curlen > len)
len = curlen;
}
/* Get space for the result list. */
@ -1300,91 +1029,6 @@ Return the string itself or the previously interned string object with the\n\
same value.";
static PyObject *
builtin_int(PyObject *self, PyObject *args)
{
PyObject *v;
int base = -909; /* unlikely! */
if (!PyArg_ParseTuple(args, "O|i:int", &v, &base))
return NULL;
if (base == -909)
return PyNumber_Int(v);
else if (PyString_Check(v))
return PyInt_FromString(PyString_AS_STRING(v), NULL, base);
else if (PyUnicode_Check(v))
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v),
base);
else {
PyErr_SetString(PyExc_TypeError,
"int() can't convert non-string with explicit base");
return NULL;
}
}
static char int_doc[] =
"int(x[, base]) -> integer\n\
\n\
Convert a string or number to an integer, if possible. A floating point\n\
argument will be truncated towards zero (this does not include a string\n\
representation of a floating point number!) When converting a string, use\n\
the optional base. It is an error to supply a base when converting a\n\
non-string.";
static PyObject *
builtin_long(PyObject *self, PyObject *args)
{
PyObject *v;
int base = -909; /* unlikely! */
if (!PyArg_ParseTuple(args, "O|i:long", &v, &base))
return NULL;
if (base == -909)
return PyNumber_Long(v);
else if (PyString_Check(v))
return PyLong_FromString(PyString_AS_STRING(v), NULL, base);
else if (PyUnicode_Check(v))
return PyLong_FromUnicode(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v),
base);
else {
PyErr_SetString(PyExc_TypeError,
"long() can't convert non-string with explicit base");
return NULL;
}
}
static char long_doc[] =
"long(x) -> long integer\n\
long(x, base) -> long integer\n\
\n\
Convert a string or number to a long integer, if possible. A floating\n\
point argument will be truncated towards zero (this does not include a\n\
string representation of a floating point number!) When converting a\n\
string, use the given base. It is an error to supply a base when\n\
converting a non-string.";
static PyObject *
builtin_float(PyObject *self, PyObject *args)
{
PyObject *v;
if (!PyArg_ParseTuple(args, "O:float", &v))
return NULL;
if (PyString_Check(v))
return PyFloat_FromString(v, NULL);
return PyNumber_Float(v);
}
static char float_doc[] =
"float(x) -> floating point number\n\
\n\
Convert a string or number to a floating point number, if possible.";
static PyObject *
builtin_iter(PyObject *self, PyObject *args)
{
@ -1431,22 +1075,6 @@ static char len_doc[] =
Return the number of items of a sequence or mapping.";
static PyObject *
builtin_list(PyObject *self, PyObject *args)
{
PyObject *v;
if (!PyArg_ParseTuple(args, "O:list", &v))
return NULL;
return PySequence_List(v);
}
static char list_doc[] =
"list(sequence) -> list\n\
\n\
Return a new list whose items are the same as those of the argument sequence.";
static PyObject *
builtin_slice(PyObject *self, PyObject *args)
{
@ -2032,58 +1660,6 @@ Round a number to a given precision in decimal digits (default 0 digits).\n\
This always returns a floating point number. Precision may be negative.";
static PyObject *
builtin_str(PyObject *self, PyObject *args)
{
PyObject *v;
if (!PyArg_ParseTuple(args, "O:str", &v))
return NULL;
return PyObject_Str(v);
}
static char str_doc[] =
"str(object) -> string\n\
\n\
Return a nice string representation of the object.\n\
If the argument is a string, the return value is the same object.";
static PyObject *
builtin_tuple(PyObject *self, PyObject *args)
{
PyObject *v;
if (!PyArg_ParseTuple(args, "O:tuple", &v))
return NULL;
return PySequence_Tuple(v);
}
static char tuple_doc[] =
"tuple(sequence) -> list\n\
\n\
Return a tuple whose items are the same as those of the argument sequence.\n\
If the argument is a tuple, the return value is the same object.";
static PyObject *
builtin_type(PyObject *self, PyObject *args)
{
PyObject *v;
if (!PyArg_ParseTuple(args, "O:type", &v))
return NULL;
v = (PyObject *)v->ob_type;
Py_INCREF(v);
return v;
}
static char type_doc[] =
"type(object) -> type object\n\
\n\
Return the type of the object.";
static PyObject *
builtin_vars(PyObject *self, PyObject *args)
{
@ -2255,16 +1831,12 @@ static PyMethodDef builtin_methods[] = {
{"cmp", builtin_cmp, 1, cmp_doc},
{"coerce", builtin_coerce, 1, coerce_doc},
{"compile", builtin_compile, 1, compile_doc},
#ifndef WITHOUT_COMPLEX
{"complex", builtin_complex, 1, complex_doc},
#endif
{"delattr", builtin_delattr, 1, delattr_doc},
{"dir", builtin_dir, 1, dir_doc},
{"divmod", builtin_divmod, 1, divmod_doc},
{"eval", builtin_eval, 1, eval_doc},
{"execfile", builtin_execfile, 1, execfile_doc},
{"filter", builtin_filter, 1, filter_doc},
{"float", builtin_float, 1, float_doc},
{"getattr", builtin_getattr, 1, getattr_doc},
{"globals", builtin_globals, 1, globals_doc},
{"hasattr", builtin_hasattr, 1, hasattr_doc},
@ -2273,14 +1845,11 @@ static PyMethodDef builtin_methods[] = {
{"id", builtin_id, 1, id_doc},
{"input", builtin_input, 1, input_doc},
{"intern", builtin_intern, 1, intern_doc},
{"int", builtin_int, 1, int_doc},
{"isinstance", builtin_isinstance, 1, isinstance_doc},
{"issubclass", builtin_issubclass, 1, issubclass_doc},
{"iter", builtin_iter, 1, iter_doc},
{"len", builtin_len, 1, len_doc},
{"list", builtin_list, 1, list_doc},
{"locals", builtin_locals, 1, locals_doc},
{"long", builtin_long, 1, long_doc},
{"map", builtin_map, 1, map_doc},
{"max", builtin_max, 1, max_doc},
{"min", builtin_min, 1, min_doc},
@ -2296,10 +1865,6 @@ static PyMethodDef builtin_methods[] = {
{"round", builtin_round, 1, round_doc},
{"setattr", builtin_setattr, 1, setattr_doc},
{"slice", builtin_slice, 1, slice_doc},
{"str", builtin_str, 1, str_doc},
{"tuple", builtin_tuple, 1, tuple_doc},
{"type", builtin_type, 1, type_doc},
{"unicode", builtin_unicode, 1, unicode_doc},
{"unichr", builtin_unichr, 1, unichr_doc},
{"vars", builtin_vars, 1, vars_doc},
{"xrange", builtin_xrange, 1, xrange_doc},
@ -2329,6 +1894,42 @@ _PyBuiltin_Init(void)
if (PyDict_SetItemString(dict, "NotImplemented",
Py_NotImplemented) < 0)
return NULL;
if (PyDict_SetItemString(dict, "classmethod",
(PyObject *) &PyClassMethod_Type) < 0)
return NULL;
#ifndef WITHOUT_COMPLEX
if (PyDict_SetItemString(dict, "complex",
(PyObject *) &PyComplex_Type) < 0)
return NULL;
#endif
if (PyDict_SetItemString(dict, "dictionary",
(PyObject *) &PyDict_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "float",
(PyObject *) &PyFloat_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "int", (PyObject *) &PyInt_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "list", (PyObject *) &PyList_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "long", (PyObject *) &PyLong_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "object",
(PyObject *) &PyBaseObject_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "staticmethod",
(PyObject *) &PyStaticMethod_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "str", (PyObject *) &PyString_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "tuple",
(PyObject *) &PyTuple_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "type", (PyObject *) &PyType_Type) < 0)
return NULL;
if (PyDict_SetItemString(dict, "unicode",
(PyObject *) &PyUnicode_Type) < 0)
return NULL;
debug = PyInt_FromLong(Py_OptimizeFlag == 0);
if (PyDict_SetItemString(dict, "__debug__", debug) < 0) {
Py_XDECREF(debug);

View File

@ -13,6 +13,7 @@
#include "frameobject.h"
#include "eval.h"
#include "opcode.h"
#include "structmember.h"
#ifdef macintosh
#include "macglue.h"
@ -32,17 +33,7 @@
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
/* Forward declarations */
static PyObject *eval_code2(PyCodeObject *,
PyObject *, PyObject *,
PyObject **, int,
PyObject **, int,
PyObject **, int,
PyObject *);
static PyObject *eval_frame(PyFrameObject *);
static char *get_func_name(PyObject *);
static char *get_func_desc(PyObject *);
static PyObject *call_object(PyObject *, PyObject *, PyObject *);
static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
@ -98,7 +89,6 @@ static long dxp[256];
#endif
#endif
staticforward PyTypeObject gentype;
typedef struct {
@ -211,24 +201,11 @@ static struct PyMethodDef gen_methods[] = {
{NULL, NULL} /* Sentinel */
};
static PyObject *
gen_getattr(genobject *gen, char *name)
{
PyObject *result;
if (strcmp(name, "gi_frame") == 0) {
result = (PyObject *)gen->gi_frame;
assert(result != NULL);
Py_INCREF(result);
}
else if (strcmp(name, "gi_running") == 0)
result = (PyObject *)PyInt_FromLong((long)gen->gi_running);
else if (strcmp(name, "__members__") == 0)
result = Py_BuildValue("[ss]", "gi_frame", "gi_running");
else
result = Py_FindMethod(gen_methods, (PyObject *)gen, name);
return result;
}
static struct memberlist gen_memberlist[] = {
{"gi_frame", T_OBJECT, offsetof(genobject, gi_frame), RO},
{"gi_running", T_INT, offsetof(genobject, gi_running), RO},
{NULL} /* Sentinel */
};
statichere PyTypeObject gentype = {
PyObject_HEAD_INIT(&PyType_Type)
@ -239,7 +216,7 @@ statichere PyTypeObject gentype = {
/* methods */
(destructor)gen_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)gen_getattr, /* tp_getattr */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
@ -249,7 +226,7 @@ statichere PyTypeObject gentype = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
@ -260,6 +237,11 @@ statichere PyTypeObject gentype = {
0, /* tp_weaklistoffset */
(getiterfunc)gen_getiter, /* tp_iter */
(iternextfunc)gen_iternext, /* tp_iternext */
gen_methods, /* tp_methods */
gen_memberlist, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
@ -505,7 +487,7 @@ static int unpack_iterable(PyObject *, int, PyObject **);
PyObject *
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
{
return eval_code2(co,
return PyEval_EvalCodeEx(co,
globals, locals,
(PyObject **)NULL, 0,
(PyObject **)NULL, 0,
@ -516,7 +498,7 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
/* Interpreter main loop */
PyObject *
static PyObject *
eval_frame(PyFrameObject *f)
{
#ifdef DXPAIRS
@ -965,7 +947,7 @@ eval_frame(PyFrameObject *f)
case BINARY_SUBSCR:
w = POP();
v = POP();
if (PyList_Check(v) && PyInt_Check(w)) {
if (v->ob_type == &PyList_Type && PyInt_Check(w)) {
/* INLINE: list[int] */
long i = PyInt_AsLong(w);
if (i < 0)
@ -2273,8 +2255,8 @@ eval_frame(PyFrameObject *f)
return retval;
}
static PyObject *
eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
PyObject *
PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
PyObject **args, int argcount, PyObject **kws, int kwcount,
PyObject **defs, int defcount, PyObject *closure)
{
@ -2973,13 +2955,13 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
return NULL;
}
result = call_object(func, arg, kw);
result = PyObject_Call(func, arg, kw);
Py_DECREF(arg);
return result;
}
/* How often is each kind of object called? The answer depends on the
program. An instrumented call_object() was used to run the Python
program. An instrumented PyObject_Call() was used to run the Python
regression test suite. The results were:
4200000 PyCFunctions
390000 fast_function() calls
@ -2992,11 +2974,11 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
most common, but not by such a large margin.
*/
static char *
get_func_name(PyObject *func)
char *
PyEval_GetFuncName(PyObject *func)
{
if (PyMethod_Check(func))
return get_func_name(PyMethod_GET_FUNCTION(func));
return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func));
else if (PyFunction_Check(func))
return PyString_AsString(((PyFunctionObject*)func)->func_name);
else if (PyCFunction_Check(func))
@ -3011,8 +2993,8 @@ get_func_name(PyObject *func)
}
}
static char *
get_func_desc(PyObject *func)
char *
PyEval_GetFuncDesc(PyObject *func)
{
if (PyMethod_Check(func))
return "()";
@ -3136,7 +3118,8 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
PyErr_Format(PyExc_TypeError,
"unbound method %s%s must be "
"called with instance as first argument",
get_func_name(func), get_func_desc(func));
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func));
return NULL;
}
Py_INCREF(arg);
@ -3199,7 +3182,7 @@ call_eval_code2(PyObject *func, PyObject *arg, PyObject *kw)
nk = 0;
}
result = eval_code2(
result = PyEval_EvalCodeEx(
(PyCodeObject *)PyFunction_GET_CODE(func),
PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
@ -3255,7 +3238,7 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = ((PyTupleObject *)argdefs)->ob_size;
}
return eval_code2((PyCodeObject *)co, globals,
return PyEval_EvalCodeEx((PyCodeObject *)co, globals,
(PyObject *)NULL, (*pp_stack)-n, na,
(*pp_stack)-2*nk, nk, d, nd,
closure);
@ -3282,8 +3265,8 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
PyErr_Format(PyExc_TypeError,
"%.200s%s got multiple values "
"for keyword argument '%.200s'",
get_func_name(func),
get_func_desc(func),
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
PyString_AsString(key));
Py_DECREF(key);
Py_DECREF(value);
@ -3356,7 +3339,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
callargs = load_args(pp_stack, na);
if (callargs == NULL)
goto call_fail;
result = call_object(func, callargs, kwdict);
result = PyObject_Call(func, callargs, kwdict);
call_fail:
Py_XDECREF(callargs);
Py_XDECREF(kwdict);
@ -3378,8 +3361,8 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
PyErr_Format(PyExc_TypeError,
"%s%s argument after ** "
"must be a dictionary",
get_func_name(func),
get_func_desc(func));
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func));
goto ext_call_fail;
}
}
@ -3393,8 +3376,8 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
PyErr_Format(PyExc_TypeError,
"%s%s argument after * "
"must be a sequence",
get_func_name(func),
get_func_desc(func));
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func));
}
goto ext_call_fail;
}
@ -3411,7 +3394,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
callargs = update_star_args(na, nstar, stararg, pp_stack);
if (callargs == NULL)
goto ext_call_fail;
result = call_object(func, callargs, kwdict);
result = PyObject_Call(func, callargs, kwdict);
ext_call_fail:
Py_XDECREF(callargs);
Py_XDECREF(kwdict);
@ -3632,63 +3615,25 @@ import_all_from(PyObject *locals, PyObject *v)
static PyObject *
build_class(PyObject *methods, PyObject *bases, PyObject *name)
{
int i, n;
if (!PyTuple_Check(bases)) {
PyErr_SetString(PyExc_SystemError,
"build_class with non-tuple bases");
return NULL;
}
if (!PyDict_Check(methods)) {
PyErr_SetString(PyExc_SystemError,
"build_class with non-dictionary");
return NULL;
}
if (!PyString_Check(name)) {
PyErr_SetString(PyExc_SystemError,
"build_class with non-string name");
return NULL;
}
n = PyTuple_Size(bases);
for (i = 0; i < n; i++) {
PyObject *base = PyTuple_GET_ITEM(bases, i);
if (!PyClass_Check(base)) {
/* Call the base's *type*, if it is callable.
This code is a hook for Donald Beaudry's
and Jim Fulton's type extensions. In
unextended Python it will never be triggered
since its types are not callable.
Ditto: call the bases's *class*, if it has
one. This makes the same thing possible
without writing C code. A true meta-object
protocol! */
PyObject *basetype = (PyObject *)base->ob_type;
PyObject *callable = NULL;
if (PyCallable_Check(basetype))
callable = basetype;
else
callable = PyObject_GetAttrString(
base, "__class__");
if (callable) {
PyObject *args;
PyObject *newclass = NULL;
args = Py_BuildValue(
"(OOO)", name, bases, methods);
if (args != NULL) {
newclass = PyEval_CallObject(
callable, args);
Py_DECREF(args);
}
if (callable != basetype) {
Py_DECREF(callable);
}
return newclass;
}
PyErr_SetString(PyExc_TypeError,
"base is not a class object");
return NULL;
PyObject *metaclass = NULL;
if (PyDict_Check(methods))
metaclass = PyDict_GetItemString(methods, "__metaclass__");
if (metaclass == NULL) {
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0)
metaclass = (PyObject *)
PyTuple_GET_ITEM(bases, 0)->ob_type;
else {
PyObject *g = PyEval_GetGlobals();
if (g != NULL && PyDict_Check(g))
metaclass = PyDict_GetItemString(
g, "__metaclass__");
if (metaclass == NULL)
metaclass = (PyObject *) &PyClass_Type;
}
}
return PyClass_New(bases, methods, name);
return PyObject_CallFunction(metaclass, "OOO", name, bases, methods);
}
static int

View File

@ -1056,23 +1056,36 @@ static struct {
DL_EXPORT(void)
init_exceptions(void)
_PyExc_Init(void)
{
char *modulename = "exceptions";
int modnamesz = strlen(modulename);
int i;
PyObject *me, *mydict, *bltinmod, *bdict, *doc, *args;
PyObject *me = Py_InitModule(modulename, functions);
PyObject *mydict = PyModule_GetDict(me);
PyObject *bltinmod = PyImport_ImportModule("__builtin__");
PyObject *bdict = PyModule_GetDict(bltinmod);
PyObject *doc = PyString_FromString(module__doc__);
PyObject *args;
me = Py_InitModule(modulename, functions);
if (me == NULL)
goto err;
mydict = PyModule_GetDict(me);
if (mydict == NULL)
goto err;
bltinmod = PyImport_ImportModule("__builtin__");
if (bltinmod == NULL)
goto err;
bdict = PyModule_GetDict(bltinmod);
if (bdict == NULL)
goto err;
doc = PyString_FromString(module__doc__);
if (doc == NULL)
goto err;
PyDict_SetItemString(mydict, "__doc__", doc);
i = PyDict_SetItemString(mydict, "__doc__", doc);
Py_DECREF(doc);
if (PyErr_Occurred())
if (i < 0) {
err:
Py_FatalError("exceptions bootstrapping error.");
return;
}
/* This is the base class of all exceptions, so make it first. */
if (make_Exception(modulename) ||
@ -1139,7 +1152,7 @@ init_exceptions(void)
DL_EXPORT(void)
fini_exceptions(void)
_PyExc_Fini(void)
{
int i;

View File

@ -43,7 +43,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
/* XXX Perhaps the magic number should be frozen and a version field
added to the .pyc file header? */
/* New way to come up with the magic number: (YEAR-1995), MONTH, DAY */
#define MAGIC (60420 | ((long)'\r'<<16) | ((long)'\n'<<24))
#define MAGIC (60717 | ((long)'\r'<<16) | ((long)'\n'<<24))
/* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the
@ -1968,8 +1968,11 @@ PyImport_Import(PyObject *module_name)
}
/* Get the __import__ function from the builtins */
if (PyDict_Check(builtins))
if (PyDict_Check(builtins)) {
import = PyObject_GetItem(builtins, import_str);
if (import == NULL)
PyErr_SetObject(PyExc_KeyError, import_str);
}
else
import = PyObject_GetAttr(builtins, import_str);
if (import == NULL)

View File

@ -115,6 +115,9 @@ Py_Initialize(void)
Py_FatalError("Py_Initialize: can't make first thread");
(void) PyThreadState_Swap(tstate);
if (PyType_InitDict(&PyType_Type) < 0)
Py_FatalError("Py_Initialize: can't initialize 'type'");
interp->modules = PyDict_New();
if (interp->modules == NULL)
Py_FatalError("Py_Initialize: can't make modules dictionary");
@ -144,7 +147,7 @@ Py_Initialize(void)
_PyImport_Init();
/* initialize builtin exceptions */
init_exceptions();
_PyExc_Init();
/* phase 2 of builtins */
_PyImport_FixupExtension("__builtin__", "__builtin__");
@ -238,7 +241,7 @@ Py_Finalize(void)
below has been checked to make sure no exceptions are ever
raised.
*/
fini_exceptions();
_PyExc_Fini();
/* Delete current thread */
PyInterpreterState_Clear(interp);
@ -1345,7 +1348,7 @@ _Py_AskYesNo(char *prompt)
{
char buf[256];
printf("%s [ny] ", prompt);
fprintf(stderr, "%s [ny] ", prompt);
if (fgets(buf, sizeof buf, stdin) == NULL)
return 0;
return buf[0] == 'y' || buf[0] == 'Y';