summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/whatsnew/3.7.rst5
-rw-r--r--Include/code.h7
-rw-r--r--Lib/test/test_collections.py3
-rw-r--r--Lib/test/test_compile.py11
-rw-r--r--Lib/test/test_keywordonlyarg.py24
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/codeobject.c20
-rw-r--r--Python/ast.c5
-rw-r--r--Python/ceval.c2
10 files changed, 33 insertions, 49 deletions
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 90ef759..ac3a151 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -75,8 +75,9 @@ New Features
Other Language Changes
======================
-* More than 255 arguments can now be passed to a function.
- (Contributed by Serhiy Storchaka in :issue:`12844`.)
+* More than 255 arguments can now be passed to a function, and a function can
+ now have more than 255 parameters.
+ (Contributed by Serhiy Storchaka in :issue:`12844` and :issue:`18896`.)
New Modules
diff --git a/Include/code.h b/Include/code.h
index c5fce3c..385258f 100644
--- a/Include/code.h
+++ b/Include/code.h
@@ -37,7 +37,7 @@ typedef struct {
for tracebacks and debuggers; otherwise, constant de-duplication
would collapse identical functions/lambdas defined on different lines.
*/
- unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
+ Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
@@ -84,9 +84,8 @@ typedef struct {
#define CO_FUTURE_GENERATOR_STOP 0x80000
/* This value is found in the co_cell2arg array when the associated cell
- variable does not correspond to an argument. The maximum number of
- arguments is 255 (indexed up to 254), so 255 work as a special flag.*/
-#define CO_CELL_NOT_AN_ARG 255
+ variable does not correspond to an argument. */
+#define CO_CELL_NOT_AN_ARG (-1)
/* This should be defined if a future statement modifies the syntax.
For example, when a keyword is added.
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 87454cc..76c7139 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -319,8 +319,7 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(Dot(1)._replace(d=999), (999,))
self.assertEqual(Dot(1)._fields, ('d',))
- # n = 5000
- n = 254 # SyntaxError: more than 255 arguments:
+ n = 5000
names = list(set(''.join([choice(string.ascii_letters)
for j in range(10)]) for i in range(n)))
n = len(names)
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 409ec86..4a7230f 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -401,16 +401,9 @@ if 1:
self.assertNotIn((Ellipsis, Ellipsis), d)
def test_annotation_limit(self):
- # 16 bits are available for # of annotations, but only 8 bits are
- # available for the parameter count, hence 255
- # is the max. Ensure the result of too many annotations is a
- # SyntaxError.
+ # more than 255 annotations, should compile ok
s = "def f(%s): pass"
- s %= ', '.join('a%d:%d' % (i,i) for i in range(256))
- self.assertRaises(SyntaxError, compile, s, '?', 'exec')
- # Test that the max # of annotations compiles.
- s = "def f(%s): pass"
- s %= ', '.join('a%d:%d' % (i,i) for i in range(255))
+ s %= ', '.join('a%d:%d' % (i,i) for i in range(300))
compile(s, '?', 'exec')
def test_mangling(self):
diff --git a/Lib/test/test_keywordonlyarg.py b/Lib/test/test_keywordonlyarg.py
index d82e33d..2cf8a89 100644
--- a/Lib/test/test_keywordonlyarg.py
+++ b/Lib/test/test_keywordonlyarg.py
@@ -51,24 +51,12 @@ class KeywordOnlyArgTestCase(unittest.TestCase):
self.assertRaisesSyntaxError("def f(p, *, (k1, k2), **kw):\n pass\n")
def testSyntaxForManyArguments(self):
- fundef = "def f("
- for i in range(255):
- fundef += "i%d, "%i
- fundef += "*, key=100):\n pass\n"
- self.assertRaisesSyntaxError(fundef)
-
- fundef2 = "def foo(i,*,"
- for i in range(255):
- fundef2 += "i%d, "%i
- fundef2 += "lastarg):\n pass\n"
- self.assertRaisesSyntaxError(fundef2)
-
- # exactly 255 arguments, should compile ok
- fundef3 = "def f(i,*,"
- for i in range(253):
- fundef3 += "i%d, "%i
- fundef3 += "lastarg):\n pass\n"
- compile(fundef3, "<test>", "single")
+ # more than 255 positional arguments, should compile ok
+ fundef = "def f(%s):\n pass\n" % ', '.join('i%d' % i for i in range(300))
+ compile(fundef, "<test>", "single")
+ # more than 255 keyword-only arguments, should compile ok
+ fundef = "def f(*, %s):\n pass\n" % ', '.join('i%d' % i for i in range(300))
+ compile(fundef, "<test>", "single")
def testTooManyPositionalErrorMessage(self):
def f(a, b=None, *, c=None):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 828421c..e6d8e50 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -926,7 +926,7 @@ class SizeofTest(unittest.TestCase):
def inner():
return x
return inner
- check(get_cell2.__code__, size('6i13P') + 1)
+ check(get_cell2.__code__, size('6i13P') + calcsize('n'))
# complex
check(complex(0,1), size('2d'))
# method_descriptor (descriptor object)
diff --git a/Misc/NEWS b/Misc/NEWS
index cbdef27..9d1ccfd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1
Core and Builtins
-----------------
+- Issue #18896: Python function can now have more than 255 parameters.
+ collections.namedtuple() now supports tuples with more than 255 elements.
+
- Issue #26919: On Android, operating system data is now always encoded/decoded
to/from UTF-8, instead of the locale encoding to avoid inconsistencies with
os.fsencode() and os.fsdecode() which are already using UTF-8.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 788818d..0857554 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -110,7 +110,7 @@ PyCode_New(int argcount, int kwonlyargcount,
PyObject *lnotab)
{
PyCodeObject *co;
- unsigned char *cell2arg = NULL;
+ Py_ssize_t *cell2arg = NULL;
Py_ssize_t i, n_cellvars;
/* Check argument types */
@@ -142,19 +142,25 @@ PyCode_New(int argcount, int kwonlyargcount,
if (n_cellvars) {
Py_ssize_t total_args = argcount + kwonlyargcount +
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
- Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars;
bool used_cell2arg = false;
- cell2arg = PyMem_MALLOC(alloc_size);
- if (cell2arg == NULL)
+ cell2arg = PyMem_NEW(Py_ssize_t, n_cellvars);
+ if (cell2arg == NULL) {
+ PyErr_NoMemory();
return NULL;
- memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size);
+ }
/* Find cells which are also arguments. */
for (i = 0; i < n_cellvars; i++) {
Py_ssize_t j;
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
+ cell2arg[i] = CO_CELL_NOT_AN_ARG;
for (j = 0; j < total_args; j++) {
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
- if (!PyUnicode_Compare(cell, arg)) {
+ int cmp = PyUnicode_Compare(cell, arg);
+ if (cmp == -1 && PyErr_Occurred()) {
+ PyMem_FREE(cell2arg);
+ return NULL;
+ }
+ if (cmp == 0) {
cell2arg[i] = j;
used_cell2arg = true;
break;
@@ -449,7 +455,7 @@ code_sizeof(PyCodeObject *co, void *unused)
res = _PyObject_SIZE(Py_TYPE(co));
if (co->co_cell2arg != NULL && co->co_cellvars != NULL)
- res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(unsigned char);
+ res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(Py_ssize_t);
return PyLong_FromSsize_t(res);
}
diff --git a/Python/ast.c b/Python/ast.c
index f07bb16..5c5738f 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -1411,11 +1411,6 @@ ast_for_arguments(struct compiling *c, const node *n)
if (!kwdefaults && nkwonlyargs)
return NULL;
- if (nposargs + nkwonlyargs > 255) {
- ast_error(c, n, "more than 255 arguments");
- return NULL;
- }
-
/* tfpdef: NAME [':' test]
vfpdef: NAME
*/
diff --git a/Python/ceval.c b/Python/ceval.c
index fc11117..f7ee041 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4100,7 +4100,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
vars into frame. */
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
PyObject *c;
- int arg;
+ Py_ssize_t arg;
/* Possibly account for the cell variable being an argument. */
if (co->co_cell2arg != NULL &&
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) {