Commit 9acdd738 authored by Georg Brandl's avatar Georg Brandl

Introduce support for documenting which C API elements are not part of the stable/limited API.

parent 60194c1a
...@@ -13,6 +13,7 @@ document the API functions in detail. ...@@ -13,6 +13,7 @@ document the API functions in detail.
:maxdepth: 2 :maxdepth: 2
intro.rst intro.rst
stable.rst
veryhigh.rst veryhigh.rst
refcounting.rst refcounting.rst
exceptions.rst exceptions.rst
...@@ -22,5 +23,4 @@ document the API functions in detail. ...@@ -22,5 +23,4 @@ document the API functions in detail.
init.rst init.rst
memory.rst memory.rst
objimpl.rst objimpl.rst
stable.rst
apiabiversion.rst apiabiversion.rst
...@@ -6,36 +6,33 @@ ...@@ -6,36 +6,33 @@
Stable Application Binary Interface Stable Application Binary Interface
*********************************** ***********************************
Traditionally, the C API of Python will change with every release. Traditionally, the C API of Python will change with every release. Most changes
Most changes will be source-compatible, typically by only adding API, will be source-compatible, typically by only adding API, rather than changing
rather than changing existing API or removing API (although some existing API or removing API (although some interfaces do get removed after
interfaces do get removed after being deprecated first). being deprecated first).
Unfortunately, the API compatibility does not extend to binary Unfortunately, the API compatibility does not extend to binary compatibility
compatibility (the ABI). The reason is primarily the evolution of (the ABI). The reason is primarily the evolution of struct definitions, where
struct definitions, where addition of a new field, or changing addition of a new field, or changing the type of a field, might not break the
the type of a field, might not break the API, but can break the ABI. API, but can break the ABI. As a consequence, extension modules need to be
As a consequence, extension modules need to be recompiled for recompiled for every Python release (although an exception is possible on Unix
every Python release (although an exception is possible on Unix when none of the affected interfaces are used). In addition, on Windows,
when none of the affected interfaces are used). In addition, on extension modules link with a specific pythonXY.dll and need to be recompiled to
Windows, extension modules link with a specific pythonXY.dll and link with a newer one.
need to be recompiled to link with a newer one.
Since Python 3.2, a subset of the API has been declared to guarantee a stable
Since Python 3.2, a subset of the API has been declared to guarantee ABI. Extension modules wishing to use this API (called "limited API") need to
a stable ABI. Extension modules wishing to use this API need to define define ``Py_LIMITED_API``. A number of interpreter details then become hidden
``Py_LIMITED_API``. A number of interpreter details then become hidden from the extension module; in return, a module is built that works on any 3.x
from the extension module; in return, a module is built that works version (x>=2) without recompilation.
on any 3.x version (x>=2) without recompilation.
In some cases, the stable ABI needs to be extended with new functions. In some cases, the stable ABI needs to be extended with new functions.
Extension modules wishing to use these new APIs need to set Extension modules wishing to use these new APIs need to set ``Py_LIMITED_API``
``Py_LIMITED_API`` to the ``PY_VERSION_HEX`` value (see to the ``PY_VERSION_HEX`` value (see :ref:`apiabiversion`) of the minimum Python
:ref:`apiabiversion`) of the minimum Python version they want to version they want to support (e.g. ``0x03030000`` for Python 3.3). Such modules
support (e.g. ``0x03030000`` for Python 3.3). Such modules will work will work on all subsequent Python releases, but fail to load (because of
on all subsequent Python releases, but fail to load (because of
missing symbols) on the older releases. missing symbols) on the older releases.
As of Python 3.2, the set of functions available to the limited API As of Python 3.2, the set of functions available to the limited API is
is documented in PEP 384. documented in PEP 384. In the C API documentation, API elements that are not
part of the limited API are marked as "Not part of the limited API."
.. XXX copy exact list here? Into each functions definition?
...@@ -12,8 +12,8 @@ sys.path.append(os.path.abspath('tools/sphinxext')) ...@@ -12,8 +12,8 @@ sys.path.append(os.path.abspath('tools/sphinxext'))
# General configuration # General configuration
# --------------------- # ---------------------
extensions = ['sphinx.ext.refcounting', 'sphinx.ext.coverage', extensions = ['sphinx.ext.coverage', 'sphinx.ext.doctest',
'sphinx.ext.doctest', 'pyspecific'] 'pyspecific', 'c_annotations']
templates_path = ['tools/sphinxext'] templates_path = ['tools/sphinxext']
# General substitutions. # General substitutions.
......
# -*- coding: utf-8 -*-
"""
c_annotations.py
~~~~~~~~~~~~~~~~
Supports annotations for C API elements:
* reference count annotations for C API functions. Based on
refcount.py and anno-api.py in the old Python documentation tools.
* stable API annotations
Usage: Set the `refcount_file` config value to the path to the reference
count data file.
:copyright: Copyright 2007-2013 by Georg Brandl.
:license: Python license.
"""
from os import path
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.domains.c import CObject
class RCEntry:
def __init__(self, name):
self.name = name
self.args = []
self.result_type = ''
self.result_refs = None
class Annotations(dict):
@classmethod
def fromfile(cls, filename):
d = cls()
fp = open(filename, 'r')
try:
for line in fp:
line = line.strip()
if line[:1] in ("", "#"):
# blank lines and comments
continue
parts = line.split(":", 4)
if len(parts) != 5:
raise ValueError("Wrong field count in %r" % line)
function, type, arg, refcount, comment = parts
# Get the entry, creating it if needed:
try:
entry = d[function]
except KeyError:
entry = d[function] = RCEntry(function)
if not refcount or refcount == "null":
refcount = None
else:
refcount = int(refcount)
# Update the entry with the new parameter or the result
# information.
if arg:
entry.args.append((arg, type, refcount))
else:
entry.result_type = type
entry.result_refs = refcount
finally:
fp.close()
return d
def add_annotations(self, app, doctree):
for node in doctree.traverse(addnodes.desc_content):
par = node.parent
if par['domain'] != 'c':
continue
if par['notlimited']:
node.insert(0, nodes.emphasis(' Not part of the stable API.',
' Not part of the stable API.',
classes=['notlimited']))
if par['objtype'] != 'function':
continue
if not par[0].has_key('names') or not par[0]['names']:
continue
entry = self.get(par[0]['names'][0])
if not entry:
continue
elif entry.result_type not in ("PyObject*", "PyVarObject*"):
continue
if entry.result_refs is None:
rc = 'Return value: Always NULL.'
elif entry.result_refs:
rc = 'Return value: New reference.'
else:
rc = 'Return value: Borrowed reference.'
node.insert(0, nodes.emphasis(rc, rc, classes=['refcount']))
def init_annotations(app):
refcounts = Annotations.fromfile(
path.join(app.srcdir, app.config.refcount_file))
app.connect('doctree-read', refcounts.add_annotations)
def setup(app):
app.add_config_value('refcount_file', '', True)
app.connect('builder-inited', init_annotations)
# monkey-patch C object...
CObject.option_spec = {
'noindex': directives.flag,
'notlimited': directives.flag,
}
old_handle_signature = CObject.handle_signature
def new_handle_signature(self, sig, signode):
signode.parent['notlimited'] = 'notlimited' in self.options
return old_handle_signature(self, sig, signode)
CObject.handle_signature = new_handle_signature
...@@ -168,3 +168,11 @@ div.footer { ...@@ -168,3 +168,11 @@ div.footer {
div.footer a:hover { div.footer a:hover {
color: #0095C4; color: #0095C4;
} }
.refcount {
color: #060;
}
.notlimited {
color: #922;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment