Skip to content

Commit 98c738d

Browse files
committed
bpo-37122: Make co->co_argcount represent the total number of positional arguments in the code object
1 parent 6650105 commit 98c738d

File tree

13 files changed

+63
-68
lines changed

13 files changed

+63
-68
lines changed

Doc/c-api/code.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ bound into a function.
4242
4343
.. versionchanged:: 3.8
4444
An extra parameter is required (*posonlyargcount*) to support :PEP:`570`.
45+
The first parameter (*argcount*) now represents the total number of positional arguments,
46+
including positional-only.
4547
4648
.. audit-event:: code.__new__ "code filename name argcount kwonlyargcount nlocals stacksize flags"
4749

Doc/reference/datamodel.rst

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -907,24 +907,26 @@ Internal types
907907
single: co_freevars (code object attribute)
908908

909909
Special read-only attributes: :attr:`co_name` gives the function name;
910-
:attr:`co_argcount` is the number of positional arguments (including arguments
911-
with default values); :attr:`co_posonlyargcount` is the number of
912-
positional-only arguments (including arguments with default values);
913-
:attr:`co_kwonlyargcount` is the number of keyword-only arguments (including
914-
arguments with default values); :attr:`co_nlocals` is the number of local
915-
variables used by the function (including arguments); :attr:`co_varnames` is a
916-
tuple containing the names of the local variables (starting with the argument
917-
names); :attr:`co_cellvars` is a tuple containing the names of local variables
910+
:attr:`co_argcount` is the total number of positional arguments
911+
(including positional-only arguments and arguments with default values);
912+
:attr:`co_posonlyargcount` is the number of positional-only arguments
913+
(including arguments with default values); :attr:`co_kwonlyargcount` is
914+
the number of keyword-only arguments (including arguments with default
915+
values); :attr:`co_nlocals` is the number of local variables used by the
916+
function (including arguments); :attr:`co_varnames` is a tuple containing
917+
the names of the local variables (starting with the argument names);
918+
:attr:`co_cellvars` is a tuple containing the names of local variables
918919
that are referenced by nested functions; :attr:`co_freevars` is a tuple
919-
containing the names of free variables; :attr:`co_code` is a string representing
920-
the sequence of bytecode instructions; :attr:`co_consts` is a tuple containing
921-
the literals used by the bytecode; :attr:`co_names` is a tuple containing the
922-
names used by the bytecode; :attr:`co_filename` is the filename from which the
923-
code was compiled; :attr:`co_firstlineno` is the first line number of the
924-
function; :attr:`co_lnotab` is a string encoding the mapping from bytecode
925-
offsets to line numbers (for details see the source code of the interpreter);
926-
:attr:`co_stacksize` is the required stack size (including local variables);
927-
:attr:`co_flags` is an integer encoding a number of flags for the interpreter.
920+
containing the names of free variables; :attr:`co_code` is a string
921+
representing the sequence of bytecode instructions; :attr:`co_consts` is
922+
a tuple containing the literals used by the bytecode; :attr:`co_names` is
923+
a tuple containing the names used by the bytecode; :attr:`co_filename` is
924+
the filename from which the code was compiled; :attr:`co_firstlineno` is
925+
the first line number of the function; :attr:`co_lnotab` is a string
926+
encoding the mapping from bytecode offsets to line numbers (for details
927+
see the source code of the interpreter); :attr:`co_stacksize` is the
928+
required stack size (including local variables); :attr:`co_flags` is an
929+
integer encoding a number of flags for the interpreter.
928930

929931
.. index:: object: generator
930932

Doc/whatsnew/3.8.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,8 +1177,10 @@ Changes in the Python API
11771177

11781178
* :class:`types.CodeType` has a new parameter in the second position of the
11791179
constructor (*posonlyargcount*) to support positional-only arguments defined
1180-
in :pep:`570`. A new ``replace()`` method of :class:`types.CodeType` can be
1181-
used to make the code future-proof.
1180+
in :pep:`570`. The first argument (*argcount*) now represents the total
1181+
number of positional arguments (including positional-only arguments). A new
1182+
``replace()`` method of :class:`types.CodeType` can be used to make the code
1183+
future-proof.
11821184

11831185

11841186
Changes in the C API

Lib/inspect.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,15 +1037,11 @@ def getargs(co):
10371037

10381038
names = co.co_varnames
10391039
nargs = co.co_argcount
1040-
nposonlyargs = co.co_posonlyargcount
10411040
nkwargs = co.co_kwonlyargcount
1042-
nposargs = nargs + nposonlyargs
1043-
posonlyargs = list(names[:nposonlyargs])
1044-
args = list(names[nposonlyargs:nposonlyargs+nargs])
1045-
kwonlyargs = list(names[nposargs:nposargs+nkwargs])
1041+
args = list(names[:nargs])
1042+
kwonlyargs = list(names[nargs:nargs+nkwargs])
10461043
step = 0
10471044

1048-
nargs += nposonlyargs
10491045
nargs += nkwargs
10501046
varargs = None
10511047
if co.co_flags & CO_VARARGS:
@@ -1054,7 +1050,7 @@ def getargs(co):
10541050
varkw = None
10551051
if co.co_flags & CO_VARKEYWORDS:
10561052
varkw = co.co_varnames[nargs]
1057-
return Arguments(posonlyargs + args + kwonlyargs, varargs, varkw)
1053+
return Arguments(args + kwonlyargs, varargs, varkw)
10581054

10591055
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
10601056

@@ -2136,11 +2132,9 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21362132
pos_count = func_code.co_argcount
21372133
arg_names = func_code.co_varnames
21382134
posonly_count = func_code.co_posonlyargcount
2139-
positional_count = posonly_count + pos_count
2140-
positional_only = tuple(arg_names[:posonly_count])
2141-
positional = tuple(arg_names[posonly_count:positional_count])
2135+
positional = tuple(arg_names[:pos_count])
21422136
keyword_only_count = func_code.co_kwonlyargcount
2143-
keyword_only = arg_names[positional_count:(positional_count + keyword_only_count)]
2137+
keyword_only = arg_names[pos_count:(pos_count+ keyword_only_count)]
21442138
annotations = func.__annotations__
21452139
defaults = func.__defaults__
21462140
kwdefaults = func.__kwdefaults__
@@ -2152,13 +2146,11 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21522146

21532147
parameters = []
21542148

2155-
non_default_count = positional_count - pos_default_count
2156-
all_positional = positional_only + positional
2157-
2149+
non_default_count = pos_count - pos_default_count
21582150
posonly_left = posonly_count
21592151

21602152
# Non-keyword-only parameters w/o defaults.
2161-
for name in all_positional[:non_default_count]:
2153+
for name in positional[:non_default_count]:
21622154
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
21632155
annotation = annotations.get(name, _empty)
21642156
parameters.append(Parameter(name, annotation=annotation,
@@ -2167,7 +2159,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21672159
posonly_left -= 1
21682160

21692161
# ... w/ defaults.
2170-
for offset, name in enumerate(all_positional[non_default_count:]):
2162+
for offset, name in enumerate(positional[non_default_count:]):
21712163
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
21722164
annotation = annotations.get(name, _empty)
21732165
parameters.append(Parameter(name, annotation=annotation,
@@ -2178,7 +2170,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21782170

21792171
# *args
21802172
if func_code.co_flags & CO_VARARGS:
2181-
name = arg_names[positional_count + keyword_only_count]
2173+
name = arg_names[pos_count + keyword_only_count]
21822174
annotation = annotations.get(name, _empty)
21832175
parameters.append(Parameter(name, annotation=annotation,
21842176
kind=_VAR_POSITIONAL))
@@ -2195,7 +2187,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21952187
default=default))
21962188
# **kwargs
21972189
if func_code.co_flags & CO_VARKEYWORDS:
2198-
index = positional_count + keyword_only_count
2190+
index = pos_count + keyword_only_count
21992191
if func_code.co_flags & CO_VARARGS:
22002192
index += 1
22012193

Lib/pdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ def do_args(self, arg):
11321132
"""
11331133
co = self.curframe.f_code
11341134
dict = self.curframe_locals
1135-
n = co.co_argcount + co.co_posonlyargcount + co.co_kwonlyargcount
1135+
n = co.co_argcount + co.co_kwonlyargcount
11361136
if co.co_flags & inspect.CO_VARARGS: n = n+1
11371137
if co.co_flags & inspect.CO_VARKEYWORDS: n = n+1
11381138
for i in range(n):

Lib/test/test_code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
113113
>>> dump(posonly_args.__code__)
114114
name: posonly_args
115-
argcount: 1
115+
argcount: 3
116116
posonlyargcount: 2
117117
kwonlyargcount: 0
118118
names: ()

Lib/test/test_dis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ def f(c=c):
640640
code_info_tricky = """\
641641
Name: tricky
642642
Filename: (.*)
643-
Argument count: 3
643+
Argument count: 5
644644
Positional-only arguments: 2
645645
Kw-only arguments: 3
646646
Number of locals: 10

Lib/test/test_positional_only_arg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ def test_pos_only_definition(self):
100100
def f(a, b, c, /, d, e=1, *, f, g=2):
101101
pass
102102

103-
self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
103+
self.assertEqual(5, f.__code__.co_argcount) # 3 posonly + 2 "standard args"
104104
self.assertEqual(3, f.__code__.co_posonlyargcount)
105105
self.assertEqual((1,), f.__defaults__)
106106

107107
def f(a, b, c=1, /, d=2, e=3, *, f, g=4):
108108
pass
109109

110-
self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
110+
self.assertEqual(5, f.__code__.co_argcount) # 3 posonly + 2 "standard args"
111111
self.assertEqual(3, f.__code__.co_posonlyargcount)
112112
self.assertEqual((1, 2, 3), f.__defaults__)
113113

Objects/call.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,11 @@ _PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs
308308
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
309309
{
310310
/* Fast paths */
311-
if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount == nargs) {
311+
if (argdefs == NULL && co->co_argcount == nargs) {
312312
return function_code_fastcall(co, args, nargs, globals);
313313
}
314314
else if (nargs == 0 && argdefs != NULL
315-
&& co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
315+
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
316316
/* function called with no arguments, but all parameters have
317317
a default value: use default values as arguments .*/
318318
args = _PyTuple_ITEMS(argdefs);
@@ -396,11 +396,11 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
396396
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
397397
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
398398
{
399-
if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount== nargs) {
399+
if (argdefs == NULL && co->co_argcount == nargs) {
400400
return function_code_fastcall(co, stack, nargs, globals);
401401
}
402402
else if (nargs == 0 && argdefs != NULL
403-
&& co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
403+
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
404404
/* function called with no arguments, but all parameters have
405405
a default value: use default values as arguments .*/
406406
stack = _PyTuple_ITEMS(argdefs);

Objects/codeobject.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,10 @@ PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
152152
}
153153

154154
n_varnames = PyTuple_GET_SIZE(varnames);
155-
if (posonlyargcount + argcount <= n_varnames
155+
if (argcount <= n_varnames
156156
&& kwonlyargcount <= n_varnames) {
157157
/* Never overflows. */
158-
total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
159-
+ (Py_ssize_t)kwonlyargcount +
158+
total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
160159
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
161160
}
162161
else {

Objects/typeobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7807,7 +7807,7 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
78077807
"super(): no code object");
78087808
return -1;
78097809
}
7810-
if (co->co_posonlyargcount + co->co_argcount == 0) {
7810+
if (co->co_argcount == 0) {
78117811
PyErr_SetString(PyExc_RuntimeError,
78127812
"super(): no arguments");
78137813
return -1;

Python/ceval.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3757,10 +3757,10 @@ missing_arguments(PyThreadState *tstate, PyCodeObject *co,
37573757
return;
37583758
if (positional) {
37593759
start = 0;
3760-
end = co->co_posonlyargcount + co->co_argcount - defcount;
3760+
end = co->co_argcount - defcount;
37613761
}
37623762
else {
3763-
start = co->co_posonlyargcount + co->co_argcount;
3763+
start = co->co_argcount;
37643764
end = start + co->co_kwonlyargcount;
37653765
}
37663766
for (i = start; i < end; i++) {
@@ -3788,25 +3788,23 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co,
37883788
Py_ssize_t kwonly_given = 0;
37893789
Py_ssize_t i;
37903790
PyObject *sig, *kwonly_sig;
3791-
Py_ssize_t co_posonlyargcount = co->co_posonlyargcount;
37923791
Py_ssize_t co_argcount = co->co_argcount;
3793-
Py_ssize_t total_positional = co_argcount + co_posonlyargcount;
37943792

37953793
assert((co->co_flags & CO_VARARGS) == 0);
37963794
/* Count missing keyword-only args. */
3797-
for (i = total_positional; i < total_positional + co->co_kwonlyargcount; i++) {
3795+
for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) {
37983796
if (GETLOCAL(i) != NULL) {
37993797
kwonly_given++;
38003798
}
38013799
}
38023800
if (defcount) {
3803-
Py_ssize_t atleast = total_positional - defcount;
3801+
Py_ssize_t atleast = co_argcount - defcount;
38043802
plural = 1;
3805-
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, total_positional);
3803+
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount);
38063804
}
38073805
else {
3808-
plural = (total_positional != 1);
3809-
sig = PyUnicode_FromFormat("%zd", total_positional);
3806+
plural = (co_argcount != 1);
3807+
sig = PyUnicode_FromFormat("%zd", co_argcount);
38103808
}
38113809
if (sig == NULL)
38123810
return;
@@ -3917,7 +3915,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
39173915
PyObject *retval = NULL;
39183916
PyObject **fastlocals, **freevars;
39193917
PyObject *x, *u;
3920-
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
3918+
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
39213919
Py_ssize_t i, j, n;
39223920
PyObject *kwdict;
39233921

@@ -3954,7 +3952,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
39543952
}
39553953

39563954
/* Copy positional only arguments into local variables */
3957-
if (argcount > co->co_argcount + co->co_posonlyargcount) {
3955+
if (argcount > co->co_argcount) {
39583956
n = co->co_posonlyargcount;
39593957
}
39603958
else {
@@ -3968,8 +3966,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
39683966

39693967

39703968
/* Copy positional arguments into local variables */
3971-
if (argcount > co->co_argcount + co->co_posonlyargcount) {
3972-
n += co->co_argcount;
3969+
if (argcount > co->co_argcount) {
3970+
n = co->co_argcount;
39733971
}
39743972
else {
39753973
n = argcount;
@@ -4059,14 +4057,14 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
40594057
}
40604058

40614059
/* Check the number of positional arguments */
4062-
if ((argcount > co->co_argcount + co->co_posonlyargcount) && !(co->co_flags & CO_VARARGS)) {
4060+
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
40634061
too_many_positional(tstate, co, argcount, defcount, fastlocals);
40644062
goto fail;
40654063
}
40664064

40674065
/* Add missing positional arguments (copy default values from defs) */
4068-
if (argcount < co->co_posonlyargcount + co->co_argcount) {
4069-
Py_ssize_t m = co->co_posonlyargcount + co->co_argcount - defcount;
4066+
if (argcount < co->co_argcount) {
4067+
Py_ssize_t m = co->co_argcount - defcount;
40704068
Py_ssize_t missing = 0;
40714069
for (i = argcount; i < m; i++) {
40724070
if (GETLOCAL(i) == NULL) {
@@ -4093,7 +4091,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
40934091
/* Add missing keyword arguments (copy default values from kwdefs) */
40944092
if (co->co_kwonlyargcount > 0) {
40954093
Py_ssize_t missing = 0;
4096-
for (i = co->co_posonlyargcount + co->co_argcount; i < total_args; i++) {
4094+
for (i = co->co_argcount; i < total_args; i++) {
40974095
PyObject *name;
40984096
if (GETLOCAL(i) != NULL)
40994097
continue;

Python/compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5815,7 +5815,7 @@ makecode(struct compiler *c, struct assembler *a)
58155815
if (maxdepth < 0) {
58165816
goto error;
58175817
}
5818-
co = PyCode_New(argcount, posonlyargcount, kwonlyargcount,
5818+
co = PyCode_New(argcount+posonlyargcount, posonlyargcount, kwonlyargcount,
58195819
nlocals_int, maxdepth, flags,
58205820
bytecode, consts, names, varnames,
58215821
freevars, cellvars,

0 commit comments

Comments
 (0)