From 00c44d6f662628104cc68d028a5f04b9c0025ac3 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 29 Nov 2024 18:12:04 +0100 Subject: [PATCH 1/2] Add Function behavior --- guidelines.rst | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/guidelines.rst b/guidelines.rst index bf92d85..723e3b0 100644 --- a/guidelines.rst +++ b/guidelines.rst @@ -522,6 +522,73 @@ documentation of each function they're relevant to. - https://github.com/capi-workgroup/api-evolution/issues/32 +Function behavior +================= + +Do not suppress errors +---------------------- + +New C API functions must not suppress unknown exceptions, except ones that +specifically do just that (e.g. ``PyErr_Clear``). + +If a function has a common “failure” mode, like “attribute not found” from a +``getattr``, you can treat it as success and signal it with a dedicated +return value. This avoids creating an exception object. +See also “Lookup” in :ref:`return schemes`. + +.. note:: + + For background and discussions, see: + + - https://github.com/capi-workgroup/api-evolution/issues/35 + + +Do not allow mutating immutable objects +--------------------------------------- + +If an object is immutable in Python, C API may not mutate it either. + +It is of course fine to mutate implementation details: refcounts, lazily +computed attributes and so on. + +Note that current API like ``PyUnicode_WRITE`` allows mutation to create an +object, and it's up to the user to not use this API once the object is no +longer “fresh”. +A better precedent is the ``PyUnicodeWriter`` API, which allows complex set-up +before creating a ``PyObject*`` object. + +.. note:: + + For background and discussions, see: + + - https://github.com/capi-workgroup/api-evolution/issues/20 + + +Do not allow creating incomplete/invalid objects +------------------------------------------------ + +C API should not allow creating objects that cannot be immediately safely +used from Python code. + +This rule is most important for -- but not limited to -- the GC protocol. +Specifically, a traverse function must be safe to call right after an object +is tracked with the GC. + +This is often realized by adding API to “finalize” an object after some initial +set-up. +It should be hard for users to forget calling such “finalization” functions. +To make it hard, you can make the “unfinalized” object unusable or add a +separate C type for the “unfinalized” object. +(This separate type might share the final object's memory layout to make +“finalization” inexpensive.) + +.. note:: + + For background and discussions, see: + + - https://github.com/capi-workgroup/api-evolution/issues/36 + + .. _shadowing example: Appendix A. Shadowing example From 77081de24603b41e987e00083ccb7045d05f2cec Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 18 Nov 2025 10:48:40 +0100 Subject: [PATCH 2/2] Use ASCII quotes --- guidelines.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/guidelines.rst b/guidelines.rst index 723e3b0..a99e070 100644 --- a/guidelines.rst +++ b/guidelines.rst @@ -298,7 +298,7 @@ avoid some of C's features: * Avoid C-specific types like ``long long``, ``enum`` or bit fields (see :ref:`types`). -Once you add API that conforms to this “portable subset”, +Once you add API that conforms to this "portable subset", you can add additional C/C++-specific API. Usually, the additional API will be either more performant, or easier to use from C. For example: @@ -531,10 +531,10 @@ Do not suppress errors New C API functions must not suppress unknown exceptions, except ones that specifically do just that (e.g. ``PyErr_Clear``). -If a function has a common “failure” mode, like “attribute not found” from a +If a function has a common "failure" mode, like “attribute not found” from a ``getattr``, you can treat it as success and signal it with a dedicated return value. This avoids creating an exception object. -See also “Lookup” in :ref:`return schemes`. +See also "Lookup" in :ref:`return schemes`. .. note:: @@ -553,7 +553,7 @@ computed attributes and so on. Note that current API like ``PyUnicode_WRITE`` allows mutation to create an object, and it's up to the user to not use this API once the object is no -longer “fresh”. +longer "fresh". A better precedent is the ``PyUnicodeWriter`` API, which allows complex set-up before creating a ``PyObject*`` object. @@ -574,13 +574,13 @@ This rule is most important for -- but not limited to -- the GC protocol. Specifically, a traverse function must be safe to call right after an object is tracked with the GC. -This is often realized by adding API to “finalize” an object after some initial +This is often realized by adding API to "finalize" an object after some initial set-up. -It should be hard for users to forget calling such “finalization” functions. -To make it hard, you can make the “unfinalized” object unusable or add a -separate C type for the “unfinalized” object. +It should be hard for users to forget calling such "finalization" functions. +To make it hard, you can make the "unfinalized" object unusable or add a +separate C type for the "unfinalized" object. (This separate type might share the final object's memory layout to make -“finalization” inexpensive.) +"finalization" inexpensive.) .. note:: @@ -644,12 +644,12 @@ Here are common schemes of how to encode return values. * ``0`` for ``false`` * ``-1``, with an exception set, for failure -* Lookup (“getattr”, “getitem” or “setdefault” style) functions: return +* Lookup ("getattr", “getitem” or “setdefault” style) functions: return ``int``; the lookup result is passed via an :ref:`output argument `): - * ``1`` for “found” (*result* is set) - * ``0`` for “not found” + * ``1`` for "found" (*result* is set) + * ``0`` for "not found" (*result* is set to ``NULL`` or other zero/empty value) * ``-1``, with an exception set, for failure (*result* is set to ``NULL`` or other zero/empty value)