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