mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	Fixed some errors in refcounts.dat, remove functions removed in Python 3, and add more entries for documented functions. This will add several automatically generated notes about return values.
		
			
				
	
	
		
			121 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
	
		
			4 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-2014 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
 | 
						|
            name = par[0]['names'][0]
 | 
						|
            if name.startswith("c."):
 | 
						|
                name = name[2:]
 | 
						|
            entry = self.get(name)
 | 
						|
            if not entry:
 | 
						|
                continue
 | 
						|
            elif not entry.result_type.endswith("Object*"):
 | 
						|
                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
 | 
						|
    return {'version': '1.0', 'parallel_read_safe': True}
 |