]> granicus.if.org Git - python/commitdiff
Introduce two new flag bits that can be set in a PyMethodDef method
authorFred Drake <fdrake@acm.org>
Thu, 28 Mar 2002 05:33:33 +0000 (05:33 +0000)
committerFred Drake <fdrake@acm.org>
Thu, 28 Mar 2002 05:33:33 +0000 (05:33 +0000)
descriptor, as used for the tp_methods slot of a type.  These new flag
bits are both optional, and mutually exclusive.  Most methods will not
use either.  These flags are used to create special method types which
exist in the same namespace as normal methods without having to use
tedious construction code to insert the new special method objects in
the type's tp_dict after PyType_Ready() has been called.

If METH_CLASS is specified, the method will represent a class method
like that returned by the classmethod() built-in.

If METH_STATIC is specified, the method will represent a static method
like that returned by the staticmethod() built-in.

These flags may not be used in the PyMethodDef table for modules since
these special method types are not meaningful in that case; a
ValueError will be raised if these flags are found in that context.

Doc/api/newtypes.tex
Include/methodobject.h
Objects/methodobject.c
Objects/typeobject.c
Python/modsupport.c

index 8ab8e3cdce3c139440f10dcfcdbd702c80a60fc8..b4f90e57a0cce878d2d21ee113cec619126a5fe0 100644 (file)
@@ -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
index e47ebea76935b542b01141001b2120f7e5d5a0b8..21dcdda927ac1d53d2403312b91726de076d3792 100644 (file)
@@ -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 */
index 05474b5f54e3a5fce712ea2ec7ae0e001d7d643f..0cb4fd88955c819fc166b92a54d46f4f48869a04 100644 (file)
@@ -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) {
index c938f524536d527b63e17739ab62a0aa3f4dd95e..a5967210cbf0e5a8077ccc3daf6e3516569b8c3a 100644 (file)
@@ -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);
        }
index 0450a8a1c08481866d540b76d4e19d80900fbb7b..f29b27cd229de644bad841c10b2d78153aaa2899 100644 (file)
@@ -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;