summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2018-09-24 10:42:33 (GMT)
committerGitHub <noreply@github.com>2018-09-24 10:42:33 (GMT)
commit2d3ff2b5ea6c903973f99d2155c9c1b60591dceb (patch)
treeb31605483f70808db5c61d89782d3bf0ada20c48 /Doc
parent558c49bcf3a8543d64a68de836b5d855efd56696 (diff)
downloadcpython-2d3ff2b5ea6c903973f99d2155c9c1b60591dceb.zip
cpython-2d3ff2b5ea6c903973f99d2155c9c1b60591dceb.tar.gz
cpython-2d3ff2b5ea6c903973f99d2155c9c1b60591dceb.tar.bz2
bpo-24937: Replace the extension module porting HOWTO by links to external projects (GH-9317)
Diffstat (limited to 'Doc')
-rw-r--r--Doc/howto/cporting.rst267
-rw-r--r--Doc/includes/capsulethunk.h134
-rw-r--r--Doc/tools/susp-ignored.csv2
3 files changed, 18 insertions, 385 deletions
diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst
index 7cacb0a..b638e32 100644
--- a/Doc/howto/cporting.rst
+++ b/Doc/howto/cporting.rst
@@ -6,252 +6,21 @@
Porting Extension Modules to Python 3
*************************************
-:author: Benjamin Peterson
-
-
-.. topic:: Abstract
-
- Although changing the C-API was not one of Python 3's objectives,
- the many Python-level changes made leaving Python 2's API intact
- impossible. In fact, some changes such as :func:`int` and
- :func:`long` unification are more obvious on the C level. This
- document endeavors to document incompatibilities and how they can
- be worked around.
-
-
-Conditional compilation
-=======================
-
-The easiest way to compile only some code for Python 3 is to check
-if :c:macro:`PY_MAJOR_VERSION` is greater than or equal to 3. ::
-
- #if PY_MAJOR_VERSION >= 3
- #define IS_PY3K
- #endif
-
-API functions that are not present can be aliased to their equivalents within
-conditional blocks.
-
-
-Changes to Object APIs
-======================
-
-Python 3 merged together some types with similar functions while cleanly
-separating others.
-
-
-str/unicode Unification
------------------------
-
-Python 3's :func:`str` type is equivalent to Python 2's :func:`unicode`; the C
-functions are called ``PyUnicode_*`` for both. The old 8-bit string type has become
-:func:`bytes`, with C functions called ``PyBytes_*``. Python 2.6 and later provide a compatibility header,
-:file:`bytesobject.h`, mapping ``PyBytes`` names to ``PyString`` ones. For best
-compatibility with Python 3, :c:type:`PyUnicode` should be used for textual data and
-:c:type:`PyBytes` for binary data. It's also important to remember that
-:c:type:`PyBytes` and :c:type:`PyUnicode` in Python 3 are not interchangeable like
-:c:type:`PyString` and :c:type:`PyUnicode` are in Python 2. The following example
-shows best practices with regards to :c:type:`PyUnicode`, :c:type:`PyString`,
-and :c:type:`PyBytes`. ::
-
- #include "stdlib.h"
- #include "Python.h"
- #include "bytesobject.h"
-
- /* text example */
- static PyObject *
- say_hello(PyObject *self, PyObject *args) {
- PyObject *name, *result;
-
- if (!PyArg_ParseTuple(args, "U:say_hello", &name))
- return NULL;
-
- result = PyUnicode_FromFormat("Hello, %S!", name);
- return result;
- }
-
- /* just a forward */
- static char * do_encode(PyObject *);
-
- /* bytes example */
- static PyObject *
- encode_object(PyObject *self, PyObject *args) {
- char *encoded;
- PyObject *result, *myobj;
-
- if (!PyArg_ParseTuple(args, "O:encode_object", &myobj))
- return NULL;
-
- encoded = do_encode(myobj);
- if (encoded == NULL)
- return NULL;
- result = PyBytes_FromString(encoded);
- free(encoded);
- return result;
- }
-
-
-long/int Unification
---------------------
-
-Python 3 has only one integer type, :func:`int`. But it actually
-corresponds to Python 2's :func:`long` type—the :func:`int` type
-used in Python 2 was removed. In the C-API, ``PyInt_*`` functions
-are replaced by their ``PyLong_*`` equivalents.
-
-
-Module initialization and state
-===============================
-
-Python 3 has a revamped extension module initialization system. (See
-:pep:`3121`.) Instead of storing module state in globals, they should
-be stored in an interpreter specific structure. Creating modules that
-act correctly in both Python 2 and Python 3 is tricky. The following
-simple example demonstrates how. ::
-
- #include "Python.h"
-
- struct module_state {
- PyObject *error;
- };
-
- #if PY_MAJOR_VERSION >= 3
- #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
- #else
- #define GETSTATE(m) (&_state)
- static struct module_state _state;
- #endif
-
- static PyObject *
- error_out(PyObject *m) {
- struct module_state *st = GETSTATE(m);
- PyErr_SetString(st->error, "something bad happened");
- return NULL;
- }
-
- static PyMethodDef myextension_methods[] = {
- {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
- {NULL, NULL}
- };
-
- #if PY_MAJOR_VERSION >= 3
-
- static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {
- Py_VISIT(GETSTATE(m)->error);
- return 0;
- }
-
- static int myextension_clear(PyObject *m) {
- Py_CLEAR(GETSTATE(m)->error);
- return 0;
- }
-
-
- static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "myextension",
- NULL,
- sizeof(struct module_state),
- myextension_methods,
- NULL,
- myextension_traverse,
- myextension_clear,
- NULL
- };
-
- #define INITERROR return NULL
-
- PyMODINIT_FUNC
- PyInit_myextension(void)
-
- #else
- #define INITERROR return
-
- void
- initmyextension(void)
- #endif
- {
- #if PY_MAJOR_VERSION >= 3
- PyObject *module = PyModule_Create(&moduledef);
- #else
- PyObject *module = Py_InitModule("myextension", myextension_methods);
- #endif
-
- if (module == NULL)
- INITERROR;
- struct module_state *st = GETSTATE(module);
-
- st->error = PyErr_NewException("myextension.Error", NULL, NULL);
- if (st->error == NULL) {
- Py_DECREF(module);
- INITERROR;
- }
-
- #if PY_MAJOR_VERSION >= 3
- return module;
- #endif
- }
-
-
-CObject replaced with Capsule
-=============================
-
-The :c:type:`Capsule` object was introduced in Python 3.1 and 2.7 to replace
-:c:type:`CObject`. CObjects were useful,
-but the :c:type:`CObject` API was problematic: it didn't permit distinguishing
-between valid CObjects, which allowed mismatched CObjects to crash the
-interpreter, and some of its APIs relied on undefined behavior in C.
-(For further reading on the rationale behind Capsules, please see :issue:`5630`.)
-
-If you're currently using CObjects, and you want to migrate to 3.1 or newer,
-you'll need to switch to Capsules.
-:c:type:`CObject` was deprecated in 3.1 and 2.7 and completely removed in
-Python 3.2. If you only support 2.7, or 3.1 and above, you
-can simply switch to :c:type:`Capsule`. If you need to support Python 3.0,
-or versions of Python earlier than 2.7,
-you'll have to support both CObjects and Capsules.
-(Note that Python 3.0 is no longer supported, and it is not recommended
-for production use.)
-
-The following example header file :file:`capsulethunk.h` may
-solve the problem for you. Simply write your code against the
-:c:type:`Capsule` API and include this header file after
-:file:`Python.h`. Your code will automatically use Capsules
-in versions of Python with Capsules, and switch to CObjects
-when Capsules are unavailable.
-
-:file:`capsulethunk.h` simulates Capsules using CObjects. However,
-:c:type:`CObject` provides no place to store the capsule's "name". As a
-result the simulated :c:type:`Capsule` objects created by :file:`capsulethunk.h`
-behave slightly differently from real Capsules. Specifically:
-
- * The name parameter passed in to :c:func:`PyCapsule_New` is ignored.
-
- * The name parameter passed in to :c:func:`PyCapsule_IsValid` and
- :c:func:`PyCapsule_GetPointer` is ignored, and no error checking
- of the name is performed.
-
- * :c:func:`PyCapsule_GetName` always returns NULL.
-
- * :c:func:`PyCapsule_SetName` always raises an exception and
- returns failure. (Since there's no way to store a name
- in a CObject, noisy failure of :c:func:`PyCapsule_SetName`
- was deemed preferable to silent failure here. If this is
- inconvenient, feel free to modify your local
- copy as you see fit.)
-
-You can find :file:`capsulethunk.h` in the Python source distribution
-as :source:`Doc/includes/capsulethunk.h`. We also include it here for
-your convenience:
-
-.. literalinclude:: ../includes/capsulethunk.h
-
-
-
-Other options
-=============
-
-If you are writing a new extension module, you might consider `Cython
-<http://cython.org/>`_. It translates a Python-like language to C. The
-extension modules it creates are compatible with Python 3 and Python 2.
-
+We recommend the following resources for porting extension modules to Python 3:
+
+* The `Migrating C extensions`_ chapter from
+ *Supporting Python 3: An in-depth guide*, a book on moving from Python 2
+ to Python 3 in general, guides the reader through porting an extension
+ module.
+* The `Porting guide`_ from the *py3c* project provides opinionated
+ suggestions with supporting code.
+* The `Cython`_ and `CFFI`_ libraries offer abstractions over
+ Python's C API.
+ Extensions generally need to be re-written to use one of them,
+ but the library then handles differences between various Python
+ versions and implementations.
+
+.. _Migrating C extensions: http://python3porting.com/cextensions.html
+.. _Porting guide: https://py3c.readthedocs.io/en/latest/guide.html
+.. _Cython: http://cython.org/
+.. _CFFI: https://cffi.readthedocs.io/en/latest/
diff --git a/Doc/includes/capsulethunk.h b/Doc/includes/capsulethunk.h
deleted file mode 100644
index 6b20564..0000000
--- a/Doc/includes/capsulethunk.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef __CAPSULETHUNK_H
-#define __CAPSULETHUNK_H
-
-#if ( (PY_VERSION_HEX < 0x02070000) \
- || ((PY_VERSION_HEX >= 0x03000000) \
- && (PY_VERSION_HEX < 0x03010000)) )
-
-#define __PyCapsule_GetField(capsule, field, default_value) \
- ( PyCapsule_CheckExact(capsule) \
- ? (((PyCObject *)capsule)->field) \
- : (default_value) \
- ) \
-
-#define __PyCapsule_SetField(capsule, field, value) \
- ( PyCapsule_CheckExact(capsule) \
- ? (((PyCObject *)capsule)->field = value), 1 \
- : 0 \
- ) \
-
-
-#define PyCapsule_Type PyCObject_Type
-
-#define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
-#define PyCapsule_IsValid(capsule, name) (PyCObject_Check(capsule))
-
-
-#define PyCapsule_New(pointer, name, destructor) \
- (PyCObject_FromVoidPtr(pointer, destructor))
-
-
-#define PyCapsule_GetPointer(capsule, name) \
- (PyCObject_AsVoidPtr(capsule))
-
-/* Don't call PyCObject_SetPointer here, it fails if there's a destructor */
-#define PyCapsule_SetPointer(capsule, pointer) \
- __PyCapsule_SetField(capsule, cobject, pointer)
-
-
-#define PyCapsule_GetDestructor(capsule) \
- __PyCapsule_GetField(capsule, destructor)
-
-#define PyCapsule_SetDestructor(capsule, dtor) \
- __PyCapsule_SetField(capsule, destructor, dtor)
-
-
-/*
- * Sorry, there's simply no place
- * to store a Capsule "name" in a CObject.
- */
-#define PyCapsule_GetName(capsule) NULL
-
-static int
-PyCapsule_SetName(PyObject *capsule, const char *unused)
-{
- unused = unused;
- PyErr_SetString(PyExc_NotImplementedError,
- "can't use PyCapsule_SetName with CObjects");
- return 1;
-}
-
-
-
-#define PyCapsule_GetContext(capsule) \
- __PyCapsule_GetField(capsule, descr)
-
-#define PyCapsule_SetContext(capsule, context) \
- __PyCapsule_SetField(capsule, descr, context)
-
-
-static void *
-PyCapsule_Import(const char *name, int no_block)
-{
- PyObject *object = NULL;
- void *return_value = NULL;
- char *trace;
- size_t name_length = (strlen(name) + 1) * sizeof(char);
- char *name_dup = (char *)PyMem_MALLOC(name_length);
-
- if (!name_dup) {
- return NULL;
- }
-
- memcpy(name_dup, name, name_length);
-
- trace = name_dup;
- while (trace) {
- char *dot = strchr(trace, '.');
- if (dot) {
- *dot++ = '\0';
- }
-
- if (object == NULL) {
- if (no_block) {
- object = PyImport_ImportModuleNoBlock(trace);
- } else {
- object = PyImport_ImportModule(trace);
- if (!object) {
- PyErr_Format(PyExc_ImportError,
- "PyCapsule_Import could not "
- "import module \"%s\"", trace);
- }
- }
- } else {
- PyObject *object2 = PyObject_GetAttrString(object, trace);
- Py_DECREF(object);
- object = object2;
- }
- if (!object) {
- goto EXIT;
- }
-
- trace = dot;
- }
-
- if (PyCObject_Check(object)) {
- PyCObject *cobject = (PyCObject *)object;
- return_value = cobject->cobject;
- } else {
- PyErr_Format(PyExc_AttributeError,
- "PyCapsule_Import \"%s\" is not valid",
- name);
- }
-
-EXIT:
- Py_XDECREF(object);
- if (name_dup) {
- PyMem_FREE(name_dup);
- }
- return return_value;
-}
-
-#endif /* #if PY_VERSION_HEX < 0x02070000 */
-
-#endif /* __CAPSULETHUNK_H */
diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv
index 33cd48f..bb3310b 100644
--- a/Doc/tools/susp-ignored.csv
+++ b/Doc/tools/susp-ignored.csv
@@ -15,8 +15,6 @@ faq/programming,,::,for x in sequence[::-1]:
faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,"
faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,"
faq/windows,,:bd8afb90ebf2,"Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32"
-howto/cporting,,:encode,"if (!PyArg_ParseTuple(args, ""O:encode_object"", &myobj))"
-howto/cporting,,:say,"if (!PyArg_ParseTuple(args, ""U:say_hello"", &name))"
howto/curses,,:black,"colors when it activates color mode. They are: 0:black, 1:red,"
howto/curses,,:red,"colors when it activates color mode. They are: 0:black, 1:red,"
howto/curses,,:green,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The"