Merge of descr-branch back into trunk.
This commit is contained in:
parent
52d55a3926
commit
6d6c1a35e0
|
@ -89,6 +89,7 @@
|
|||
#include "sliceobject.h"
|
||||
#include "cellobject.h"
|
||||
#include "iterobject.h"
|
||||
#include "descrobject.h"
|
||||
|
||||
#include "codecs.h"
|
||||
#include "pyerrors.h"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 *);
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 >= ... */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
|
@ -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()
|
||||
|
|
12
Lib/types.py
12
Lib/types.py
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
11
Misc/NEWS
11
Misc/NEWS
|
@ -44,6 +44,17 @@ What's New in Python 2.2a1?
|
|||
|
||||
Core
|
||||
|
||||
- TENTATIVELY, a large amount of code implementing much of what's
|
||||
described in PEP 252 (Making Types Look More Like Classes) and PEP
|
||||
253 (Subtyping Built-in Types) was added. This will be released
|
||||
with Python 2.2a1. Documentation will be provided separately
|
||||
through http://www.python.org/2.2/. The purpose of releasing this
|
||||
with Python 2.2a1 is to test backwards compatibility. It is
|
||||
possible, though not likely, that a decision is made not to release
|
||||
this code as part of 2.2 final, if any serious backwards
|
||||
incompapatibilities are found during alpha testing that cannot be
|
||||
repaired.
|
||||
|
||||
- Generators were added; this is a new way to create an iterator (see
|
||||
below) using what looks like a simple function containing one or
|
||||
more 'yield' statements. See PEP 255. Since this adds a new
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -37,7 +37,7 @@ struct _inittab _PyImport_Inittab[] = {
|
|||
{"__main__", NULL},
|
||||
{"__builtin__", NULL},
|
||||
{"sys", NULL},
|
||||
{"exceptions", init_exceptions},
|
||||
{"exceptions", NULL},
|
||||
|
||||
/* Sentinel */
|
||||
{0, 0}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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", ¶m))
|
||||
return NULL;
|
||||
|
||||
if (PyDict_Check(param)) {
|
||||
other = (dictobject*)param;
|
||||
if (a == NULL || !PyDict_Check(a) || b == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
mp = (dictobject*)a;
|
||||
if (PyDict_Check(b)) {
|
||||
other = (dictobject*)b;
|
||||
if (other == mp || other->ma_used == 0)
|
||||
/* a.update(a) or a.update({}); nothing to do */
|
||||
goto done;
|
||||
return 0;
|
||||
/* Do one big resize at the start, rather than
|
||||
* incrementally resizing as we insert new items. Expect
|
||||
* that there will be no (or few) overlapping keys.
|
||||
*/
|
||||
if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
|
||||
if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i <= other->ma_mask; i++) {
|
||||
entry = &other->ma_table[i];
|
||||
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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! */
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
293
Objects/object.c
293
Objects/object.c
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
2358
Objects/typeobject.c
2358
Objects/typeobject.c
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
|
|
@ -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 -- */
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ******************************************************************
|
|
@ -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);
|
||||
|
|
163
Python/ceval.c
163
Python/ceval.c
|
@ -13,6 +13,7 @@
|
|||
#include "frameobject.h"
|
||||
#include "eval.h"
|
||||
#include "opcode.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#ifdef macintosh
|
||||
#include "macglue.h"
|
||||
|
@ -32,17 +33,7 @@
|
|||
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
static PyObject *eval_code2(PyCodeObject *,
|
||||
PyObject *, PyObject *,
|
||||
PyObject **, int,
|
||||
PyObject **, int,
|
||||
PyObject **, int,
|
||||
PyObject *);
|
||||
|
||||
static PyObject *eval_frame(PyFrameObject *);
|
||||
static char *get_func_name(PyObject *);
|
||||
static char *get_func_desc(PyObject *);
|
||||
static PyObject *call_object(PyObject *, PyObject *, PyObject *);
|
||||
static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
|
||||
static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
|
||||
|
@ -98,7 +89,6 @@ 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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in New Issue