mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00
Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!"
format unit.
This commit is contained in:
parent
16c5191ab3
commit
77561cccb2
5 changed files with 4387 additions and 4396 deletions
|
@ -640,7 +640,7 @@ on the right is the text you'd replace it with.
|
||||||
``'K'`` ``unsigned_PY_LONG_LONG``
|
``'K'`` ``unsigned_PY_LONG_LONG``
|
||||||
``'L'`` ``PY_LONG_LONG``
|
``'L'`` ``PY_LONG_LONG``
|
||||||
``'n'`` ``Py_ssize_t``
|
``'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(converter='name_of_c_function')``
|
||||||
``'O'`` ``object``
|
``'O'`` ``object``
|
||||||
``'p'`` ``bool``
|
``'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
|
(But "legacy converters" don't support arguments. That's why we
|
||||||
skipped them for your first function.) The argument you specified
|
skipped them for your first function.) The argument you specified
|
||||||
to the format unit is now an argument to the converter; this
|
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``).
|
or ``encoding`` (for all the format units that start with ``e``).
|
||||||
|
|
||||||
Note that ``object()`` must explicitly support each Python type you specify
|
When using ``subclass_of``, you may also want to use the other
|
||||||
for the ``type`` argument. Currently it only supports ``str``. It should be
|
custom argument for ``object()``: ``type``, which lets you set the type
|
||||||
easy to add more, just edit ``Tools/clinic/clinic.py``, search for ``O!`` in
|
actually used for the parameter. For example, if you want to ensure
|
||||||
the text, and add more entries to the dict mapping types to strings just above it.
|
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
|
One possible problem with using Argument Clinic: it takes away some possible
|
||||||
units starting with ``e``. It used to be possible to decide at runtime what
|
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
|
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
|
be hard-coded at Argument-Clinic-preprocessing-time. This limitation is deliberate;
|
||||||
this format unit much easier, and may allow for future compile-time optimizations.
|
it made supporting this format unit much easier, and may allow for future optimizations.
|
||||||
This restriction does not seem unreasonable; CPython itself always passes in static
|
This restriction doesn't seem unreasonable; CPython itself always passes in static
|
||||||
hard-coded encoding strings for parameters whose format units start with ``e``.
|
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.
|
``self_converter`` or a subclass thereof.
|
||||||
|
|
||||||
What's the point? This lets you automatically cast ``self``
|
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?
|
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``,
|
If you only have one or two functions with the same type for ``self``,
|
||||||
|
|
|
@ -21,6 +21,9 @@ Library
|
||||||
Tools/Demos
|
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
|
- Issue #20144: Argument Clinic now supports simple symbolic constants
|
||||||
as parameter default values.
|
as parameter default values.
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ static Py_UCS4 getuchar(PyUnicodeObject *obj)
|
||||||
|
|
||||||
unicodedata.UCD.decimal
|
unicodedata.UCD.decimal
|
||||||
|
|
||||||
unichr: object(type='str')
|
unichr: object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')
|
||||||
default: object=NULL
|
default: object=NULL
|
||||||
/
|
/
|
||||||
|
|
||||||
|
@ -140,13 +140,13 @@ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__,
|
||||||
{"decimal", (PyCFunction)unicodedata_UCD_decimal, METH_VARARGS, unicodedata_UCD_decimal__doc__},
|
{"decimal", (PyCFunction)unicodedata_UCD_decimal, METH_VARARGS, unicodedata_UCD_decimal__doc__},
|
||||||
|
|
||||||
static PyObject *
|
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 *
|
static PyObject *
|
||||||
unicodedata_UCD_decimal(PyObject *self, PyObject *args)
|
unicodedata_UCD_decimal(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
PyObject *unichr;
|
PyUnicodeObject *unichr;
|
||||||
PyObject *default_value = NULL;
|
PyObject *default_value = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,
|
if (!PyArg_ParseTuple(args,
|
||||||
|
@ -160,8 +160,8 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value)
|
unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value)
|
||||||
/*[clinic checksum: 9576fa55f4ea0be82968af39dc9d0283e634beeb]*/
|
/*[clinic checksum: 73edde0e9cd5913ea174c4fa81504369761b7426]*/
|
||||||
{
|
{
|
||||||
PyUnicodeObject *v = (PyUnicodeObject *)unichr;
|
PyUnicodeObject *v = (PyUnicodeObject *)unichr;
|
||||||
int have_old = 0;
|
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'.
|
# by format units starting with 'e'.
|
||||||
encoding = None
|
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?
|
# Do we want an adjacent '_length' variable for this variable?
|
||||||
# Only used by format units ending with '#'.
|
# Only used by format units ending with '#'.
|
||||||
length = False
|
length = False
|
||||||
|
@ -1446,7 +1452,9 @@ class CConverter(metaclass=CConverterAutoRegister):
|
||||||
list.append(self.converter)
|
list.append(self.converter)
|
||||||
|
|
||||||
if self.encoding:
|
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)
|
legal_name = ensure_legal_c_identifier(self.name)
|
||||||
s = ("&" if self.parse_by_reference else "") + legal_name
|
s = ("&" if self.parse_by_reference else "") + legal_name
|
||||||
|
@ -1627,20 +1635,12 @@ class object_converter(CConverter):
|
||||||
type = 'PyObject *'
|
type = 'PyObject *'
|
||||||
format_unit = 'O'
|
format_unit = 'O'
|
||||||
|
|
||||||
def converter_init(self, *, type=None):
|
def converter_init(self, *, type=None, subclass_of=None):
|
||||||
if type:
|
if subclass_of:
|
||||||
assert isinstance(type, str)
|
|
||||||
assert type.isidentifier()
|
|
||||||
try:
|
|
||||||
type = eval(type)
|
|
||||||
# need more of these!
|
|
||||||
type = {
|
|
||||||
str: '&PyUnicode_Type',
|
|
||||||
}[type]
|
|
||||||
except NameError:
|
|
||||||
type = type
|
|
||||||
self.format_unit = 'O!'
|
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)
|
@add_legacy_c_converter('s#', length=True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue