summaryrefslogtreecommitdiffstats
path: root/Doc/howto
diff options
context:
space:
mode:
authorLarry Hastings <larry@hastings.org>2014-02-01 06:03:12 (GMT)
committerLarry Hastings <larry@hastings.org>2014-02-01 06:03:12 (GMT)
commit7726ac9163081a3730d30d4334135d6bf26900fc (patch)
treeeac56b188bab64935e41c848a274d2ec47ed40f0 /Doc/howto
parent04edd2eb7f29eb147d54bd32c2e0a55af44a4323 (diff)
downloadcpython-7726ac9163081a3730d30d4334135d6bf26900fc.zip
cpython-7726ac9163081a3730d30d4334135d6bf26900fc.tar.gz
cpython-7726ac9163081a3730d30d4334135d6bf26900fc.tar.bz2
#Issue 20456: Several improvements and bugfixes for Argument Clinic,
including correctly generating code for Clinic blocks inside C preprocessor conditional blocks.
Diffstat (limited to 'Doc/howto')
-rw-r--r--Doc/howto/clinic.rst172
1 files changed, 100 insertions, 72 deletions
diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst
index 8fcc2e8..750ddbe 100644
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -561,8 +561,8 @@ in ``Lib/inspect.py``.
to allow full expressions like ``CONSTANT - 1``.)
-Renaming the C functions generated by Argument Clinic
------------------------------------------------------
+Renaming the C functions and variables generated by Argument Clinic
+-------------------------------------------------------------------
Argument Clinic automatically names the functions it generates for you.
Occasionally this may cause a problem, if the generated name collides with
@@ -584,6 +584,25 @@ The base function would now be named ``pickler_dumper()``,
and the impl function would now be named ``pickler_dumper_impl()``.
+Similarly, you may have a problem where you want to give a parameter
+a specific Python name, but that name may be inconvenient in C. Argument
+Clinic allows you to give a parameter different names in Python and in C,
+using the same ``"as"`` syntax::
+
+ /*[clinic input]
+ pickle.Pickler.dump
+
+ obj: object
+ file as file_obj: object
+ protocol: object = NULL
+ *
+ fix_imports: bool = True
+
+Here, the name used in Python (in the signature and the ``keywords``
+array) would be ``file``, but the C variable would be named ``file_obj``.
+
+You can use this to rename the ``self`` parameter too!
+
Converting functions using PyArg_UnpackTuple
--------------------------------------------
@@ -1308,74 +1327,6 @@ them ``__new__`` or ``__init__`` as appropriate. Notes:
(If your function doesn't support keywords, the parsing function
generated will throw an exception if it receives any.)
-The #ifdef trick
-----------------------------------------------
-
-If you're converting a function that isn't available on all platforms,
-there's a trick you can use to make life a little easier. The existing
-code probably looks like this::
-
- #ifdef HAVE_FUNCTIONNAME
- static module_functionname(...)
- {
- ...
- }
- #endif /* HAVE_FUNCTIONNAME */
-
-And then in the ``PyMethodDef`` structure at the bottom you'll have::
-
- #ifdef HAVE_FUNCTIONNAME
- {'functionname', ... },
- #endif /* HAVE_FUNCTIONNAME */
-
-In this scenario, you should change the code to look like the following::
-
- #ifdef HAVE_FUNCTIONNAME
- /*[clinic input]
- module.functionname
- ...
- [clinic start generated code]*/
- static module_functionname(...)
- {
- ...
- }
- #endif /* HAVE_FUNCTIONNAME */
-
-Run Argument Clinic on the code in this state, then refresh the file in
-your editor. Now you'll have the generated code, including the #define
-for the ``PyMethodDef``, like so::
-
- #ifdef HAVE_FUNCTIONNAME
- /*[clinic input]
- ...
- [clinic start generated code]*/
- ...
- #define MODULE_FUNCTIONNAME \
- {'functionname', ... },
- ...
- /*[clinic end generated code: checksum=...]*/
- static module_functionname(...)
- {
- ...
- }
- #endif /* HAVE_FUNCTIONNAME */
-
-Change the #endif at the bottom as follows::
-
- #else
- #define MODULE_FUNCTIONNAME
- #endif /* HAVE_FUNCTIONNAME */
-
-Now you can remove the #ifdefs around the ``PyMethodDef`` structure
-at the end, and replace those three lines with ``MODULE_FUNCTIONNAME``.
-If the function is available, the macro turns into the ``PyMethodDef``
-static value, including the trailing comma; if the function isn't
-available, the macro turns into nothing. Perfect!
-
-(This is the preferred approach for optional functions; in the future,
-Argument Clinic may generate the entire ``PyMethodDef`` structure.)
-
-
Changing and redirecting Clinic's output
----------------------------------------
@@ -1491,8 +1442,9 @@ previous configuration.
``output preset`` sets Clinic's output to one of several built-in
preset configurations, as follows:
- ``original``
- Clinic's starting configuration.
+ ``block``
+ Clinic's original starting configuration. Writes everything
+ immediately after the input block.
Suppress the ``parser_prototype``
and ``docstring_prototype``, write everything else to ``block``.
@@ -1640,6 +1592,82 @@ it in a Clinic block lets Clinic use its existing checksum functionality to ensu
the file was not modified by hand before it gets overwritten.
+The #ifdef trick
+----------------------------------------------
+
+If you're converting a function that isn't available on all platforms,
+there's a trick you can use to make life a little easier. The existing
+code probably looks like this::
+
+ #ifdef HAVE_FUNCTIONNAME
+ static module_functionname(...)
+ {
+ ...
+ }
+ #endif /* HAVE_FUNCTIONNAME */
+
+And then in the ``PyMethodDef`` structure at the bottom the existing code
+will have::
+
+ #ifdef HAVE_FUNCTIONNAME
+ {'functionname', ... },
+ #endif /* HAVE_FUNCTIONNAME */
+
+In this scenario, you should enclose the body of your impl function inside the ``#ifdef``,
+like so::
+
+ #ifdef HAVE_FUNCTIONNAME
+ /*[clinic input]
+ module.functionname
+ ...
+ [clinic start generated code]*/
+ static module_functionname(...)
+ {
+ ...
+ }
+ #endif /* HAVE_FUNCTIONNAME */
+
+Then, remove those three lines from the ``PyMethodDef`` structure,
+replacing them with the macro Argument Clinic generated::
+
+ MODULE_FUNCTIONNAME_METHODDEF
+
+(You can find the real name for this macro inside the generated code.
+Or you can calculate it yourself: it's the name of your function as defined
+on the first line of your block, but with periods changed to underscores,
+uppercased, and ``"_METHODDEF"`` added to the end.)
+
+Perhaps you're wondering: what if ``HAVE_FUNCTIONNAME`` isn't defined?
+The ``MODULE_FUNCTIONNAME_METHODDEF`` macro won't be defined either!
+
+Here's where Argument Clinic gets very clever. It actually detects that the
+Argument Clinic block might be deactivated by the ``#ifdef``. When that
+happens, it generates a little extra code that looks like this::
+
+ #ifndef MODULE_FUNCTIONNAME_METHODDEF
+ #define MODULE_FUNCTIONNAME_METHODDEF
+ #endif /* !defined(MODULE_FUNCTIONNAME_METHODDEF) */
+
+That means the macro always works. If the function is defined, this turns
+into the correct structure, including the trailing comma. If the function is
+undefined, this turns into nothing.
+
+However, this causes one ticklish problem: where should Argument Clinic put this
+extra code when using the "block" output preset? It can't go in the output block,
+because that could be decativated by the ``#ifdef``. (That's the whole point!)
+
+In this situation, Argument Clinic writes the extra code to the "buffer" destination.
+This may mean that you get a complaint from Argument Clinic::
+
+ Warning in file "Modules/posixmodule.c" on line 12357:
+ Destination buffer 'buffer' not empty at end of file, emptying.
+
+When this happens, just open your file, find the ``dump buffer`` block that
+Argument Clinic added to your file (it'll be at the very bottom), then
+move it above the ``PyMethodDef`` structure where that macro is used.
+
+
+
Using Argument Clinic in Python files
-------------------------------------