[Python-checkins] cpython: Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!"

larry.hastings python-checkins at python.org
Tue Jan 7 21:13:46 CET 2014


http://hg.python.org/cpython/rev/ddb5cd3e0860
changeset:   88342:ddb5cd3e0860
user:        Larry Hastings <larry at hastings.org>
date:        Tue Jan 07 12:13:13 2014 -0800
summary:
  Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!"
format unit.

files:
  Doc/howto/clinic.rst   |    27 +-
  Misc/NEWS              |     3 +
  Modules/unicodedata.c  |    10 +-
  Python/importlib.h     |  8709 +++++++++++++--------------
  Tools/clinic/clinic.py |    28 +-
  5 files changed, 4384 insertions(+), 4393 deletions(-)


diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -640,7 +640,7 @@
 ``'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 @@
 (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 @@
 ``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``,
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,9 @@
 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.
 
diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c
--- a/Modules/unicodedata.c
+++ b/Modules/unicodedata.c
@@ -117,7 +117,7 @@
 
 unicodedata.UCD.decimal
 
-    unichr: object(type='str')
+    unichr: object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')
     default: object=NULL
     /
 
@@ -140,13 +140,13 @@
     {"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 @@
 }
 
 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;
diff --git a/Python/importlib.h b/Python/importlib.h
--- a/Python/importlib.h
+++ b/Python/importlib.h
[stripped]
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -1358,6 +1358,12 @@
     # 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 @@
             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 @@
     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)

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list