mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
Merge of descr-branch back into trunk.
This commit is contained in:
parent
52d55a3926
commit
6d6c1a35e0
57 changed files with 6923 additions and 1309 deletions
|
@ -89,6 +89,7 @@
|
||||||
#include "sliceobject.h"
|
#include "sliceobject.h"
|
||||||
#include "cellobject.h"
|
#include "cellobject.h"
|
||||||
#include "iterobject.h"
|
#include "iterobject.h"
|
||||||
|
#include "descrobject.h"
|
||||||
|
|
||||||
#include "codecs.h"
|
#include "codecs.h"
|
||||||
#include "pyerrors.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,
|
DL_IMPORT(PyObject *) PyObject_CallObject(PyObject *callable_object,
|
||||||
PyObject *args);
|
PyObject *args);
|
||||||
|
|
|
@ -45,6 +45,9 @@ DL_IMPORT(int) Py_MakePendingCalls(void);
|
||||||
DL_IMPORT(void) Py_SetRecursionLimit(int);
|
DL_IMPORT(void) Py_SetRecursionLimit(int);
|
||||||
DL_IMPORT(int) Py_GetRecursionLimit(void);
|
DL_IMPORT(int) Py_GetRecursionLimit(void);
|
||||||
|
|
||||||
|
DL_IMPORT(char *) PyEval_GetFuncName(PyObject *);
|
||||||
|
DL_IMPORT(char *) PyEval_GetFuncDesc(PyObject *);
|
||||||
|
|
||||||
/* Interface for threads.
|
/* Interface for threads.
|
||||||
|
|
||||||
A module that plans to do a blocking system call (or something else
|
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 *) PyInstance_NewRaw(PyObject *, PyObject *);
|
||||||
extern DL_IMPORT(PyObject *) PyMethod_New(PyObject *, 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*
|
/* Macros for direct access to these values. Type checks are *not*
|
||||||
done, so use with care. */
|
done, so use with care. */
|
||||||
#define PyMethod_GET_FUNCTION(meth) \
|
#define PyMethod_GET_FUNCTION(meth) \
|
||||||
|
|
32
Include/descrobject.h
Normal file
32
Include/descrobject.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* XXX getter, setter, getsetlist and wrapperbase need 'Py'-prefixed names */
|
||||||
|
|
||||||
|
typedef PyObject *(*getter)(PyObject *, void *);
|
||||||
|
typedef int (*setter)(PyObject *, PyObject *, void *);
|
||||||
|
|
||||||
|
struct getsetlist {
|
||||||
|
char *name;
|
||||||
|
getter get;
|
||||||
|
setter set;
|
||||||
|
void *closure;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
|
||||||
|
void *wrapped);
|
||||||
|
|
||||||
|
struct wrapperbase {
|
||||||
|
char *name;
|
||||||
|
wrapperfunc wrapper;
|
||||||
|
char *doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
|
||||||
|
extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
|
||||||
|
struct memberlist *);
|
||||||
|
extern DL_IMPORT(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
|
||||||
|
struct getsetlist *);
|
||||||
|
extern DL_IMPORT(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
|
||||||
|
struct wrapperbase *, void *);
|
||||||
|
extern DL_IMPORT(int) PyDescr_IsData(PyObject *);
|
||||||
|
|
||||||
|
extern DL_IMPORT(PyObject *) PyDictProxy_New(PyObject *);
|
||||||
|
extern DL_IMPORT(PyObject *) PyWrapper_New(PyObject *, PyObject *);
|
|
@ -7,9 +7,83 @@ extern "C" {
|
||||||
|
|
||||||
/* Dictionary object type -- mapping from hashable object to object */
|
/* 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;
|
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_New(void);
|
||||||
extern DL_IMPORT(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
|
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(PyObject *) PyDict_Items(PyObject *mp);
|
||||||
extern DL_IMPORT(int) PyDict_Size(PyObject *mp);
|
extern DL_IMPORT(int) PyDict_Size(PyObject *mp);
|
||||||
extern DL_IMPORT(PyObject *) PyDict_Copy(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);
|
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_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,6 +42,13 @@ extern DL_IMPORT(int) PyFunction_SetClosure(PyObject *, PyObject *);
|
||||||
#define PyFunction_GET_CLOSURE(func) \
|
#define PyFunction_GET_CLOSURE(func) \
|
||||||
(((PyFunctionObject *)func) -> func_closure)
|
(((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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,7 +26,7 @@ typedef struct {
|
||||||
|
|
||||||
extern DL_IMPORT(PyTypeObject) PyList_Type;
|
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(PyObject *) PyList_New(int size);
|
||||||
extern DL_IMPORT(int) PyList_Size(PyObject *);
|
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_AddIntConstant(PyObject *, char *, long);
|
||||||
extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
|
extern DL_IMPORT(int) PyModule_AddStringConstant(PyObject *, char *, char *);
|
||||||
|
|
||||||
#define PYTHON_API_VERSION 1010
|
#define PYTHON_API_VERSION 1011
|
||||||
#define PYTHON_API_STRING "1010"
|
#define PYTHON_API_STRING "1011"
|
||||||
/* The API version is maintained (independently from the Python version)
|
/* The API version is maintained (independently from the Python version)
|
||||||
so we can detect mismatches between the interpreter and dynamically
|
so we can detect mismatches between the interpreter and dynamically
|
||||||
loaded modules. These are diagnosed by an error message but
|
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
|
Please add a line or two to the top of this log for each API
|
||||||
version change:
|
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
|
25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and
|
||||||
PyFrame_New(); Python 2.1a2
|
PyFrame_New(); Python 2.1a2
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,11 @@ typedef long (*hashfunc)(PyObject *);
|
||||||
typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
|
typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
|
||||||
typedef PyObject *(*getiterfunc) (PyObject *);
|
typedef PyObject *(*getiterfunc) (PyObject *);
|
||||||
typedef PyObject *(*iternextfunc) (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 {
|
typedef struct _typeobject {
|
||||||
PyObject_VAR_HEAD
|
PyObject_VAR_HEAD
|
||||||
|
@ -255,18 +260,48 @@ typedef struct _typeobject {
|
||||||
getiterfunc tp_iter;
|
getiterfunc tp_iter;
|
||||||
iternextfunc tp_iternext;
|
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
|
#ifdef COUNT_ALLOCS
|
||||||
/* these must be last and never explicitly initialized */
|
/* these must be last and never explicitly initialized */
|
||||||
int tp_alloc;
|
int tp_allocs;
|
||||||
int tp_free;
|
int tp_frees;
|
||||||
int tp_maxalloc;
|
int tp_maxalloc;
|
||||||
struct _typeobject *tp_next;
|
struct _typeobject *tp_next;
|
||||||
#endif
|
#endif
|
||||||
} PyTypeObject;
|
} 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 */
|
/* Generic operations on objects */
|
||||||
extern DL_IMPORT(int) PyObject_Print(PyObject *, FILE *, int);
|
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(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
|
||||||
extern DL_IMPORT(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
|
extern DL_IMPORT(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
|
||||||
extern DL_IMPORT(int) PyObject_HasAttr(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(long) PyObject_Hash(PyObject *);
|
||||||
extern DL_IMPORT(int) PyObject_IsTrue(PyObject *);
|
extern DL_IMPORT(int) PyObject_IsTrue(PyObject *);
|
||||||
extern DL_IMPORT(int) PyObject_Not(PyObject *);
|
extern DL_IMPORT(int) PyObject_Not(PyObject *);
|
||||||
|
@ -357,6 +396,18 @@ given type object has a specified feature.
|
||||||
/* tp_iter is defined */
|
/* tp_iter is defined */
|
||||||
#define Py_TPFLAGS_HAVE_ITER (1L<<7)
|
#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 ( \
|
#define Py_TPFLAGS_DEFAULT ( \
|
||||||
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
|
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
|
||||||
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
|
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
|
||||||
|
@ -364,6 +415,7 @@ given type object has a specified feature.
|
||||||
Py_TPFLAGS_HAVE_RICHCOMPARE | \
|
Py_TPFLAGS_HAVE_RICHCOMPARE | \
|
||||||
Py_TPFLAGS_HAVE_WEAKREFS | \
|
Py_TPFLAGS_HAVE_WEAKREFS | \
|
||||||
Py_TPFLAGS_HAVE_ITER | \
|
Py_TPFLAGS_HAVE_ITER | \
|
||||||
|
Py_TPFLAGS_HAVE_CLASS | \
|
||||||
0)
|
0)
|
||||||
|
|
||||||
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 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
|
#ifndef Py_TRACE_REFS
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
#define _Py_Dealloc(op) ((op)->ob_type->tp_free++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
|
#define _Py_Dealloc(op) ((op)->ob_type->tp_frees++, (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
|
||||||
#define _Py_ForgetReference(op) ((op)->ob_type->tp_free++)
|
#define _Py_ForgetReference(op) ((op)->ob_type->tp_frees++)
|
||||||
#else /* !COUNT_ALLOCS */
|
#else /* !COUNT_ALLOCS */
|
||||||
#define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op))
|
#define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op))
|
||||||
#define _Py_ForgetReference(op) /*empty*/
|
#define _Py_ForgetReference(op) /*empty*/
|
||||||
|
|
|
@ -236,7 +236,13 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
|
||||||
#define PyObject_GC_Fini(op)
|
#define PyObject_GC_Fini(op)
|
||||||
#define PyObject_AS_GC(op) (op)
|
#define PyObject_AS_GC(op) (op)
|
||||||
#define PyObject_FROM_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
|
#else
|
||||||
|
|
||||||
/* Add the object into the container set */
|
/* Add the object into the container set */
|
||||||
|
@ -269,6 +275,13 @@ typedef struct _gc_head {
|
||||||
/* Get the object given the PyGC_Head */
|
/* Get the object given the PyGC_Head */
|
||||||
#define PyObject_FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
|
#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 *);
|
extern DL_IMPORT(void) _PyGC_Dump(PyGC_Head *);
|
||||||
|
|
||||||
#endif /* WITH_CYCLE_GC */
|
#endif /* WITH_CYCLE_GC */
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
#define PY_MINOR_VERSION 2
|
#define PY_MINOR_VERSION 2
|
||||||
#define PY_MICRO_VERSION 0
|
#define PY_MICRO_VERSION 0
|
||||||
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
|
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
|
||||||
#define PY_RELEASE_SERIAL 0
|
#define PY_RELEASE_SERIAL 1
|
||||||
|
|
||||||
/* Version as a string */
|
/* Version as a string */
|
||||||
#define PY_VERSION "2.2a0"
|
#define PY_VERSION "2.2a1"
|
||||||
|
|
||||||
/* Historic */
|
/* Historic */
|
||||||
#define PATCHLEVEL "2.2a0"
|
#define PATCHLEVEL "2.2a1"
|
||||||
|
|
||||||
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
|
/* 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 >= ... */
|
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 *) _PyBuiltin_Init(void);
|
||||||
DL_IMPORT(PyObject *) _PySys_Init(void);
|
DL_IMPORT(PyObject *) _PySys_Init(void);
|
||||||
DL_IMPORT(void) _PyImport_Init(void);
|
DL_IMPORT(void) _PyImport_Init(void);
|
||||||
DL_IMPORT(void) init_exceptions(void);
|
DL_IMPORT(void) _PyExc_Init(void);
|
||||||
|
|
||||||
/* Various internal finalizers */
|
/* Various internal finalizers */
|
||||||
DL_IMPORT(void) fini_exceptions(void);
|
DL_IMPORT(void) _PyExc_Fini(void);
|
||||||
DL_IMPORT(void) _PyImport_Fini(void);
|
DL_IMPORT(void) _PyImport_Fini(void);
|
||||||
DL_IMPORT(void) PyMethod_Fini(void);
|
DL_IMPORT(void) PyMethod_Fini(void);
|
||||||
DL_IMPORT(void) PyFrame_Fini(void);
|
DL_IMPORT(void) PyFrame_Fini(void);
|
||||||
|
|
|
@ -504,6 +504,7 @@ class Pickler:
|
||||||
dispatch[ClassType] = save_global
|
dispatch[ClassType] = save_global
|
||||||
dispatch[FunctionType] = save_global
|
dispatch[FunctionType] = save_global
|
||||||
dispatch[BuiltinFunctionType] = save_global
|
dispatch[BuiltinFunctionType] = save_global
|
||||||
|
dispatch[TypeType] = save_global
|
||||||
|
|
||||||
|
|
||||||
def _keep_alive(x, memo):
|
def _keep_alive(x, memo):
|
||||||
|
|
|
@ -62,7 +62,7 @@ class Repr:
|
||||||
s = s + ': ' + self.repr1(x[key], level-1)
|
s = s + ': ' + self.repr1(x[key], level-1)
|
||||||
if n > self.maxdict: s = s + ', ...'
|
if n > self.maxdict: s = s + ', ...'
|
||||||
return '{' + s + '}'
|
return '{' + s + '}'
|
||||||
def repr_string(self, x, level):
|
def repr_str(self, x, level):
|
||||||
s = `x[:self.maxstring]`
|
s = `x[:self.maxstring]`
|
||||||
if len(s) > self.maxstring:
|
if len(s) > self.maxstring:
|
||||||
i = max(0, (self.maxstring-3)/2)
|
i = max(0, (self.maxstring-3)/2)
|
||||||
|
@ -70,7 +70,7 @@ class Repr:
|
||||||
s = `x[:i] + x[len(x)-j:]`
|
s = `x[:i] + x[len(x)-j:]`
|
||||||
s = s[:i] + '...' + s[len(s)-j:]
|
s = s[:i] + '...' + s[len(s)-j:]
|
||||||
return s
|
return s
|
||||||
def repr_long_int(self, x, level):
|
def repr_long(self, x, level):
|
||||||
s = `x` # XXX Hope this isn't too slow...
|
s = `x` # XXX Hope this isn't too slow...
|
||||||
if len(s) > self.maxlong:
|
if len(s) > self.maxlong:
|
||||||
i = max(0, (self.maxlong-3)/2)
|
i = max(0, (self.maxlong-3)/2)
|
||||||
|
|
829
Lib/test/test_descr.py
Normal file
829
Lib/test/test_descr.py
Normal file
|
@ -0,0 +1,829 @@
|
||||||
|
# Test descriptor-related enhancements
|
||||||
|
|
||||||
|
from test_support import verify, verbose
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
def testunop(a, res, expr="len(a)", meth="__len__"):
|
||||||
|
if verbose: print "checking", expr
|
||||||
|
dict = {'a': a}
|
||||||
|
verify(eval(expr, dict) == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
verify(m(a) == res)
|
||||||
|
bm = getattr(a, meth)
|
||||||
|
verify(bm() == res)
|
||||||
|
|
||||||
|
def testbinop(a, b, res, expr="a+b", meth="__add__"):
|
||||||
|
if verbose: print "checking", expr
|
||||||
|
dict = {'a': a, 'b': b}
|
||||||
|
verify(eval(expr, dict) == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
verify(m(a, b) == res)
|
||||||
|
bm = getattr(a, meth)
|
||||||
|
verify(bm(b) == res)
|
||||||
|
|
||||||
|
def testternop(a, b, c, res, expr="a[b:c]", meth="__getslice__"):
|
||||||
|
if verbose: print "checking", expr
|
||||||
|
dict = {'a': a, 'b': b, 'c': c}
|
||||||
|
verify(eval(expr, dict) == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
verify(m(a, b, c) == res)
|
||||||
|
bm = getattr(a, meth)
|
||||||
|
verify(bm(b, c) == res)
|
||||||
|
|
||||||
|
def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"):
|
||||||
|
if verbose: print "checking", stmt
|
||||||
|
dict = {'a': deepcopy(a), 'b': b}
|
||||||
|
exec stmt in dict
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
m(dict['a'], b)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
bm = getattr(dict['a'], meth)
|
||||||
|
bm(b)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
|
||||||
|
def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"):
|
||||||
|
if verbose: print "checking", stmt
|
||||||
|
dict = {'a': deepcopy(a), 'b': b, 'c': c}
|
||||||
|
exec stmt in dict
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
m(dict['a'], b, c)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
bm = getattr(dict['a'], meth)
|
||||||
|
bm(b, c)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
|
||||||
|
def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
|
||||||
|
if verbose: print "checking", stmt
|
||||||
|
dict = {'a': deepcopy(a), 'b': b, 'c': c, 'd': d}
|
||||||
|
exec stmt in dict
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
t = type(a)
|
||||||
|
m = getattr(t, meth)
|
||||||
|
verify(m == t.__dict__[meth])
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
m(dict['a'], b, c, d)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
dict['a'] = deepcopy(a)
|
||||||
|
bm = getattr(dict['a'], meth)
|
||||||
|
bm(b, c, d)
|
||||||
|
verify(dict['a'] == res)
|
||||||
|
|
||||||
|
def lists():
|
||||||
|
if verbose: print "Testing list operations..."
|
||||||
|
testbinop([1], [2], [1,2], "a+b", "__add__")
|
||||||
|
testbinop([1,2,3], 2, 1, "b in a", "__contains__")
|
||||||
|
testbinop([1,2,3], 4, 0, "b in a", "__contains__")
|
||||||
|
testbinop([1,2,3], 1, 2, "a[b]", "__getitem__")
|
||||||
|
testternop([1,2,3], 0, 2, [1,2], "a[b:c]", "__getslice__")
|
||||||
|
testsetop([1], [2], [1,2], "a+=b", "__iadd__")
|
||||||
|
testsetop([1,2], 3, [1,2,1,2,1,2], "a*=b", "__imul__")
|
||||||
|
testunop([1,2,3], 3, "len(a)", "__len__")
|
||||||
|
testbinop([1,2], 3, [1,2,1,2,1,2], "a*b", "__mul__")
|
||||||
|
testbinop([1,2], 3, [1,2,1,2,1,2], "b*a", "__rmul__")
|
||||||
|
testset2op([1,2], 1, 3, [1,3], "a[b]=c", "__setitem__")
|
||||||
|
testset3op([1,2,3,4], 1, 3, [5,6], [1,5,6,4], "a[b:c]=d", "__setslice__")
|
||||||
|
|
||||||
|
def dicts():
|
||||||
|
if verbose: print "Testing dict operations..."
|
||||||
|
testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__")
|
||||||
|
testbinop({1:2,3:4}, 1, 1, "b in a", "__contains__")
|
||||||
|
testbinop({1:2,3:4}, 2, 0, "b in a", "__contains__")
|
||||||
|
testbinop({1:2,3:4}, 1, 2, "a[b]", "__getitem__")
|
||||||
|
d = {1:2,3:4}
|
||||||
|
l1 = []
|
||||||
|
for i in d.keys(): l1.append(i)
|
||||||
|
l = []
|
||||||
|
for i in iter(d): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
l = []
|
||||||
|
for i in d.__iter__(): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
l = []
|
||||||
|
for i in dictionary.__iter__(d): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
d = {1:2, 3:4}
|
||||||
|
testunop(d, 2, "len(a)", "__len__")
|
||||||
|
verify(eval(repr(d), {}) == d)
|
||||||
|
verify(eval(d.__repr__(), {}) == d)
|
||||||
|
testset2op({1:2,3:4}, 2, 3, {1:2,2:3,3:4}, "a[b]=c", "__setitem__")
|
||||||
|
|
||||||
|
binops = {
|
||||||
|
'add': '+',
|
||||||
|
'sub': '-',
|
||||||
|
'mul': '*',
|
||||||
|
'div': '/',
|
||||||
|
'mod': '%',
|
||||||
|
'divmod': 'divmod',
|
||||||
|
'pow': '**',
|
||||||
|
'lshift': '<<',
|
||||||
|
'rshift': '>>',
|
||||||
|
'and': '&',
|
||||||
|
'xor': '^',
|
||||||
|
'or': '|',
|
||||||
|
'cmp': 'cmp',
|
||||||
|
'lt': '<',
|
||||||
|
'le': '<=',
|
||||||
|
'eq': '==',
|
||||||
|
'ne': '!=',
|
||||||
|
'gt': '>',
|
||||||
|
'ge': '>=',
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, expr in binops.items():
|
||||||
|
if expr.islower():
|
||||||
|
expr = expr + "(a, b)"
|
||||||
|
else:
|
||||||
|
expr = 'a %s b' % expr
|
||||||
|
binops[name] = expr
|
||||||
|
|
||||||
|
unops = {
|
||||||
|
'pos': '+',
|
||||||
|
'neg': '-',
|
||||||
|
'abs': 'abs',
|
||||||
|
'invert': '~',
|
||||||
|
'int': 'int',
|
||||||
|
'long': 'long',
|
||||||
|
'float': 'float',
|
||||||
|
'oct': 'oct',
|
||||||
|
'hex': 'hex',
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, expr in unops.items():
|
||||||
|
if expr.islower():
|
||||||
|
expr = expr + "(a)"
|
||||||
|
else:
|
||||||
|
expr = '%s a' % expr
|
||||||
|
unops[name] = expr
|
||||||
|
|
||||||
|
def numops(a, b, skip=[]):
|
||||||
|
dict = {'a': a, 'b': b}
|
||||||
|
for name, expr in binops.items():
|
||||||
|
if name not in skip:
|
||||||
|
name = "__%s__" % name
|
||||||
|
if hasattr(a, name):
|
||||||
|
res = eval(expr, dict)
|
||||||
|
testbinop(a, b, res, expr, name)
|
||||||
|
for name, expr in unops.items():
|
||||||
|
name = "__%s__" % name
|
||||||
|
if hasattr(a, name):
|
||||||
|
res = eval(expr, dict)
|
||||||
|
testunop(a, res, expr, name)
|
||||||
|
|
||||||
|
def ints():
|
||||||
|
if verbose: print "Testing int operations..."
|
||||||
|
numops(100, 3)
|
||||||
|
|
||||||
|
def longs():
|
||||||
|
if verbose: print "Testing long operations..."
|
||||||
|
numops(100L, 3L)
|
||||||
|
|
||||||
|
def floats():
|
||||||
|
if verbose: print "Testing float operations..."
|
||||||
|
numops(100.0, 3.0)
|
||||||
|
|
||||||
|
def complexes():
|
||||||
|
if verbose: print "Testing complex operations..."
|
||||||
|
numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge'])
|
||||||
|
class Number(complex):
|
||||||
|
__slots__ = ['prec']
|
||||||
|
def __init__(self, *args, **kwds):
|
||||||
|
self.prec = kwds.get('prec', 12)
|
||||||
|
def __repr__(self):
|
||||||
|
prec = self.prec
|
||||||
|
if self.imag == 0.0:
|
||||||
|
return "%.*g" % (prec, self.real)
|
||||||
|
if self.real == 0.0:
|
||||||
|
return "%.*gj" % (prec, self.imag)
|
||||||
|
return "(%.*g+%.*gj)" % (prec, self.real, prec, self.imag)
|
||||||
|
__str__ = __repr__
|
||||||
|
a = Number(3.14, prec=6)
|
||||||
|
verify(`a` == "3.14")
|
||||||
|
verify(a.prec == 6)
|
||||||
|
|
||||||
|
def spamlists():
|
||||||
|
if verbose: print "Testing spamlist operations..."
|
||||||
|
import copy, xxsubtype as spam
|
||||||
|
def spamlist(l, memo=None):
|
||||||
|
import xxsubtype as spam
|
||||||
|
return spam.spamlist(l)
|
||||||
|
# This is an ugly hack:
|
||||||
|
copy._deepcopy_dispatch[spam.spamlist] = spamlist
|
||||||
|
|
||||||
|
testbinop(spamlist([1]), spamlist([2]), spamlist([1,2]), "a+b", "__add__")
|
||||||
|
testbinop(spamlist([1,2,3]), 2, 1, "b in a", "__contains__")
|
||||||
|
testbinop(spamlist([1,2,3]), 4, 0, "b in a", "__contains__")
|
||||||
|
testbinop(spamlist([1,2,3]), 1, 2, "a[b]", "__getitem__")
|
||||||
|
testternop(spamlist([1,2,3]), 0, 2, spamlist([1,2]),
|
||||||
|
"a[b:c]", "__getslice__")
|
||||||
|
testsetop(spamlist([1]), spamlist([2]), spamlist([1,2]),
|
||||||
|
"a+=b", "__iadd__")
|
||||||
|
testsetop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*=b", "__imul__")
|
||||||
|
testunop(spamlist([1,2,3]), 3, "len(a)", "__len__")
|
||||||
|
testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*b", "__mul__")
|
||||||
|
testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "b*a", "__rmul__")
|
||||||
|
testset2op(spamlist([1,2]), 1, 3, spamlist([1,3]), "a[b]=c", "__setitem__")
|
||||||
|
testset3op(spamlist([1,2,3,4]), 1, 3, spamlist([5,6]),
|
||||||
|
spamlist([1,5,6,4]), "a[b:c]=d", "__setslice__")
|
||||||
|
# Test subclassing
|
||||||
|
class C(spam.spamlist):
|
||||||
|
def foo(self): return 1
|
||||||
|
a = C()
|
||||||
|
verify(a == [])
|
||||||
|
verify(a.foo() == 1)
|
||||||
|
a.append(100)
|
||||||
|
verify(a == [100])
|
||||||
|
verify(a.getstate() == 0)
|
||||||
|
a.setstate(42)
|
||||||
|
verify(a.getstate() == 42)
|
||||||
|
|
||||||
|
def spamdicts():
|
||||||
|
if verbose: print "Testing spamdict operations..."
|
||||||
|
import copy, xxsubtype as spam
|
||||||
|
def spamdict(d, memo=None):
|
||||||
|
import xxsubtype as spam
|
||||||
|
sd = spam.spamdict()
|
||||||
|
for k, v in d.items(): sd[k] = v
|
||||||
|
return sd
|
||||||
|
# This is an ugly hack:
|
||||||
|
copy._deepcopy_dispatch[spam.spamdict] = spamdict
|
||||||
|
|
||||||
|
testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__")
|
||||||
|
testbinop(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__")
|
||||||
|
testbinop(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__")
|
||||||
|
testbinop(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__")
|
||||||
|
d = spamdict({1:2,3:4})
|
||||||
|
l1 = []
|
||||||
|
for i in d.keys(): l1.append(i)
|
||||||
|
l = []
|
||||||
|
for i in iter(d): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
l = []
|
||||||
|
for i in d.__iter__(): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
l = []
|
||||||
|
for i in type(spamdict({})).__iter__(d): l.append(i)
|
||||||
|
verify(l == l1)
|
||||||
|
straightd = {1:2, 3:4}
|
||||||
|
spamd = spamdict(straightd)
|
||||||
|
testunop(spamd, 2, "len(a)", "__len__")
|
||||||
|
testunop(spamd, repr(straightd), "repr(a)", "__repr__")
|
||||||
|
testset2op(spamdict({1:2,3:4}), 2, 3, spamdict({1:2,2:3,3:4}),
|
||||||
|
"a[b]=c", "__setitem__")
|
||||||
|
# Test subclassing
|
||||||
|
class C(spam.spamdict):
|
||||||
|
def foo(self): return 1
|
||||||
|
a = C()
|
||||||
|
verify(a.items() == [])
|
||||||
|
verify(a.foo() == 1)
|
||||||
|
a['foo'] = 'bar'
|
||||||
|
verify(a.items() == [('foo', 'bar')])
|
||||||
|
verify(a.getstate() == 0)
|
||||||
|
a.setstate(100)
|
||||||
|
verify(a.getstate() == 100)
|
||||||
|
|
||||||
|
def pydicts():
|
||||||
|
if verbose: print "Testing Python subclass of dict..."
|
||||||
|
verify(issubclass(dictionary, dictionary))
|
||||||
|
verify(isinstance({}, dictionary))
|
||||||
|
d = dictionary()
|
||||||
|
verify(d == {})
|
||||||
|
verify(d.__class__ is dictionary)
|
||||||
|
verify(isinstance(d, dictionary))
|
||||||
|
class C(dictionary):
|
||||||
|
state = -1
|
||||||
|
def __init__(self, *a, **kw):
|
||||||
|
if a:
|
||||||
|
assert len(a) == 1
|
||||||
|
self.state = a[0]
|
||||||
|
if kw:
|
||||||
|
for k, v in kw.items(): self[v] = k
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.get(key, 0)
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
assert isinstance(key, type(0))
|
||||||
|
dictionary.__setitem__(self, key, value)
|
||||||
|
def setstate(self, state):
|
||||||
|
self.state = state
|
||||||
|
def getstate(self):
|
||||||
|
return self.state
|
||||||
|
verify(issubclass(C, dictionary))
|
||||||
|
a1 = C(12)
|
||||||
|
verify(a1.state == 12)
|
||||||
|
a2 = C(foo=1, bar=2)
|
||||||
|
verify(a2[1] == 'foo' and a2[2] == 'bar')
|
||||||
|
a = C()
|
||||||
|
verify(a.state == -1)
|
||||||
|
verify(a.getstate() == -1)
|
||||||
|
a.setstate(0)
|
||||||
|
verify(a.state == 0)
|
||||||
|
verify(a.getstate() == 0)
|
||||||
|
a.setstate(10)
|
||||||
|
verify(a.state == 10)
|
||||||
|
verify(a.getstate() == 10)
|
||||||
|
verify(a[42] == 0)
|
||||||
|
a[42] = 24
|
||||||
|
verify(a[42] == 24)
|
||||||
|
if verbose: print "pydict stress test ..."
|
||||||
|
N = 50
|
||||||
|
for i in range(N):
|
||||||
|
a[i] = C()
|
||||||
|
for j in range(N):
|
||||||
|
a[i][j] = i*j
|
||||||
|
for i in range(N):
|
||||||
|
for j in range(N):
|
||||||
|
verify(a[i][j] == i*j)
|
||||||
|
|
||||||
|
def pylists():
|
||||||
|
if verbose: print "Testing Python subclass of list..."
|
||||||
|
class C(list):
|
||||||
|
def __getitem__(self, i):
|
||||||
|
return list.__getitem__(self, i) + 100
|
||||||
|
def __getslice__(self, i, j):
|
||||||
|
return (i, j)
|
||||||
|
a = C()
|
||||||
|
a.extend([0,1,2])
|
||||||
|
verify(a[0] == 100)
|
||||||
|
verify(a[1] == 101)
|
||||||
|
verify(a[2] == 102)
|
||||||
|
verify(a[100:200] == (100,200))
|
||||||
|
|
||||||
|
def metaclass():
|
||||||
|
if verbose: print "Testing __metaclass__..."
|
||||||
|
global C
|
||||||
|
class C:
|
||||||
|
__metaclass__ = type
|
||||||
|
def __init__(self):
|
||||||
|
self.__state = 0
|
||||||
|
def getstate(self):
|
||||||
|
return self.__state
|
||||||
|
def setstate(self, state):
|
||||||
|
self.__state = state
|
||||||
|
a = C()
|
||||||
|
verify(a.getstate() == 0)
|
||||||
|
a.setstate(10)
|
||||||
|
verify(a.getstate() == 10)
|
||||||
|
class D:
|
||||||
|
class __metaclass__(type):
|
||||||
|
def myself(cls): return cls
|
||||||
|
verify(D.myself() == D)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
MT = type(sys)
|
||||||
|
|
||||||
|
def pymods():
|
||||||
|
if verbose: print "Testing Python subclass of module..."
|
||||||
|
global log
|
||||||
|
log = []
|
||||||
|
class MM(MT):
|
||||||
|
def __init__(self):
|
||||||
|
MT.__init__(self)
|
||||||
|
def __getattr__(self, name):
|
||||||
|
log.append(("getattr", name))
|
||||||
|
return MT.__getattr__(self, name)
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
log.append(("setattr", name, value))
|
||||||
|
MT.__setattr__(self, name, value)
|
||||||
|
def __delattr__(self, name):
|
||||||
|
log.append(("delattr", name))
|
||||||
|
MT.__delattr__(self, name)
|
||||||
|
a = MM()
|
||||||
|
a.foo = 12
|
||||||
|
x = a.foo
|
||||||
|
del a.foo
|
||||||
|
verify(log == [('getattr', '__init__'),
|
||||||
|
('getattr', '__setattr__'),
|
||||||
|
("setattr", "foo", 12),
|
||||||
|
("getattr", "foo"),
|
||||||
|
('getattr', '__delattr__'),
|
||||||
|
("delattr", "foo")], log)
|
||||||
|
|
||||||
|
def multi():
|
||||||
|
if verbose: print "Testing multiple inheritance..."
|
||||||
|
global C
|
||||||
|
class C(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.__state = 0
|
||||||
|
def getstate(self):
|
||||||
|
return self.__state
|
||||||
|
def setstate(self, state):
|
||||||
|
self.__state = state
|
||||||
|
a = C()
|
||||||
|
verify(a.getstate() == 0)
|
||||||
|
a.setstate(10)
|
||||||
|
verify(a.getstate() == 10)
|
||||||
|
class D(dictionary, C):
|
||||||
|
def __init__(self):
|
||||||
|
type({}).__init__(self)
|
||||||
|
C.__init__(self)
|
||||||
|
d = D()
|
||||||
|
verify(d.keys() == [])
|
||||||
|
d["hello"] = "world"
|
||||||
|
verify(d.items() == [("hello", "world")])
|
||||||
|
verify(d["hello"] == "world")
|
||||||
|
verify(d.getstate() == 0)
|
||||||
|
d.setstate(10)
|
||||||
|
verify(d.getstate() == 10)
|
||||||
|
verify(D.__mro__ == (D, dictionary, C, object))
|
||||||
|
|
||||||
|
def diamond():
|
||||||
|
if verbose: print "Testing multiple inheritance special cases..."
|
||||||
|
class A(object):
|
||||||
|
def spam(self): return "A"
|
||||||
|
verify(A().spam() == "A")
|
||||||
|
class B(A):
|
||||||
|
def boo(self): return "B"
|
||||||
|
def spam(self): return "B"
|
||||||
|
verify(B().spam() == "B")
|
||||||
|
verify(B().boo() == "B")
|
||||||
|
class C(A):
|
||||||
|
def boo(self): return "C"
|
||||||
|
verify(C().spam() == "A")
|
||||||
|
verify(C().boo() == "C")
|
||||||
|
class D(B, C): pass
|
||||||
|
verify(D().spam() == "B")
|
||||||
|
verify(D().boo() == "B")
|
||||||
|
verify(D.__mro__ == (D, B, C, A, object))
|
||||||
|
class E(C, B): pass
|
||||||
|
verify(E().spam() == "B")
|
||||||
|
verify(E().boo() == "C")
|
||||||
|
verify(E.__mro__ == (E, C, B, A, object))
|
||||||
|
class F(D, E): pass
|
||||||
|
verify(F().spam() == "B")
|
||||||
|
verify(F().boo() == "B")
|
||||||
|
verify(F.__mro__ == (F, D, E, B, C, A, object))
|
||||||
|
class G(E, D): pass
|
||||||
|
verify(G().spam() == "B")
|
||||||
|
verify(G().boo() == "C")
|
||||||
|
verify(G.__mro__ == (G, E, D, C, B, A, object))
|
||||||
|
|
||||||
|
def objects():
|
||||||
|
if verbose: print "Testing object class..."
|
||||||
|
a = object()
|
||||||
|
verify(a.__class__ == object == type(a))
|
||||||
|
b = object()
|
||||||
|
verify(a is not b)
|
||||||
|
verify(not hasattr(a, "foo"))
|
||||||
|
try:
|
||||||
|
a.foo = 12
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "object() should not allow setting a foo attribute")
|
||||||
|
verify(not hasattr(object(), "__dict__"))
|
||||||
|
|
||||||
|
class Cdict(object):
|
||||||
|
pass
|
||||||
|
x = Cdict()
|
||||||
|
verify(x.__dict__ is None)
|
||||||
|
x.foo = 1
|
||||||
|
verify(x.foo == 1)
|
||||||
|
verify(x.__dict__ == {'foo': 1})
|
||||||
|
|
||||||
|
def slots():
|
||||||
|
if verbose: print "Testing __slots__..."
|
||||||
|
class C0(object):
|
||||||
|
__slots__ = []
|
||||||
|
x = C0()
|
||||||
|
verify(not hasattr(x, "__dict__"))
|
||||||
|
verify(not hasattr(x, "foo"))
|
||||||
|
|
||||||
|
class C1(object):
|
||||||
|
__slots__ = ['a']
|
||||||
|
x = C1()
|
||||||
|
verify(not hasattr(x, "__dict__"))
|
||||||
|
verify(x.a == None)
|
||||||
|
x.a = 1
|
||||||
|
verify(x.a == 1)
|
||||||
|
del x.a
|
||||||
|
verify(x.a == None)
|
||||||
|
|
||||||
|
class C3(object):
|
||||||
|
__slots__ = ['a', 'b', 'c']
|
||||||
|
x = C3()
|
||||||
|
verify(not hasattr(x, "__dict__"))
|
||||||
|
verify(x.a is None)
|
||||||
|
verify(x.b is None)
|
||||||
|
verify(x.c is None)
|
||||||
|
x.a = 1
|
||||||
|
x.b = 2
|
||||||
|
x.c = 3
|
||||||
|
verify(x.a == 1)
|
||||||
|
verify(x.b == 2)
|
||||||
|
verify(x.c == 3)
|
||||||
|
|
||||||
|
def dynamics():
|
||||||
|
if verbose: print "Testing __dynamic__..."
|
||||||
|
verify(object.__dynamic__ == 0)
|
||||||
|
verify(list.__dynamic__ == 0)
|
||||||
|
class S1:
|
||||||
|
__metaclass__ = type
|
||||||
|
verify(S1.__dynamic__ == 0)
|
||||||
|
class S(object):
|
||||||
|
pass
|
||||||
|
verify(C.__dynamic__ == 0)
|
||||||
|
class D(object):
|
||||||
|
__dynamic__ = 1
|
||||||
|
verify(D.__dynamic__ == 1)
|
||||||
|
class E(D, S):
|
||||||
|
pass
|
||||||
|
verify(E.__dynamic__ == 1)
|
||||||
|
class F(S, D):
|
||||||
|
pass
|
||||||
|
verify(F.__dynamic__ == 1)
|
||||||
|
try:
|
||||||
|
S.foo = 1
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "assignment to a static class attribute should be illegal")
|
||||||
|
D.foo = 1
|
||||||
|
verify(D.foo == 1)
|
||||||
|
# Test that dynamic attributes are inherited
|
||||||
|
verify(E.foo == 1)
|
||||||
|
verify(F.foo == 1)
|
||||||
|
class SS(D):
|
||||||
|
__dynamic__ = 0
|
||||||
|
verify(SS.__dynamic__ == 0)
|
||||||
|
verify(SS.foo == 1)
|
||||||
|
try:
|
||||||
|
SS.foo = 1
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "assignment to SS.foo should be illegal")
|
||||||
|
|
||||||
|
def errors():
|
||||||
|
if verbose: print "Testing errors..."
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(list, dictionary):
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from both list and dict should be illegal")
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(object, None):
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from non-type should be illegal")
|
||||||
|
class Classic:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(object, Classic):
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from object and Classic should be illegal")
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(int):
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from int should be illegal")
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(object):
|
||||||
|
__slots__ = 1
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "__slots__ = 1 should be illegal")
|
||||||
|
|
||||||
|
try:
|
||||||
|
class C(object):
|
||||||
|
__slots__ = [1]
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "__slots__ = [1] should be illegal")
|
||||||
|
|
||||||
|
def classmethods():
|
||||||
|
if verbose: print "Testing class methods..."
|
||||||
|
class C(object):
|
||||||
|
def foo(*a): return a
|
||||||
|
goo = classmethod(foo)
|
||||||
|
c = C()
|
||||||
|
verify(C.goo(1) == (C, 1))
|
||||||
|
verify(c.goo(1) == (C, 1))
|
||||||
|
verify(c.foo(1) == (c, 1))
|
||||||
|
class D(C):
|
||||||
|
pass
|
||||||
|
d = D()
|
||||||
|
verify(D.goo(1) == (D, 1))
|
||||||
|
verify(d.goo(1) == (D, 1))
|
||||||
|
verify(d.foo(1) == (d, 1))
|
||||||
|
verify(D.foo(d, 1) == (d, 1))
|
||||||
|
|
||||||
|
def staticmethods():
|
||||||
|
if verbose: print "Testing static methods..."
|
||||||
|
class C(object):
|
||||||
|
def foo(*a): return a
|
||||||
|
goo = staticmethod(foo)
|
||||||
|
c = C()
|
||||||
|
verify(C.goo(1) == (1,))
|
||||||
|
verify(c.goo(1) == (1,))
|
||||||
|
verify(c.foo(1) == (c, 1,))
|
||||||
|
class D(C):
|
||||||
|
pass
|
||||||
|
d = D()
|
||||||
|
verify(D.goo(1) == (1,))
|
||||||
|
verify(d.goo(1) == (1,))
|
||||||
|
verify(d.foo(1) == (d, 1))
|
||||||
|
verify(D.foo(d, 1) == (d, 1))
|
||||||
|
|
||||||
|
def classic():
|
||||||
|
if verbose: print "Testing classic classes..."
|
||||||
|
class C:
|
||||||
|
def foo(*a): return a
|
||||||
|
goo = classmethod(foo)
|
||||||
|
c = C()
|
||||||
|
verify(C.goo(1) == (C, 1))
|
||||||
|
verify(c.goo(1) == (C, 1))
|
||||||
|
verify(c.foo(1) == (c, 1))
|
||||||
|
class D(C):
|
||||||
|
pass
|
||||||
|
d = D()
|
||||||
|
verify(D.goo(1) == (D, 1))
|
||||||
|
verify(d.goo(1) == (D, 1))
|
||||||
|
verify(d.foo(1) == (d, 1))
|
||||||
|
verify(D.foo(d, 1) == (d, 1))
|
||||||
|
|
||||||
|
def compattr():
|
||||||
|
if verbose: print "Testing computed attributes..."
|
||||||
|
class C(object):
|
||||||
|
class computed_attribute(object):
|
||||||
|
def __init__(self, get, set=None):
|
||||||
|
self.__get = get
|
||||||
|
self.__set = set
|
||||||
|
def __get__(self, obj, type=None):
|
||||||
|
return self.__get(obj)
|
||||||
|
def __set__(self, obj, value):
|
||||||
|
return self.__set(obj, value)
|
||||||
|
def __init__(self):
|
||||||
|
self.__x = 0
|
||||||
|
def __get_x(self):
|
||||||
|
x = self.__x
|
||||||
|
self.__x = x+1
|
||||||
|
return x
|
||||||
|
def __set_x(self, x):
|
||||||
|
self.__x = x
|
||||||
|
x = computed_attribute(__get_x, __set_x)
|
||||||
|
a = C()
|
||||||
|
verify(a.x == 0)
|
||||||
|
verify(a.x == 1)
|
||||||
|
a.x = 10
|
||||||
|
verify(a.x == 10)
|
||||||
|
verify(a.x == 11)
|
||||||
|
|
||||||
|
def newslot():
|
||||||
|
if verbose: print "Testing __new__ slot override..."
|
||||||
|
class C(list):
|
||||||
|
def __new__(cls):
|
||||||
|
self = list.__new__(cls)
|
||||||
|
self.foo = 1
|
||||||
|
return self
|
||||||
|
def __init__(self):
|
||||||
|
self.foo = self.foo + 2
|
||||||
|
a = C()
|
||||||
|
verify(a.foo == 3)
|
||||||
|
verify(a.__class__ is C)
|
||||||
|
class D(C):
|
||||||
|
pass
|
||||||
|
b = D()
|
||||||
|
verify(b.foo == 3)
|
||||||
|
verify(b.__class__ is D)
|
||||||
|
|
||||||
|
class PerverseMetaType(type):
|
||||||
|
def mro(cls):
|
||||||
|
L = type.mro(cls)
|
||||||
|
L.reverse()
|
||||||
|
return L
|
||||||
|
|
||||||
|
def altmro():
|
||||||
|
if verbose: print "Testing mro() and overriding it..."
|
||||||
|
class A(object):
|
||||||
|
def f(self): return "A"
|
||||||
|
class B(A):
|
||||||
|
pass
|
||||||
|
class C(A):
|
||||||
|
def f(self): return "C"
|
||||||
|
class D(B, C):
|
||||||
|
pass
|
||||||
|
verify(D.mro() == [D, B, C, A, object] == list(D.__mro__))
|
||||||
|
verify(D().f() == "C")
|
||||||
|
class X(A,B,C,D):
|
||||||
|
__metaclass__ = PerverseMetaType
|
||||||
|
verify(X.__mro__ == (object, A, C, B, D, X))
|
||||||
|
verify(X().f() == "A")
|
||||||
|
|
||||||
|
def overloading():
|
||||||
|
if verbose: print "testing operator overloading..."
|
||||||
|
|
||||||
|
class B(object):
|
||||||
|
"Intermediate class because object doesn't have a __setattr__"
|
||||||
|
|
||||||
|
class C(B):
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name == "foo":
|
||||||
|
return ("getattr", name)
|
||||||
|
else:
|
||||||
|
return B.__getattr__(self, name)
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if name == "foo":
|
||||||
|
self.setattr = (name, value)
|
||||||
|
else:
|
||||||
|
return B.__setattr__(self, name, value)
|
||||||
|
def __delattr__(self, name):
|
||||||
|
if name == "foo":
|
||||||
|
self.delattr = name
|
||||||
|
else:
|
||||||
|
return B.__delattr__(self, name)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return ("getitem", key)
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self.setitem = (key, value)
|
||||||
|
def __delitem__(self, key):
|
||||||
|
self.delitem = key
|
||||||
|
|
||||||
|
def __getslice__(self, i, j):
|
||||||
|
return ("getslice", i, j)
|
||||||
|
def __setslice__(self, i, j, value):
|
||||||
|
self.setslice = (i, j, value)
|
||||||
|
def __delslice__(self, i, j):
|
||||||
|
self.delslice = (i, j)
|
||||||
|
|
||||||
|
a = C()
|
||||||
|
verify(a.foo == ("getattr", "foo"))
|
||||||
|
a.foo = 12
|
||||||
|
verify(a.setattr == ("foo", 12))
|
||||||
|
del a.foo
|
||||||
|
verify(a.delattr == "foo")
|
||||||
|
|
||||||
|
verify(a[12] == ("getitem", 12))
|
||||||
|
a[12] = 21
|
||||||
|
verify(a.setitem == (12, 21))
|
||||||
|
del a[12]
|
||||||
|
verify(a.delitem == 12)
|
||||||
|
|
||||||
|
verify(a[0:10] == ("getslice", 0, 10))
|
||||||
|
a[0:10] = "foo"
|
||||||
|
verify(a.setslice == (0, 10, "foo"))
|
||||||
|
del a[0:10]
|
||||||
|
verify(a.delslice == (0, 10))
|
||||||
|
|
||||||
|
def all():
|
||||||
|
lists()
|
||||||
|
dicts()
|
||||||
|
ints()
|
||||||
|
longs()
|
||||||
|
floats()
|
||||||
|
complexes()
|
||||||
|
spamlists()
|
||||||
|
spamdicts()
|
||||||
|
pydicts()
|
||||||
|
pylists()
|
||||||
|
metaclass()
|
||||||
|
pymods()
|
||||||
|
multi()
|
||||||
|
diamond()
|
||||||
|
objects()
|
||||||
|
slots()
|
||||||
|
dynamics()
|
||||||
|
errors()
|
||||||
|
classmethods()
|
||||||
|
staticmethods()
|
||||||
|
classic()
|
||||||
|
compattr()
|
||||||
|
newslot()
|
||||||
|
altmro()
|
||||||
|
overloading()
|
||||||
|
|
||||||
|
all()
|
||||||
|
|
||||||
|
if verbose: print "All OK"
|
|
@ -380,10 +380,16 @@ From the Iterators list, about the types of these things.
|
||||||
>>> i = g()
|
>>> i = g()
|
||||||
>>> type(i)
|
>>> type(i)
|
||||||
<type 'generator'>
|
<type 'generator'>
|
||||||
|
|
||||||
|
XXX dir(object) *generally* doesn't return useful stuff in descr-branch.
|
||||||
>>> dir(i)
|
>>> dir(i)
|
||||||
|
[]
|
||||||
|
|
||||||
|
Was hoping to see this instead:
|
||||||
['gi_frame', 'gi_running', 'next']
|
['gi_frame', 'gi_running', 'next']
|
||||||
|
|
||||||
>>> print i.next.__doc__
|
>>> print i.next.__doc__
|
||||||
next() -- get the next value, or raise StopIteration
|
x.next() -> the next value, or raise StopIteration
|
||||||
>>> iter(i) is i
|
>>> iter(i) is i
|
||||||
1
|
1
|
||||||
>>> import types
|
>>> import types
|
||||||
|
@ -399,7 +405,7 @@ And more, added later.
|
||||||
>>> i.gi_running = 42
|
>>> i.gi_running = 42
|
||||||
Traceback (most recent call last):
|
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():
|
>>> def g():
|
||||||
... yield me.gi_running
|
... yield me.gi_running
|
||||||
>>> me = g()
|
>>> me = g()
|
||||||
|
|
12
Lib/types.py
12
Lib/types.py
|
@ -7,7 +7,8 @@ from __future__ import generators
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
NoneType = type(None)
|
NoneType = type(None)
|
||||||
TypeType = type(NoneType)
|
TypeType = type
|
||||||
|
ObjectType = object
|
||||||
|
|
||||||
IntType = type(0)
|
IntType = type(0)
|
||||||
LongType = type(0L)
|
LongType = type(0L)
|
||||||
|
@ -22,8 +23,8 @@ UnicodeType = type(u'')
|
||||||
BufferType = type(buffer(''))
|
BufferType = type(buffer(''))
|
||||||
|
|
||||||
TupleType = type(())
|
TupleType = type(())
|
||||||
ListType = type([])
|
ListType = list
|
||||||
DictType = DictionaryType = type({})
|
DictType = DictionaryType = dictionary
|
||||||
|
|
||||||
def _f(): pass
|
def _f(): pass
|
||||||
FunctionType = type(_f)
|
FunctionType = type(_f)
|
||||||
|
@ -71,4 +72,9 @@ except TypeError:
|
||||||
SliceType = type(slice(0))
|
SliceType = type(slice(0))
|
||||||
EllipsisType = type(Ellipsis)
|
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
|
del sys, _f, _C, _x # Not for export
|
||||||
|
|
|
@ -237,6 +237,7 @@ OBJECT_OBJS= \
|
||||||
Objects/classobject.o \
|
Objects/classobject.o \
|
||||||
Objects/cobject.o \
|
Objects/cobject.o \
|
||||||
Objects/complexobject.o \
|
Objects/complexobject.o \
|
||||||
|
Objects/descrobject.o \
|
||||||
Objects/fileobject.o \
|
Objects/fileobject.o \
|
||||||
Objects/floatobject.o \
|
Objects/floatobject.o \
|
||||||
Objects/frameobject.o \
|
Objects/frameobject.o \
|
||||||
|
@ -438,6 +439,7 @@ PYTHON_HEADERS= \
|
||||||
Include/tupleobject.h \
|
Include/tupleobject.h \
|
||||||
Include/listobject.h \
|
Include/listobject.h \
|
||||||
Include/iterobject.h \
|
Include/iterobject.h \
|
||||||
|
Include/descrobject.h \
|
||||||
Include/dictobject.h \
|
Include/dictobject.h \
|
||||||
Include/methodobject.h \
|
Include/methodobject.h \
|
||||||
Include/moduleobject.h \
|
Include/moduleobject.h \
|
||||||
|
|
11
Misc/NEWS
11
Misc/NEWS
|
@ -44,6 +44,17 @@ What's New in Python 2.2a1?
|
||||||
|
|
||||||
Core
|
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
|
- Generators were added; this is a new way to create an iterator (see
|
||||||
below) using what looks like a simple function containing one or
|
below) using what looks like a simple function containing one or
|
||||||
more 'yield' statements. See PEP 255. Since this adds a new
|
more 'yield' statements. See PEP 255. Since this adds a new
|
||||||
|
|
|
@ -464,3 +464,5 @@ GLHACK=-Dclear=__GLclear
|
||||||
# Example -- included for reference only:
|
# Example -- included for reference only:
|
||||||
# xx xxmodule.c
|
# 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);
|
res = save_tuple(self, args);
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
if (type == &PyType_Type) {
|
||||||
|
res = save_global(self, args, NULL);
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct _inittab _PyImport_Inittab[] = {
|
||||||
{"__main__", NULL},
|
{"__main__", NULL},
|
||||||
{"__builtin__", NULL},
|
{"__builtin__", NULL},
|
||||||
{"sys", NULL},
|
{"sys", NULL},
|
||||||
{"exceptions", init_exceptions},
|
{"exceptions", NULL},
|
||||||
|
|
||||||
/* Sentinel */
|
/* Sentinel */
|
||||||
{0, 0}
|
{0, 0}
|
||||||
|
|
233
Modules/xxsubtype.c
Normal file
233
Modules/xxsubtype.c
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
#include "Python.h"
|
||||||
|
|
||||||
|
/* Examples showing how to subtype the builtin list and dict types from C. */
|
||||||
|
|
||||||
|
/* spamlist -- a list subtype */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyListObject list;
|
||||||
|
int state;
|
||||||
|
} spamlistobject;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
spamlist_getstate(spamlistobject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":getstate"))
|
||||||
|
return NULL;
|
||||||
|
return PyInt_FromLong(self->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
spamlist_setstate(spamlistobject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "i:setstate", &state))
|
||||||
|
return NULL;
|
||||||
|
self->state = state;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef spamlist_methods[] = {
|
||||||
|
{"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
|
||||||
|
"getstate() -> state"},
|
||||||
|
{"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
|
||||||
|
"setstate(state)"},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
staticforward PyTypeObject spamlist_type;
|
||||||
|
|
||||||
|
static int
|
||||||
|
spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
|
||||||
|
return -1;
|
||||||
|
self->state = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyTypeObject spamlist_type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"spamlist",
|
||||||
|
sizeof(spamlistobject),
|
||||||
|
0,
|
||||||
|
0, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
0, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
spamlist_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
&PyList_Type, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
(initproc)spamlist_init, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
0, /* tp_new */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* spamdict -- a dict subtype */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyDictObject dict;
|
||||||
|
int state;
|
||||||
|
} spamdictobject;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
spamdict_getstate(spamdictobject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":getstate"))
|
||||||
|
return NULL;
|
||||||
|
return PyInt_FromLong(self->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
spamdict_setstate(spamdictobject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "i:setstate", &state))
|
||||||
|
return NULL;
|
||||||
|
self->state = state;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef spamdict_methods[] = {
|
||||||
|
{"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
|
||||||
|
"getstate() -> state"},
|
||||||
|
{"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
|
||||||
|
"setstate(state)"},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
staticforward PyTypeObject spamdict_type;
|
||||||
|
|
||||||
|
static int
|
||||||
|
spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
|
||||||
|
return -1;
|
||||||
|
self->state = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyTypeObject spamdict_type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"spamdict",
|
||||||
|
sizeof(spamdictobject),
|
||||||
|
0,
|
||||||
|
0, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
0, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
spamdict_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
&PyDict_Type, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
(initproc)spamdict_init, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
0, /* tp_new */
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
spam_bench(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *obj, *name, *res;
|
||||||
|
int n = 1000;
|
||||||
|
time_t t0, t1;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n))
|
||||||
|
return NULL;
|
||||||
|
t0 = clock();
|
||||||
|
while (--n >= 0) {
|
||||||
|
res = PyObject_GetAttr(obj, name);
|
||||||
|
if (res == NULL)
|
||||||
|
return NULL;
|
||||||
|
Py_DECREF(res);
|
||||||
|
}
|
||||||
|
t1 = clock();
|
||||||
|
return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef xxsubtype_functions[] = {
|
||||||
|
{"bench", spam_bench, METH_VARARGS},
|
||||||
|
{NULL, NULL} /* sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
DL_EXPORT(void)
|
||||||
|
initxxsubtype(void)
|
||||||
|
{
|
||||||
|
PyObject *m, *d;
|
||||||
|
|
||||||
|
m = Py_InitModule("xxsubtype", xxsubtype_functions);
|
||||||
|
if (m == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PyType_InitDict(&spamlist_type) < 0)
|
||||||
|
return;
|
||||||
|
if (PyType_InitDict(&spamdict_type) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d = PyModule_GetDict(m);
|
||||||
|
if (d == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Py_INCREF(&spamlist_type);
|
||||||
|
if (PyDict_SetItemString(d, "spamlist",
|
||||||
|
(PyObject *) &spamlist_type) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Py_INCREF(&spamdict_type);
|
||||||
|
if (PyDict_SetItemString(d, "spamdict",
|
||||||
|
(PyObject *) &spamdict_type) < 0)
|
||||||
|
return;
|
||||||
|
}
|
|
@ -1588,6 +1588,24 @@ PyObject_CallObject(PyObject *o, PyObject *a)
|
||||||
return r;
|
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 *
|
||||||
PyObject_CallFunction(PyObject *callable, char *format, ...)
|
PyObject_CallFunction(PyObject *callable, char *format, ...)
|
||||||
{
|
{
|
||||||
|
@ -1746,7 +1764,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (PyType_Check(cls)) {
|
else if (PyType_Check(cls)) {
|
||||||
retval = ((PyObject *)(inst->ob_type) == cls);
|
retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
|
||||||
}
|
}
|
||||||
else if (!PyInstance_Check(inst)) {
|
else if (!PyInstance_Check(inst)) {
|
||||||
if (__class__ == NULL) {
|
if (__class__ == NULL) {
|
||||||
|
|
|
@ -537,21 +537,21 @@ PyTypeObject PyBuffer_Type = {
|
||||||
"buffer",
|
"buffer",
|
||||||
sizeof(PyBufferObject),
|
sizeof(PyBufferObject),
|
||||||
0,
|
0,
|
||||||
(destructor)buffer_dealloc, /*tp_dealloc*/
|
(destructor)buffer_dealloc, /* tp_dealloc */
|
||||||
0, /*tp_print*/
|
0, /* tp_print */
|
||||||
0, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
(cmpfunc)buffer_compare, /*tp_compare*/
|
(cmpfunc)buffer_compare, /* tp_compare */
|
||||||
(reprfunc)buffer_repr, /*tp_repr*/
|
(reprfunc)buffer_repr, /* tp_repr */
|
||||||
0, /*tp_as_number*/
|
0, /* tp_as_number */
|
||||||
&buffer_as_sequence, /*tp_as_sequence*/
|
&buffer_as_sequence, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)buffer_hash, /*tp_hash*/
|
(hashfunc)buffer_hash, /* tp_hash */
|
||||||
0, /*tp_call*/
|
0, /* tp_call */
|
||||||
(reprfunc)buffer_str, /*tp_str*/
|
(reprfunc)buffer_str, /* tp_str */
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /*tp_setattro*/
|
0, /* tp_setattro */
|
||||||
&buffer_as_buffer, /*tp_as_buffer*/
|
&buffer_as_buffer, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
0, /*tp_doc*/
|
0, /* tp_doc */
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,7 +106,7 @@ PyTypeObject PyCell_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
|
|
|
@ -36,12 +36,12 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (name == NULL || !PyString_Check(name)) {
|
if (name == NULL || !PyString_Check(name)) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"PyClass_New: name must be a string");
|
"PyClass_New: name must be a string");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (dict == NULL || !PyDict_Check(dict)) {
|
if (dict == NULL || !PyDict_Check(dict)) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"PyClass_New: dict must be a dictionary");
|
"PyClass_New: dict must be a dictionary");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -67,14 +67,14 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
if (!PyTuple_Check(bases)) {
|
if (!PyTuple_Check(bases)) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"PyClass_New: bases must be a tuple");
|
"PyClass_New: bases must be a tuple");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
i = PyTuple_Size(bases);
|
i = PyTuple_Size(bases);
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
if (!PyClass_Check(PyTuple_GetItem(bases, i))) {
|
if (!PyClass_Check(PyTuple_GetItem(bases, i))) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"PyClass_New: base must be a class");
|
"PyClass_New: base must be a class");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,18 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
||||||
return (PyObject *) op;
|
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 */
|
/* Class methods */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -149,6 +161,8 @@ class_getattr(register PyClassObject *op, PyObject *name)
|
||||||
register PyObject *v;
|
register PyObject *v;
|
||||||
register char *sname = PyString_AsString(name);
|
register char *sname = PyString_AsString(name);
|
||||||
PyClassObject *class;
|
PyClassObject *class;
|
||||||
|
descrgetfunc f;
|
||||||
|
|
||||||
if (sname[0] == '_' && sname[1] == '_') {
|
if (sname[0] == '_' && sname[1] == '_') {
|
||||||
if (strcmp(sname, "__dict__") == 0) {
|
if (strcmp(sname, "__dict__") == 0) {
|
||||||
if (PyEval_GetRestricted()) {
|
if (PyEval_GetRestricted()) {
|
||||||
|
@ -186,6 +200,11 @@ class_getattr(register PyClassObject *op, PyObject *name)
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
v = w;
|
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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +415,7 @@ PyTypeObject PyClass_Type = {
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
PyInstance_New, /* tp_call */
|
||||||
(reprfunc)class_str, /* tp_str */
|
(reprfunc)class_str, /* tp_str */
|
||||||
(getattrofunc)class_getattr, /* tp_getattro */
|
(getattrofunc)class_getattr, /* tp_getattro */
|
||||||
(setattrofunc)class_setattr, /* tp_setattro */
|
(setattrofunc)class_setattr, /* tp_setattro */
|
||||||
|
@ -404,6 +423,22 @@ PyTypeObject PyClass_Type = {
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
(traverseproc)class_traverse, /* tp_traverse */
|
(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
|
int
|
||||||
|
@ -531,7 +566,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
||||||
/* compensate for boost in _Py_NewReference; note that
|
/* compensate for boost in _Py_NewReference; note that
|
||||||
* _Py_RefTotal was also boosted; we'll knock that down later.
|
* _Py_RefTotal was also boosted; we'll knock that down later.
|
||||||
*/
|
*/
|
||||||
inst->ob_type->tp_alloc--;
|
inst->ob_type->tp_allocs--;
|
||||||
#endif
|
#endif
|
||||||
#else /* !Py_TRACE_REFS */
|
#else /* !Py_TRACE_REFS */
|
||||||
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
|
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
|
||||||
|
@ -564,7 +599,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
||||||
#endif
|
#endif
|
||||||
if (--inst->ob_refcnt > 0) {
|
if (--inst->ob_refcnt > 0) {
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
inst->ob_type->tp_free--;
|
inst->ob_type->tp_frees--;
|
||||||
#endif
|
#endif
|
||||||
return; /* __del__ added a reference; don't delete now */
|
return; /* __del__ added a reference; don't delete now */
|
||||||
}
|
}
|
||||||
|
@ -572,7 +607,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
||||||
_Py_ForgetReference((PyObject *)inst);
|
_Py_ForgetReference((PyObject *)inst);
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
/* compensate for increment in _Py_ForgetReference */
|
/* compensate for increment in _Py_ForgetReference */
|
||||||
inst->ob_type->tp_free--;
|
inst->ob_type->tp_frees--;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WITH_CYCLE_GC
|
#ifndef WITH_CYCLE_GC
|
||||||
inst->ob_type = NULL;
|
inst->ob_type = NULL;
|
||||||
|
@ -619,6 +654,8 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
|
||||||
{
|
{
|
||||||
register PyObject *v;
|
register PyObject *v;
|
||||||
PyClassObject *class;
|
PyClassObject *class;
|
||||||
|
descrgetfunc f;
|
||||||
|
|
||||||
class = NULL;
|
class = NULL;
|
||||||
v = PyDict_GetItem(inst->in_dict, name);
|
v = PyDict_GetItem(inst->in_dict, name);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
|
@ -628,17 +665,20 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
|
||||||
}
|
}
|
||||||
Py_INCREF(v);
|
Py_INCREF(v);
|
||||||
if (class != NULL) {
|
if (class != NULL) {
|
||||||
if (PyFunction_Check(v)) {
|
f = v->ob_type->tp_descr_get;
|
||||||
PyObject *w = PyMethod_New(v, (PyObject *)inst,
|
if (f != NULL) {
|
||||||
(PyObject *)class);
|
PyObject *w = f(v, (PyObject *)inst,
|
||||||
|
(PyObject *)(inst->in_class));
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
v = w;
|
v = w;
|
||||||
}
|
}
|
||||||
else if (PyMethod_Check(v)) {
|
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 */
|
/* Only if classes are compatible */
|
||||||
if (PyClass_IsSubclass((PyObject *)class, im_class)) {
|
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 *w = PyMethod_New(im_func,
|
||||||
(PyObject *)inst, im_class);
|
(PyObject *)inst, im_class);
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
|
@ -1814,6 +1854,23 @@ instance_iternext(PyInstanceObject *self)
|
||||||
return NULL;
|
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 = {
|
static PyNumberMethods instance_as_number = {
|
||||||
(binaryfunc)instance_add, /* nb_add */
|
(binaryfunc)instance_add, /* nb_add */
|
||||||
|
@ -1868,7 +1925,7 @@ PyTypeObject PyInstance_Type = {
|
||||||
&instance_as_sequence, /* tp_as_sequence */
|
&instance_as_sequence, /* tp_as_sequence */
|
||||||
&instance_as_mapping, /* tp_as_mapping */
|
&instance_as_mapping, /* tp_as_mapping */
|
||||||
(hashfunc)instance_hash, /* tp_hash */
|
(hashfunc)instance_hash, /* tp_hash */
|
||||||
0, /* tp_call */
|
instance_call, /* tp_call */
|
||||||
(reprfunc)instance_str, /* tp_str */
|
(reprfunc)instance_str, /* tp_str */
|
||||||
(getattrofunc)instance_getattr, /* tp_getattro */
|
(getattrofunc)instance_getattr, /* tp_getattro */
|
||||||
(setattrofunc)instance_setattr, /* tp_setattro */
|
(setattrofunc)instance_setattr, /* tp_setattro */
|
||||||
|
@ -1921,36 +1978,6 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
|
||||||
return (PyObject *)im;
|
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 */
|
/* Class method methods */
|
||||||
|
|
||||||
#define OFF(x) offsetof(PyMethodObject, x)
|
#define OFF(x) offsetof(PyMethodObject, x)
|
||||||
|
@ -2028,43 +2055,52 @@ instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
instancemethod_repr(PyMethodObject *a)
|
instancemethod_repr(PyMethodObject *a)
|
||||||
{
|
{
|
||||||
char buf[240];
|
char buffer[240];
|
||||||
PyInstanceObject *self = (PyInstanceObject *)(a->im_self);
|
PyObject *self = a->im_self;
|
||||||
PyObject *func = a->im_func;
|
PyObject *func = a->im_func;
|
||||||
PyClassObject *class = (PyClassObject *)(a->im_class);
|
PyObject *klass = a->im_class;
|
||||||
PyObject *fclassname, *iclassname, *funcname;
|
PyObject *funcname = NULL, *klassname = NULL, *result = NULL;
|
||||||
char *fcname, *icname, *fname;
|
char *sfuncname = "?", *sklassname = "?";
|
||||||
fclassname = class->cl_name;
|
|
||||||
if (PyFunction_Check(func)) {
|
funcname = PyObject_GetAttrString(func, "__name__");
|
||||||
funcname = ((PyFunctionObject *)func)->func_name;
|
if (funcname == NULL)
|
||||||
Py_INCREF(funcname);
|
PyErr_Clear();
|
||||||
|
else if (!PyString_Check(funcname)) {
|
||||||
|
Py_DECREF(funcname);
|
||||||
|
funcname = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
funcname = PyObject_GetAttrString(func,"__name__");
|
sfuncname = PyString_AS_STRING(funcname);
|
||||||
if (funcname == NULL)
|
klassname = PyObject_GetAttrString(klass, "__name__");
|
||||||
PyErr_Clear();
|
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
|
else
|
||||||
fname = "?";
|
sklassname = PyString_AS_STRING(klassname);
|
||||||
if (fclassname != NULL && PyString_Check(fclassname))
|
|
||||||
fcname = PyString_AsString(fclassname);
|
|
||||||
else
|
|
||||||
fcname = "?";
|
|
||||||
if (self == NULL)
|
if (self == NULL)
|
||||||
sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
|
sprintf(buffer, "<unbound method %.100s.%.100s>",
|
||||||
|
sklassname, sfuncname);
|
||||||
else {
|
else {
|
||||||
iclassname = self->in_class->cl_name;
|
/* XXX Shouldn't use repr() here! */
|
||||||
if (iclassname != NULL && PyString_Check(iclassname))
|
PyObject *selfrepr = PyObject_Repr(self);
|
||||||
icname = PyString_AsString(iclassname);
|
if (selfrepr == NULL)
|
||||||
else
|
goto fail;
|
||||||
icname = "?";
|
if (!PyString_Check(selfrepr)) {
|
||||||
sprintf(buf, "<method %.60s.%.60s of %.60s instance at %p>",
|
Py_DECREF(selfrepr);
|
||||||
fcname, fname, icname, self);
|
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);
|
Py_XDECREF(funcname);
|
||||||
return PyString_FromString(buf);
|
Py_XDECREF(klassname);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
|
@ -2105,6 +2141,57 @@ instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg)
|
||||||
return 0;
|
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 = {
|
PyTypeObject PyMethod_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0,
|
||||||
|
@ -2121,7 +2208,7 @@ PyTypeObject PyMethod_Type = {
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)instancemethod_hash, /* tp_hash */
|
(hashfunc)instancemethod_hash, /* tp_hash */
|
||||||
0, /* tp_call */
|
instancemethod_call, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
(getattrofunc)instancemethod_getattro, /* tp_getattro */
|
(getattrofunc)instancemethod_getattro, /* tp_getattro */
|
||||||
(setattrofunc)instancemethod_setattro, /* tp_setattro */
|
(setattrofunc)instancemethod_setattro, /* tp_setattro */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#ifndef WITHOUT_COMPLEX
|
#ifndef WITHOUT_COMPLEX
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "structmember.h"
|
||||||
|
|
||||||
/* Precisions used by repr() and str(), respectively.
|
/* 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 *
|
PyObject *
|
||||||
PyComplex_FromCComplex(Py_complex cval)
|
PyComplex_FromCComplex(Py_complex cval)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +208,15 @@ PyComplex_FromCComplex(Py_complex cval)
|
||||||
return (PyObject *) op;
|
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 *
|
PyObject *
|
||||||
PyComplex_FromDoubles(double real, double imag)
|
PyComplex_FromDoubles(double real, double imag)
|
||||||
{
|
{
|
||||||
|
@ -559,19 +580,261 @@ static PyMethodDef complex_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{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 *
|
static PyObject *
|
||||||
complex_getattr(PyComplexObject *self, char *name)
|
complex_subtype_from_string(PyTypeObject *type, PyObject *v)
|
||||||
{
|
{
|
||||||
if (strcmp(name, "real") == 0)
|
extern double strtod(const char *, char **);
|
||||||
return (PyObject *)PyFloat_FromDouble(self->cval.real);
|
const char *s, *start;
|
||||||
else if (strcmp(name, "imag") == 0)
|
char *end;
|
||||||
return (PyObject *)PyFloat_FromDouble(self->cval.imag);
|
double x=0.0, y=0.0, z;
|
||||||
else if (strcmp(name, "__members__") == 0)
|
int got_re=0, got_im=0, done=0;
|
||||||
return Py_BuildValue("[ss]", "imag", "real");
|
int digit_or_dot;
|
||||||
return Py_FindMethod(complex_methods, (PyObject *)self, name);
|
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 = {
|
static PyNumberMethods complex_as_number = {
|
||||||
(binaryfunc)complex_add, /* nb_add */
|
(binaryfunc)complex_add, /* nb_add */
|
||||||
(binaryfunc)complex_sub, /* nb_subtract */
|
(binaryfunc)complex_sub, /* nb_subtract */
|
||||||
|
@ -606,7 +869,7 @@ PyTypeObject PyComplex_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)complex_dealloc, /* tp_dealloc */
|
(destructor)complex_dealloc, /* tp_dealloc */
|
||||||
(printfunc)complex_print, /* tp_print */
|
(printfunc)complex_print, /* tp_print */
|
||||||
(getattrfunc)complex_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
(reprfunc)complex_repr, /* tp_repr */
|
(reprfunc)complex_repr, /* tp_repr */
|
||||||
|
@ -616,14 +879,28 @@ PyTypeObject PyComplex_Type = {
|
||||||
(hashfunc)complex_hash, /* tp_hash */
|
(hashfunc)complex_hash, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
(reprfunc)complex_str, /* tp_str */
|
(reprfunc)complex_str, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
0, /* tp_doc */
|
complex_doc, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
complex_richcompare, /* tp_richcompare */
|
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
|
#endif
|
||||||
|
|
854
Objects/descrobject.c
Normal file
854
Objects/descrobject.c
Normal file
|
@ -0,0 +1,854 @@
|
||||||
|
/* Descriptors -- a new, flexible way to describe attributes */
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
#include "structmember.h" /* Why is this not included in Python.h? */
|
||||||
|
|
||||||
|
/* Various kinds of descriptor objects */
|
||||||
|
|
||||||
|
#define COMMON \
|
||||||
|
PyObject_HEAD \
|
||||||
|
PyTypeObject *d_type; \
|
||||||
|
PyObject *d_name
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
COMMON;
|
||||||
|
} PyDescrObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
COMMON;
|
||||||
|
PyMethodDef *d_method;
|
||||||
|
} PyMethodDescrObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
COMMON;
|
||||||
|
struct memberlist *d_member;
|
||||||
|
} PyMemberDescrObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
COMMON;
|
||||||
|
struct getsetlist *d_getset;
|
||||||
|
} PyGetSetDescrObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
COMMON;
|
||||||
|
struct wrapperbase *d_base;
|
||||||
|
void *d_wrapped; /* This can be any function pointer */
|
||||||
|
} PyWrapperDescrObject;
|
||||||
|
|
||||||
|
static void
|
||||||
|
descr_dealloc(PyDescrObject *descr)
|
||||||
|
{
|
||||||
|
Py_XDECREF(descr->d_type);
|
||||||
|
Py_XDECREF(descr->d_name);
|
||||||
|
PyObject_DEL(descr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
descr_name(PyDescrObject *descr)
|
||||||
|
{
|
||||||
|
if (descr->d_name != NULL && PyString_Check(descr->d_name))
|
||||||
|
return PyString_AS_STRING(descr->d_name);
|
||||||
|
else
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
descr_repr(PyDescrObject *descr, char *format)
|
||||||
|
{
|
||||||
|
char buffer[500];
|
||||||
|
|
||||||
|
sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name);
|
||||||
|
return PyString_FromString(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
method_repr(PyMethodDescrObject *descr)
|
||||||
|
{
|
||||||
|
return descr_repr((PyDescrObject *)descr,
|
||||||
|
"<method '%.300s' of '%.100s' objects>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
member_repr(PyMemberDescrObject *descr)
|
||||||
|
{
|
||||||
|
return descr_repr((PyDescrObject *)descr,
|
||||||
|
"<member '%.300s' of '%.100s' objects>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
getset_repr(PyGetSetDescrObject *descr)
|
||||||
|
{
|
||||||
|
return descr_repr((PyDescrObject *)descr,
|
||||||
|
"<attribute '%.300s' of '%.100s' objects>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_repr(PyWrapperDescrObject *descr)
|
||||||
|
{
|
||||||
|
return descr_repr((PyDescrObject *)descr,
|
||||||
|
"<slot wrapper '%.300s' of '%.100s' objects>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
|
||||||
|
PyObject **pres)
|
||||||
|
{
|
||||||
|
if (obj == NULL || obj == Py_None) {
|
||||||
|
Py_INCREF(descr);
|
||||||
|
*pres = (PyObject *)descr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.200s' for '%.100s' objects "
|
||||||
|
"doesn't apply to '%.100s' object",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name,
|
||||||
|
obj->ob_type->tp_name);
|
||||||
|
*pres = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||||
|
return res;
|
||||||
|
return PyCFunction_New(descr->d_method, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||||
|
return res;
|
||||||
|
return PyMember_Get((char *)obj, descr->d_member,
|
||||||
|
descr->d_member->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||||
|
return res;
|
||||||
|
if (descr->d_getset->get != NULL)
|
||||||
|
return descr->d_getset->get(obj, descr->d_getset->closure);
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"attribute '%300s' of '%.100s' objects is not readable",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||||
|
return res;
|
||||||
|
return PyWrapper_New((PyObject *)descr, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
|
||||||
|
int *pres)
|
||||||
|
{
|
||||||
|
assert(obj != NULL);
|
||||||
|
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.200s' for '%.100s' objects "
|
||||||
|
"doesn't apply to '%.100s' object",
|
||||||
|
descr_name(descr),
|
||||||
|
descr->d_type->tp_name,
|
||||||
|
obj->ob_type->tp_name);
|
||||||
|
*pres = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
|
||||||
|
return res;
|
||||||
|
return PyMember_Set((char *)obj, descr->d_member,
|
||||||
|
descr->d_member->name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
|
||||||
|
return res;
|
||||||
|
if (descr->d_getset->set != NULL)
|
||||||
|
return descr->d_getset->set(obj, value,
|
||||||
|
descr->d_getset->closure);
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"attribute '%300s' of '%.100s' objects is not writable",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
PyObject *self, *func, *result;
|
||||||
|
|
||||||
|
/* Make sure that the first argument is acceptable as 'self' */
|
||||||
|
assert(PyTuple_Check(args));
|
||||||
|
argc = PyTuple_GET_SIZE(args);
|
||||||
|
if (argc < 1) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.300s' of '%.100s' "
|
||||||
|
"object needs an argument",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
self = PyTuple_GET_ITEM(args, 0);
|
||||||
|
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.200s' "
|
||||||
|
"requires a '%.100s' object "
|
||||||
|
"but received a '%.100s'",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name,
|
||||||
|
self->ob_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
func = PyCFunction_New(descr->d_method, self);
|
||||||
|
if (func == NULL)
|
||||||
|
return NULL;
|
||||||
|
args = PyTuple_GetSlice(args, 1, argc);
|
||||||
|
if (args == NULL) {
|
||||||
|
Py_DECREF(func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = PyEval_CallObjectWithKeywords(func, args, kwds);
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(func);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
PyObject *self, *func, *result;
|
||||||
|
|
||||||
|
/* Make sure that the first argument is acceptable as 'self' */
|
||||||
|
assert(PyTuple_Check(args));
|
||||||
|
argc = PyTuple_GET_SIZE(args);
|
||||||
|
if (argc < 1) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.300s' of '%.100s' "
|
||||||
|
"object needs an argument",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
self = PyTuple_GET_ITEM(args, 0);
|
||||||
|
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%.200s' "
|
||||||
|
"requires a '%.100s' object "
|
||||||
|
"but received a '%.100s'",
|
||||||
|
descr_name((PyDescrObject *)descr),
|
||||||
|
descr->d_type->tp_name,
|
||||||
|
self->ob_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
func = PyWrapper_New((PyObject *)descr, self);
|
||||||
|
if (func == NULL)
|
||||||
|
return NULL;
|
||||||
|
args = PyTuple_GetSlice(args, 1, argc);
|
||||||
|
if (args == NULL) {
|
||||||
|
Py_DECREF(func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = PyEval_CallObjectWithKeywords(func, args, kwds);
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(func);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
member_get_doc(PyMethodDescrObject *descr, void *closure)
|
||||||
|
{
|
||||||
|
if (descr->d_method->ml_doc == NULL) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
return PyString_FromString(descr->d_method->ml_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct memberlist descr_members[] = {
|
||||||
|
{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
|
||||||
|
{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct getsetlist member_getset[] = {
|
||||||
|
{"__doc__", (getter)member_get_doc},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
|
||||||
|
{
|
||||||
|
if (descr->d_base->doc == NULL) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
return PyString_FromString(descr->d_base->doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct getsetlist wrapper_getset[] = {
|
||||||
|
{"__doc__", (getter)wrapper_get_doc},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject PyMethodDescr_Type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"method_descriptor",
|
||||||
|
sizeof(PyMethodDescrObject),
|
||||||
|
0,
|
||||||
|
(destructor)descr_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)method_repr, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
(ternaryfunc)methoddescr_call, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
descr_members, /* tp_members */
|
||||||
|
member_getset, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
(descrgetfunc)method_get, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject PyMemberDescr_Type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"member_descriptor",
|
||||||
|
sizeof(PyMemberDescrObject),
|
||||||
|
0,
|
||||||
|
(destructor)descr_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)member_repr, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
(ternaryfunc)0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
descr_members, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
(descrgetfunc)member_get, /* tp_descr_get */
|
||||||
|
(descrsetfunc)member_set, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject PyGetSetDescr_Type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"getset_descriptor",
|
||||||
|
sizeof(PyGetSetDescrObject),
|
||||||
|
0,
|
||||||
|
(destructor)descr_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)getset_repr, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
(ternaryfunc)0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
descr_members, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
(descrgetfunc)getset_get, /* tp_descr_get */
|
||||||
|
(descrsetfunc)getset_set, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject PyWrapperDescr_Type = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0,
|
||||||
|
"wrapper_descriptor",
|
||||||
|
sizeof(PyWrapperDescrObject),
|
||||||
|
0,
|
||||||
|
(destructor)descr_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)wrapper_repr, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
(ternaryfunc)wrapperdescr_call, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
descr_members, /* tp_members */
|
||||||
|
wrapper_getset, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
(descrgetfunc)wrapper_get, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyDescrObject *
|
||||||
|
descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
|
||||||
|
{
|
||||||
|
PyDescrObject *descr;
|
||||||
|
|
||||||
|
descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
|
||||||
|
if (descr != NULL) {
|
||||||
|
Py_XINCREF(type);
|
||||||
|
descr->d_type = type;
|
||||||
|
descr->d_name = PyString_InternFromString(name);
|
||||||
|
if (descr->d_name == NULL) {
|
||||||
|
Py_DECREF(descr);
|
||||||
|
descr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
|
||||||
|
{
|
||||||
|
PyMethodDescrObject *descr;
|
||||||
|
|
||||||
|
descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
|
||||||
|
type, method->ml_name);
|
||||||
|
if (descr != NULL)
|
||||||
|
descr->d_method = method;
|
||||||
|
return (PyObject *)descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
|
||||||
|
{
|
||||||
|
PyMemberDescrObject *descr;
|
||||||
|
|
||||||
|
descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
|
||||||
|
type, member->name);
|
||||||
|
if (descr != NULL)
|
||||||
|
descr->d_member = member;
|
||||||
|
return (PyObject *)descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
|
||||||
|
{
|
||||||
|
PyGetSetDescrObject *descr;
|
||||||
|
|
||||||
|
descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
|
||||||
|
type, getset->name);
|
||||||
|
if (descr != NULL)
|
||||||
|
descr->d_getset = getset;
|
||||||
|
return (PyObject *)descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
|
||||||
|
{
|
||||||
|
PyWrapperDescrObject *descr;
|
||||||
|
|
||||||
|
descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
|
||||||
|
type, base->name);
|
||||||
|
if (descr != NULL) {
|
||||||
|
descr->d_base = base;
|
||||||
|
descr->d_wrapped = wrapped;
|
||||||
|
}
|
||||||
|
return (PyObject *)descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyDescr_IsData(PyObject *d)
|
||||||
|
{
|
||||||
|
return d->ob_type->tp_descr_set != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Readonly proxy for dictionaries (actually any mapping) --- */
|
||||||
|
|
||||||
|
/* This has no reason to be in this file except that adding new files is a
|
||||||
|
bit of a pain */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *dict;
|
||||||
|
} proxyobject;
|
||||||
|
|
||||||
|
static int
|
||||||
|
proxy_len(proxyobject *pp)
|
||||||
|
{
|
||||||
|
return PyObject_Size(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_getitem(proxyobject *pp, PyObject *key)
|
||||||
|
{
|
||||||
|
return PyObject_GetItem(pp->dict, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMappingMethods proxy_as_mapping = {
|
||||||
|
(inquiry)proxy_len, /* mp_length */
|
||||||
|
(binaryfunc)proxy_getitem, /* mp_subscript */
|
||||||
|
0, /* mp_ass_subscript */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
proxy_contains(proxyobject *pp, PyObject *key)
|
||||||
|
{
|
||||||
|
return PySequence_Contains(pp->dict, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PySequenceMethods proxy_as_sequence = {
|
||||||
|
0, /* sq_length */
|
||||||
|
0, /* sq_concat */
|
||||||
|
0, /* sq_repeat */
|
||||||
|
0, /* sq_item */
|
||||||
|
0, /* sq_slice */
|
||||||
|
0, /* sq_ass_item */
|
||||||
|
0, /* sq_ass_slice */
|
||||||
|
(objobjproc)proxy_contains, /* sq_contains */
|
||||||
|
0, /* sq_inplace_concat */
|
||||||
|
0, /* sq_inplace_repeat */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_has_key(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *key;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O:has_key", &key))
|
||||||
|
return NULL;
|
||||||
|
return PyInt_FromLong(PySequence_Contains(pp->dict, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_get(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *key, *def = Py_None;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
|
||||||
|
return NULL;
|
||||||
|
return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_keys(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":keys"))
|
||||||
|
return NULL;
|
||||||
|
return PyMapping_Keys(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_values(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":values"))
|
||||||
|
return NULL;
|
||||||
|
return PyMapping_Values(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_items(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":items"))
|
||||||
|
return NULL;
|
||||||
|
return PyMapping_Items(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_copy(proxyobject *pp, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ":copy"))
|
||||||
|
return NULL;
|
||||||
|
return PyObject_CallMethod(pp->dict, "copy", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef proxy_methods[] = {
|
||||||
|
{"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"},
|
||||||
|
{"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
|
||||||
|
{"keys", (PyCFunction)proxy_keys, METH_VARARGS, "XXX"},
|
||||||
|
{"values", (PyCFunction)proxy_values, METH_VARARGS, "XXX"},
|
||||||
|
{"items", (PyCFunction)proxy_items, METH_VARARGS, "XXX"},
|
||||||
|
{"copy", (PyCFunction)proxy_copy, METH_VARARGS, "XXX"},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_dealloc(proxyobject *pp)
|
||||||
|
{
|
||||||
|
Py_DECREF(pp->dict);
|
||||||
|
PyObject_DEL(pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
proxy_getiter(proxyobject *pp)
|
||||||
|
{
|
||||||
|
return PyObject_GetIter(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
proxy_str(proxyobject *pp)
|
||||||
|
{
|
||||||
|
return PyObject_Str(pp->dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyTypeObject proxytype = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0, /* ob_size */
|
||||||
|
"dict-proxy", /* tp_name */
|
||||||
|
sizeof(proxyobject), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
/* methods */
|
||||||
|
(destructor)proxy_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
&proxy_as_sequence, /* tp_as_sequence */
|
||||||
|
&proxy_as_mapping, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
(reprfunc)proxy_str, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
(getiterfunc)proxy_getiter, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
proxy_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyDictProxy_New(PyObject *dict)
|
||||||
|
{
|
||||||
|
proxyobject *pp;
|
||||||
|
|
||||||
|
pp = PyObject_NEW(proxyobject, &proxytype);
|
||||||
|
if (pp != NULL) {
|
||||||
|
Py_INCREF(dict);
|
||||||
|
pp->dict = dict;
|
||||||
|
}
|
||||||
|
return (PyObject *)pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Wrapper object for "slot" methods --- */
|
||||||
|
|
||||||
|
/* This has no reason to be in this file except that adding new files is a
|
||||||
|
bit of a pain */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyWrapperDescrObject *descr;
|
||||||
|
PyObject *self;
|
||||||
|
} wrapperobject;
|
||||||
|
|
||||||
|
static void
|
||||||
|
wrapper_dealloc(wrapperobject *wp)
|
||||||
|
{
|
||||||
|
Py_XDECREF(wp->descr);
|
||||||
|
Py_XDECREF(wp->self);
|
||||||
|
PyObject_DEL(wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef wrapper_methods[] = {
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_name(wrapperobject *wp)
|
||||||
|
{
|
||||||
|
char *s = wp->descr->d_base->name;
|
||||||
|
|
||||||
|
return PyString_FromString(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_doc(wrapperobject *wp)
|
||||||
|
{
|
||||||
|
char *s = wp->descr->d_base->doc;
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return PyString_FromString(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct getsetlist wrapper_getsets[] = {
|
||||||
|
{"__name__", (getter)wrapper_name},
|
||||||
|
{"__doc__", (getter)wrapper_doc},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
wrapperfunc wrapper = wp->descr->d_base->wrapper;
|
||||||
|
PyObject *self = wp->self;
|
||||||
|
|
||||||
|
return (*wrapper)(self, args, wp->descr->d_wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyTypeObject wrappertype = {
|
||||||
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
0, /* ob_size */
|
||||||
|
"method-wrapper", /* tp_name */
|
||||||
|
sizeof(wrapperobject), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
/* methods */
|
||||||
|
(destructor)wrapper_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
(ternaryfunc)wrapper_call, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
wrapper_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
wrapper_getsets, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyWrapper_New(PyObject *d, PyObject *self)
|
||||||
|
{
|
||||||
|
wrapperobject *wp;
|
||||||
|
PyWrapperDescrObject *descr;
|
||||||
|
|
||||||
|
assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
|
||||||
|
descr = (PyWrapperDescrObject *)d;
|
||||||
|
assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
|
||||||
|
|
||||||
|
wp = PyObject_NEW(wrapperobject, &wrappertype);
|
||||||
|
if (wp != NULL) {
|
||||||
|
Py_INCREF(descr);
|
||||||
|
wp->descr = descr;
|
||||||
|
Py_INCREF(self);
|
||||||
|
wp->self = self;
|
||||||
|
}
|
||||||
|
return (PyObject *)wp;
|
||||||
|
}
|
|
@ -3,15 +3,8 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
/* MINSIZE is the minimum size of a dictionary. This many slots are
|
typedef PyDictEntry dictentry;
|
||||||
* allocated directly in the dict object (in the ma_smalltable member).
|
typedef PyDictObject dictobject;
|
||||||
* 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
|
|
||||||
|
|
||||||
/* Define this out if you don't want conversion statistics on exit. */
|
/* Define this out if you don't want conversion statistics on exit. */
|
||||||
#undef SHOW_CONVERSION_COUNTS
|
#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 */
|
/* Object used as dummy key to fill deleted entries */
|
||||||
static PyObject *dummy; /* Initialized by first call to newdictobject() */
|
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 */
|
/* forward declarations */
|
||||||
static dictentry *
|
static dictentry *
|
||||||
lookdict_string(dictobject *mp, PyObject *key, long hash);
|
lookdict_string(dictobject *mp, PyObject *key, long hash);
|
||||||
|
@ -196,12 +126,24 @@ show_counts(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set dictobject* mp to empty but w/ MINSIZE slots, using ma_smalltable. */
|
/* Initialization macros.
|
||||||
#define empty_to_minsize(mp) do { \
|
There are two ways to create a dict: PyDict_New() is the main C API
|
||||||
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
|
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_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; \
|
(mp)->ma_used = (mp)->ma_fill = 0; \
|
||||||
|
INIT_NONZERO_DICT_SLOTS(mp); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -219,7 +161,7 @@ PyDict_New(void)
|
||||||
mp = PyObject_NEW(dictobject, &PyDict_Type);
|
mp = PyObject_NEW(dictobject, &PyDict_Type);
|
||||||
if (mp == NULL)
|
if (mp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
empty_to_minsize(mp);
|
EMPTY_TO_MINSIZE(mp);
|
||||||
mp->ma_lookup = lookdict_string;
|
mp->ma_lookup = lookdict_string;
|
||||||
#ifdef SHOW_CONVERSION_COUNTS
|
#ifdef SHOW_CONVERSION_COUNTS
|
||||||
++created;
|
++created;
|
||||||
|
@ -418,7 +360,10 @@ insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
|
||||||
{
|
{
|
||||||
PyObject *old_value;
|
PyObject *old_value;
|
||||||
register dictentry *ep;
|
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) {
|
if (ep->me_value != NULL) {
|
||||||
old_value = ep->me_value;
|
old_value = ep->me_value;
|
||||||
ep->me_value = value;
|
ep->me_value = value;
|
||||||
|
@ -449,12 +394,12 @@ dictresize(dictobject *mp, int minused)
|
||||||
dictentry *oldtable, *newtable, *ep;
|
dictentry *oldtable, *newtable, *ep;
|
||||||
int i;
|
int i;
|
||||||
int is_oldtable_malloced;
|
int is_oldtable_malloced;
|
||||||
dictentry small_copy[MINSIZE];
|
dictentry small_copy[PyDict_MINSIZE];
|
||||||
|
|
||||||
assert(minused >= 0);
|
assert(minused >= 0);
|
||||||
|
|
||||||
/* Find the smallest table size > minused. */
|
/* Find the smallest table size > minused. */
|
||||||
for (newsize = MINSIZE;
|
for (newsize = PyDict_MINSIZE;
|
||||||
newsize <= minused && newsize > 0;
|
newsize <= minused && newsize > 0;
|
||||||
newsize <<= 1)
|
newsize <<= 1)
|
||||||
;
|
;
|
||||||
|
@ -468,7 +413,7 @@ dictresize(dictobject *mp, int minused)
|
||||||
assert(oldtable != NULL);
|
assert(oldtable != NULL);
|
||||||
is_oldtable_malloced = oldtable != mp->ma_smalltable;
|
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. */
|
/* A large table is shrinking, or we can't get any smaller. */
|
||||||
newtable = mp->ma_smalltable;
|
newtable = mp->ma_smalltable;
|
||||||
if (newtable == oldtable) {
|
if (newtable == oldtable) {
|
||||||
|
@ -649,7 +594,7 @@ PyDict_Clear(PyObject *op)
|
||||||
dictentry *ep, *table;
|
dictentry *ep, *table;
|
||||||
int table_is_malloced;
|
int table_is_malloced;
|
||||||
int fill;
|
int fill;
|
||||||
dictentry small_copy[MINSIZE];
|
dictentry small_copy[PyDict_MINSIZE];
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
int i, n;
|
int i, n;
|
||||||
#endif
|
#endif
|
||||||
|
@ -674,7 +619,7 @@ PyDict_Clear(PyObject *op)
|
||||||
*/
|
*/
|
||||||
fill = mp->ma_fill;
|
fill = mp->ma_fill;
|
||||||
if (table_is_malloced)
|
if (table_is_malloced)
|
||||||
empty_to_minsize(mp);
|
EMPTY_TO_MINSIZE(mp);
|
||||||
|
|
||||||
else if (fill > 0) {
|
else if (fill > 0) {
|
||||||
/* It's a small table with something that needs to be cleared.
|
/* 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));
|
memcpy(small_copy, table, sizeof(small_copy));
|
||||||
table = small_copy;
|
table = small_copy;
|
||||||
empty_to_minsize(mp);
|
EMPTY_TO_MINSIZE(mp);
|
||||||
}
|
}
|
||||||
/* else it's a small table that's already empty */
|
/* else it's a small table that's already empty */
|
||||||
|
|
||||||
|
@ -1042,32 +987,47 @@ dict_items(register dictobject *mp, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
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;
|
register int i;
|
||||||
dictobject *other;
|
|
||||||
dictentry *entry;
|
dictentry *entry;
|
||||||
PyObject *param;
|
|
||||||
/* We accept for the argument either a concrete dictionary object,
|
/* We accept for the argument either a concrete dictionary object,
|
||||||
* or an abstract "mapping" object. For the former, we can do
|
* or an abstract "mapping" object. For the former, we can do
|
||||||
* things quite efficiently. For the latter, we only require that
|
* things quite efficiently. For the latter, we only require that
|
||||||
* PyMapping_Keys() and PyObject_GetItem() be supported.
|
* PyMapping_Keys() and PyObject_GetItem() be supported.
|
||||||
*/
|
*/
|
||||||
if (!PyArg_ParseTuple(args, "O:update", ¶m))
|
if (a == NULL || !PyDict_Check(a) || b == NULL) {
|
||||||
return NULL;
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
if (PyDict_Check(param)) {
|
}
|
||||||
other = (dictobject*)param;
|
mp = (dictobject*)a;
|
||||||
|
if (PyDict_Check(b)) {
|
||||||
|
other = (dictobject*)b;
|
||||||
if (other == mp || other->ma_used == 0)
|
if (other == mp || other->ma_used == 0)
|
||||||
/* a.update(a) or a.update({}); nothing to do */
|
/* a.update(a) or a.update({}); nothing to do */
|
||||||
goto done;
|
return 0;
|
||||||
/* Do one big resize at the start, rather than
|
/* Do one big resize at the start, rather than
|
||||||
* incrementally resizing as we insert new items. Expect
|
* incrementally resizing as we insert new items. Expect
|
||||||
* that there will be no (or few) overlapping keys.
|
* that there will be no (or few) overlapping keys.
|
||||||
*/
|
*/
|
||||||
if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
|
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)
|
if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
for (i = 0; i <= other->ma_mask; i++) {
|
for (i = 0; i <= other->ma_mask; i++) {
|
||||||
entry = &other->ma_table[i];
|
entry = &other->ma_table[i];
|
||||||
|
@ -1081,7 +1041,7 @@ dict_update(register dictobject *mp, PyObject *args)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Do it the generic, slower way */
|
/* Do it the generic, slower way */
|
||||||
PyObject *keys = PyMapping_Keys(param);
|
PyObject *keys = PyMapping_Keys(b);
|
||||||
PyObject *iter;
|
PyObject *iter;
|
||||||
PyObject *key, *value;
|
PyObject *key, *value;
|
||||||
int status;
|
int status;
|
||||||
|
@ -1092,37 +1052,34 @@ dict_update(register dictobject *mp, PyObject *args)
|
||||||
* AttributeError to percolate up. Might as well
|
* AttributeError to percolate up. Might as well
|
||||||
* do the same for any other error.
|
* do the same for any other error.
|
||||||
*/
|
*/
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
iter = PyObject_GetIter(keys);
|
iter = PyObject_GetIter(keys);
|
||||||
Py_DECREF(keys);
|
Py_DECREF(keys);
|
||||||
if (iter == NULL)
|
if (iter == NULL)
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
|
for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
|
||||||
value = PyObject_GetItem(param, key);
|
value = PyObject_GetItem(b, key);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
Py_DECREF(iter);
|
Py_DECREF(iter);
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
status = PyDict_SetItem((PyObject*)mp, key, value);
|
status = PyDict_SetItem((PyObject*)mp, key, value);
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
Py_DECREF(iter);
|
Py_DECREF(iter);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(iter);
|
Py_DECREF(iter);
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
/* Iterator completed, via error */
|
/* Iterator completed, via error */
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
done:
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1694,12 +1651,6 @@ static PyMethodDef mapp_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
dict_getattr(dictobject *mp, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dict_contains(dictobject *mp, PyObject *key)
|
dict_contains(dictobject *mp, PyObject *key)
|
||||||
{
|
{
|
||||||
|
@ -1731,6 +1682,26 @@ static PySequenceMethods dict_as_sequence = {
|
||||||
0, /* sq_inplace_repeat */
|
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 *
|
static PyObject *
|
||||||
dict_iter(dictobject *dict)
|
dict_iter(dictobject *dict)
|
||||||
{
|
{
|
||||||
|
@ -1745,7 +1716,7 @@ PyTypeObject PyDict_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)dict_dealloc, /* tp_dealloc */
|
(destructor)dict_dealloc, /* tp_dealloc */
|
||||||
(printfunc)dict_print, /* tp_print */
|
(printfunc)dict_print, /* tp_print */
|
||||||
(getattrfunc)dict_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
(cmpfunc)dict_compare, /* tp_compare */
|
(cmpfunc)dict_compare, /* tp_compare */
|
||||||
(reprfunc)dict_repr, /* tp_repr */
|
(reprfunc)dict_repr, /* tp_repr */
|
||||||
|
@ -1755,17 +1726,29 @@ PyTypeObject PyDict_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
|
||||||
0, /* tp_doc */
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
"dictionary type", /* tp_doc */
|
||||||
(traverseproc)dict_traverse, /* tp_traverse */
|
(traverseproc)dict_traverse, /* tp_traverse */
|
||||||
(inquiry)dict_tp_clear, /* tp_clear */
|
(inquiry)dict_tp_clear, /* tp_clear */
|
||||||
dict_richcompare, /* tp_richcompare */
|
dict_richcompare, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)dict_iter, /* tp_iter */
|
(getiterfunc)dict_iter, /* tp_iter */
|
||||||
0, /* tp_iternext */
|
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 */
|
/* For backward compatibility with old dictionary interface */
|
||||||
|
@ -1873,12 +1856,6 @@ static PyMethodDef dictiter_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{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)
|
static PyObject *dictiter_iternext(dictiterobject *di)
|
||||||
{
|
{
|
||||||
PyObject *key, *value;
|
PyObject *key, *value;
|
||||||
|
@ -1903,7 +1880,7 @@ PyTypeObject PyDictIter_Type = {
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)dictiter_dealloc, /* tp_dealloc */
|
(destructor)dictiter_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)dictiter_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
0, /* tp_repr */
|
0, /* tp_repr */
|
||||||
|
@ -1913,7 +1890,7 @@ PyTypeObject PyDictIter_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
@ -1924,4 +1901,11 @@ PyTypeObject PyDictIter_Type = {
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)dictiter_getiter, /* tp_iter */
|
(getiterfunc)dictiter_getiter, /* tp_iter */
|
||||||
(iternextfunc)dictiter_iternext, /* tp_iternext */
|
(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 *
|
static PyObject *
|
||||||
file_getattr(PyFileObject *f, char *name)
|
get_closed(PyFileObject *f, void *closure)
|
||||||
{
|
{
|
||||||
PyObject *res;
|
return PyInt_FromLong((long)(f->f_fp == 0));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct getsetlist file_getsetlist[] = {
|
||||||
file_setattr(PyFileObject *f, char *name, PyObject *v)
|
{"closed", (getter)get_closed, NULL, NULL},
|
||||||
{
|
{0},
|
||||||
if (v == NULL) {
|
};
|
||||||
PyErr_SetString(PyExc_AttributeError,
|
|
||||||
"can't delete file attributes");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return PyMember_Set((char *)f, file_memberlist, name, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
file_getiter(PyObject *f)
|
file_getiter(PyObject *f)
|
||||||
|
@ -1311,27 +1297,32 @@ PyTypeObject PyFile_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)file_dealloc, /* tp_dealloc */
|
(destructor)file_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)file_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
(setattrfunc)file_setattr, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
(reprfunc)file_repr, /* tp_repr */
|
(reprfunc)file_repr, /* tp_repr */
|
||||||
0, /* tp_as_number */
|
0, /* tp_as_number */
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
file_getiter, /* tp_iter */
|
file_getiter, /* tp_iter */
|
||||||
0, /* tp_iternext */
|
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. */
|
/* 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 = {
|
static PyNumberMethods float_as_number = {
|
||||||
(binaryfunc)float_add, /*nb_add*/
|
(binaryfunc)float_add, /*nb_add*/
|
||||||
(binaryfunc)float_sub, /*nb_subtract*/
|
(binaryfunc)float_sub, /*nb_subtract*/
|
||||||
|
@ -679,22 +699,40 @@ PyTypeObject PyFloat_Type = {
|
||||||
"float",
|
"float",
|
||||||
sizeof(PyFloatObject),
|
sizeof(PyFloatObject),
|
||||||
0,
|
0,
|
||||||
(destructor)float_dealloc, /*tp_dealloc*/
|
(destructor)float_dealloc, /* tp_dealloc */
|
||||||
(printfunc)float_print, /*tp_print*/
|
(printfunc)float_print, /* tp_print */
|
||||||
0, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
(cmpfunc)float_compare, /*tp_compare*/
|
(cmpfunc)float_compare, /* tp_compare */
|
||||||
(reprfunc)float_repr, /*tp_repr*/
|
(reprfunc)float_repr, /* tp_repr */
|
||||||
&float_as_number, /*tp_as_number*/
|
&float_as_number, /* tp_as_number */
|
||||||
0, /*tp_as_sequence*/
|
0, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)float_hash, /*tp_hash*/
|
(hashfunc)float_hash, /* tp_hash */
|
||||||
0, /*tp_call*/
|
0, /* tp_call */
|
||||||
(reprfunc)float_str, /*tp_str*/
|
(reprfunc)float_str, /* tp_str */
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /*tp_setattro*/
|
0, /* tp_setattro */
|
||||||
0, /*tp_as_buffer*/
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
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
|
void
|
||||||
|
|
|
@ -15,7 +15,6 @@ static struct memberlist frame_memberlist[] = {
|
||||||
{"f_code", T_OBJECT, OFF(f_code), RO},
|
{"f_code", T_OBJECT, OFF(f_code), RO},
|
||||||
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},
|
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},
|
||||||
{"f_globals", T_OBJECT, OFF(f_globals), 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_lasti", T_INT, OFF(f_lasti), RO},
|
||||||
{"f_lineno", T_INT, OFF(f_lineno), RO},
|
{"f_lineno", T_INT, OFF(f_lineno), RO},
|
||||||
{"f_restricted",T_INT, OFF(f_restricted),RO},
|
{"f_restricted",T_INT, OFF(f_restricted),RO},
|
||||||
|
@ -27,18 +26,17 @@ static struct memberlist frame_memberlist[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
frame_getattr(PyFrameObject *f, char *name)
|
frame_getlocals(PyFrameObject *f, void *closure)
|
||||||
{
|
{
|
||||||
if (strcmp(name, "f_locals") == 0)
|
PyFrame_FastToLocals(f);
|
||||||
PyFrame_FastToLocals(f);
|
Py_INCREF(f->f_locals);
|
||||||
return PyMember_Get((char *)f, frame_memberlist, name);
|
return f->f_locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct getsetlist frame_getsetlist[] = {
|
||||||
frame_setattr(PyFrameObject *f, char *name, PyObject *value)
|
{"f_locals", (getter)frame_getlocals, NULL, NULL},
|
||||||
{
|
{0}
|
||||||
return PyMember_Set((char *)f, frame_memberlist, name, value);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/* Stack frames are allocated and deallocated at a considerable rate.
|
/* Stack frames are allocated and deallocated at a considerable rate.
|
||||||
In an attempt to improve the speed of function calls, we maintain a
|
In an attempt to improve the speed of function calls, we maintain a
|
||||||
|
@ -177,8 +175,8 @@ PyTypeObject PyFrame_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)frame_dealloc, /* tp_dealloc */
|
(destructor)frame_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)frame_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
(setattrfunc)frame_setattr, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
0, /* tp_repr */
|
0, /* tp_repr */
|
||||||
0, /* tp_as_number */
|
0, /* tp_as_number */
|
||||||
|
@ -187,13 +185,22 @@ PyTypeObject PyFrame_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
PyObject_GenericSetAttr, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
(traverseproc)frame_traverse, /* tp_traverse */
|
(traverseproc)frame_traverse, /* tp_traverse */
|
||||||
(inquiry)frame_clear, /* tp_clear */
|
(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 *
|
PyFrameObject *
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
|
#include "eval.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -141,9 +142,8 @@ static struct memberlist func_memberlist[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
func_getattro(PyFunctionObject *op, PyObject *name)
|
func_getattro(PyObject *op, PyObject *name)
|
||||||
{
|
{
|
||||||
PyObject *rtn;
|
|
||||||
char *sname = PyString_AsString(name);
|
char *sname = PyString_AsString(name);
|
||||||
|
|
||||||
if (sname[0] != '_' && PyEval_GetRestricted()) {
|
if (sname[0] != '_' && PyEval_GetRestricted()) {
|
||||||
|
@ -152,25 +152,12 @@ func_getattro(PyFunctionObject *op, PyObject *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no API for PyMember_HasAttr() */
|
return PyObject_GenericGetAttr(op, name);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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);
|
char *sname = PyString_AsString(name);
|
||||||
|
|
||||||
if (PyEval_GetRestricted()) {
|
if (PyEval_GetRestricted()) {
|
||||||
|
@ -216,31 +203,7 @@ func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
|
return PyObject_GenericSetAttr(op, name, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -314,31 +277,324 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
|
||||||
return 0;
|
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 = {
|
PyTypeObject PyFunction_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0,
|
||||||
"function",
|
"function",
|
||||||
sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
|
sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
|
||||||
0,
|
0,
|
||||||
(destructor)func_dealloc, /* tp_dealloc */
|
(destructor)func_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
0, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
(reprfunc)func_repr, /* tp_repr */
|
(reprfunc)func_repr, /* tp_repr */
|
||||||
0, /* tp_as_number */
|
0, /* tp_as_number */
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
function_call, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
(getattrofunc)func_getattro, /* tp_getattro */
|
func_getattro, /* tp_getattro */
|
||||||
(setattrofunc)func_setattro, /* tp_setattro */
|
func_setattro, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
(traverseproc)func_traverse, /* tp_traverse */
|
(traverseproc)func_traverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
|
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);
|
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 = {
|
static PyNumberMethods int_as_number = {
|
||||||
(binaryfunc)int_add, /*nb_add*/
|
(binaryfunc)int_add, /*nb_add*/
|
||||||
(binaryfunc)int_sub, /*nb_subtract*/
|
(binaryfunc)int_sub, /*nb_subtract*/
|
||||||
|
@ -785,22 +820,40 @@ PyTypeObject PyInt_Type = {
|
||||||
"int",
|
"int",
|
||||||
sizeof(PyIntObject),
|
sizeof(PyIntObject),
|
||||||
0,
|
0,
|
||||||
(destructor)int_dealloc, /*tp_dealloc*/
|
(destructor)int_dealloc, /* tp_dealloc */
|
||||||
(printfunc)int_print, /*tp_print*/
|
(printfunc)int_print, /* tp_print */
|
||||||
0, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
(cmpfunc)int_compare, /*tp_compare*/
|
(cmpfunc)int_compare, /* tp_compare */
|
||||||
(reprfunc)int_repr, /*tp_repr*/
|
(reprfunc)int_repr, /* tp_repr */
|
||||||
&int_as_number, /*tp_as_number*/
|
&int_as_number, /* tp_as_number */
|
||||||
0, /*tp_as_sequence*/
|
0, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)int_hash, /*tp_hash*/
|
(hashfunc)int_hash, /* tp_hash */
|
||||||
0, /*tp_call*/
|
0, /* tp_call */
|
||||||
0, /*tp_str*/
|
0, /* tp_str */
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /*tp_setattro*/
|
0, /* tp_setattro */
|
||||||
0, /*tp_as_buffer*/
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
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
|
void
|
||||||
|
|
|
@ -96,12 +96,6 @@ static PyMethodDef iter_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
iter_getattr(seqiterobject *it, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(iter_methods, (PyObject *)it, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject PySeqIter_Type = {
|
PyTypeObject PySeqIter_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
|
@ -111,7 +105,7 @@ PyTypeObject PySeqIter_Type = {
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)iter_dealloc, /* tp_dealloc */
|
(destructor)iter_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)iter_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
0, /* tp_repr */
|
0, /* tp_repr */
|
||||||
|
@ -121,7 +115,7 @@ PyTypeObject PySeqIter_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
|
@ -132,6 +126,13 @@ PyTypeObject PySeqIter_Type = {
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)iter_getiter, /* tp_iter */
|
(getiterfunc)iter_getiter, /* tp_iter */
|
||||||
(iternextfunc)iter_iternext, /* tp_iternext */
|
(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 */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
calliter_getattr(calliterobject *it, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(calliter_methods, (PyObject *)it, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
calliter_iternext(calliterobject *it)
|
calliter_iternext(calliterobject *it)
|
||||||
{
|
{
|
||||||
|
@ -228,7 +223,7 @@ PyTypeObject PyCallIter_Type = {
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)calliter_dealloc, /* tp_dealloc */
|
(destructor)calliter_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)calliter_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
0, /* tp_repr */
|
0, /* tp_repr */
|
||||||
|
@ -238,7 +233,7 @@ PyTypeObject PyCallIter_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
|
@ -249,4 +244,11 @@ PyTypeObject PyCallIter_Type = {
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)iter_getiter, /* tp_iter */
|
(getiterfunc)iter_getiter, /* tp_iter */
|
||||||
(iternextfunc)calliter_iternext, /* tp_iternext */
|
(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);
|
Py_XDECREF(*p);
|
||||||
PyMem_DEL(recycle);
|
PyMem_DEL(recycle);
|
||||||
}
|
}
|
||||||
|
if (a->ob_size == 0 && a->ob_item != NULL) {
|
||||||
|
PyMem_FREE(a->ob_item);
|
||||||
|
a->ob_item = NULL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#undef b
|
#undef b
|
||||||
}
|
}
|
||||||
|
@ -1289,16 +1293,18 @@ listsort(PyListObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
PyObject *compare = NULL;
|
PyObject *compare = NULL;
|
||||||
|
PyTypeObject *savetype;
|
||||||
|
|
||||||
if (args != NULL) {
|
if (args != NULL) {
|
||||||
if (!PyArg_ParseTuple(args, "|O:sort", &compare))
|
if (!PyArg_ParseTuple(args, "|O:sort", &compare))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
savetype = self->ob_type;
|
||||||
self->ob_type = &immutable_list_type;
|
self->ob_type = &immutable_list_type;
|
||||||
err = samplesortslice(self->ob_item,
|
err = samplesortslice(self->ob_item,
|
||||||
self->ob_item + self->ob_size,
|
self->ob_item + self->ob_size,
|
||||||
compare);
|
compare);
|
||||||
self->ob_type = &PyList_Type;
|
self->ob_type = savetype;
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(Py_None);
|
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);
|
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[] =
|
static char append_doc[] =
|
||||||
"L.append(object) -- append object to end";
|
"L.append(object) -- append object to end";
|
||||||
static char extend_doc[] =
|
static char extend_doc[] =
|
||||||
|
@ -1573,12 +1673,6 @@ static PyMethodDef list_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
list_getattr(PyListObject *f, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(list_methods, (PyObject *)f, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PySequenceMethods list_as_sequence = {
|
static PySequenceMethods list_as_sequence = {
|
||||||
(inquiry)list_length, /* sq_length */
|
(inquiry)list_length, /* sq_length */
|
||||||
(binaryfunc)list_concat, /* sq_concat */
|
(binaryfunc)list_concat, /* sq_concat */
|
||||||
|
@ -1592,6 +1686,10 @@ static PySequenceMethods list_as_sequence = {
|
||||||
(intargfunc)list_inplace_repeat, /* sq_inplace_repeat */
|
(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 = {
|
PyTypeObject PyList_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0,
|
||||||
|
@ -1600,7 +1698,7 @@ PyTypeObject PyList_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)list_dealloc, /* tp_dealloc */
|
(destructor)list_dealloc, /* tp_dealloc */
|
||||||
(printfunc)list_print, /* tp_print */
|
(printfunc)list_print, /* tp_print */
|
||||||
(getattrfunc)list_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
(reprfunc)list_repr, /* tp_repr */
|
(reprfunc)list_repr, /* tp_repr */
|
||||||
|
@ -1610,14 +1708,29 @@ PyTypeObject PyList_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
|
||||||
0, /* tp_doc */
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
list_doc, /* tp_doc */
|
||||||
(traverseproc)list_traverse, /* tp_traverse */
|
(traverseproc)list_traverse, /* tp_traverse */
|
||||||
(inquiry)list_clear, /* tp_clear */
|
(inquiry)list_clear, /* tp_clear */
|
||||||
list_richcompare, /* tp_richcompare */
|
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 */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
immutable_list_getattr(PyListObject *f, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(immutable_list_methods, (PyObject *)f, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
immutable_list_ass(void)
|
immutable_list_ass(void)
|
||||||
{
|
{
|
||||||
|
@ -1678,7 +1785,7 @@ static PyTypeObject immutable_list_type = {
|
||||||
0,
|
0,
|
||||||
0, /* Cannot happen */ /* tp_dealloc */
|
0, /* Cannot happen */ /* tp_dealloc */
|
||||||
(printfunc)list_print, /* tp_print */
|
(printfunc)list_print, /* tp_print */
|
||||||
(getattrfunc)immutable_list_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* Won't be called */ /* tp_compare */
|
0, /* Won't be called */ /* tp_compare */
|
||||||
(reprfunc)list_repr, /* tp_repr */
|
(reprfunc)list_repr, /* tp_repr */
|
||||||
|
@ -1688,13 +1795,24 @@ static PyTypeObject immutable_list_type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
list_doc, /* tp_doc */
|
||||||
(traverseproc)list_traverse, /* tp_traverse */
|
(traverseproc)list_traverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
list_richcompare, /* tp_richcompare */
|
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! */
|
/* NOTE: This is *not* the standard list_type struct! */
|
||||||
};
|
};
|
||||||
|
|
|
@ -2031,6 +2031,43 @@ long_hex(PyObject *v)
|
||||||
return long_format(v, 16, 1);
|
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 = {
|
static PyNumberMethods long_as_number = {
|
||||||
(binaryfunc) long_add, /*nb_add*/
|
(binaryfunc) long_add, /*nb_add*/
|
||||||
(binaryfunc) long_sub, /*nb_subtract*/
|
(binaryfunc) long_sub, /*nb_subtract*/
|
||||||
|
@ -2070,24 +2107,42 @@ static PyNumberMethods long_as_number = {
|
||||||
|
|
||||||
PyTypeObject PyLong_Type = {
|
PyTypeObject PyLong_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0, /* ob_size */
|
||||||
"long int",
|
"long", /* tp_name */
|
||||||
sizeof(PyLongObject) - sizeof(digit),
|
sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */
|
||||||
sizeof(digit),
|
sizeof(digit), /* tp_itemsize */
|
||||||
(destructor)long_dealloc, /*tp_dealloc*/
|
(destructor)long_dealloc, /* tp_dealloc */
|
||||||
0, /*tp_print*/
|
0, /* tp_print */
|
||||||
0, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
(cmpfunc)long_compare, /*tp_compare*/
|
(cmpfunc)long_compare, /* tp_compare */
|
||||||
(reprfunc)long_repr, /*tp_repr*/
|
(reprfunc)long_repr, /* tp_repr */
|
||||||
&long_as_number, /*tp_as_number*/
|
&long_as_number, /* tp_as_number */
|
||||||
0, /*tp_as_sequence*/
|
0, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)long_hash, /*tp_hash*/
|
(hashfunc)long_hash, /* tp_hash */
|
||||||
0, /*tp_call*/
|
0, /* tp_call */
|
||||||
(reprfunc)long_str, /*tp_str*/
|
(reprfunc)long_str, /* tp_str */
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /*tp_setattro*/
|
0, /* tp_setattro */
|
||||||
0, /*tp_as_buffer*/
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
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 "Python.h"
|
||||||
|
|
||||||
#include "token.h"
|
|
||||||
|
|
||||||
static PyCFunctionObject *free_list = NULL;
|
static PyCFunctionObject *free_list = NULL;
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -69,6 +67,23 @@ meth_dealloc(PyCFunctionObject *m)
|
||||||
free_list = 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
|
static int
|
||||||
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -79,39 +94,28 @@ meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
meth_getattr(PyCFunctionObject *m, char *name)
|
meth_get__self__(PyCFunctionObject *m, void *closure)
|
||||||
{
|
{
|
||||||
if (strcmp(name, "__name__") == 0) {
|
PyObject *self;
|
||||||
return PyString_FromString(m->m_ml->ml_name);
|
if (PyEval_GetRestricted()) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"method.__self__ not accessible in restricted mode");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strcmp(name, "__doc__") == 0) {
|
self = m->m_self;
|
||||||
char *doc = m->m_ml->ml_doc;
|
if (self == NULL)
|
||||||
if (doc != NULL)
|
self = Py_None;
|
||||||
return PyString_FromString(doc);
|
Py_INCREF(self);
|
||||||
Py_INCREF(Py_None);
|
return self;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 *
|
static PyObject *
|
||||||
meth_repr(PyCFunctionObject *m)
|
meth_repr(PyCFunctionObject *m)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +163,41 @@ meth_hash(PyCFunctionObject *a)
|
||||||
return x;
|
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 = {
|
PyTypeObject PyCFunction_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0,
|
||||||
|
@ -167,7 +206,7 @@ PyTypeObject PyCFunction_Type = {
|
||||||
0,
|
0,
|
||||||
(destructor)meth_dealloc, /* tp_dealloc */
|
(destructor)meth_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)meth_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
(cmpfunc)meth_compare, /* tp_compare */
|
(cmpfunc)meth_compare, /* tp_compare */
|
||||||
(reprfunc)meth_repr, /* tp_repr */
|
(reprfunc)meth_repr, /* tp_repr */
|
||||||
|
@ -175,14 +214,24 @@ PyTypeObject PyCFunction_Type = {
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)meth_hash, /* tp_hash */
|
(hashfunc)meth_hash, /* tp_hash */
|
||||||
0, /* tp_call */
|
meth_call, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
(traverseproc)meth_traverse, /* tp_traverse */
|
(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 */
|
/* List all methods in a chain -- helper for findmethodinchain */
|
||||||
|
|
|
@ -2,12 +2,18 @@
|
||||||
/* Module object implementation */
|
/* Module object implementation */
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "structmember.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *md_dict;
|
PyObject *md_dict;
|
||||||
} PyModuleObject;
|
} PyModuleObject;
|
||||||
|
|
||||||
|
struct memberlist module_members[] = {
|
||||||
|
{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyModule_New(char *name)
|
PyModule_New(char *name)
|
||||||
{
|
{
|
||||||
|
@ -128,6 +134,15 @@ _PyModule_Clear(PyObject *m)
|
||||||
|
|
||||||
/* Methods */
|
/* 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
|
static void
|
||||||
module_dealloc(PyModuleObject *m)
|
module_dealloc(PyModuleObject *m)
|
||||||
{
|
{
|
||||||
|
@ -161,59 +176,6 @@ module_repr(PyModuleObject *m)
|
||||||
return PyString_FromString(buf);
|
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
|
/* 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
|
is in a cycle, md_dict will be cleared as well, which will break
|
||||||
the cycle. */
|
the cycle. */
|
||||||
|
@ -229,24 +191,41 @@ PyTypeObject PyModule_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
"module", /* tp_name */
|
"module", /* tp_name */
|
||||||
sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
|
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /* tp_size */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */
|
||||||
(destructor)module_dealloc, /* tp_dealloc */
|
(destructor)module_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
0, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
(reprfunc)module_repr, /* tp_repr */
|
(reprfunc)module_repr, /* tp_repr */
|
||||||
0, /* tp_as_number */
|
0, /* tp_as_number */
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
(getattrofunc)module_getattro, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
(setattrofunc)module_setattro, /* tp_setattro */
|
PyObject_GenericSetAttr, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
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 */
|
0, /* tp_doc */
|
||||||
(traverseproc)module_traverse, /* tp_traverse */
|
(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)
|
for (tp = type_list; tp; tp = tp->tp_next)
|
||||||
fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n",
|
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);
|
tp->tp_maxalloc);
|
||||||
fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
|
fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
|
||||||
fast_tuple_allocs, tuple_zero_allocs);
|
fast_tuple_allocs, tuple_zero_allocs);
|
||||||
|
@ -53,8 +53,8 @@ get_counts(void)
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (tp = type_list; tp; tp = tp->tp_next) {
|
for (tp = type_list; tp; tp = tp->tp_next) {
|
||||||
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_alloc,
|
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_allocs,
|
||||||
tp->tp_free, tp->tp_maxalloc);
|
tp->tp_frees, tp->tp_maxalloc);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -72,16 +72,16 @@ get_counts(void)
|
||||||
void
|
void
|
||||||
inc_count(PyTypeObject *tp)
|
inc_count(PyTypeObject *tp)
|
||||||
{
|
{
|
||||||
if (tp->tp_alloc == 0) {
|
if (tp->tp_allocs == 0) {
|
||||||
/* first time; insert in linked list */
|
/* first time; insert in linked list */
|
||||||
if (tp->tp_next != NULL) /* sanity check */
|
if (tp->tp_next != NULL) /* sanity check */
|
||||||
Py_FatalError("XXX inc_count sanity check");
|
Py_FatalError("XXX inc_count sanity check");
|
||||||
tp->tp_next = type_list;
|
tp->tp_next = type_list;
|
||||||
type_list = tp;
|
type_list = tp;
|
||||||
}
|
}
|
||||||
tp->tp_alloc++;
|
tp->tp_allocs++;
|
||||||
if (tp->tp_alloc - tp->tp_free > tp->tp_maxalloc)
|
if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc)
|
||||||
tp->tp_maxalloc = tp->tp_alloc - tp->tp_free;
|
tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -93,10 +93,8 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
|
||||||
"NULL object passed to PyObject_Init");
|
"NULL object passed to PyObject_Init");
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
#ifdef WITH_CYCLE_GC
|
|
||||||
if (PyType_IS_GC(tp))
|
if (PyType_IS_GC(tp))
|
||||||
op = (PyObject *) PyObject_FROM_GC(op);
|
op = (PyObject *) PyObject_FROM_GC(op);
|
||||||
#endif
|
|
||||||
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
|
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
|
||||||
op->ob_type = tp;
|
op->ob_type = tp;
|
||||||
_Py_NewReference(op);
|
_Py_NewReference(op);
|
||||||
|
@ -111,10 +109,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, int size)
|
||||||
"NULL object passed to PyObject_InitVar");
|
"NULL object passed to PyObject_InitVar");
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
#ifdef WITH_CYCLE_GC
|
|
||||||
if (PyType_IS_GC(tp))
|
if (PyType_IS_GC(tp))
|
||||||
op = (PyVarObject *) PyObject_FROM_GC(op);
|
op = (PyVarObject *) PyObject_FROM_GC(op);
|
||||||
#endif
|
|
||||||
/* Any changes should be reflected in PyObject_INIT_VAR */
|
/* Any changes should be reflected in PyObject_INIT_VAR */
|
||||||
op->ob_size = size;
|
op->ob_size = size;
|
||||||
op->ob_type = tp;
|
op->ob_type = tp;
|
||||||
|
@ -129,10 +125,8 @@ _PyObject_New(PyTypeObject *tp)
|
||||||
op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
|
op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
#ifdef WITH_CYCLE_GC
|
|
||||||
if (PyType_IS_GC(tp))
|
if (PyType_IS_GC(tp))
|
||||||
op = (PyObject *) PyObject_FROM_GC(op);
|
op = (PyObject *) PyObject_FROM_GC(op);
|
||||||
#endif
|
|
||||||
return PyObject_INIT(op, tp);
|
return PyObject_INIT(op, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,21 +137,17 @@ _PyObject_NewVar(PyTypeObject *tp, int size)
|
||||||
op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
|
op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return (PyVarObject *)PyErr_NoMemory();
|
return (PyVarObject *)PyErr_NoMemory();
|
||||||
#ifdef WITH_CYCLE_GC
|
|
||||||
if (PyType_IS_GC(tp))
|
if (PyType_IS_GC(tp))
|
||||||
op = (PyVarObject *) PyObject_FROM_GC(op);
|
op = (PyVarObject *) PyObject_FROM_GC(op);
|
||||||
#endif
|
|
||||||
return PyObject_INIT_VAR(op, tp, size);
|
return PyObject_INIT_VAR(op, tp, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyObject_Del(PyObject *op)
|
_PyObject_Del(PyObject *op)
|
||||||
{
|
{
|
||||||
#ifdef WITH_CYCLE_GC
|
|
||||||
if (op && PyType_IS_GC(op->ob_type)) {
|
if (op && PyType_IS_GC(op->ob_type)) {
|
||||||
op = (PyObject *) PyObject_AS_GC(op);
|
op = (PyObject *) PyObject_AS_GC(op);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyObject_FREE(op);
|
PyObject_FREE(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,26 +984,16 @@ PyObject_Hash(PyObject *v)
|
||||||
PyObject *
|
PyObject *
|
||||||
PyObject_GetAttrString(PyObject *v, char *name)
|
PyObject_GetAttrString(PyObject *v, char *name)
|
||||||
{
|
{
|
||||||
if (v->ob_type->tp_getattro != NULL) {
|
PyObject *w, *res;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v->ob_type->tp_getattr == NULL) {
|
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 {
|
|
||||||
return (*v->ob_type->tp_getattr)(v, name);
|
return (*v->ob_type->tp_getattr)(v, name);
|
||||||
}
|
w = PyString_InternFromString(name);
|
||||||
|
if (w == NULL)
|
||||||
|
return NULL;
|
||||||
|
res = PyObject_GetAttr(v, w);
|
||||||
|
Py_XDECREF(w);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1031,34 +1011,24 @@ PyObject_HasAttrString(PyObject *v, char *name)
|
||||||
int
|
int
|
||||||
PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
|
PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
|
||||||
{
|
{
|
||||||
if (v->ob_type->tp_setattro != NULL) {
|
PyObject *s;
|
||||||
PyObject *s;
|
int res;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v->ob_type->tp_setattr == NULL) {
|
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 {
|
|
||||||
return (*v->ob_type->tp_setattr)(v, name, w);
|
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 *
|
||||||
PyObject_GetAttr(PyObject *v, PyObject *name)
|
PyObject_GetAttr(PyObject *v, PyObject *name)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = v->ob_type;
|
||||||
|
|
||||||
/* The Unicode to string conversion is done here because the
|
/* The Unicode to string conversion is done here because the
|
||||||
existing tp_getattro slots expect a string object as name
|
existing tp_getattro slots expect a string object as name
|
||||||
and we wouldn't want to break those. */
|
and we wouldn't want to break those. */
|
||||||
|
@ -1067,16 +1037,19 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyString_Check(name)) {
|
if (!PyString_Check(name)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"attribute name must be string");
|
"attribute name must be string");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (v->ob_type->tp_getattro != NULL)
|
if (tp->tp_getattro != NULL)
|
||||||
return (*v->ob_type->tp_getattro)(v, name);
|
return (*tp->tp_getattro)(v, name);
|
||||||
else
|
if (tp->tp_getattr != NULL)
|
||||||
return PyObject_GetAttrString(v, PyString_AS_STRING(name));
|
return (*tp->tp_getattr)(v, PyString_AS_STRING(name));
|
||||||
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
"'%.50s' object has no attribute '%.400s'",
|
||||||
|
tp->tp_name, PyString_AS_STRING(name));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1094,6 +1067,7 @@ PyObject_HasAttr(PyObject *v, PyObject *name)
|
||||||
int
|
int
|
||||||
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
|
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = v->ob_type;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* The Unicode to string conversion is done here because the
|
/* 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)
|
if (name == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else if (!PyString_Check(name)){
|
||||||
Py_INCREF(name);
|
|
||||||
|
|
||||||
if (!PyString_Check(name)){
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"attribute name must be string");
|
"attribute name must be string");
|
||||||
err = -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
PyString_InternInPlace(&name);
|
Py_INCREF(name);
|
||||||
if (v->ob_type->tp_setattro != NULL)
|
|
||||||
err = (*v->ob_type->tp_setattro)(v, name, value);
|
PyString_InternInPlace(&name);
|
||||||
else
|
if (tp->tp_setattro != NULL) {
|
||||||
err = PyObject_SetAttrString(v,
|
err = (*tp->tp_setattro)(v, name, value);
|
||||||
PyString_AS_STRING(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);
|
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.
|
/* 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)
|
if (x == NULL)
|
||||||
return 0;
|
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)) {
|
if (PyInstance_Check(x)) {
|
||||||
PyObject *call = PyObject_GetAttrString(x, "__call__");
|
PyObject *call = PyObject_GetAttrString(x, "__call__");
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
|
@ -1235,7 +1360,9 @@ PyCallable_Check(PyObject *x)
|
||||||
Py_DECREF(call);
|
Py_DECREF(call);
|
||||||
return 1;
|
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_prev->_ob_next = op->_ob_next;
|
||||||
op->_ob_next = op->_ob_prev = NULL;
|
op->_ob_next = op->_ob_prev = NULL;
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
op->ob_type->tp_free++;
|
op->ob_type->tp_frees++;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,22 +310,34 @@ PyTypeObject PyRange_Type = {
|
||||||
"xrange", /* Name of this type */
|
"xrange", /* Name of this type */
|
||||||
sizeof(rangeobject), /* Basic object size */
|
sizeof(rangeobject), /* Basic object size */
|
||||||
0, /* Item size for varobject */
|
0, /* Item size for varobject */
|
||||||
(destructor)range_dealloc, /*tp_dealloc*/
|
(destructor)range_dealloc, /*tp_dealloc*/
|
||||||
0, /*tp_print*/
|
0, /*tp_print*/
|
||||||
(getattrfunc)range_getattr, /*tp_getattr*/
|
(getattrfunc)range_getattr, /*tp_getattr*/
|
||||||
0, /*tp_setattr*/
|
0, /*tp_setattr*/
|
||||||
(cmpfunc)range_compare, /*tp_compare*/
|
(cmpfunc)range_compare, /*tp_compare*/
|
||||||
(reprfunc)range_repr, /*tp_repr*/
|
(reprfunc)range_repr, /*tp_repr*/
|
||||||
0, /*tp_as_number*/
|
0, /*tp_as_number*/
|
||||||
&range_as_sequence, /*tp_as_sequence*/
|
&range_as_sequence, /*tp_as_sequence*/
|
||||||
0, /*tp_as_mapping*/
|
0, /*tp_as_mapping*/
|
||||||
0, /*tp_hash*/
|
0, /*tp_hash*/
|
||||||
0, /*tp_call*/
|
0, /*tp_call*/
|
||||||
0, /*tp_str*/
|
0, /*tp_str*/
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /*tp_getattro*/
|
||||||
0, /*tp_setattro*/
|
0, /*tp_setattro*/
|
||||||
0, /*tp_as_buffer*/
|
0, /*tp_as_buffer*/
|
||||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
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
|
#undef WARN
|
||||||
|
|
|
@ -14,6 +14,7 @@ this type and there is exactly one in existence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "structmember.h"
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
ellipsis_repr(PyObject *op)
|
ellipsis_repr(PyObject *op)
|
||||||
|
@ -128,32 +129,12 @@ slice_repr(PySliceObject *r)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct memberlist slice_members[] = {
|
||||||
static PyObject *slice_getattr(PySliceObject *self, char *name)
|
{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
|
||||||
{
|
{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
|
||||||
PyObject *ret;
|
{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
|
||||||
|
{0}
|
||||||
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 int
|
static int
|
||||||
slice_compare(PySliceObject *v, PySliceObject *w)
|
slice_compare(PySliceObject *v, PySliceObject *w)
|
||||||
|
@ -182,13 +163,32 @@ PyTypeObject PySlice_Type = {
|
||||||
"slice", /* Name of this type */
|
"slice", /* Name of this type */
|
||||||
sizeof(PySliceObject), /* Basic object size */
|
sizeof(PySliceObject), /* Basic object size */
|
||||||
0, /* Item size for varobject */
|
0, /* Item size for varobject */
|
||||||
(destructor)slice_dealloc, /*tp_dealloc*/
|
(destructor)slice_dealloc, /* tp_dealloc */
|
||||||
0, /*tp_print*/
|
0, /* tp_print */
|
||||||
(getattrfunc)slice_getattr, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
(cmpfunc)slice_compare, /*tp_compare*/
|
(cmpfunc)slice_compare, /* tp_compare */
|
||||||
(reprfunc)slice_repr, /*tp_repr*/
|
(reprfunc)slice_repr, /* tp_repr */
|
||||||
0, /*tp_as_number*/
|
0, /* tp_as_number */
|
||||||
0, /*tp_as_sequence*/
|
0, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
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 *
|
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 = {
|
PyTypeObject PyString_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0,
|
0,
|
||||||
"string",
|
"str",
|
||||||
sizeof(PyStringObject),
|
sizeof(PyStringObject),
|
||||||
sizeof(char),
|
sizeof(char),
|
||||||
(destructor)string_dealloc, /*tp_dealloc*/
|
(destructor)string_dealloc, /* tp_dealloc */
|
||||||
(printfunc)string_print, /*tp_print*/
|
(printfunc)string_print, /* tp_print */
|
||||||
(getattrfunc)string_getattr, /*tp_getattr*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_setattr */
|
||||||
0, /*tp_compare*/
|
0, /* tp_compare */
|
||||||
(reprfunc)string_repr, /*tp_repr*/
|
(reprfunc)string_repr, /* tp_repr */
|
||||||
0, /*tp_as_number*/
|
0, /* tp_as_number */
|
||||||
&string_as_sequence, /*tp_as_sequence*/
|
&string_as_sequence, /* tp_as_sequence */
|
||||||
0, /*tp_as_mapping*/
|
0, /* tp_as_mapping */
|
||||||
(hashfunc)string_hash, /*tp_hash*/
|
(hashfunc)string_hash, /* tp_hash */
|
||||||
0, /*tp_call*/
|
0, /* tp_call */
|
||||||
(reprfunc)string_str, /*tp_str*/
|
(reprfunc)string_str, /* tp_str */
|
||||||
0, /*tp_getattro*/
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /*tp_setattro*/
|
0, /* tp_setattro */
|
||||||
&string_as_buffer, /*tp_as_buffer*/
|
&string_as_buffer, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
0, /*tp_doc*/
|
string_doc, /* tp_doc */
|
||||||
0, /*tp_traverse*/
|
0, /* tp_traverse */
|
||||||
0, /*tp_clear*/
|
0, /* tp_clear */
|
||||||
(richcmpfunc)string_richcompare, /*tp_richcompare*/
|
(richcmpfunc)string_richcompare, /* tp_richcompare */
|
||||||
0, /*tp_weaklistoffset*/
|
0, /* tp_weaklistoffset */
|
||||||
0, /*tp_iter*/
|
0, /* tp_iter */
|
||||||
0, /*tp_iternext*/
|
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
|
void
|
||||||
|
|
|
@ -480,6 +480,28 @@ tuplerichcompare(PyObject *v, PyObject *w, int op)
|
||||||
return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], 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 = {
|
static PySequenceMethods tuple_as_sequence = {
|
||||||
(inquiry)tuplelength, /* sq_length */
|
(inquiry)tuplelength, /* sq_length */
|
||||||
(binaryfunc)tupleconcat, /* sq_concat */
|
(binaryfunc)tupleconcat, /* sq_concat */
|
||||||
|
@ -509,14 +531,28 @@ PyTypeObject PyTuple_Type = {
|
||||||
(hashfunc)tuplehash, /* tp_hash */
|
(hashfunc)tuplehash, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
0, /* tp_doc */
|
tuple_doc, /* tp_doc */
|
||||||
(traverseproc)tupletraverse, /* tp_traverse */
|
(traverseproc)tupletraverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
tuplerichcompare, /* tp_richcompare */
|
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:
|
/* 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}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
unicode_getattr(PyUnicodeObject *self, char *name)
|
|
||||||
{
|
|
||||||
return Py_FindMethod(unicode_methods, (PyObject*) self, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PySequenceMethods unicode_as_sequence = {
|
static PySequenceMethods unicode_as_sequence = {
|
||||||
(inquiry) unicode_length, /* sq_length */
|
(inquiry) unicode_length, /* sq_length */
|
||||||
(binaryfunc) PyUnicode_Concat, /* sq_concat */
|
(binaryfunc) PyUnicode_Concat, /* sq_concat */
|
||||||
|
@ -5346,6 +5340,30 @@ static PyBufferProcs unicode_as_buffer = {
|
||||||
(getcharbufferproc) unicode_buffer_getcharbuf,
|
(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 = {
|
PyTypeObject PyUnicode_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
|
@ -5355,7 +5373,7 @@ PyTypeObject PyUnicode_Type = {
|
||||||
/* Slots */
|
/* Slots */
|
||||||
(destructor)_PyUnicode_Free, /* tp_dealloc */
|
(destructor)_PyUnicode_Free, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)unicode_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
(cmpfunc) unicode_compare, /* tp_compare */
|
(cmpfunc) unicode_compare, /* tp_compare */
|
||||||
(reprfunc) unicode_repr, /* tp_repr */
|
(reprfunc) unicode_repr, /* tp_repr */
|
||||||
|
@ -5365,10 +5383,28 @@ PyTypeObject PyUnicode_Type = {
|
||||||
(hashfunc) unicode_hash, /* tp_hash*/
|
(hashfunc) unicode_hash, /* tp_hash*/
|
||||||
0, /* tp_call*/
|
0, /* tp_call*/
|
||||||
(reprfunc) unicode_str, /* tp_str */
|
(reprfunc) unicode_str, /* tp_str */
|
||||||
(getattrofunc) NULL, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
(setattrofunc) NULL, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
&unicode_as_buffer, /* tp_as_buffer */
|
&unicode_as_buffer, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
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 */
|
/* Initialize the Unicode implementation */
|
||||||
|
|
|
@ -44,6 +44,7 @@ extern void init_locale(void);
|
||||||
extern void init_codecs(void);
|
extern void init_codecs(void);
|
||||||
extern void initxreadlines(void);
|
extern void initxreadlines(void);
|
||||||
extern void init_weakref(void);
|
extern void init_weakref(void);
|
||||||
|
extern void initxxsubtype(void);
|
||||||
|
|
||||||
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
|
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
|
||||||
/* -- ADDMODULE MARKER 1 -- */
|
/* -- ADDMODULE MARKER 1 -- */
|
||||||
|
@ -98,6 +99,8 @@ struct _inittab _PyImport_Inittab[] = {
|
||||||
{"xreadlines", initxreadlines},
|
{"xreadlines", initxreadlines},
|
||||||
{"_weakref", init_weakref},
|
{"_weakref", init_weakref},
|
||||||
|
|
||||||
|
{"xxsubtype", initxxsubtype},
|
||||||
|
|
||||||
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
|
/* XXX tim: what's the purpose of ADDMODULE MARKER? */
|
||||||
/* -- ADDMODULE MARKER 2 -- */
|
/* -- ADDMODULE MARKER 2 -- */
|
||||||
|
|
||||||
|
|
|
@ -495,6 +495,21 @@ SOURCE=..\Modules\cStringIO.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=..\Objects\dictobject.c
|
||||||
|
|
||||||
!IF "$(CFG)" == "pythoncore - Win32 Release"
|
!IF "$(CFG)" == "pythoncore - Win32 Release"
|
||||||
|
@ -1737,6 +1752,21 @@ SOURCE=..\Modules\xreadlinesmodule.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=..\Modules\yuvconvert.c
|
||||||
|
|
||||||
!IF "$(CFG)" == "pythoncore - Win32 Release"
|
!IF "$(CFG)" == "pythoncore - Win32 Release"
|
||||||
|
|
431
PLAN.txt
Normal file
431
PLAN.txt
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
Project: core implementation
|
||||||
|
****************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Do binary operators properly. nb_add should try to call self.__add__
|
||||||
|
and other.__radd__. I think I'll exclude base types that define any
|
||||||
|
binary operator without setting the CHECKTYPES flag.
|
||||||
|
|
||||||
|
Fix comparisons. There's some nasty stuff here: when two types are
|
||||||
|
not the same, and they're not instances, the fallback code doesn't
|
||||||
|
account for the possibility that they might be subtypes of a common
|
||||||
|
base type that defines a comparison.
|
||||||
|
|
||||||
|
Fix subtype_dealloc(). This currently searches through the list of
|
||||||
|
base types until it finds a type whose tp_dealloc is not
|
||||||
|
subtype_dealloc. I think this is not safe. I think the alloc/dealloc
|
||||||
|
policy needs to be rethought. *** There's an idea here that I haven't
|
||||||
|
worked out yet: just as object creation now has separate API's tp_new,
|
||||||
|
tp_alloc, and tp_init, destruction has tp_dealloc and tp_free. (Maybe
|
||||||
|
tp_fini should be added to correspond to tp_init?) Something
|
||||||
|
could/should be done with this. ***
|
||||||
|
|
||||||
|
Clean up isinstance(), issubclass() and their C equivalents. There
|
||||||
|
are a bunch of different APIs here and not all of them do the right
|
||||||
|
thing yet. There should be fewer APIs and their implementation should
|
||||||
|
be simpler. The old "abstract subclass" test should probably
|
||||||
|
disappear (if we want to root out ExtensionClass). *** I think I've
|
||||||
|
done 90% of this by creating PyType_IsSubtype() and using it
|
||||||
|
appropriately. For now, the old "abstract subclass" test is still
|
||||||
|
there, and there may be some places where PyObject_IsSubclass() is
|
||||||
|
called where PyType_IsSubtype() would be more appropriate. ***
|
||||||
|
|
||||||
|
Check for conflicts between base classes. I fear that the rules used
|
||||||
|
to decide whether multiple bases have conflicting instance variables
|
||||||
|
aren't strict enough. I think that sometimes two different classes
|
||||||
|
adding __dict__ may be incompatible after all.
|
||||||
|
|
||||||
|
Check for order conflicts. Suppose there are two base classes X and
|
||||||
|
Y. Suppose class B derives from X and Y, and class C from Y and X (in
|
||||||
|
that order). Now suppose class D derives from B and C. In which
|
||||||
|
order should the base classes X and Y be searched? This is an order
|
||||||
|
conflict, and should be disallowed; currently the test for this is not
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
Clean up the GC interface. Currently, tp_basicsize includes the GC
|
||||||
|
head size iff tp_flags includes the GC flag bit. This makes object
|
||||||
|
size math a pain (e.g. to see if two object types have the same
|
||||||
|
instance size, you can't just compare the tp_basicsize fields -- you
|
||||||
|
have to conditionally subtract the GC head size). Neil has a patch
|
||||||
|
that improves the API in this area, but it's backwards incompatible.
|
||||||
|
(http://sf.net/tracker/?func=detail&aid=421893&group_id=5470&atid=305470)
|
||||||
|
I think I know of a way to fix the incompatibility (by switching to a
|
||||||
|
different flag bit). *** Tim proposed a better idea: macros to access
|
||||||
|
tp_basicsize while hiding the nastiness. This is done now, so I think
|
||||||
|
the rest of this task needn't be done. ***
|
||||||
|
|
||||||
|
Make the __dict__ of types declared with Python class statements
|
||||||
|
writable -- only statically declared types must have an immutable
|
||||||
|
dict, because they're shared between interpreter instances. Possibly
|
||||||
|
trap writes to the __dict__ to update the corresponding tp_<slot> if
|
||||||
|
an __<slot>__ name is affected. *** Done as part of the next task. ***
|
||||||
|
|
||||||
|
It should be an option (maybe a different metaclass, maybe a flag) to
|
||||||
|
*not* merge __dict__ with all the bases, but instead search the
|
||||||
|
__dict__ (or __introduced__?) of all bases in __mro__ order. (This is
|
||||||
|
needed anyway to unify classes completely.) *** Partly done.
|
||||||
|
Inheritance of slots from bases is still icky: (1) MRO is not always
|
||||||
|
respected when inheriting slots; (2) dynamic classes can't add slot
|
||||||
|
implementations in Python after creation (e.g., setting C.__hash__
|
||||||
|
doesn't set the tp_hash slot). ***
|
||||||
|
|
||||||
|
Universal base class (object). How can we make the object class
|
||||||
|
subclassable and define simple default methods for everything without
|
||||||
|
having these inherited by built-in types that don't want these
|
||||||
|
defaults? *** Done, really. ***
|
||||||
|
|
||||||
|
Add error checking to the MRO calculation. *** Done. ***
|
||||||
|
|
||||||
|
Make __new__ overridable through a Python class method (!). Make more
|
||||||
|
of the sub-algorithms of type construction available as methods. ***
|
||||||
|
After I implemented class methods, I found that in order to be able
|
||||||
|
to make an upcall to Base.__new__() and have it create an instance of
|
||||||
|
your class (rather than a Base instance), you can't use class methods
|
||||||
|
-- you must use static methods. So I've implemented those too. I've
|
||||||
|
hooked up __new__ in the right places, so the first part of this is
|
||||||
|
now done. I've also exported the MRO calculation and made it
|
||||||
|
overridable, as metamethod mro(). I believe that closes this topic
|
||||||
|
for now. I expect that some warts will only be really debugged when
|
||||||
|
we try to use this for some, eh, interesting types such as tuples. ***
|
||||||
|
|
||||||
|
More -- I'm sure new issues will crop up as we go.
|
||||||
|
|
||||||
|
|
||||||
|
Project: loose ends and follow-through
|
||||||
|
**************************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Make more (most?) built-in types act as their own factory functions.
|
||||||
|
|
||||||
|
Make more (most?) built-in types subtypable -- with or without
|
||||||
|
overridable allocation. *** This includes descriptors! It should be
|
||||||
|
possible to write descriptors in Python, so metaclasses can do clever
|
||||||
|
things with them. ***
|
||||||
|
|
||||||
|
Exceptions should be types. This changes the rules, since now almost
|
||||||
|
anything can be raised (as maybe it should). Or should we strive for
|
||||||
|
enforcement of the convention that all exceptions should be derived
|
||||||
|
from Exception? String exceptions will be another hassle, to be
|
||||||
|
deprecated and eventually ruled out.
|
||||||
|
|
||||||
|
Standardize a module containing names for all built-in types, and
|
||||||
|
standardize on names. E.g. should the official name of the string
|
||||||
|
type be 'str', 'string', or 'StringType'?
|
||||||
|
|
||||||
|
Create a hierarchy of types, so that e.g. int and long are both
|
||||||
|
subtypes of an abstract base type integer, which is itself a subtype
|
||||||
|
of number, etc. A lot of thinking can go into this!
|
||||||
|
|
||||||
|
*** NEW TASK??? ***
|
||||||
|
Implement "signature" objects. These are alluded to in PEP 252 but
|
||||||
|
not yet specified. Supposedly they provide an easily usable API to
|
||||||
|
find out about function/method arguments. Building these for Python
|
||||||
|
functions is simple. Building these for built-in functions will
|
||||||
|
require a change to the PyMethodDef structure, so that a type can
|
||||||
|
provide signature information for its C methods. (This would also
|
||||||
|
help in supporting keyword arguments for C methods with less work than
|
||||||
|
PyArg_ParseTupleAndKeywords() currently requires.) But should we do
|
||||||
|
this? It's additional work and not required for any of the other
|
||||||
|
parts.
|
||||||
|
|
||||||
|
|
||||||
|
Project: making classes use the new machinery
|
||||||
|
*********************************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Try to get rid of all code in classobject.c by deferring to the new
|
||||||
|
mechanisms. How far can we get without breaking backwards
|
||||||
|
compatibility? This is underspecified because I haven't thought much
|
||||||
|
about it yet. Can we lose the use of PyInstance_Check() everywhere?
|
||||||
|
I would hope so!
|
||||||
|
|
||||||
|
|
||||||
|
Project: backwards compatibility
|
||||||
|
********************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Make sure all code checks the proper tp_flags bit before accessing
|
||||||
|
type object fields.
|
||||||
|
|
||||||
|
Identify areas of incompatibility with Python 2.1. Design solutions.
|
||||||
|
Implement and test.
|
||||||
|
|
||||||
|
Some specific areas: a fair amount of code probably depends on
|
||||||
|
specific types having __members__ and/or __methods__ attributes.
|
||||||
|
These are currently not present (conformant to PEP 252, which proposes
|
||||||
|
to drop them) but we may have to add them back. This can be done in a
|
||||||
|
generic way with not too much effort. Tim adds: Perhaps that dir(object)
|
||||||
|
rarely returns anything but [] now is a consequence of this. I'm very
|
||||||
|
used to doing, e.g., dir([]) or dir("") in an interactive shell to jog my
|
||||||
|
memory; also one of the reasons test_generators failed.
|
||||||
|
|
||||||
|
Another area: going all the way with classes and instances means that
|
||||||
|
type(x) == types.InstanceType won't work any more to detect instances.
|
||||||
|
Should there be a mode where this still works? Maybe this should be
|
||||||
|
the default mode, with a warning, and an explicit way to get the new
|
||||||
|
way to work? (Instead of a __future__ statement, I'm thinking of a
|
||||||
|
module global __metaclass__ which would provide the default metaclass
|
||||||
|
for baseless class statements.)
|
||||||
|
|
||||||
|
|
||||||
|
Project: testing
|
||||||
|
****************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Identify new functionality that needs testing. Conceive unit tests
|
||||||
|
for all new functionality. Conceive stress tests for critical
|
||||||
|
features. Run the tests. Fix bugs. Repeat until satisfied.
|
||||||
|
|
||||||
|
Note: this may interact with the branch integration task.
|
||||||
|
|
||||||
|
|
||||||
|
Project: integration with main branch
|
||||||
|
*************************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Merge changes in the HEAD branch into the descr-branch. Then merge
|
||||||
|
the descr-branch back into the HEAD branch.
|
||||||
|
|
||||||
|
The longer we wait, the more effort this will be -- the descr-branch
|
||||||
|
forked off quite a long time ago, and there are changes everywhere in
|
||||||
|
the HEAD branch (e.g. the dict object has been radically rewritten).
|
||||||
|
|
||||||
|
On the other hand, if we do this too early, we'll have to do it again
|
||||||
|
later.
|
||||||
|
|
||||||
|
Note from Tim: We should never again wait until literally 100s of files
|
||||||
|
are out of synch. I don't care how often I need to do this, provided only
|
||||||
|
that it's a tractable task each time. Once per week sounds like a good
|
||||||
|
idea. As is, even the trunk change to rangeobject.c created more than its
|
||||||
|
proper share of merge headaches, because it confused all the other reasons
|
||||||
|
include file merges were getting conflicts (the more changes there are, the
|
||||||
|
worse diff does; indeed, I came up with the ndiff algorithm in the 80s
|
||||||
|
precisely because the source-control diff program Cray used at the time
|
||||||
|
produced minimal but *senseless* diffs, thus creating artificial conflicts;
|
||||||
|
paying unbounded attention to context does a much better job of putting
|
||||||
|
changes where they make semantic sense too; but we're stuck with Unix diff
|
||||||
|
here, and it isn't robust in this sense; if we don't keep its job simple,
|
||||||
|
it will make my job hell).
|
||||||
|
|
||||||
|
Done:
|
||||||
|
To undo or rename before final merge: Modules/spam.c has worked its
|
||||||
|
way into the branch Unix and Windows builds (pythoncore.dsp and
|
||||||
|
PC/config.c); also imported by test_descr.py. How about renaming to
|
||||||
|
xxsubtype.c (whatever) now?
|
||||||
|
|
||||||
|
|
||||||
|
Project: performance tuning
|
||||||
|
***************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Pick or create a general performance benchmark for Python. Benchmark
|
||||||
|
the new system vs. the old system. Profile the new system. Improve
|
||||||
|
hotspots. Repeat until satisfied.
|
||||||
|
|
||||||
|
Note: this may interact with the branch integration task.
|
||||||
|
|
||||||
|
|
||||||
|
Project: documentation
|
||||||
|
**********************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Update PEP 252 (descriptors). Describe more of the prototype
|
||||||
|
implementation
|
||||||
|
|
||||||
|
Update PEP 253 (subtyping). Complicated architectural wrangling with
|
||||||
|
metaclasses. There is an interaction between implementation and
|
||||||
|
description.
|
||||||
|
|
||||||
|
Write PEP 254 (unification of classes). This should discuss what
|
||||||
|
changes for ordinary classes, and how we can make it more b/w
|
||||||
|
compatible.
|
||||||
|
|
||||||
|
Other documentation. There needs to be user documentation,
|
||||||
|
eventually.
|
||||||
|
|
||||||
|
|
||||||
|
Project: community interaction
|
||||||
|
******************************
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
Once the PEPs are written, solicit community feedback, and formulate
|
||||||
|
responses to the feedback. Give the community enough time to think
|
||||||
|
over this complicated proposal. Provide the community with a
|
||||||
|
prototype implementation to test. Try to do this *before* casting
|
||||||
|
everything in stone!
|
||||||
|
|
||||||
|
MERGE BEGIN ****************************************************************
|
||||||
|
Merge details (this section is Tim's scratchpad, but should help a lot if
|
||||||
|
he dies of frustration while wrestling with CVS <0.9 wink>).
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-08-01 Merging descr-branch back into trunk.
|
||||||
|
|
||||||
|
Tagged trunk about 22:05:
|
||||||
|
cvs tag date2001-08-01 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch:
|
||||||
|
cvs -q -z3 up -j date2001-07-30 -j date2001-08-01 descr
|
||||||
|
|
||||||
|
No conflicts (! first time ever!) ... but problems with pythoncore.dsp.
|
||||||
|
Resolved.
|
||||||
|
|
||||||
|
Rebuilt from scratch; ran all tests; checked into branch about 22:40.
|
||||||
|
|
||||||
|
Merged descr-branch back into trunk:
|
||||||
|
cvs -q -z3 up -j descr-branch python
|
||||||
|
|
||||||
|
34 conflicts. Hmm! OK, looks like every file in the project with an
|
||||||
|
embedded RCS Id is "a conflict". Others make no sense, e.g., a dozen
|
||||||
|
conflicts in dictobject.c, sometimes enclosing identical(!) blobs of
|
||||||
|
source code. And CVS remains utterly baffled by Python type object decls.
|
||||||
|
Every line of ceval.c's generator code si in conflict blocks ... OK,
|
||||||
|
there's no pattern or sense here, I'll just deal with it.
|
||||||
|
|
||||||
|
Conflicts resolved; rebuilt from scratch; test_weakref fails.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-30
|
||||||
|
|
||||||
|
Doing this again while the expat and Windows installer changes are still
|
||||||
|
fresh on my mind.
|
||||||
|
|
||||||
|
Tagged trunk about 23:50 EDT on the 29th:
|
||||||
|
cvs tag date2001-07-30 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch:
|
||||||
|
|
||||||
|
cvs -q -z3 up -j date2001-07-28 -j date2001-07-30 descr
|
||||||
|
|
||||||
|
2 conflicts, resolved.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-28
|
||||||
|
|
||||||
|
Tagged trunk about 00:31 EDT:
|
||||||
|
cvs tag date2001-07-28 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch:
|
||||||
|
cvs -q -z3 up -j date2001-07-21 -j date2001-07-28 descr
|
||||||
|
|
||||||
|
4 conflicts, all RCS Ids. Resolved.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-21
|
||||||
|
|
||||||
|
Tagged trunk about 01:00 EDT:
|
||||||
|
cvs tag date2001-07-21 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch:
|
||||||
|
cvs -q -z3 up -j date2001-07-17b -j date2001-07-21 descr
|
||||||
|
|
||||||
|
4 conflicts, mostly RCS Id thingies. Resolved.
|
||||||
|
|
||||||
|
Legit failure in new test_repr, because repr.py dispatches on the exact
|
||||||
|
string returned by type(x). type(1L) and type('s') differ in descr-branch
|
||||||
|
now, and repr.py didn't realize that, falling back to the "unknown type"
|
||||||
|
case for longs and strings. Repaired descr-branch repr.py.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-19
|
||||||
|
|
||||||
|
Removed the r22a1-branch tag (see next entry). Turns out Guido did add a
|
||||||
|
r22a1 tag, so the r22a1-branch tag served no point anymore.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-18 2.2a1 releaase
|
||||||
|
|
||||||
|
Immediately after the merge just below, I tagged descr-branch via
|
||||||
|
|
||||||
|
cvs tag r22a1-branch descr
|
||||||
|
|
||||||
|
Guido may or may not want to add another tag here (? maybe he wants to do
|
||||||
|
some more Unix fiddling first).
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-17 building 2.2a1 release, from descr-branch
|
||||||
|
|
||||||
|
Tagged trunk about 22:00 EDT, like so:
|
||||||
|
cvs tag date2001-07-17b python
|
||||||
|
|
||||||
|
Merged trunk delta into branch via:
|
||||||
|
cvs -q -z3 up -j date2001-07-17a -j date2001-07-17b descr
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-17
|
||||||
|
|
||||||
|
Tagged trunk about 00:05 EDT, like so:
|
||||||
|
cvs tag date2001-07-17a python
|
||||||
|
|
||||||
|
Merged trunk delta into branch via:
|
||||||
|
cvs -q -z3 up -j date2001-07-16 -j date2001-07-17a descr
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-16
|
||||||
|
|
||||||
|
Tagged trunk about 15:20 EDT, like so:
|
||||||
|
cvs tag date2001-07-16 python
|
||||||
|
|
||||||
|
Guido then added all the other dist/ directories to descr-branch from that
|
||||||
|
trunk tag.
|
||||||
|
|
||||||
|
Tim then merged trunk delta into the branch via:
|
||||||
|
cvs -q -z3 up -j date2001-07-15 -j date2001-07-16 descr
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-15
|
||||||
|
|
||||||
|
Tagged trunk about 15:44 EDT, like so:
|
||||||
|
cvs tag date2001-07-15 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch via:
|
||||||
|
cvs -q -z3 up -j date2001-07-13 -j date2001-07-15 descr
|
||||||
|
|
||||||
|
Four files with conflicts, all artificial RCS Id & Revision thingies.
|
||||||
|
Resolved and committed.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-13
|
||||||
|
|
||||||
|
Tagged trunk about 22:13 EDT, like so:
|
||||||
|
cvs tag date2001-07-13 python
|
||||||
|
|
||||||
|
Merged trunk delta into branch via:
|
||||||
|
cvs -q -z3 up -j date2001-07-06 -j date2001-07-13 descr
|
||||||
|
|
||||||
|
Six(!) files with conflicts, mostly related to NeilS's generator gc patches.
|
||||||
|
Unsure why, but CVS seems always to think there are conflicts whenever a
|
||||||
|
line in a type object decl gets changed, and the conflict marking seems
|
||||||
|
maximally confused in these cases. Anyway, since I reviewed those patches
|
||||||
|
on the trunk, good thing I'm merging them, and darned glad it's still fresh
|
||||||
|
on my mind.
|
||||||
|
|
||||||
|
Resolved the conflicts, and committed the changes in a few hours total.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-07
|
||||||
|
|
||||||
|
Merge of trunk tag date2001-07-06 into descr-branch, via
|
||||||
|
cvs -q -z3 up -j date2001-07-06 mergedescr
|
||||||
|
was committed on 2001-07-07.
|
||||||
|
|
||||||
|
Merge issues:
|
||||||
|
|
||||||
|
(all resolved -- GvR)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
2001-07-06
|
||||||
|
|
||||||
|
Tagged trunk a bit after midnight, like so:
|
||||||
|
|
||||||
|
C:\Code>cvs tag date2001-07-06 python
|
||||||
|
cvs server: Tagging python
|
||||||
|
cvs server: Tagging python/dist
|
||||||
|
cvs server: Tagging python/dist/src
|
||||||
|
T python/dist/src/.cvsignore
|
||||||
|
T python/dist/src/LICENSE
|
||||||
|
T python/dist/src/Makefile.pre.in
|
||||||
|
T python/dist/src/README
|
||||||
|
... [& about 3000 lines more] ...
|
||||||
|
|
||||||
|
This is the first trunk snapshot to be merged into the descr-branch.
|
||||||
|
Gave it a date instead of a goofy name because there's going to be more
|
||||||
|
than one of these, and at least it's obvious which of two ISO dates comes
|
||||||
|
earlier. These tags should go away after all merging is complete.
|
||||||
|
MERGE END ******************************************************************
|
|
@ -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).";
|
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 *
|
static PyObject *
|
||||||
builtin_callable(PyObject *self, PyObject *args)
|
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.";
|
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 *
|
static PyObject *
|
||||||
builtin_dir(PyObject *self, PyObject *args)
|
builtin_dir(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -1060,8 +789,8 @@ builtin_map(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
if (curlen < 0)
|
if (curlen < 0)
|
||||||
curlen = 8; /* arbitrary */
|
curlen = 8; /* arbitrary */
|
||||||
if (curlen > len)
|
if (curlen > len)
|
||||||
len = curlen;
|
len = curlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get space for the result list. */
|
/* 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.";
|
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 *
|
static PyObject *
|
||||||
builtin_iter(PyObject *self, PyObject *args)
|
builtin_iter(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -1431,22 +1075,6 @@ static char len_doc[] =
|
||||||
Return the number of items of a sequence or mapping.";
|
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 *
|
static PyObject *
|
||||||
builtin_slice(PyObject *self, PyObject *args)
|
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.";
|
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 *
|
static PyObject *
|
||||||
builtin_vars(PyObject *self, PyObject *args)
|
builtin_vars(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -2255,16 +1831,12 @@ static PyMethodDef builtin_methods[] = {
|
||||||
{"cmp", builtin_cmp, 1, cmp_doc},
|
{"cmp", builtin_cmp, 1, cmp_doc},
|
||||||
{"coerce", builtin_coerce, 1, coerce_doc},
|
{"coerce", builtin_coerce, 1, coerce_doc},
|
||||||
{"compile", builtin_compile, 1, compile_doc},
|
{"compile", builtin_compile, 1, compile_doc},
|
||||||
#ifndef WITHOUT_COMPLEX
|
|
||||||
{"complex", builtin_complex, 1, complex_doc},
|
|
||||||
#endif
|
|
||||||
{"delattr", builtin_delattr, 1, delattr_doc},
|
{"delattr", builtin_delattr, 1, delattr_doc},
|
||||||
{"dir", builtin_dir, 1, dir_doc},
|
{"dir", builtin_dir, 1, dir_doc},
|
||||||
{"divmod", builtin_divmod, 1, divmod_doc},
|
{"divmod", builtin_divmod, 1, divmod_doc},
|
||||||
{"eval", builtin_eval, 1, eval_doc},
|
{"eval", builtin_eval, 1, eval_doc},
|
||||||
{"execfile", builtin_execfile, 1, execfile_doc},
|
{"execfile", builtin_execfile, 1, execfile_doc},
|
||||||
{"filter", builtin_filter, 1, filter_doc},
|
{"filter", builtin_filter, 1, filter_doc},
|
||||||
{"float", builtin_float, 1, float_doc},
|
|
||||||
{"getattr", builtin_getattr, 1, getattr_doc},
|
{"getattr", builtin_getattr, 1, getattr_doc},
|
||||||
{"globals", builtin_globals, 1, globals_doc},
|
{"globals", builtin_globals, 1, globals_doc},
|
||||||
{"hasattr", builtin_hasattr, 1, hasattr_doc},
|
{"hasattr", builtin_hasattr, 1, hasattr_doc},
|
||||||
|
@ -2273,14 +1845,11 @@ static PyMethodDef builtin_methods[] = {
|
||||||
{"id", builtin_id, 1, id_doc},
|
{"id", builtin_id, 1, id_doc},
|
||||||
{"input", builtin_input, 1, input_doc},
|
{"input", builtin_input, 1, input_doc},
|
||||||
{"intern", builtin_intern, 1, intern_doc},
|
{"intern", builtin_intern, 1, intern_doc},
|
||||||
{"int", builtin_int, 1, int_doc},
|
|
||||||
{"isinstance", builtin_isinstance, 1, isinstance_doc},
|
{"isinstance", builtin_isinstance, 1, isinstance_doc},
|
||||||
{"issubclass", builtin_issubclass, 1, issubclass_doc},
|
{"issubclass", builtin_issubclass, 1, issubclass_doc},
|
||||||
{"iter", builtin_iter, 1, iter_doc},
|
{"iter", builtin_iter, 1, iter_doc},
|
||||||
{"len", builtin_len, 1, len_doc},
|
{"len", builtin_len, 1, len_doc},
|
||||||
{"list", builtin_list, 1, list_doc},
|
|
||||||
{"locals", builtin_locals, 1, locals_doc},
|
{"locals", builtin_locals, 1, locals_doc},
|
||||||
{"long", builtin_long, 1, long_doc},
|
|
||||||
{"map", builtin_map, 1, map_doc},
|
{"map", builtin_map, 1, map_doc},
|
||||||
{"max", builtin_max, 1, max_doc},
|
{"max", builtin_max, 1, max_doc},
|
||||||
{"min", builtin_min, 1, min_doc},
|
{"min", builtin_min, 1, min_doc},
|
||||||
|
@ -2296,10 +1865,6 @@ static PyMethodDef builtin_methods[] = {
|
||||||
{"round", builtin_round, 1, round_doc},
|
{"round", builtin_round, 1, round_doc},
|
||||||
{"setattr", builtin_setattr, 1, setattr_doc},
|
{"setattr", builtin_setattr, 1, setattr_doc},
|
||||||
{"slice", builtin_slice, 1, slice_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},
|
{"unichr", builtin_unichr, 1, unichr_doc},
|
||||||
{"vars", builtin_vars, 1, vars_doc},
|
{"vars", builtin_vars, 1, vars_doc},
|
||||||
{"xrange", builtin_xrange, 1, xrange_doc},
|
{"xrange", builtin_xrange, 1, xrange_doc},
|
||||||
|
@ -2329,6 +1894,42 @@ _PyBuiltin_Init(void)
|
||||||
if (PyDict_SetItemString(dict, "NotImplemented",
|
if (PyDict_SetItemString(dict, "NotImplemented",
|
||||||
Py_NotImplemented) < 0)
|
Py_NotImplemented) < 0)
|
||||||
return NULL;
|
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);
|
debug = PyInt_FromLong(Py_OptimizeFlag == 0);
|
||||||
if (PyDict_SetItemString(dict, "__debug__", debug) < 0) {
|
if (PyDict_SetItemString(dict, "__debug__", debug) < 0) {
|
||||||
Py_XDECREF(debug);
|
Py_XDECREF(debug);
|
||||||
|
|
163
Python/ceval.c
163
Python/ceval.c
|
@ -13,6 +13,7 @@
|
||||||
#include "frameobject.h"
|
#include "frameobject.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
|
#include "structmember.h"
|
||||||
|
|
||||||
#ifdef macintosh
|
#ifdef macintosh
|
||||||
#include "macglue.h"
|
#include "macglue.h"
|
||||||
|
@ -32,17 +33,7 @@
|
||||||
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
|
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
||||||
static PyObject *eval_code2(PyCodeObject *,
|
|
||||||
PyObject *, PyObject *,
|
|
||||||
PyObject **, int,
|
|
||||||
PyObject **, int,
|
|
||||||
PyObject **, int,
|
|
||||||
PyObject *);
|
|
||||||
|
|
||||||
static PyObject *eval_frame(PyFrameObject *);
|
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_object(PyObject *, PyObject *, PyObject *);
|
||||||
static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
|
static PyObject *call_cfunction(PyObject *, PyObject *, PyObject *);
|
||||||
static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
|
static PyObject *call_instance(PyObject *, PyObject *, PyObject *);
|
||||||
|
@ -98,7 +89,6 @@ static long dxp[256];
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
staticforward PyTypeObject gentype;
|
staticforward PyTypeObject gentype;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -211,24 +201,11 @@ static struct PyMethodDef gen_methods[] = {
|
||||||
{NULL, NULL} /* Sentinel */
|
{NULL, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static struct memberlist gen_memberlist[] = {
|
||||||
gen_getattr(genobject *gen, char *name)
|
{"gi_frame", T_OBJECT, offsetof(genobject, gi_frame), RO},
|
||||||
{
|
{"gi_running", T_INT, offsetof(genobject, gi_running), RO},
|
||||||
PyObject *result;
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
statichere PyTypeObject gentype = {
|
statichere PyTypeObject gentype = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
@ -239,7 +216,7 @@ statichere PyTypeObject gentype = {
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)gen_dealloc, /* tp_dealloc */
|
(destructor)gen_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
(getattrfunc)gen_getattr, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
0, /* tp_compare */
|
0, /* tp_compare */
|
||||||
0, /* tp_repr */
|
0, /* tp_repr */
|
||||||
|
@ -249,7 +226,7 @@ statichere PyTypeObject gentype = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||||
|
@ -260,6 +237,11 @@ statichere PyTypeObject gentype = {
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)gen_getiter, /* tp_iter */
|
(getiterfunc)gen_getiter, /* tp_iter */
|
||||||
(iternextfunc)gen_iternext, /* tp_iternext */
|
(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 *
|
PyObject *
|
||||||
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
|
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
|
||||||
{
|
{
|
||||||
return eval_code2(co,
|
return PyEval_EvalCodeEx(co,
|
||||||
globals, locals,
|
globals, locals,
|
||||||
(PyObject **)NULL, 0,
|
(PyObject **)NULL, 0,
|
||||||
(PyObject **)NULL, 0,
|
(PyObject **)NULL, 0,
|
||||||
|
@ -516,7 +498,7 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
|
||||||
|
|
||||||
/* Interpreter main loop */
|
/* Interpreter main loop */
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
eval_frame(PyFrameObject *f)
|
eval_frame(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
#ifdef DXPAIRS
|
#ifdef DXPAIRS
|
||||||
|
@ -965,7 +947,7 @@ eval_frame(PyFrameObject *f)
|
||||||
case BINARY_SUBSCR:
|
case BINARY_SUBSCR:
|
||||||
w = POP();
|
w = POP();
|
||||||
v = POP();
|
v = POP();
|
||||||
if (PyList_Check(v) && PyInt_Check(w)) {
|
if (v->ob_type == &PyList_Type && PyInt_Check(w)) {
|
||||||
/* INLINE: list[int] */
|
/* INLINE: list[int] */
|
||||||
long i = PyInt_AsLong(w);
|
long i = PyInt_AsLong(w);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
|
@ -2273,8 +2255,8 @@ eval_frame(PyFrameObject *f)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
PyObject *
|
||||||
eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
PyObject **args, int argcount, PyObject **kws, int kwcount,
|
PyObject **args, int argcount, PyObject **kws, int kwcount,
|
||||||
PyObject **defs, int defcount, PyObject *closure)
|
PyObject **defs, int defcount, PyObject *closure)
|
||||||
{
|
{
|
||||||
|
@ -2973,13 +2955,13 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = call_object(func, arg, kw);
|
result = PyObject_Call(func, arg, kw);
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* How often is each kind of object called? The answer depends on the
|
/* 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:
|
regression test suite. The results were:
|
||||||
4200000 PyCFunctions
|
4200000 PyCFunctions
|
||||||
390000 fast_function() calls
|
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.
|
most common, but not by such a large margin.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *
|
char *
|
||||||
get_func_name(PyObject *func)
|
PyEval_GetFuncName(PyObject *func)
|
||||||
{
|
{
|
||||||
if (PyMethod_Check(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))
|
else if (PyFunction_Check(func))
|
||||||
return PyString_AsString(((PyFunctionObject*)func)->func_name);
|
return PyString_AsString(((PyFunctionObject*)func)->func_name);
|
||||||
else if (PyCFunction_Check(func))
|
else if (PyCFunction_Check(func))
|
||||||
|
@ -3011,8 +2993,8 @@ get_func_name(PyObject *func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
char *
|
||||||
get_func_desc(PyObject *func)
|
PyEval_GetFuncDesc(PyObject *func)
|
||||||
{
|
{
|
||||||
if (PyMethod_Check(func))
|
if (PyMethod_Check(func))
|
||||||
return "()";
|
return "()";
|
||||||
|
@ -3136,7 +3118,8 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"unbound method %s%s must be "
|
"unbound method %s%s must be "
|
||||||
"called with instance as first argument",
|
"called with instance as first argument",
|
||||||
get_func_name(func), get_func_desc(func));
|
PyEval_GetFuncName(func),
|
||||||
|
PyEval_GetFuncDesc(func));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_INCREF(arg);
|
Py_INCREF(arg);
|
||||||
|
@ -3199,7 +3182,7 @@ call_eval_code2(PyObject *func, PyObject *arg, PyObject *kw)
|
||||||
nk = 0;
|
nk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = eval_code2(
|
result = PyEval_EvalCodeEx(
|
||||||
(PyCodeObject *)PyFunction_GET_CODE(func),
|
(PyCodeObject *)PyFunction_GET_CODE(func),
|
||||||
PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
|
PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
|
||||||
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
|
&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);
|
d = &PyTuple_GET_ITEM(argdefs, 0);
|
||||||
nd = ((PyTupleObject *)argdefs)->ob_size;
|
nd = ((PyTupleObject *)argdefs)->ob_size;
|
||||||
}
|
}
|
||||||
return eval_code2((PyCodeObject *)co, globals,
|
return PyEval_EvalCodeEx((PyCodeObject *)co, globals,
|
||||||
(PyObject *)NULL, (*pp_stack)-n, na,
|
(PyObject *)NULL, (*pp_stack)-n, na,
|
||||||
(*pp_stack)-2*nk, nk, d, nd,
|
(*pp_stack)-2*nk, nk, d, nd,
|
||||||
closure);
|
closure);
|
||||||
|
@ -3282,8 +3265,8 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s%s got multiple values "
|
"%.200s%s got multiple values "
|
||||||
"for keyword argument '%.200s'",
|
"for keyword argument '%.200s'",
|
||||||
get_func_name(func),
|
PyEval_GetFuncName(func),
|
||||||
get_func_desc(func),
|
PyEval_GetFuncDesc(func),
|
||||||
PyString_AsString(key));
|
PyString_AsString(key));
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
|
@ -3356,7 +3339,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
|
||||||
callargs = load_args(pp_stack, na);
|
callargs = load_args(pp_stack, na);
|
||||||
if (callargs == NULL)
|
if (callargs == NULL)
|
||||||
goto call_fail;
|
goto call_fail;
|
||||||
result = call_object(func, callargs, kwdict);
|
result = PyObject_Call(func, callargs, kwdict);
|
||||||
call_fail:
|
call_fail:
|
||||||
Py_XDECREF(callargs);
|
Py_XDECREF(callargs);
|
||||||
Py_XDECREF(kwdict);
|
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,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%s%s argument after ** "
|
"%s%s argument after ** "
|
||||||
"must be a dictionary",
|
"must be a dictionary",
|
||||||
get_func_name(func),
|
PyEval_GetFuncName(func),
|
||||||
get_func_desc(func));
|
PyEval_GetFuncDesc(func));
|
||||||
goto ext_call_fail;
|
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,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%s%s argument after * "
|
"%s%s argument after * "
|
||||||
"must be a sequence",
|
"must be a sequence",
|
||||||
get_func_name(func),
|
PyEval_GetFuncName(func),
|
||||||
get_func_desc(func));
|
PyEval_GetFuncDesc(func));
|
||||||
}
|
}
|
||||||
goto ext_call_fail;
|
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);
|
callargs = update_star_args(na, nstar, stararg, pp_stack);
|
||||||
if (callargs == NULL)
|
if (callargs == NULL)
|
||||||
goto ext_call_fail;
|
goto ext_call_fail;
|
||||||
result = call_object(func, callargs, kwdict);
|
result = PyObject_Call(func, callargs, kwdict);
|
||||||
ext_call_fail:
|
ext_call_fail:
|
||||||
Py_XDECREF(callargs);
|
Py_XDECREF(callargs);
|
||||||
Py_XDECREF(kwdict);
|
Py_XDECREF(kwdict);
|
||||||
|
@ -3632,63 +3615,25 @@ import_all_from(PyObject *locals, PyObject *v)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
build_class(PyObject *methods, PyObject *bases, PyObject *name)
|
build_class(PyObject *methods, PyObject *bases, PyObject *name)
|
||||||
{
|
{
|
||||||
int i, n;
|
PyObject *metaclass = NULL;
|
||||||
if (!PyTuple_Check(bases)) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
if (PyDict_Check(methods))
|
||||||
"build_class with non-tuple bases");
|
metaclass = PyDict_GetItemString(methods, "__metaclass__");
|
||||||
return NULL;
|
|
||||||
}
|
if (metaclass == NULL) {
|
||||||
if (!PyDict_Check(methods)) {
|
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0)
|
||||||
PyErr_SetString(PyExc_SystemError,
|
metaclass = (PyObject *)
|
||||||
"build_class with non-dictionary");
|
PyTuple_GET_ITEM(bases, 0)->ob_type;
|
||||||
return NULL;
|
else {
|
||||||
}
|
PyObject *g = PyEval_GetGlobals();
|
||||||
if (!PyString_Check(name)) {
|
if (g != NULL && PyDict_Check(g))
|
||||||
PyErr_SetString(PyExc_SystemError,
|
metaclass = PyDict_GetItemString(
|
||||||
"build_class with non-string name");
|
g, "__metaclass__");
|
||||||
return NULL;
|
if (metaclass == NULL)
|
||||||
}
|
metaclass = (PyObject *) &PyClass_Type;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PyClass_New(bases, methods, name);
|
return PyObject_CallFunction(metaclass, "OOO", name, bases, methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -1056,23 +1056,36 @@ static struct {
|
||||||
|
|
||||||
|
|
||||||
DL_EXPORT(void)
|
DL_EXPORT(void)
|
||||||
init_exceptions(void)
|
_PyExc_Init(void)
|
||||||
{
|
{
|
||||||
char *modulename = "exceptions";
|
char *modulename = "exceptions";
|
||||||
int modnamesz = strlen(modulename);
|
int modnamesz = strlen(modulename);
|
||||||
int i;
|
int i;
|
||||||
|
PyObject *me, *mydict, *bltinmod, *bdict, *doc, *args;
|
||||||
|
|
||||||
PyObject *me = Py_InitModule(modulename, functions);
|
me = Py_InitModule(modulename, functions);
|
||||||
PyObject *mydict = PyModule_GetDict(me);
|
if (me == NULL)
|
||||||
PyObject *bltinmod = PyImport_ImportModule("__builtin__");
|
goto err;
|
||||||
PyObject *bdict = PyModule_GetDict(bltinmod);
|
mydict = PyModule_GetDict(me);
|
||||||
PyObject *doc = PyString_FromString(module__doc__);
|
if (mydict == NULL)
|
||||||
PyObject *args;
|
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);
|
Py_DECREF(doc);
|
||||||
if (PyErr_Occurred())
|
if (i < 0) {
|
||||||
|
err:
|
||||||
Py_FatalError("exceptions bootstrapping error.");
|
Py_FatalError("exceptions bootstrapping error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is the base class of all exceptions, so make it first. */
|
/* This is the base class of all exceptions, so make it first. */
|
||||||
if (make_Exception(modulename) ||
|
if (make_Exception(modulename) ||
|
||||||
|
@ -1139,7 +1152,7 @@ init_exceptions(void)
|
||||||
|
|
||||||
|
|
||||||
DL_EXPORT(void)
|
DL_EXPORT(void)
|
||||||
fini_exceptions(void)
|
_PyExc_Fini(void)
|
||||||
{
|
{
|
||||||
int i;
|
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
|
/* XXX Perhaps the magic number should be frozen and a version field
|
||||||
added to the .pyc file header? */
|
added to the .pyc file header? */
|
||||||
/* New way to come up with the magic number: (YEAR-1995), MONTH, DAY */
|
/* 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
|
/* Magic word as global; note that _PyImport_Init() can change the
|
||||||
value of this global to accommodate for alterations of how 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 */
|
/* Get the __import__ function from the builtins */
|
||||||
if (PyDict_Check(builtins))
|
if (PyDict_Check(builtins)) {
|
||||||
import = PyObject_GetItem(builtins, import_str);
|
import = PyObject_GetItem(builtins, import_str);
|
||||||
|
if (import == NULL)
|
||||||
|
PyErr_SetObject(PyExc_KeyError, import_str);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
import = PyObject_GetAttr(builtins, import_str);
|
import = PyObject_GetAttr(builtins, import_str);
|
||||||
if (import == NULL)
|
if (import == NULL)
|
||||||
|
|
|
@ -115,6 +115,9 @@ Py_Initialize(void)
|
||||||
Py_FatalError("Py_Initialize: can't make first thread");
|
Py_FatalError("Py_Initialize: can't make first thread");
|
||||||
(void) PyThreadState_Swap(tstate);
|
(void) PyThreadState_Swap(tstate);
|
||||||
|
|
||||||
|
if (PyType_InitDict(&PyType_Type) < 0)
|
||||||
|
Py_FatalError("Py_Initialize: can't initialize 'type'");
|
||||||
|
|
||||||
interp->modules = PyDict_New();
|
interp->modules = PyDict_New();
|
||||||
if (interp->modules == NULL)
|
if (interp->modules == NULL)
|
||||||
Py_FatalError("Py_Initialize: can't make modules dictionary");
|
Py_FatalError("Py_Initialize: can't make modules dictionary");
|
||||||
|
@ -144,7 +147,7 @@ Py_Initialize(void)
|
||||||
_PyImport_Init();
|
_PyImport_Init();
|
||||||
|
|
||||||
/* initialize builtin exceptions */
|
/* initialize builtin exceptions */
|
||||||
init_exceptions();
|
_PyExc_Init();
|
||||||
|
|
||||||
/* phase 2 of builtins */
|
/* phase 2 of builtins */
|
||||||
_PyImport_FixupExtension("__builtin__", "__builtin__");
|
_PyImport_FixupExtension("__builtin__", "__builtin__");
|
||||||
|
@ -238,7 +241,7 @@ Py_Finalize(void)
|
||||||
below has been checked to make sure no exceptions are ever
|
below has been checked to make sure no exceptions are ever
|
||||||
raised.
|
raised.
|
||||||
*/
|
*/
|
||||||
fini_exceptions();
|
_PyExc_Fini();
|
||||||
|
|
||||||
/* Delete current thread */
|
/* Delete current thread */
|
||||||
PyInterpreterState_Clear(interp);
|
PyInterpreterState_Clear(interp);
|
||||||
|
@ -1345,7 +1348,7 @@ _Py_AskYesNo(char *prompt)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
printf("%s [ny] ", prompt);
|
fprintf(stderr, "%s [ny] ", prompt);
|
||||||
if (fgets(buf, sizeof buf, stdin) == NULL)
|
if (fgets(buf, sizeof buf, stdin) == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return buf[0] == 'y' || buf[0] == 'Y';
|
return buf[0] == 'y' || buf[0] == 'Y';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue