diff options
author | Petr Viktorin <encukou@gmail.com> | 2021-05-11 14:04:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-11 14:04:33 (GMT) |
commit | b05955d6f5f149523b5855a335444b7c6324bdb7 (patch) | |
tree | 0829fa3eafc60cba7f67e5e36966bf26b40c81c8 /Doc/tools | |
parent | d1b81574edd75e33ae85c525ac988ce772675a07 (diff) | |
download | cpython-b05955d6f5f149523b5855a335444b7c6324bdb7.zip cpython-b05955d6f5f149523b5855a335444b7c6324bdb7.tar.gz cpython-b05955d6f5f149523b5855a335444b7c6324bdb7.tar.bz2 |
bpo-43795: PEP 652 user documentation (GH-25668)
- Reformat the C API and ABI Versioning page (and extend/clarify a bit)
- Rewrite the stable ABI docs into a general text on C API Compatibility
- Add a list of Limited API contents, and notes for the individual items.
- Replace `Include/README.rst` with a link to a devguide page with the same info
Diffstat (limited to 'Doc/tools')
-rw-r--r-- | Doc/tools/extensions/c_annotations.py | 110 |
1 files changed, 88 insertions, 22 deletions
diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 76c9d92..489f066 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -10,8 +10,10 @@ * stable API annotations - Usage: Set the `refcount_file` config value to the path to the reference + Usage: + * Set the `refcount_file` config value to the path to the reference count data file. + * Set the `stable_abi_file` config value to the path to stable ABI list. :copyright: Copyright 2007-2014 by Georg Brandl. :license: Python license. @@ -20,11 +22,23 @@ from os import path from docutils import nodes from docutils.parsers.rst import directives +from docutils.parsers.rst import Directive +from docutils.statemachine import StringList +import csv from sphinx import addnodes from sphinx.domains.c import CObject +REST_ROLE_MAP = { + 'function': 'func', + 'var': 'data', + 'type': 'type', + 'macro': 'macro', + 'type': 'type', +} + + class RCEntry: def __init__(self, name): self.name = name @@ -33,12 +47,10 @@ class RCEntry: self.result_refs = None -class Annotations(dict): - @classmethod - def fromfile(cls, filename): - d = cls() - fp = open(filename, 'r') - try: +class Annotations: + def __init__(self, refcount_filename, stable_abi_file): + self.refcount_data = {} + with open(refcount_filename, 'r') as fp: for line in fp: line = line.strip() if line[:1] in ("", "#"): @@ -50,9 +62,9 @@ class Annotations(dict): function, type, arg, refcount, comment = parts # Get the entry, creating it if needed: try: - entry = d[function] + entry = self.refcount_data[function] except KeyError: - entry = d[function] = RCEntry(function) + entry = self.refcount_data[function] = RCEntry(function) if not refcount or refcount == "null": refcount = None else: @@ -64,27 +76,58 @@ class Annotations(dict): else: entry.result_type = type entry.result_refs = refcount - finally: - fp.close() - return d + + self.stable_abi_data = {} + with open(stable_abi_file, 'r') as fp: + for record in csv.DictReader(fp): + role = record['role'] + name = record['name'] + self.stable_abi_data[name] = record 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('ids') or not par[0]['ids']: continue name = par[0]['ids'][0] if name.startswith("c."): name = name[2:] - entry = self.get(name) + + objtype = par['objtype'] + + # Stable ABI annotation. These have two forms: + # Part of the [Stable ABI](link). + # Part of the [Stable ABI](link) since version X.Y. + record = self.stable_abi_data.get(name) + if record: + if record['role'] != objtype: + raise ValueError( + f"Object type mismatch in limited API annotation " + f"for {name}: {record['role']!r} != {objtype!r}") + stable_added = record['added'] + message = ' Part of the ' + emph_node = nodes.emphasis(message, message, + classes=['stableabi']) + ref_node = addnodes.pending_xref( + 'Stable ABI', refdomain="std", reftarget='stable', + reftype='ref', refexplicit="False") + ref_node += nodes.Text('Stable ABI') + emph_node += ref_node + if record['ifdef_note']: + emph_node += nodes.Text(' ' + record['ifdef_note']) + if stable_added == '3.2': + # Stable ABI was introduced in 3.2. + emph_node += nodes.Text('.') + else: + emph_node += nodes.Text(f' since version {stable_added}.') + node.insert(0, emph_node) + + # Return value annotation + if objtype != 'function': + continue + entry = self.refcount_data.get(name) if not entry: continue elif not entry.result_type.endswith("Object*"): @@ -99,13 +142,36 @@ class Annotations(dict): def init_annotations(app): - refcounts = Annotations.fromfile( - path.join(app.srcdir, app.config.refcount_file)) - app.connect('doctree-read', refcounts.add_annotations) + annotations = Annotations( + path.join(app.srcdir, app.config.refcount_file), + path.join(app.srcdir, app.config.stable_abi_file), + ) + app.connect('doctree-read', annotations.add_annotations) + + class LimitedAPIList(Directive): + + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True + + def run(self): + content = [] + for record in annotations.stable_abi_data.values(): + role = REST_ROLE_MAP[record['role']] + name = record['name'] + content.append(f'* :c:{role}:`{name}`') + + pnode = nodes.paragraph() + self.state.nested_parse(StringList(content), 0, pnode) + return [pnode] + + app.add_directive('limited-api-list', LimitedAPIList) def setup(app): app.add_config_value('refcount_file', '', True) + app.add_config_value('stable_abi_file', '', True) app.connect('builder-inited', init_annotations) # monkey-patch C object... |