summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/code.rst2
-rw-r--r--Doc/reference/datamodel.rst36
-rw-r--r--Doc/whatsnew/3.8.rst6
-rw-r--r--Lib/inspect.py28
-rwxr-xr-xLib/pdb.py2
-rw-r--r--Lib/test/test_code.py2
-rw-r--r--Lib/test/test_dis.py2
-rw-r--r--Lib/test/test_positional_only_arg.py4
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-06-01-16-53-41.bpo-37122.dZ3-NY.rst5
-rw-r--r--Objects/call.c8
-rw-r--r--Objects/codeobject.c11
-rw-r--r--Objects/typeobject.c2
-rw-r--r--Python/ceval.c46
-rw-r--r--Python/compile.c8
14 files changed, 74 insertions, 88 deletions
diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst
index 7aa91ee84d..92baa4c7df 100644
--- a/Doc/c-api/code.rst
+++ b/Doc/c-api/code.rst
@@ -42,6 +42,8 @@ bound into a function.
.. versionchanged:: 3.8
An extra parameter is required (*posonlyargcount*) to support :PEP:`570`.
+ The first parameter (*argcount*) now represents the total number of positional arguments,
+ including positional-only.
.. audit-event:: code.__new__ "code filename name argcount kwonlyargcount nlocals stacksize flags"
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index c566dfdf85..44017d8a55 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -907,24 +907,26 @@ Internal types
single: co_freevars (code object attribute)
Special read-only attributes: :attr:`co_name` gives the function name;
- :attr:`co_argcount` is the number of positional arguments (including arguments
- with default values); :attr:`co_posonlyargcount` is the number of
- positional-only arguments (including arguments with default values);
- :attr:`co_kwonlyargcount` is the number of keyword-only arguments (including
- arguments with default values); :attr:`co_nlocals` is the number of local
- variables used by the function (including arguments); :attr:`co_varnames` is a
- tuple containing the names of the local variables (starting with the argument
- names); :attr:`co_cellvars` is a tuple containing the names of local variables
+ :attr:`co_argcount` is the total number of positional arguments
+ (including positional-only arguments and arguments with default values);
+ :attr:`co_posonlyargcount` is the number of positional-only arguments
+ (including arguments with default values); :attr:`co_kwonlyargcount` is
+ the number of keyword-only arguments (including arguments with default
+ values); :attr:`co_nlocals` is the number of local variables used by the
+ function (including arguments); :attr:`co_varnames` is a tuple containing
+ the names of the local variables (starting with the argument names);
+ :attr:`co_cellvars` is a tuple containing the names of local variables
that are referenced by nested functions; :attr:`co_freevars` is a tuple
- containing the names of free variables; :attr:`co_code` is a string representing
- the sequence of bytecode instructions; :attr:`co_consts` is a tuple containing
- the literals used by the bytecode; :attr:`co_names` is a tuple containing the
- names used by the bytecode; :attr:`co_filename` is the filename from which the
- code was compiled; :attr:`co_firstlineno` is the first line number of the
- function; :attr:`co_lnotab` is a string encoding the mapping from bytecode
- offsets to line numbers (for details see the source code of the interpreter);
- :attr:`co_stacksize` is the required stack size (including local variables);
- :attr:`co_flags` is an integer encoding a number of flags for the interpreter.
+ containing the names of free variables; :attr:`co_code` is a string
+ representing the sequence of bytecode instructions; :attr:`co_consts` is
+ a tuple containing the literals used by the bytecode; :attr:`co_names` is
+ a tuple containing the names used by the bytecode; :attr:`co_filename` is
+ the filename from which the code was compiled; :attr:`co_firstlineno` is
+ the first line number of the function; :attr:`co_lnotab` is a string
+ encoding the mapping from bytecode offsets to line numbers (for details
+ see the source code of the interpreter); :attr:`co_stacksize` is the
+ required stack size (including local variables); :attr:`co_flags` is an
+ integer encoding a number of flags for the interpreter.
.. index:: object: generator
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 2d5291102d..4c5a9bb0cd 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -1177,8 +1177,10 @@ Changes in the Python API
* :class:`types.CodeType` has a new parameter in the second position of the
constructor (*posonlyargcount*) to support positional-only arguments defined
- in :pep:`570`. A new ``replace()`` method of :class:`types.CodeType` can be
- used to make the code future-proof.
+ in :pep:`570`. The first argument (*argcount*) now represents the total
+ number of positional arguments (including positional-only arguments). A new
+ ``replace()`` method of :class:`types.CodeType` can be used to make the code
+ future-proof.
Changes in the C API
diff --git a/Lib/inspect.py b/Lib/inspect.py
index ca81a24f06..91d209dc64 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1037,15 +1037,11 @@ def getargs(co):
names = co.co_varnames
nargs = co.co_argcount
- nposonlyargs = co.co_posonlyargcount
nkwargs = co.co_kwonlyargcount
- nposargs = nargs + nposonlyargs
- posonlyargs = list(names[:nposonlyargs])
- args = list(names[nposonlyargs:nposonlyargs+nargs])
- kwonlyargs = list(names[nposargs:nposargs+nkwargs])
+ args = list(names[:nargs])
+ kwonlyargs = list(names[nargs:nargs+nkwargs])
step = 0
- nargs += nposonlyargs
nargs += nkwargs
varargs = None
if co.co_flags & CO_VARARGS:
@@ -1054,7 +1050,7 @@ def getargs(co):
varkw = None
if co.co_flags & CO_VARKEYWORDS:
varkw = co.co_varnames[nargs]
- return Arguments(posonlyargs + args + kwonlyargs, varargs, varkw)
+ return Arguments(args + kwonlyargs, varargs, varkw)
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
@@ -2136,11 +2132,9 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
pos_count = func_code.co_argcount
arg_names = func_code.co_varnames
posonly_count = func_code.co_posonlyargcount
- positional_count = posonly_count + pos_count
- positional_only = tuple(arg_names[:posonly_count])
- positional = tuple(arg_names[posonly_count:positional_count])
+ positional = arg_names[:pos_count]
keyword_only_count = func_code.co_kwonlyargcount
- keyword_only = arg_names[positional_count:(positional_count + keyword_only_count)]
+ keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
annotations = func.__annotations__
defaults = func.__defaults__
kwdefaults = func.__kwdefaults__
@@ -2152,13 +2146,11 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
parameters = []
- non_default_count = positional_count - pos_default_count
- all_positional = positional_only + positional
-
+ non_default_count = pos_count - pos_default_count
posonly_left = posonly_count
# Non-keyword-only parameters w/o defaults.
- for name in all_positional[:non_default_count]:
+ for name in positional[:non_default_count]:
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation,
@@ -2167,7 +2159,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
posonly_left -= 1
# ... w/ defaults.
- for offset, name in enumerate(all_positional[non_default_count:]):
+ for offset, name in enumerate(positional[non_default_count:]):
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation,
@@ -2178,7 +2170,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
# *args
if func_code.co_flags & CO_VARARGS:
- name = arg_names[positional_count + keyword_only_count]
+ name = arg_names[pos_count + keyword_only_count]
annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation,
kind=_VAR_POSITIONAL))
@@ -2195,7 +2187,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
default=default))
# **kwargs
if func_code.co_flags & CO_VARKEYWORDS:
- index = positional_count + keyword_only_count
+ index = pos_count + keyword_only_count
if func_code.co_flags & CO_VARARGS:
index += 1
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 13068ce27b..0e7609e43d 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -1132,7 +1132,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
"""
co = self.curframe.f_code
dict = self.curframe_locals
- n = co.co_argcount + co.co_posonlyargcount + co.co_kwonlyargcount
+ n = co.co_argcount + co.co_kwonlyargcount
if co.co_flags & inspect.CO_VARARGS: n = n+1
if co.co_flags & inspect.CO_VARKEYWORDS: n = n+1
for i in range(n):
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 91008c04f7..0d80af44d9 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -112,7 +112,7 @@ consts: ('None',)
>>> dump(posonly_args.__code__)
name: posonly_args
-argcount: 1
+argcount: 3
posonlyargcount: 2
kwonlyargcount: 0
names: ()
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 1561021f5b..652af45d55 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -640,7 +640,7 @@ def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
code_info_tricky = """\
Name: tricky
Filename: (.*)
-Argument count: 3
+Argument count: 5
Positional-only arguments: 2
Kw-only arguments: 3
Number of locals: 10
diff --git a/Lib/test/test_positional_only_arg.py b/Lib/test/test_positional_only_arg.py
index 0aaad84cb3..59b0b8fb55 100644
--- a/Lib/test/test_positional_only_arg.py
+++ b/Lib/test/test_positional_only_arg.py
@@ -100,14 +100,14 @@ class PositionalOnlyTestCase(unittest.TestCase):
def f(a, b, c, /, d, e=1, *, f, g=2):
pass
- self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
+ self.assertEqual(5, f.__code__.co_argcount) # 3 posonly + 2 "standard args"
self.assertEqual(3, f.__code__.co_posonlyargcount)
self.assertEqual((1,), f.__defaults__)
def f(a, b, c=1, /, d=2, e=3, *, f, g=4):
pass
- self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
+ self.assertEqual(5, f.__code__.co_argcount) # 3 posonly + 2 "standard args"
self.assertEqual(3, f.__code__.co_posonlyargcount)
self.assertEqual((1, 2, 3), f.__defaults__)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-06-01-16-53-41.bpo-37122.dZ3-NY.rst b/Misc/NEWS.d/next/Core and Builtins/2019-06-01-16-53-41.bpo-37122.dZ3-NY.rst
new file mode 100644
index 0000000000..b9584b50e6
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-06-01-16-53-41.bpo-37122.dZ3-NY.rst
@@ -0,0 +1,5 @@
+Make the *co_argcount* attribute of code objects represent the total number
+of positional arguments (including positional-only arguments). The value of
+*co_posonlyargcount* can be used to distinguish which arguments are
+positional only, and the difference (*co_argcount* - *co_posonlyargcount*)
+is the number of positional-or-keyword arguments. Patch by Pablo Galindo.
diff --git a/Objects/call.c b/Objects/call.c
index acd1f26dcb..c0d14567e4 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -308,11 +308,11 @@ _PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{
/* Fast paths */
- if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount == nargs) {
+ if (argdefs == NULL && co->co_argcount == nargs) {
return function_code_fastcall(co, args, nargs, globals);
}
else if (nargs == 0 && argdefs != NULL
- && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
+ && co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
/* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/
args = _PyTuple_ITEMS(argdefs);
@@ -396,11 +396,11 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{
- if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount== nargs) {
+ if (argdefs == NULL && co->co_argcount == nargs) {
return function_code_fastcall(co, stack, nargs, globals);
}
else if (nargs == 0 && argdefs != NULL
- && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
+ && co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
/* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/
stack = _PyTuple_ITEMS(argdefs);
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 886ce41944..bf68e54f42 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -114,8 +114,9 @@ PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
Py_ssize_t i, n_cellvars, n_varnames, total_args;
/* Check argument types */
- if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 ||
- nlocals < 0 || stacksize < 0 || flags < 0 ||
+ if (argcount < posonlyargcount || posonlyargcount < 0 ||
+ kwonlyargcount < 0 || nlocals < 0 ||
+ stacksize < 0 || flags < 0 ||
code == NULL || !PyBytes_Check(code) ||
consts == NULL || !PyTuple_Check(consts) ||
names == NULL || !PyTuple_Check(names) ||
@@ -152,11 +153,9 @@ PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
}
n_varnames = PyTuple_GET_SIZE(varnames);
- if (posonlyargcount + argcount <= n_varnames
- && kwonlyargcount <= n_varnames) {
+ if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
/* Never overflows. */
- total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
- + (Py_ssize_t)kwonlyargcount +
+ total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
}
else {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index da249b569a..b6d925c144 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -7807,7 +7807,7 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
"super(): no code object");
return -1;
}
- if (co->co_posonlyargcount + co->co_argcount == 0) {
+ if (co->co_argcount == 0) {
PyErr_SetString(PyExc_RuntimeError,
"super(): no arguments");
return -1;
diff --git a/Python/ceval.c b/Python/ceval.c
index f9ff4e09f1..d9a71e9421 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3757,10 +3757,10 @@ missing_arguments(PyThreadState *tstate, PyCodeObject *co,
return;
if (positional) {
start = 0;
- end = co->co_posonlyargcount + co->co_argcount - defcount;
+ end = co->co_argcount - defcount;
}
else {
- start = co->co_posonlyargcount + co->co_argcount;
+ start = co->co_argcount;
end = start + co->co_kwonlyargcount;
}
for (i = start; i < end; i++) {
@@ -3788,25 +3788,23 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co,
Py_ssize_t kwonly_given = 0;
Py_ssize_t i;
PyObject *sig, *kwonly_sig;
- Py_ssize_t co_posonlyargcount = co->co_posonlyargcount;
Py_ssize_t co_argcount = co->co_argcount;
- Py_ssize_t total_positional = co_argcount + co_posonlyargcount;
assert((co->co_flags & CO_VARARGS) == 0);
/* Count missing keyword-only args. */
- for (i = total_positional; i < total_positional + co->co_kwonlyargcount; i++) {
+ for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) {
if (GETLOCAL(i) != NULL) {
kwonly_given++;
}
}
if (defcount) {
- Py_ssize_t atleast = total_positional - defcount;
+ Py_ssize_t atleast = co_argcount - defcount;
plural = 1;
- sig = PyUnicode_FromFormat("from %zd to %zd", atleast, total_positional);
+ sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount);
}
else {
- plural = (total_positional != 1);
- sig = PyUnicode_FromFormat("%zd", total_positional);
+ plural = (co_argcount != 1);
+ sig = PyUnicode_FromFormat("%zd", co_argcount);
}
if (sig == NULL)
return;
@@ -3917,7 +3915,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject *retval = NULL;
PyObject **fastlocals, **freevars;
PyObject *x, *u;
- const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
+ const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
Py_ssize_t i, j, n;
PyObject *kwdict;
@@ -3953,9 +3951,9 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
kwdict = NULL;
}
- /* Copy positional only arguments into local variables */
- if (argcount > co->co_argcount + co->co_posonlyargcount) {
- n = co->co_posonlyargcount;
+ /* Copy all positional arguments into local variables */
+ if (argcount > co->co_argcount) {
+ n = co->co_argcount;
}
else {
n = argcount;
@@ -3966,20 +3964,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
SETLOCAL(j, x);
}
-
- /* Copy positional arguments into local variables */
- if (argcount > co->co_argcount + co->co_posonlyargcount) {
- n += co->co_argcount;
- }
- else {
- n = argcount;
- }
- for (i = j; i < n; i++) {
- x = args[i];
- Py_INCREF(x);
- SETLOCAL(i, x);
- }
-
/* Pack other positional arguments into the *args argument */
if (co->co_flags & CO_VARARGS) {
u = _PyTuple_FromArray(args + n, argcount - n);
@@ -4059,14 +4043,14 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
/* Check the number of positional arguments */
- if ((argcount > co->co_argcount + co->co_posonlyargcount) && !(co->co_flags & CO_VARARGS)) {
+ if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
too_many_positional(tstate, co, argcount, defcount, fastlocals);
goto fail;
}
/* Add missing positional arguments (copy default values from defs) */
- if (argcount < co->co_posonlyargcount + co->co_argcount) {
- Py_ssize_t m = co->co_posonlyargcount + co->co_argcount - defcount;
+ if (argcount < co->co_argcount) {
+ Py_ssize_t m = co->co_argcount - defcount;
Py_ssize_t missing = 0;
for (i = argcount; i < m; i++) {
if (GETLOCAL(i) == NULL) {
@@ -4093,7 +4077,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
/* Add missing keyword arguments (copy default values from kwdefs) */
if (co->co_kwonlyargcount > 0) {
Py_ssize_t missing = 0;
- for (i = co->co_posonlyargcount + co->co_argcount; i < total_args; i++) {
+ for (i = co->co_argcount; i < total_args; i++) {
PyObject *name;
if (GETLOCAL(i) != NULL)
continue;
diff --git a/Python/compile.c b/Python/compile.c
index f6ec929b3c..9e4a2094ac 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -5764,7 +5764,7 @@ makecode(struct compiler *c, struct assembler *a)
Py_ssize_t nlocals;
int nlocals_int;
int flags;
- int argcount, posonlyargcount, kwonlyargcount, maxdepth;
+ int posorkeywordargcount, posonlyargcount, kwonlyargcount, maxdepth;
consts = consts_dict_keys_inorder(c->u->u_consts);
names = dict_keys_inorder(c->u->u_names, 0);
@@ -5808,15 +5808,15 @@ makecode(struct compiler *c, struct assembler *a)
goto error;
}
- argcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
posonlyargcount = Py_SAFE_DOWNCAST(c->u->u_posonlyargcount, Py_ssize_t, int);
+ posorkeywordargcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
maxdepth = stackdepth(c);
if (maxdepth < 0) {
goto error;
}
- co = PyCode_New(argcount, posonlyargcount, kwonlyargcount,
- nlocals_int, maxdepth, flags,
+ co = PyCode_New(posonlyargcount+posorkeywordargcount, posonlyargcount,
+ kwonlyargcount, nlocals_int, maxdepth, flags,
bytecode, consts, names, varnames,
freevars, cellvars,
c->c_filename, c->u->u_name,