summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/api/newtypes.tex32
-rw-r--r--Include/methodobject.h8
-rw-r--r--Objects/methodobject.c2
-rw-r--r--Objects/typeobject.c31
-rw-r--r--Python/modsupport.c7
5 files changed, 74 insertions, 6 deletions
diff --git a/Doc/api/newtypes.tex b/Doc/api/newtypes.tex
index 8ab8e3c..b4f90e5 100644
--- a/Doc/api/newtypes.tex
+++ b/Doc/api/newtypes.tex
@@ -152,8 +152,12 @@ a cast in the method table. Even though \ctype{PyCFunction} defines
the first parameter as \ctype{PyObject*}, it is common that the method
implementation uses a the specific C type of the \var{self} object.
-The flags can have the following values. Only \constant{METH_VARARGS}
-and \constant{METH_KEYWORDS} can be combined; the others can't.
+The \member{ml_flags} field is a bitfield which can include the
+following flags. The individual flags indicate either a calling
+convention or a binding convention. Of the calling convention flags,
+only \constant{METH_VARARGS} and \constant{METH_KEYWORDS} can be
+combined. Any of the calling convention flags can be combined with a
+binding flag.
\begin{datadesc}{METH_VARARGS}
This is the typical calling convention, where the methods have the
@@ -203,6 +207,30 @@ and \constant{METH_KEYWORDS} can be combined; the others can't.
argument.
\end{datadesc}
+These two constants are not used to indicate the calling convention
+but the binding when use with methods of classes. These may not be
+used for functions defined for modules. At most one of these flags
+may be set for any given method.
+
+\begin{datadesc}{METH_CLASS}
+ The method will be passed the type object as the first parameter
+ rather than an instance of the type. This is used to create
+ \emph{class methods}, similar to what is created when using the
+ \function{classmethod()}\bifuncindex{classmethod} built-in
+ function.
+ \versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{METH_STATIC}
+ The method will be passed \NULL{} as the first parameter rather than
+ an instance of the type. This is used to create \emph{static
+ methods}, similar to what is created when using the
+ \function{staticmethod()}\bifuncindex{staticmethod} built-in
+ function.
+ \versionadded{2.3}
+\end{datadesc}
+
+
\begin{cfuncdesc}{PyObject*}{Py_FindMethod}{PyMethodDef table[],
PyObject *ob, char *name}
Return a bound method object for an extension type implemented in
diff --git a/Include/methodobject.h b/Include/methodobject.h
index e47ebea..21dcdda 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -46,10 +46,16 @@ extern DL_IMPORT(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *);
#define METH_OLDARGS 0x0000
#define METH_VARARGS 0x0001
#define METH_KEYWORDS 0x0002
-/* METH_NOARGS and METH_O must not be combined with any other flag. */
+/* METH_NOARGS and METH_O must not be combined with the flags above. */
#define METH_NOARGS 0x0004
#define METH_O 0x0008
+/* METH_CLASS and METH_STATIC are a little different; these control
+ the construction of methods for a class. These cannot be used for
+ functions in modules. */
+#define METH_CLASS 0x0010
+#define METH_STATIC 0x0020
+
typedef struct PyMethodChain {
PyMethodDef *methods; /* Methods of this type */
struct PyMethodChain *link; /* NULL or base type */
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 05474b5..0cb4fd8 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -62,7 +62,7 @@ PyCFunction_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);
+ int flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC);
int size = PyTuple_GET_SIZE(arg);
if (flags & METH_KEYWORDS) {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c938f52..a596721 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1694,6 +1694,20 @@ PyTypeObject PyBaseObject_Type = {
/* Initialize the __dict__ in a type object */
+static PyObject *
+create_specialmethod(PyMethodDef *meth, PyObject *(*func)(PyObject *))
+{
+ PyObject *cfunc;
+ PyObject *result;
+
+ cfunc = PyCFunction_New(meth, NULL);
+ if (cfunc == NULL)
+ return NULL;
+ result = func(cfunc);
+ Py_DECREF(cfunc);
+ return result;
+}
+
static int
add_methods(PyTypeObject *type, PyMethodDef *meth)
{
@@ -1703,10 +1717,23 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
PyObject *descr;
if (PyDict_GetItemString(dict, meth->ml_name))
continue;
- descr = PyDescr_NewMethod(type, meth);
+ if (meth->ml_flags & METH_CLASS) {
+ if (meth->ml_flags & METH_STATIC) {
+ PyErr_SetString(PyExc_ValueError,
+ "method cannot be both class and static");
+ return -1;
+ }
+ descr = create_specialmethod(meth, PyClassMethod_New);
+ }
+ else if (meth->ml_flags & METH_STATIC) {
+ descr = create_specialmethod(meth, PyStaticMethod_New);
+ }
+ else {
+ descr = PyDescr_NewMethod(type, meth);
+ }
if (descr == NULL)
return -1;
- if (PyDict_SetItemString(dict,meth->ml_name, descr) < 0)
+ if (PyDict_SetItemString(dict, meth->ml_name, descr) < 0)
return -1;
Py_DECREF(descr);
}
diff --git a/Python/modsupport.c b/Python/modsupport.c
index 0450a8a..f29b27c 100644
--- a/Python/modsupport.c
+++ b/Python/modsupport.c
@@ -57,6 +57,13 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
return NULL;
d = PyModule_GetDict(m);
for (ml = methods; ml->ml_name != NULL; ml++) {
+ if ((ml->ml_flags & METH_CLASS) ||
+ (ml->ml_flags & METH_STATIC)) {
+ PyErr_SetString(PyExc_ValueError,
+ "module functions cannot set"
+ " METH_CLASS or METH_STATIC");
+ return NULL;
+ }
v = PyCFunction_New(ml, passthrough);
if (v == NULL)
return NULL;