mirror of https://github.com/python/cpython
118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
# -*- 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['stableabi']:
|
|
node.insert(0, nodes.emphasis(' Part of the stable ABI.',
|
|
' Part of the stable ABI.',
|
|
classes=['stableabi']))
|
|
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,
|
|
'stableabi': directives.flag,
|
|
}
|
|
old_handle_signature = CObject.handle_signature
|
|
def new_handle_signature(self, sig, signode):
|
|
signode.parent['stableabi'] = 'stableabi' in self.options
|
|
return old_handle_signature(self, sig, signode)
|
|
CObject.handle_signature = new_handle_signature
|