diff Python/getargs.c @ 75842:052779d34945

Issue #14328: Add keyword-only parameters to PyArg_ParseTupleAndKeywords. They're optional-only for now (unlike in pure Python) but that's all I needed. The syntax can easily be relaxed if we want to support required keyword-only arguments for extension types in the future.
author Larry Hastings <larry@hastings.org>
date Tue, 20 Mar 2012 20:06:16 +0000
parents d08f0f3ab23e
children bc6d28e726d8
line wrap: on
line diff
--- a/Python/getargs.c	Tue Mar 20 16:44:24 2012 +0100
+++ b/Python/getargs.c	Tue Mar 20 20:06:16 2012 +0000
@@ -1403,6 +1403,7 @@
     int levels[32];
     const char *fname, *msg, *custom_msg, *keyword;
     int min = INT_MAX;
+    int max = INT_MAX;
     int i, len, nargs, nkeywords;
     PyObject *current_arg;
     freelist_t freelist = {0, NULL};
@@ -1452,8 +1453,39 @@
     for (i = 0; i < len; i++) {
         keyword = kwlist[i];
         if (*format == '|') {
+            if (min != INT_MAX) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                "Invalid format string (| specified twice)");
+                return cleanreturn(0, &freelist);
+            }
+
             min = i;
             format++;
+
+            if (max != INT_MAX) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                "Invalid format string ($ before |)");
+                return cleanreturn(0, &freelist);
+            }
+        }
+        if (*format == '$') {
+            if (max != INT_MAX) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                "Invalid format string ($ specified twice)");
+                return cleanreturn(0, &freelist);
+            }
+
+            max = i;
+            format++;
+
+            if (max < nargs) {
+                PyErr_Format(PyExc_TypeError,
+                             "Function takes %s %d positional arguments"
+                             " (%d given)",
+                             (min != INT_MAX) ? "at most" : "exactly",
+                             max, nargs);
+                return cleanreturn(0, &freelist);
+            }
         }
         if (IS_END_OF_FORMAT(*format)) {
             PyErr_Format(PyExc_RuntimeError,
@@ -1514,7 +1546,7 @@
         }
     }
 
-    if (!IS_END_OF_FORMAT(*format) && *format != '|') {
+    if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
         PyErr_Format(PyExc_RuntimeError,
             "more argument specifiers than keyword list entries "
             "(remaining format:'%s')", format);