Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!"
format unit.
This commit is contained in:
parent
16c5191ab3
commit
77561cccb2
|
@ -640,7 +640,7 @@ on the right is the text you'd replace it with.
|
|||
``'K'`` ``unsigned_PY_LONG_LONG``
|
||||
``'L'`` ``PY_LONG_LONG``
|
||||
``'n'`` ``Py_ssize_t``
|
||||
``'O!'`` ``object(type='name_of_Python_type')``
|
||||
``'O!'`` ``object(subclass_of='&PySomething_Type')``
|
||||
``'O&'`` ``object(converter='name_of_c_function')``
|
||||
``'O'`` ``object``
|
||||
``'p'`` ``bool``
|
||||
|
@ -693,20 +693,22 @@ conversion functions, or types, or strings specifying an encoding.
|
|||
(But "legacy converters" don't support arguments. That's why we
|
||||
skipped them for your first function.) The argument you specified
|
||||
to the format unit is now an argument to the converter; this
|
||||
argument is either ``converter`` (for ``O&``), ``type`` (for ``O!``),
|
||||
argument is either ``converter`` (for ``O&``), ``subclass_of`` (for ``O!``),
|
||||
or ``encoding`` (for all the format units that start with ``e``).
|
||||
|
||||
Note that ``object()`` must explicitly support each Python type you specify
|
||||
for the ``type`` argument. Currently it only supports ``str``. It should be
|
||||
easy to add more, just edit ``Tools/clinic/clinic.py``, search for ``O!`` in
|
||||
the text, and add more entries to the dict mapping types to strings just above it.
|
||||
When using ``subclass_of``, you may also want to use the other
|
||||
custom argument for ``object()``: ``type``, which lets you set the type
|
||||
actually used for the parameter. For example, if you want to ensure
|
||||
that the object is a subclass of ``PyUnicode_Type``, you probably want
|
||||
to use the converter ``object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')``.
|
||||
|
||||
Note also that this approach takes away some possible flexibility for the format
|
||||
units starting with ``e``. It used to be possible to decide at runtime what
|
||||
One possible problem with using Argument Clinic: it takes away some possible
|
||||
flexibility for the format units starting with ``e``. When writing a
|
||||
``PyArg_Parse`` call by hand, you could theoretically decide at runtime what
|
||||
encoding string to pass in to :c:func:`PyArg_ParseTuple`. But now this string must
|
||||
be hard-coded at compile-time. This limitation is deliberate; it made supporting
|
||||
this format unit much easier, and may allow for future compile-time optimizations.
|
||||
This restriction does not seem unreasonable; CPython itself always passes in static
|
||||
be hard-coded at Argument-Clinic-preprocessing-time. This limitation is deliberate;
|
||||
it made supporting this format unit much easier, and may allow for future optimizations.
|
||||
This restriction doesn't seem unreasonable; CPython itself always passes in static
|
||||
hard-coded encoding strings for parameters whose format units start with ``e``.
|
||||
|
||||
|
||||
|
@ -796,7 +798,8 @@ block, and ensure that its converter is an instance of
|
|||
``self_converter`` or a subclass thereof.
|
||||
|
||||
What's the point? This lets you automatically cast ``self``
|
||||
from ``PyObject *`` to a custom type.
|
||||
from ``PyObject *`` to a custom type, just like ``object()``
|
||||
does with its ``type`` parameter.
|
||||
|
||||
How do you specify the custom type you want to cast ``self`` to?
|
||||
If you only have one or two functions with the same type for ``self``,
|
||||
|
|
|
@ -21,6 +21,9 @@ Library
|
|||
Tools/Demos
|
||||
-----------
|
||||
|
||||
- Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!"
|
||||
format unit.
|
||||
|
||||
- Issue #20144: Argument Clinic now supports simple symbolic constants
|
||||
as parameter default values.
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ static Py_UCS4 getuchar(PyUnicodeObject *obj)
|
|||
|
||||
unicodedata.UCD.decimal
|
||||
|
||||
unichr: object(type='str')
|
||||
unichr: object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')
|
||||
default: object=NULL
|
||||
/
|
||||
|
||||
|
@ -140,13 +140,13 @@ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__,
|
|||
{"decimal", (PyCFunction)unicodedata_UCD_decimal, METH_VARARGS, unicodedata_UCD_decimal__doc__},
|
||||
|
||||
static PyObject *
|
||||
unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value);
|
||||
unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value);
|
||||
|
||||
static PyObject *
|
||||
unicodedata_UCD_decimal(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *unichr;
|
||||
PyUnicodeObject *unichr;
|
||||
PyObject *default_value = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
|
@ -160,8 +160,8 @@ exit:
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value)
|
||||
/*[clinic checksum: 9576fa55f4ea0be82968af39dc9d0283e634beeb]*/
|
||||
unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value)
|
||||
/*[clinic checksum: 73edde0e9cd5913ea174c4fa81504369761b7426]*/
|
||||
{
|
||||
PyUnicodeObject *v = (PyUnicodeObject *)unichr;
|
||||
int have_old = 0;
|
||||
|
|
8715
Python/importlib.h
8715
Python/importlib.h
File diff suppressed because it is too large
Load Diff
|
@ -1358,6 +1358,12 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
# by format units starting with 'e'.
|
||||
encoding = None
|
||||
|
||||
# Should this object be required to be a subclass of a specific type?
|
||||
# If not None, should be a string representing a pointer to a
|
||||
# PyTypeObject (e.g. "&PyUnicode_Type").
|
||||
# Only used by the 'O!' format unit (and the "object" converter).
|
||||
subclass_of = None
|
||||
|
||||
# Do we want an adjacent '_length' variable for this variable?
|
||||
# Only used by format units ending with '#'.
|
||||
length = False
|
||||
|
@ -1446,7 +1452,9 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
list.append(self.converter)
|
||||
|
||||
if self.encoding:
|
||||
list.append(self.encoding)
|
||||
list.append(c_repr(self.encoding))
|
||||
elif self.subclass_of:
|
||||
list.append(self.subclass_of)
|
||||
|
||||
legal_name = ensure_legal_c_identifier(self.name)
|
||||
s = ("&" if self.parse_by_reference else "") + legal_name
|
||||
|
@ -1627,20 +1635,12 @@ class object_converter(CConverter):
|
|||
type = 'PyObject *'
|
||||
format_unit = 'O'
|
||||
|
||||
def converter_init(self, *, type=None):
|
||||
if type:
|
||||
assert isinstance(type, str)
|
||||
assert type.isidentifier()
|
||||
try:
|
||||
type = eval(type)
|
||||
# need more of these!
|
||||
type = {
|
||||
str: '&PyUnicode_Type',
|
||||
}[type]
|
||||
except NameError:
|
||||
type = type
|
||||
def converter_init(self, *, type=None, subclass_of=None):
|
||||
if subclass_of:
|
||||
self.format_unit = 'O!'
|
||||
self.encoding = type
|
||||
self.subclass_of = subclass_of
|
||||
if type is not None:
|
||||
self.type = type
|
||||
|
||||
|
||||
@add_legacy_c_converter('s#', length=True)
|
||||
|
|
Loading…
Reference in New Issue