gh-107704: Argument Clinic: add support for deprecating keyword use of parameters (GH-107984)

It is now possible to deprecate passing keyword arguments for
keyword-or-positional parameters with Argument Clinic, using the new
'/ [from X.Y]' syntax.
(To be read as "positional-only from Python version X.Y")

Co-authored-by: Erlend E. Aasland <erlend@python.org>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Serhiy Storchaka 2023-08-19 10:13:35 +03:00 committed by GitHub
parent eb953d6e44
commit 2f311437cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 2993 additions and 1345 deletions

View file

@ -1941,54 +1941,70 @@ The generated docstring ends up looking like this:
.. _clinic-howto-deprecate-positional:
.. _clinic-howto-deprecate-keyword:
How to deprecate passing parameters positionally
------------------------------------------------
How to deprecate passing parameters positionally or by keyword
--------------------------------------------------------------
Argument Clinic provides syntax that makes it possible to generate code that
deprecates passing :term:`arguments <argument>` positionally.
deprecates passing :term:`arguments <argument>` for positional-or-keyword
:term:`parameters <parameter>` positionally or by keyword.
For example, say we've got a module-level function :py:func:`!foo.myfunc`
that has three :term:`parameters <parameter>`:
positional-or-keyword parameters *a* and *b*, and a keyword-only parameter *c*::
that has five parameters: a positional-only parameter *a*, three
positional-or-keyword parameters *b*, *c* and *d*, and a keyword-only
parameter *e*::
/*[clinic input]
module foo
myfunc
a: int
/
b: int
*
c: int
d: int
*
e: int
[clinic start generated output]*/
We now want to make the *b* parameter keyword-only;
however, we'll have to wait two releases before making this change,
We now want to make the *b* parameter positional-only and the *d* parameter
keyword-only;
however, we'll have to wait two releases before making these changes,
as mandated by Python's backwards-compatibility policy (see :pep:`387`).
For this example, imagine we're in the development phase for Python 3.12:
that means we'll be allowed to introduce deprecation warnings in Python 3.12
whenever the *b* parameter is passed positionally,
and we'll be allowed to make it keyword-only in Python 3.14 at the earliest.
whenever an argument for the *b* parameter is passed by keyword or an argument
for the *d* parameter is passed positionally, and we'll be allowed to make
them positional-only and keyword-only respectively in Python 3.14 at
the earliest.
We can use Argument Clinic to emit the desired deprecation warnings
using the ``* [from ...]`` syntax,
by adding the line ``* [from 3.14]`` right above the *b* parameter::
using the ``[from ...]`` syntax, by adding the line ``/ [from 3.14]`` right
below the *b* parameter and adding the line ``* [from 3.14]`` right above
the *d* parameter::
/*[clinic input]
module foo
myfunc
a: int
* [from 3.14]
/
b: int
*
/ [from 3.14]
c: int
* [from 3.14]
d: int
*
e: int
[clinic start generated output]*/
Next, regenerate Argument Clinic code (``make clinic``),
and add unit tests for the new behaviour.
The generated code will now emit a :exc:`DeprecationWarning`
when an :term:`argument` for the :term:`parameter` *b* is passed positionally.
when an :term:`argument` for the :term:`parameter` *d* is passed positionally
(e.g ``myfunc(1, 2, 3, 4, e=5)``) or an argument for the parameter *b* is
passed by keyword (e.g ``myfunc(1, b=2, c=3, d=4, e=5)``).
C preprocessor directives are also generated for emitting
compiler warnings if the ``* [from ...]`` line has not been removed
compiler warnings if the ``[from ...]`` lines have not been removed
from the Argument Clinic input when the deprecation period is over,
which means when the alpha phase of the specified Python version kicks in.
@ -2001,21 +2017,26 @@ Luckily for us, compiler warnings are now generated:
.. code-block:: none
In file included from Modules/foomodule.c:139:
Modules/clinic/foomodule.c.h:139:8: warning: In 'foomodule.c', update parameter(s) 'a' and 'b' in the clinic input of 'mymod.myfunc' to be keyword-only. [-W#warnings]
# warning "In 'foomodule.c', update parameter(s) 'a' and 'b' in the clinic input of 'mymod.myfunc' to be keyword-only. [-W#warnings]"
Modules/clinic/foomodule.c.h:139:8: warning: In 'foomodule.c', update the clinic input of 'mymod.myfunc'. [-W#warnings]
# warning "In 'foomodule.c', update the clinic input of 'mymod.myfunc'. [-W#warnings]"
^
We now close the deprecation phase by making *b* keyword-only;
replace the ``* [from ...]`` line above *b*
with the ``*`` from the line above *c*::
We now close the deprecation phase by making *a* positional-only and *c*
keyword-only;
replace the ``/ [from ...]`` line below *b* with the ``/`` from the line
below *a* and the ``* [from ...]`` line above *d* with the ``*`` from
the line above *e*::
/*[clinic input]
module foo
myfunc
a: int
*
b: int
/
c: int
*
d: int
e: int
[clinic start generated output]*/
Finally, run ``make clinic`` to regenerate the Argument Clinic code,