PEP 436: fix markup and make it consistent.

This commit is contained in:
gbrandl 2013-10-08 16:09:05 +02:00
parent 3f90114628
commit 298f064289
1 changed files with 170 additions and 186 deletions

View File

@ -49,62 +49,62 @@ But over the years the ``PyArg_Parse`` interface has been extended
in numerous ways. The modern API is complex, to the point that it
is somewhat painful to use. Consider:
* There are now forty different "format units"; a few are even three
characters long. This makes it difficult for the programmer to
understand what the format string says--or even perhaps to parse
it--without constantly cross-indexing it with the documentation.
* There are also six meta-format units that may be buried in the
format string. (They are: ``"()|$:;"``.)
* The more format units are added, the less likely it is the
implementer can pick an easy-to-use mnemonic for the format unit,
because the character of choice is probably already in use. In
other words, the more format units we have, the more obtuse the
format units become.
* Several format units are nearly identical to others, having only
subtle differences. This makes understanding the exact semantics
of the format string even harder, and can make it difficult to
figure out exactly which format unit you want.
* The docstring is specified as a static C string, making it mildly
bothersome to read and edit since it must obey C string quoting rules.
* When adding a new parameter to a function using
``PyArg_ParseTupleAndKeywords()``, it's necessary to touch six
different places in the code: [4]_
* There are now forty different "format units"; a few are even three
characters long. This makes it difficult for the programmer to
understand what the format string says--or even perhaps to parse
it--without constantly cross-indexing it with the documentation.
* There are also six meta-format units that may be buried in the
format string. (They are: ``"()|$:;"``.)
* The more format units are added, the less likely it is the
implementer can pick an easy-to-use mnemonic for the format unit,
because the character of choice is probably already in use. In
other words, the more format units we have, the more obtuse the
format units become.
* Several format units are nearly identical to others, having only
subtle differences. This makes understanding the exact semantics
of the format string even harder, and can make it difficult to
figure out exactly which format unit you want.
* The docstring is specified as a static C string, making it mildly
bothersome to read and edit since it must obey C string quoting rules.
* When adding a new parameter to a function using
``PyArg_ParseTupleAndKeywords()``, it's necessary to touch six
different places in the code: [4]_
* Declaring the variable to store the argument.
* Passing in a pointer to that variable in the correct spot in
``PyArg_ParseTupleAndKeywords()``, also passing in any
"length" or "converter" arguments in the correct order.
* Adding the name of the argument in the correct spot of the
"keywords" array passed in to
``PyArg_ParseTupleAndKeywords()``.
* Adding the format unit to the correct spot in the format
string.
* Adding the parameter to the prototype in the docstring.
* Documenting the parameter in the docstring.
* Declaring the variable to store the argument.
* Passing in a pointer to that variable in the correct spot in
``PyArg_ParseTupleAndKeywords()``, also passing in any
"length" or "converter" arguments in the correct order.
* Adding the name of the argument in the correct spot of the
"keywords" array passed in to
``PyArg_ParseTupleAndKeywords()``.
* Adding the format unit to the correct spot in the format
string.
* Adding the parameter to the prototype in the docstring.
* Documenting the parameter in the docstring.
* There is currently no mechanism for builtin functions to provide
their "signature" information (see ``inspect.getfullargspec`` and
``inspect.Signature``). Adding this information using a mechanism
similar to the existing ``PyArg_Parse`` functions would require
repeating ourselves yet again.
* There is currently no mechanism for builtin functions to provide
their "signature" information (see ``inspect.getfullargspec`` and
``inspect.Signature``). Adding this information using a mechanism
similar to the existing ``PyArg_Parse`` functions would require
repeating ourselves yet again.
The goal of Argument Clinic is to replace this API with a mechanism
inheriting none of these downsides:
* You need specify each parameter only once.
* All information about a parameter is kept together in one place.
* For each parameter, you specify a conversion function; Argument
Clinic handles the translation from Python value into C value for
you.
* Argument Clinic also allows for fine-tuning of argument processing
behavior with parameterized conversion functions.
* Docstrings are written in plain text. Function docstrings are
required; per-parameter docstrings are encouraged.
* From this, Argument Clinic generates for you all the mundane,
repetitious code and data structures CPython needs internally.
Once you've specified the interface, the next step is simply to
write your implementation using native C types. Every detail of
argument parsing is handled for you.
* You need specify each parameter only once.
* All information about a parameter is kept together in one place.
* For each parameter, you specify a conversion function; Argument
Clinic handles the translation from Python value into C value for
you.
* Argument Clinic also allows for fine-tuning of argument processing
behavior with parameterized conversion functions.
* Docstrings are written in plain text. Function docstrings are
required; per-parameter docstrings are encouraged.
* From this, Argument Clinic generates for you all the mundane,
repetitious code and data structures CPython needs internally.
Once you've specified the interface, the next step is simply to
write your implementation using native C types. Every detail of
argument parsing is handled for you.
Argument Clinic is implemented as a preprocessor. It draws inspiration
for its workflow directly from [Cog]_ by Ned Batchelder. To use Clinic,
@ -121,11 +121,11 @@ interpreter.
Future goals of Argument Clinic include:
* providing signature information for builtins,
* enabling alternative implementations of Python to create
automated library compatibility tests, and
* speeding up argument parsing with improvements to the
generated code.
* providing signature information for builtins,
* enabling alternative implementations of Python to create
automated library compatibility tests, and
* speeding up argument parsing with improvements to the
generated code.
DSL Syntax Summary
@ -141,117 +141,115 @@ statement, lending it some familiarity to Python core developers.
::
+-----------------------+-----------------------------------------------------------------+
| Section | Example |
+-----------------------+-----------------------------------------------------------------+
| Clinic DSL start | /*[clinic] |
| Module declaration | module module_name |
| Class declaration | class module_name.class_name |
| Function declaration | module_name.function_name -> return_annotation |
| Parameter declaration | name : converter(param=value) |
| Parameter docstring | Lorem ipsum dolor sit amet, consectetur |
| | adipisicing elit, sed do eiusmod tempor |
| Function docstring | Lorem ipsum dolor sit amet, consectetur adipisicing |
| | elit, sed do eiusmod tempor incididunt ut labore et |
| Clinic DSL end | [clinic]*/ |
| Clinic output | ... |
| Clinic output end | /*[clinic end output:<checksum>]*/ |
+-----------------------+-----------------------------------------------------------------+
+-----------------------+-----------------------------------------------------------------+
| Section | Example |
+-----------------------+-----------------------------------------------------------------+
| Clinic DSL start | /*[clinic] |
| Module declaration | module module_name |
| Class declaration | class module_name.class_name |
| Function declaration | module_name.function_name -> return_annotation |
| Parameter declaration | name : converter(param=value) |
| Parameter docstring | Lorem ipsum dolor sit amet, consectetur |
| | adipisicing elit, sed do eiusmod tempor |
| Function docstring | Lorem ipsum dolor sit amet, consectetur adipisicing |
| | elit, sed do eiusmod tempor incididunt ut labore et |
| Clinic DSL end | [clinic]*/ |
| Clinic output | ... |
| Clinic output end | /*[clinic end output:<checksum>]*/ |
+-----------------------+-----------------------------------------------------------------+
To give some flavor of the proposed DSL syntax, here are some sample Clinic
code blocks. This first block reflects the normally preferred style, including
blank lines between parameters and per-argument docstrings.
It also includes a user-defined converter (``path_t``) created
locally
locally::
::
/*[clinic]
os.stat as os_stat_fn -> stat result
/*[clinic]
os.stat as os_stat_fn -> stat result
path: path_t(allow_fd=1)
Path to be examined; can be string, bytes, or open-file-descriptor int.
path: path_t(allow_fd=1)
Path to be examined; can be string, bytes, or open-file-descriptor int.
*
*
dir_fd: OS_STAT_DIR_FD_CONVERTER = DEFAULT_DIR_FD
If not None, it should be a file descriptor open to a directory,
and path should be a relative string; path will then be relative to
that directory.
dir_fd: OS_STAT_DIR_FD_CONVERTER = DEFAULT_DIR_FD
If not None, it should be a file descriptor open to a directory,
and path should be a relative string; path will then be relative to
that directory.
follow_symlinks: bool = True
If False, and the last element of the path is a symbolic link,
stat will examine the symbolic link itself instead of the file
the link points to.
follow_symlinks: bool = True
If False, and the last element of the path is a symbolic link,
stat will examine the symbolic link itself instead of the file
the link points to.
Perform a stat system call on the given path.
Perform a stat system call on the given path.
{parameters}
{parameters}
dir_fd and follow_symlinks may not be implemented
on your platform. If they are unavailable, using them will raise a
NotImplementedError.
dir_fd and follow_symlinks may not be implemented
on your platform. If they are unavailable, using them will raise a
NotImplementedError.
It's an error to use dir_fd or follow_symlinks when specifying path as
an open file descriptor.
It's an error to use dir_fd or follow_symlinks when specifying path as
an open file descriptor.
[clinic]*/
[clinic]*/
This second example shows a minimal Clinic code block, omitting all
parameter docstrings and non-significant blank lines::
/*[clinic]
os.access
path: path
mode: int
*
dir_fd: OS_ACCESS_DIR_FD_CONVERTER = 1
effective_ids: bool = False
follow_symlinks: bool = True
Use the real uid/gid to test for access to a path.
Returns True if granted, False otherwise.
/*[clinic]
os.access
path: path
mode: int
*
dir_fd: OS_ACCESS_DIR_FD_CONVERTER = 1
effective_ids: bool = False
follow_symlinks: bool = True
Use the real uid/gid to test for access to a path.
Returns True if granted, False otherwise.
{parameters}
{parameters}
dir_fd, effective_ids, and follow_symlinks may not be implemented
on your platform. If they are unavailable, using them will raise a
NotImplementedError.
dir_fd, effective_ids, and follow_symlinks may not be implemented
on your platform. If they are unavailable, using them will raise a
NotImplementedError.
Note that most operations will use the effective uid/gid, therefore this
routine can be used in a suid/sgid environment to test if the invoking user
has the specified access to the path.
Note that most operations will use the effective uid/gid, therefore this
routine can be used in a suid/sgid environment to test if the invoking user
has the specified access to the path.
[clinic]*/
[clinic]*/
This final example shows a Clinic code block handling groups of
optional parameters, including parameters on the left::
/*[clinic]
curses.window.addch
/*[clinic]
curses.window.addch
[
y: int
Y-coordinate.
[
y: int
Y-coordinate.
x: int
X-coordinate.
]
x: int
X-coordinate.
]
ch: char
Character to add.
ch: char
Character to add.
[
attr: long
Attributes for the character.
]
[
attr: long
Attributes for the character.
]
/
/
Paint character ch at (y, x) with attributes attr,
overwriting any character previously painter at that location.
By default, the character position and attributes are the
current settings for the window object.
[clinic]*/
Paint character ch at (y, x) with attributes attr,
overwriting any character previously painter at that location.
By default, the character position and attributes are the
current settings for the window object.
[clinic]*/
General Behavior Of the Argument Clinic DSL
@ -275,17 +273,13 @@ Module and Class Declarations
-----------------------------
When a C file implements a module or class, this should be declared to
Clinic. The syntax is simple:
Clinic. The syntax is simple::
::
module module_name
module module_name
or ::
or
::
class module_name.class_name
class module_name.class_name
(Note that these are not actually special syntax; they are implemented
as `Directives`_.)
@ -297,11 +291,9 @@ from the top-level module. Nested modules and classes are supported.
Function Declaration
--------------------
The full form of the function declaration is as follows:
The full form of the function declaration is as follows::
::
dotted.name [ as legal_c_id ] [ -> return_annotation ]
dotted.name [ as legal_c_id ] [ -> return_annotation ]
The dotted name should be the full name of the function, starting
with the highest-level package (e.g. "os.stat" or "curses.window.addch").
@ -323,11 +315,9 @@ a *return converter*.
Parameter Declaration
---------------------
The full form of the parameter declaration line as as follows:
The full form of the parameter declaration line as as follows::
::
name: converter [ (parameter=value [, parameter2=value2]) ] [ = default]
name: converter [ (parameter=value [, parameter2=value2]) ] [ = default]
The "name" must be a legal C identifier. Whitespace is permitted between
the name and the colon (though this is not the preferred style). Whitespace
@ -377,11 +367,9 @@ For convenience's sake in converting existing code to Argument Clinic,
Clinic provides a set of legacy converters that match ``PyArg_ParseTuple``
format units. They are specified as a C string containing the format
unit. For example, to specify a parameter "foo" as taking a Python
"int" and emitting a C int, you could specify:
"int" and emitting a C int, you could specify::
::
foo : "i"
foo : "i"
(To more closely resemble a C string, these must always use double quotes.)
@ -554,11 +542,9 @@ Argument Clinic also permits "directives" in Clinic code blocks.
Directives are similar to *pragmas* in C; they are statements
that modify Argument Clinic's behavior.
The format of a directive is as follows:
The format of a directive is as follows::
::
directive_name [argument [second_argument [ ... ]]]
directive_name [argument [second_argument [ ... ]]]
Directives only take positional arguments.
@ -566,7 +552,7 @@ A Clinic code block must contain either one or more directives,
or a function declaration. It may contain both, in which
case all directives must come before the function declaration.
Internally directives map directly to Python callables.
Internally directives map directly to Python callables.
The directive's arguments are passed directly to the callable
as positional arguments of type ``str()``.
@ -581,18 +567,16 @@ Python Code
Argument Clinic also permits embedding Python code inside C files,
which is executed in-place when Argument Clinic processes the file.
Embedded code looks like this:
Embedded code looks like this::
::
/*[python]
/*[python]
# this is python code!
print("/" + "* Hello world! *" + "/")
# this is python code!
print("/" + "* Hello world! *" + "/")
[python]*/
/* Hello world! */
/*[python end:da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
[python]*/
/* Hello world! */
/*[python end:da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
The ``"/* Hello world! */"`` line above was generated by running the Python
code in the preceding comment.
@ -610,14 +594,14 @@ after the section of Clinic code. For "python" sections, the output
is everything printed using ``builtins.print``. For "clinic"
sections, the output is valid C code, including:
* a ``#define`` providing the correct ``methoddef`` structure for the
function
* a prototype for the "impl" function -- this is what you'll write
to implement this function
* a function that handles all argument processing, which calls your
"impl" function
* the definition line of the "impl" function
* and a comment indicating the end of output.
* a ``#define`` providing the correct ``methoddef`` structure for the
function
* a prototype for the "impl" function -- this is what you'll write
to implement this function
* a function that handles all argument processing, which calls your
"impl" function
* the definition line of the "impl" function
* and a comment indicating the end of output.
The intention is that you write the body of your impl function immediately
after the output -- as in, you write a left-curly-brace immediately after
@ -738,15 +722,15 @@ Notes / TBD
::
/*[clinic]
... prototype and parameters (including parameter docstrings) go here
[clinic]*/
... some output ...
/*[clinic docstring start]*/
... hand-edited function docstring goes here <-- you edit this by hand!
/*[clinic docstring end]*/
... more output
/*[clinic output end]*/
/*[clinic]
... prototype and parameters (including parameter docstrings) go here
[clinic]*/
... some output ...
/*[clinic docstring start]*/
... hand-edited function docstring goes here <-- you edit this by hand!
/*[clinic docstring end]*/
... more output
/*[clinic output end]*/
I tried it this way and don't like it -- I think it's clumsy. I
prefer that everything you write goes in one place, rather than
@ -756,7 +740,7 @@ Notes / TBD
* Argument Clinic does not support automatic tuple unpacking
(the "``(OOO)``" style format string for ``PyArg_ParseTuple()``.)
* Argument Clinic removes some dynamism / flexibility. With
* Argument Clinic removes some dynamism / flexibility. With
``PyArg_ParseTuple()`` one could theoretically pass in different
encodings at runtime for the "``es``"/"``et``" format units.
AFAICT CPython doesn't do this itself, however it's possible
@ -773,7 +757,7 @@ shamelessly rip off his clever design for Cog--"my favorite tool
that I've never gotten to use". Thanks also to everyone who provided
feedback on the [bugtracker issue] and on python-dev. Special thanks
to Nick Coglan and Guido van Rossum for a rousing two-hour in-person
deep dive on the topic at PyCon US 2013.
deep dive on the topic at PyCon US 2013.
References