Skip to content

Commit

Permalink
dd refcounts_borrowed.py
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Jul 29, 2018
1 parent d31c0c9 commit 7eaf950
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 30 deletions.
5 changes: 4 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ Brainstorm to change the Python C API (to make it better):
* `capi-sig mailing list
<https://mail.python.org/mm3/mailman3/lists/capi-sig.python.org/>`_

The current documentation can be found in the ``doc/`` subdirectory.
Content:
* ``doc/`` subdirectory: the current documentation
* ``refcounts_borrowed.py``: search for functions returning a borrowed
reference from CPython ``Doc/data/refcounts.dat`` file.
71 changes: 42 additions & 29 deletions doc/bad_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,48 @@ The C API must not leak implementation details anymore.
Borrowed references
===================

Borrowed references: Too many functions :-(

CPython contains ``Doc/data/refcounts.dat`` which documents how functions
handle reference count. This file is edited manually.

Attempt to list them:

* ``PyCell_GET()``
* ``PyDict_GetItem()``
* ``PyDict_GetItemWithError()``
* ``PyDict_GetItemString()``
* ``PyDict_SetDefault()``
* ``PyErr_Occurred()``
* ``PyEval_GetBuiltins()``
* ``PyEval_GetLocals()``
* ``PyEval_GetGlobals()``
* ``PyEval_GetFrame()``
* ``PyFunction_GetClosure()``
* ``Py_InitModule()``
* ``PyImport_GetModuleDict()``
* ``PyList_GET_ITEM()``
* ``PyList_GetItem()``
* ``PyMethod_GET_SELF()``
* ``PySequence_Fast_GET_ITEM()``
* ``PySys_GetObject()``
* ``PyThreadState_GetDict()``
* ``PyTuple_GET_ITEM()``
* ``PyTuple_GetItem()``
* ``PyWeakref_GetObject()``
CPython 3.7 has 36 functions and macros which return borrowed references:

* ``PyCell_GET()``
* ``PyDict_GetItem()``
* ``PyDict_GetItemWithError()``
* ``PyDict_GetItemString()``
* ``PyDict_SetDefault()``
* ``PyErr_Occurred()``
* ``PyEval_GetBuiltins()``
* ``PyFile_Name()``
* ``PyFunction_GetClosure()``
* ``PyFunction_GetCode()``
* ``PyFunction_GetDefaults()``
* ``PyFunction_GetGlobals()``
* ``PyFunction_GetModule()``
* ``Py_InitModule()``
* ``Py_InitModule3()``
* ``Py_InitModule4()``
* ``PyImport_GetModuleDict()``
* ``PyList_GET_ITEM()``
* ``PyList_GetItem()``
* ``PyMethod_Class()``
* ``PyMethod_Function()``
* ``PyMethod_GET_CLASS()``
* ``PyMethod_GET_FUNCTION()``
* ``PyMethod_GET_SELF()``
* ``PyMethod_Self()``
* ``PyModule_GetDict()``
* ``PyNumber_Check()``
* ``PyObject_Init()``
* ``PySequence_Fast_GET_ITEM()``
* ``PySys_GetObject()``
* ``PySys_GetXOptions()``
* ``PyThreadState_GetDict()``
* ``PyTuple_GET_ITEM()``
* ``PyTuple_GetItem()``
* ``PyWeakref_GET_OBJECT()``
* ``PyWeakref_GetObject()``

CPython contains ``Doc/data/refcounts.dat`` (file is edited manually) which
documents how functions handle reference count.


``PyObject**``
==============
Expand Down
41 changes: 41 additions & 0 deletions refcounts_borrowed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""
Script parsing CPython Doc/data/refcounts.dat to list functions which
return a borrow PyObject* reference.
"""
import sys


def parse_refcounts(filename):
total = 0
header = True
for line in open(filename, encoding="utf8"):
pos = line.find('#')
if pos >= 0:
line = line[pos:]
line = line.strip()
if not line:
header = True
continue
if not header:
continue
if ':PyObject*:' in line and line.endswith((':0', ':0:')):
func = line.split(':')[0]
print("Borrowed reference: %s()" % func)
total += 1
header = False

print()
print("Total: %s functions" % total)


def main():
if len(sys.argv) != 2:
print("usage: %s cpython/Doc/data/refcounts.dat" % sys.argv[0])
sys.exit(1)
filename = sys.argv[1]
parse_refcounts(filename)


if __name__ == "__main__":
main()

0 comments on commit 7eaf950

Please sign in to comment.