bpo-36540: PEP 570 -- Implementation (GH-12701)

This commit contains the implementation of PEP570: Python positional-only parameters.

* Update Grammar/Grammar with new typedarglist and varargslist

* Regenerate grammar files

* Update and regenerate AST related files

* Update code object

* Update marshal.c

* Update compiler and symtable

* Regenerate importlib files

* Update callable objects

* Implement positional-only args logic in ceval.c

* Regenerate frozen data

* Update standard library to account for positional-only args

* Add test file for positional-only args

* Update other test files to account for positional-only args

* Add News entry

* Update inspect module and related tests
This commit is contained in:
Pablo Galindo 2019-04-29 13:36:57 +01:00 committed by GitHub
parent 99fcc616d4
commit 8c77b8cb91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 5771 additions and 4710 deletions

View File

@ -22,13 +22,55 @@ async_funcdef: ASYNC funcdef
funcdef: 'def' NAME parameters ['->' test] ':' [TYPE_COMMENT] func_body_suite funcdef: 'def' NAME parameters ['->' test] ':' [TYPE_COMMENT] func_body_suite
parameters: '(' [typedargslist] ')' parameters: '(' [typedargslist] ')'
typedargslist: (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
# The following definition for typedarglist is equivalent to this set of rules:
#
# arguments = argument (',' [TYPE_COMMENT] argument)*
# argument = tfpdef ['=' test]
# kwargs = '**' tfpdef [','] [TYPE_COMMENT]
# args = '*' [tfpdef]
# kwonly_kwargs = (',' [TYPE_COMMENT] argument)* (TYPE_COMMENT | [',' [TYPE_COMMENT] [kwargs]])
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
# poskeyword_args_kwonly_kwargs = arguments ( TYPE_COMMENT | [',' [TYPE_COMMENT] [args_kwonly_kwargs]])
# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
# typedarglist = (arguments ',' [TYPE_COMMENT] '/' [',' [[TYPE_COMMENT] typedargslist_no_posonly]])|(typedargslist_no_posonly)"
#
# It needs to be fully expanded to allow our LL(1) parser to work on it.
typedargslist: (
(tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* ',' [TYPE_COMMENT] '/' [',' [ [TYPE_COMMENT] tfpdef ['=' test] (
',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
'*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
| '**' tfpdef [','] [TYPE_COMMENT]]]) | '**' tfpdef [','] [TYPE_COMMENT]]])
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) | '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
| '**' tfpdef [','] [TYPE_COMMENT]]] )
| (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
'*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
| '**' tfpdef [','] [TYPE_COMMENT]]])
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
| '**' tfpdef [','] [TYPE_COMMENT]) | '**' tfpdef [','] [TYPE_COMMENT])
)
tfpdef: NAME [':' test] tfpdef: NAME [':' test]
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
# The following definition for varargslist is equivalent to this set of rules:
#
# arguments = argument (',' argument )*
# argument = vfpdef ['=' test]
# kwargs = '**' vfpdef [',']
# args = '*' [vfpdef]
# kwonly_kwargs = (',' argument )* [',' [kwargs]]
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly)
#
# It needs to be fully expanded to allow our LL(1) parser to work on it.
varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']]]
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']) ]] | (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']]] | '**' vfpdef [',']]]
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]

10
Include/Python-ast.h generated
View File

@ -427,6 +427,7 @@ struct _excepthandler {
struct _arguments { struct _arguments {
asdl_seq *args; asdl_seq *args;
asdl_seq *posonlyargs;
arg_ty vararg; arg_ty vararg;
asdl_seq *kwonlyargs; asdl_seq *kwonlyargs;
asdl_seq *kw_defaults; asdl_seq *kw_defaults;
@ -684,10 +685,11 @@ excepthandler_ty _Py_ExceptHandler(expr_ty type, identifier name, asdl_seq *
body, int lineno, int col_offset, int body, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena end_lineno, int end_col_offset, PyArena
*arena); *arena);
#define arguments(a0, a1, a2, a3, a4, a5, a6) _Py_arguments(a0, a1, a2, a3, a4, a5, a6) #define arguments(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arguments(a0, a1, a2, a3, a4, a5, a6, a7)
arguments_ty _Py_arguments(asdl_seq * args, arg_ty vararg, asdl_seq * arguments_ty _Py_arguments(asdl_seq * args, asdl_seq * posonlyargs, arg_ty
kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, vararg, asdl_seq * kwonlyargs, asdl_seq *
asdl_seq * defaults, PyArena *arena); kw_defaults, arg_ty kwarg, asdl_seq * defaults,
PyArena *arena);
#define arg(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arg(a0, a1, a2, a3, a4, a5, a6, a7) #define arg(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arg(a0, a1, a2, a3, a4, a5, a6, a7)
arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int
lineno, int col_offset, int end_lineno, int end_col_offset, lineno, int col_offset, int end_lineno, int end_col_offset,

View File

@ -21,6 +21,7 @@ typedef uint16_t _Py_CODEUNIT;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
int co_argcount; /* #arguments, except *args */ int co_argcount; /* #arguments, except *args */
int co_posonlyargcount; /* #positional only arguments */
int co_kwonlyargcount; /* #keyword only arguments */ int co_kwonlyargcount; /* #keyword only arguments */
int co_nlocals; /* #local variables */ int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */ int co_stacksize; /* #entries needed for evaluation stack */
@ -102,7 +103,7 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
/* Public interface */ /* Public interface */
PyAPI_FUNC(PyCodeObject *) PyCode_New( PyAPI_FUNC(PyCodeObject *) PyCode_New(
int, int, int, int, int, PyObject *, PyObject *, int, int, int, int, int, int, PyObject *, PyObject *,
PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *,
PyObject *, PyObject *, int, PyObject *); PyObject *, PyObject *, int, PyObject *);
/* same as struct above */ /* same as struct above */

View File

@ -80,9 +80,9 @@ class PythonValuesTestCase(unittest.TestCase):
continue continue
items.append((entry.name.decode("ascii"), entry.size)) items.append((entry.name.decode("ascii"), entry.size))
expected = [("__hello__", 139), expected = [("__hello__", 141),
("__phello__", -139), ("__phello__", -141),
("__phello__.spam", 139), ("__phello__.spam", 141),
] ]
self.assertEqual(items, expected, "PyImport_FrozenModules example " self.assertEqual(items, expected, "PyImport_FrozenModules example "
"in Doc/library/ctypes.rst may be out of date") "in Doc/library/ctypes.rst may be out of date")

View File

@ -157,6 +157,7 @@ def _format_code_info(co):
lines.append("Name: %s" % co.co_name) lines.append("Name: %s" % co.co_name)
lines.append("Filename: %s" % co.co_filename) lines.append("Filename: %s" % co.co_filename)
lines.append("Argument count: %s" % co.co_argcount) lines.append("Argument count: %s" % co.co_argcount)
lines.append("Positional-only arguments: %s" % co.co_posonlyargcount)
lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount) lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
lines.append("Number of locals: %s" % co.co_nlocals) lines.append("Number of locals: %s" % co.co_nlocals)
lines.append("Stack size: %s" % co.co_stacksize) lines.append("Stack size: %s" % co.co_stacksize)

View File

@ -265,6 +265,7 @@ _code_type = type(_write_atomic.__code__)
# this might affected the first line number #32911) # this might affected the first line number #32911)
# Python 3.8a1 3400 (move frame block handling to compiler #17611) # Python 3.8a1 3400 (move frame block handling to compiler #17611)
# Python 3.8a1 3401 (add END_ASYNC_FOR #33041) # Python 3.8a1 3401 (add END_ASYNC_FOR #33041)
# Python 3.8a1 3410 (PEP570 Python Positional-Only Parameters #36540)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually # longer be understood by older implementations of the eval loop (usually
@ -273,7 +274,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3401).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3410).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View File

@ -272,6 +272,7 @@ def iscode(object):
| 16=nested | 32=generator | 64=nofree | 128=coroutine | 16=nested | 32=generator | 64=nofree | 128=coroutine
| 256=iterable_coroutine | 512=async_generator | 256=iterable_coroutine | 512=async_generator
co_freevars tuple of names of free variables co_freevars tuple of names of free variables
co_posonlyargcount number of positional only arguments
co_kwonlyargcount number of keyword only arguments (not including ** arg) co_kwonlyargcount number of keyword only arguments (not including ** arg)
co_lnotab encoded mapping of line numbers to bytecode indices co_lnotab encoded mapping of line numbers to bytecode indices
co_name name with which this code object was defined co_name name with which this code object was defined
@ -1031,26 +1032,20 @@ def getargs(co):
'args' is the list of argument names. Keyword-only arguments are 'args' is the list of argument names. Keyword-only arguments are
appended. 'varargs' and 'varkw' are the names of the * and ** appended. 'varargs' and 'varkw' are the names of the * and **
arguments or None.""" arguments or None."""
args, varargs, kwonlyargs, varkw = _getfullargs(co)
return Arguments(args + kwonlyargs, varargs, varkw)
def _getfullargs(co):
"""Get information about the arguments accepted by a code object.
Four things are returned: (args, varargs, kwonlyargs, varkw), where
'args' and 'kwonlyargs' are lists of argument names, and 'varargs'
and 'varkw' are the names of the * and ** arguments or None."""
if not iscode(co): if not iscode(co):
raise TypeError('{!r} is not a code object'.format(co)) raise TypeError('{!r} is not a code object'.format(co))
nargs = co.co_argcount
names = co.co_varnames names = co.co_varnames
nargs = co.co_argcount
nposonlyargs = co.co_posonlyargcount
nkwargs = co.co_kwonlyargcount nkwargs = co.co_kwonlyargcount
args = list(names[:nargs]) nposargs = nargs + nposonlyargs
kwonlyargs = list(names[nargs:nargs+nkwargs]) posonlyargs = list(names[:nposonlyargs])
args = list(names[nposonlyargs:nposonlyargs+nargs])
kwonlyargs = list(names[nposargs:nposargs+nkwargs])
step = 0 step = 0
nargs += nposonlyargs
nargs += nkwargs nargs += nkwargs
varargs = None varargs = None
if co.co_flags & CO_VARARGS: if co.co_flags & CO_VARARGS:
@ -1059,8 +1054,7 @@ def _getfullargs(co):
varkw = None varkw = None
if co.co_flags & CO_VARKEYWORDS: if co.co_flags & CO_VARKEYWORDS:
varkw = co.co_varnames[nargs] varkw = co.co_varnames[nargs]
return args, varargs, kwonlyargs, varkw return Arguments(posonlyargs + args + kwonlyargs, varargs, varkw)
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
@ -1087,15 +1081,16 @@ def getargspec(func):
warnings.warn("inspect.getargspec() is deprecated since Python 3.0, " warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
"use inspect.signature() or inspect.getfullargspec()", "use inspect.signature() or inspect.getfullargspec()",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ args, varargs, varkw, defaults, posonlyargs, kwonlyargs, \
getfullargspec(func) kwonlydefaults, ann = getfullargspec(func)
if kwonlyargs or ann: if posonlyargs or kwonlyargs or ann:
raise ValueError("Function has keyword-only parameters or annotations" raise ValueError("Function has positional-only, keyword-only parameters"
", use getfullargspec() API which can support them") " or annotations, use getfullargspec() API which can"
" support them")
return ArgSpec(args, varargs, varkw, defaults) return ArgSpec(args, varargs, varkw, defaults)
FullArgSpec = namedtuple('FullArgSpec', FullArgSpec = namedtuple('FullArgSpec',
'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations') 'args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, annotations')
def getfullargspec(func): def getfullargspec(func):
"""Get the names and default values of a callable object's parameters. """Get the names and default values of a callable object's parameters.
@ -1145,6 +1140,7 @@ def getfullargspec(func):
args = [] args = []
varargs = None varargs = None
varkw = None varkw = None
posonlyargs = []
kwonlyargs = [] kwonlyargs = []
defaults = () defaults = ()
annotations = {} annotations = {}
@ -1159,7 +1155,9 @@ def getfullargspec(func):
name = param.name name = param.name
if kind is _POSITIONAL_ONLY: if kind is _POSITIONAL_ONLY:
args.append(name) posonlyargs.append(name)
if param.default is not param.empty:
defaults += (param.default,)
elif kind is _POSITIONAL_OR_KEYWORD: elif kind is _POSITIONAL_OR_KEYWORD:
args.append(name) args.append(name)
if param.default is not param.empty: if param.default is not param.empty:
@ -1185,7 +1183,7 @@ def getfullargspec(func):
defaults = None defaults = None
return FullArgSpec(args, varargs, varkw, defaults, return FullArgSpec(args, varargs, varkw, defaults,
kwonlyargs, kwdefaults, annotations) posonlyargs, kwonlyargs, kwdefaults, annotations)
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
@ -1216,7 +1214,8 @@ def formatannotationrelativeto(object):
return _formatannotation return _formatannotation
def formatargspec(args, varargs=None, varkw=None, defaults=None, def formatargspec(args, varargs=None, varkw=None, defaults=None,
kwonlyargs=(), kwonlydefaults={}, annotations={}, posonlyargs=(), kwonlyargs=(), kwonlydefaults={},
annotations={},
formatarg=str, formatarg=str,
formatvarargs=lambda name: '*' + name, formatvarargs=lambda name: '*' + name,
formatvarkw=lambda name: '**' + name, formatvarkw=lambda name: '**' + name,
@ -1249,12 +1248,17 @@ def formatargspec(args, varargs=None, varkw=None, defaults=None,
return result return result
specs = [] specs = []
if defaults: if defaults:
firstdefault = len(args) - len(defaults) firstdefault = len(posonlyargs) + len(args) - len(defaults)
for i, arg in enumerate(args): posonly_left = len(posonlyargs)
for i, arg in enumerate([*posonlyargs, *args]):
spec = formatargandannotation(arg) spec = formatargandannotation(arg)
if defaults and i >= firstdefault: if defaults and i >= firstdefault:
spec = spec + formatvalue(defaults[i - firstdefault]) spec = spec + formatvalue(defaults[i - firstdefault])
specs.append(spec) specs.append(spec)
posonly_left -= 1
if posonlyargs and posonly_left == 0:
specs.append('/')
if varargs is not None: if varargs is not None:
specs.append(formatvarargs(formatargandannotation(varargs))) specs.append(formatvarargs(formatargandannotation(varargs)))
else: else:
@ -1342,7 +1346,8 @@ def getcallargs(*func_and_positional, **named):
func = func_and_positional[0] func = func_and_positional[0]
positional = func_and_positional[1:] positional = func_and_positional[1:]
spec = getfullargspec(func) spec = getfullargspec(func)
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec (args, varargs, varkw, defaults, posonlyargs,
kwonlyargs, kwonlydefaults, ann) = spec
f_name = func.__name__ f_name = func.__name__
arg2value = {} arg2value = {}
@ -1351,12 +1356,16 @@ def getcallargs(*func_and_positional, **named):
# implicit 'self' (or 'cls' for classmethods) argument # implicit 'self' (or 'cls' for classmethods) argument
positional = (func.__self__,) + positional positional = (func.__self__,) + positional
num_pos = len(positional) num_pos = len(positional)
num_posonlyargs = len(posonlyargs)
num_args = len(args) num_args = len(args)
num_defaults = len(defaults) if defaults else 0 num_defaults = len(defaults) if defaults else 0
n = min(num_pos, num_posonlyargs)
for i in range(num_posonlyargs):
arg2value[posonlyargs[i]] = positional[i]
n = min(num_pos, num_args) n = min(num_pos, num_args)
for i in range(n): for i in range(n):
arg2value[args[i]] = positional[i] arg2value[args[i]] = positional[num_posonlyargs+i]
if varargs: if varargs:
arg2value[varargs] = tuple(positional[n:]) arg2value[varargs] = tuple(positional[n:])
possible_kwargs = set(args + kwonlyargs) possible_kwargs = set(args + kwonlyargs)
@ -2137,9 +2146,12 @@ def _signature_from_function(cls, func):
func_code = func.__code__ func_code = func.__code__
pos_count = func_code.co_argcount pos_count = func_code.co_argcount
arg_names = func_code.co_varnames arg_names = func_code.co_varnames
positional = tuple(arg_names[:pos_count]) 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])
keyword_only_count = func_code.co_kwonlyargcount keyword_only_count = func_code.co_kwonlyargcount
keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] keyword_only = arg_names[positional_count:(positional_count + keyword_only_count)]
annotations = func.__annotations__ annotations = func.__annotations__
defaults = func.__defaults__ defaults = func.__defaults__
kwdefaults = func.__kwdefaults__ kwdefaults = func.__kwdefaults__
@ -2151,23 +2163,33 @@ def _signature_from_function(cls, func):
parameters = [] parameters = []
non_default_count = positional_count - pos_default_count
all_positional = positional_only + positional
posonly_left = posonly_count
# Non-keyword-only parameters w/o defaults. # Non-keyword-only parameters w/o defaults.
non_default_count = pos_count - pos_default_count 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) annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation, parameters.append(Parameter(name, annotation=annotation,
kind=_POSITIONAL_OR_KEYWORD)) kind=kind))
if posonly_left:
posonly_left -= 1
# ... w/ defaults. # ... w/ defaults.
for offset, name in enumerate(positional[non_default_count:]): for offset, name in enumerate(all_positional[non_default_count:]):
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
annotation = annotations.get(name, _empty) annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation, parameters.append(Parameter(name, annotation=annotation,
kind=_POSITIONAL_OR_KEYWORD, kind=kind,
default=defaults[offset])) default=defaults[offset]))
if posonly_left:
posonly_left -= 1
# *args # *args
if func_code.co_flags & CO_VARARGS: if func_code.co_flags & CO_VARARGS:
name = arg_names[pos_count + keyword_only_count] name = arg_names[positional_count + keyword_only_count]
annotation = annotations.get(name, _empty) annotation = annotations.get(name, _empty)
parameters.append(Parameter(name, annotation=annotation, parameters.append(Parameter(name, annotation=annotation,
kind=_VAR_POSITIONAL)) kind=_VAR_POSITIONAL))
@ -2184,7 +2206,7 @@ def _signature_from_function(cls, func):
default=default)) default=default))
# **kwargs # **kwargs
if func_code.co_flags & CO_VARKEYWORDS: if func_code.co_flags & CO_VARKEYWORDS:
index = pos_count + keyword_only_count index = positional_count + keyword_only_count
if func_code.co_flags & CO_VARARGS: if func_code.co_flags & CO_VARARGS:
index += 1 index += 1

View File

@ -619,8 +619,9 @@ class ModuleFinder:
if isinstance(consts[i], type(co)): if isinstance(consts[i], type(co)):
consts[i] = self.replace_paths_in_code(consts[i]) consts[i] = self.replace_paths_in_code(consts[i])
return types.CodeType(co.co_argcount, co.co_kwonlyargcount, return types.CodeType(co.co_argcount, co.co_posonlyargcount,
co.co_nlocals, co.co_stacksize, co.co_flags, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_flags,
co.co_code, tuple(consts), co.co_names, co.co_code, tuple(consts), co.co_names,
co.co_varnames, new_filename, co.co_name, co.co_varnames, new_filename, co.co_name,
co.co_firstlineno, co.co_lnotab, co.co_freevars, co.co_firstlineno, co.co_lnotab, co.co_freevars,

View File

@ -5,7 +5,7 @@ import sys, inspect
# line 5 # line 5
# line 7 # line 7
def spam(a, b, c, d=3, e=4, f=5, *g, **h): def spam(a, /, b, c, d=3, e=4, f=5, *g, **h):
eggs(b + d, c + f) eggs(b + d, c + f)
# line 11 # line 11

View File

@ -137,3 +137,19 @@ class cls135:
def func137(): def func137():
never_reached1 never_reached1
never_reached2 never_reached2
#line 141
def positional_only_arg(a, /):
pass
#line 145
def all_markers(a, b, /, c, d, *, e, f):
pass
# line 149
def all_markers_with_args_and_kwargs(a, b, /, c, d, *args, e, f, **kwargs):
pass
#line 153
def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
pass

View File

@ -319,14 +319,14 @@ class AST_Tests(unittest.TestCase):
def test_arguments(self): def test_arguments(self):
x = ast.arguments() x = ast.arguments()
self.assertEqual(x._fields, ('args', 'vararg', 'kwonlyargs', self.assertEqual(x._fields, ('args', 'posonlyargs', 'vararg', 'kwonlyargs',
'kw_defaults', 'kwarg', 'defaults')) 'kw_defaults', 'kwarg', 'defaults'))
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
x.vararg x.vararg
x = ast.arguments(*range(1, 7)) x = ast.arguments(*range(1, 8))
self.assertEqual(x.vararg, 2) self.assertEqual(x.vararg, 3)
def test_field_attr_writable(self): def test_field_attr_writable(self):
x = ast.Num() x = ast.Num()
@ -816,22 +816,25 @@ class ASTValidatorTests(unittest.TestCase):
self.mod(m, "must have Load context", "eval") self.mod(m, "must have Load context", "eval")
def _check_arguments(self, fac, check): def _check_arguments(self, fac, check):
def arguments(args=None, vararg=None, def arguments(args=None, posonlyargs=None, vararg=None,
kwonlyargs=None, kwarg=None, kwonlyargs=None, kwarg=None,
defaults=None, kw_defaults=None): defaults=None, kw_defaults=None):
if args is None: if args is None:
args = [] args = []
if posonlyargs is None:
posonlyargs = []
if kwonlyargs is None: if kwonlyargs is None:
kwonlyargs = [] kwonlyargs = []
if defaults is None: if defaults is None:
defaults = [] defaults = []
if kw_defaults is None: if kw_defaults is None:
kw_defaults = [] kw_defaults = []
args = ast.arguments(args, vararg, kwonlyargs, kw_defaults, args = ast.arguments(args, posonlyargs, vararg, kwonlyargs,
kwarg, defaults) kw_defaults, kwarg, defaults)
return fac(args) return fac(args)
args = [ast.arg("x", ast.Name("x", ast.Store()))] args = [ast.arg("x", ast.Name("x", ast.Store()))]
check(arguments(args=args), "must have Load context") check(arguments(args=args), "must have Load context")
check(arguments(posonlyargs=args), "must have Load context")
check(arguments(kwonlyargs=args), "must have Load context") check(arguments(kwonlyargs=args), "must have Load context")
check(arguments(defaults=[ast.Num(3)]), check(arguments(defaults=[ast.Num(3)]),
"more positional defaults than args") "more positional defaults than args")
@ -847,7 +850,7 @@ class ASTValidatorTests(unittest.TestCase):
"must have Load context") "must have Load context")
def test_funcdef(self): def test_funcdef(self):
a = ast.arguments([], None, [], [], None, []) a = ast.arguments([], [], None, [], [], None, [])
f = ast.FunctionDef("x", a, [], [], None) f = ast.FunctionDef("x", a, [], [], None)
self.stmt(f, "empty body on FunctionDef") self.stmt(f, "empty body on FunctionDef")
f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())], f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())],
@ -1013,7 +1016,7 @@ class ASTValidatorTests(unittest.TestCase):
self.expr(u, "must have Load context") self.expr(u, "must have Load context")
def test_lambda(self): def test_lambda(self):
a = ast.arguments([], None, [], [], None, []) a = ast.arguments([], [], None, [], [], None, [])
self.expr(ast.Lambda(a, ast.Name("x", ast.Store())), self.expr(ast.Lambda(a, ast.Name("x", ast.Store())),
"must have Load context") "must have Load context")
def fac(args): def fac(args):
@ -1636,17 +1639,17 @@ def main():
exec_results = [ exec_results = [
('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, None))], []), ('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, None))], []),
('Module', [('Expr', (1, 0), ('Constant', (1, 0), 'module docstring', None))], []), ('Module', [('Expr', (1, 0), ('Constant', (1, 0), 'module docstring', None))], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (1, 9))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (1, 9), ('Constant', (1, 9), 'function docstring', None))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9), ('Constant', (1, 9), 'function docstring', None))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 10))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], None, [], [], None, [('Constant', (1, 8), 0, None)]), [('Pass', (1, 12))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8), 0, None)]), [('Pass', (1, 12))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], ('arg', (1, 7), 'args', None, None), [], [], None, []), [('Pass', (1, 14))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], ('arg', (1, 7), 'args', None, None), [], [], None, []), [('Pass', (1, 14))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], ('arg', (1, 8), 'kwargs', None, None), []), [('Pass', (1, 17))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8), 'kwargs', None, None), []), [('Pass', (1, 17))], [], None, None)], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None), ('arg', (1, 9), 'b', None, None), ('arg', (1, 14), 'c', None, None), ('arg', (1, 22), 'd', None, None), ('arg', (1, 28), 'e', None, None)], ('arg', (1, 35), 'args', None, None), [('arg', (1, 41), 'f', None, None)], [('Constant', (1, 43), 42, None)], ('arg', (1, 49), 'kwargs', None, None), [('Constant', (1, 11), 1, None), ('Constant', (1, 16), None, None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Expr', (1, 58), ('Constant', (1, 58), 'doc for f()', None))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None), ('arg', (1, 9), 'b', None, None), ('arg', (1, 14), 'c', None, None), ('arg', (1, 22), 'd', None, None), ('arg', (1, 28), 'e', None, None)], [], ('arg', (1, 35), 'args', None, None), [('arg', (1, 41), 'f', None, None)], [('Constant', (1, 43), 42, None)], ('arg', (1, 49), 'kwargs', None, None), [('Constant', (1, 11), 1, None), ('Constant', (1, 16), None, None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Expr', (1, 58), ('Constant', (1, 58), 'doc for f()', None))], [], None, None)], []),
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])], []), ('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])], []),
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Expr', (1, 9), ('Constant', (1, 9), 'docstring for class C', None))], [])], []), ('Module', [('ClassDef', (1, 0), 'C', [], [], [('Expr', (1, 9), ('Constant', (1, 9), 'docstring for class C', None))], [])], []),
('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])], []), ('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])], []),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Return', (1, 8), ('Constant', (1, 15), 1, None))], [], None, None)], []), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8), ('Constant', (1, 15), 1, None))], [], None, None)], []),
('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])], []), ('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])], []),
('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Constant', (1, 4), 1, None), None)], []), ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Constant', (1, 4), 1, None), None)], []),
('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 0), 'a', ('Store',)), ('Name', (1, 2), 'b', ('Store',))], ('Store',))], ('Name', (1, 6), 'c', ('Load',)), None)], []), ('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 0), 'a', ('Store',)), ('Name', (1, 2), 'b', ('Store',))], ('Store',))], ('Name', (1, 6), 'c', ('Load',)), None)], []),
@ -1677,16 +1680,16 @@ exec_results = [
('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []), ('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []),
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))], 0)]))], []), ('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))], 0)]))], []),
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [], 0)]))], []), ('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [], 0)]))], []),
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (2, 1), ('Constant', (2, 1), 'async function', None)), ('Expr', (3, 1), ('Await', (3, 1), ('Call', (3, 7), ('Name', (3, 7), 'something', ('Load',)), [], [])))], [], None, None)], []), ('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('Constant', (2, 1), 'async function', None)), ('Expr', (3, 1), ('Await', (3, 1), ('Call', (3, 7), ('Name', (3, 7), 'something', ('Load',)), [], [])))], [], None, None)], []),
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('AsyncFor', (2, 1), ('Name', (2, 11), 'e', ('Store',)), ('Name', (2, 16), 'i', ('Load',)), [('Expr', (2, 19), ('Constant', (2, 19), 1, None))], [('Expr', (3, 7), ('Constant', (3, 7), 2, None))], None)], [], None, None)], []), ('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1), ('Name', (2, 11), 'e', ('Store',)), ('Name', (2, 16), 'i', ('Load',)), [('Expr', (2, 19), ('Constant', (2, 19), 1, None))], [('Expr', (3, 7), ('Constant', (3, 7), 2, None))], None)], [], None, None)], []),
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('AsyncWith', (2, 1), [('withitem', ('Name', (2, 12), 'a', ('Load',)), ('Name', (2, 17), 'b', ('Store',)))], [('Expr', (2, 20), ('Constant', (2, 20), 1, None))], None)], [], None, None)], []), ('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1), [('withitem', ('Name', (2, 12), 'a', ('Load',)), ('Name', (2, 17), 'b', ('Store',)))], [('Expr', (2, 20), ('Constant', (2, 20), 1, None))], None)], [], None, None)], []),
('Module', [('Expr', (1, 0), ('Dict', (1, 0), [None, ('Constant', (1, 10), 2, None)], [('Dict', (1, 3), [('Constant', (1, 4), 1, None)], [('Constant', (1, 6), 2, None)]), ('Constant', (1, 12), 3, None)]))], []), ('Module', [('Expr', (1, 0), ('Dict', (1, 0), [None, ('Constant', (1, 10), 2, None)], [('Dict', (1, 3), [('Constant', (1, 4), 1, None)], [('Constant', (1, 6), 2, None)]), ('Constant', (1, 12), 3, None)]))], []),
('Module', [('Expr', (1, 0), ('Set', (1, 0), [('Starred', (1, 1), ('Set', (1, 2), [('Constant', (1, 3), 1, None), ('Constant', (1, 6), 2, None)]), ('Load',)), ('Constant', (1, 10), 3, None)]))], []), ('Module', [('Expr', (1, 0), ('Set', (1, 0), [('Starred', (1, 1), ('Set', (1, 2), [('Constant', (1, 3), 1, None), ('Constant', (1, 6), 2, None)]), ('Load',)), ('Constant', (1, 10), 3, None)]))], []),
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (2, 1), ('ListComp', (2, 1), ('Name', (2, 2), 'i', ('Load',)), [('comprehension', ('Name', (2, 14), 'b', ('Store',)), ('Name', (2, 19), 'c', ('Load',)), [], 1)]))], [], None, None)], []), ('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('ListComp', (2, 1), ('Name', (2, 2), 'i', ('Load',)), [('comprehension', ('Name', (2, 14), 'b', ('Store',)), ('Name', (2, 19), 'c', ('Load',)), [], 1)]))], [], None, None)], []),
('Module', [('FunctionDef', (3, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []), ('Module', [('FunctionDef', (3, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
('Module', [('AsyncFunctionDef', (3, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (3, 15))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []), ('Module', [('AsyncFunctionDef', (3, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (3, 15))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
('Module', [('ClassDef', (3, 0), 'C', [], [], [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])])], []), ('Module', [('ClassDef', (3, 0), 'C', [], [], [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])])], []),
('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (2, 9))], [('Call', (1, 1), ('Name', (1, 1), 'deco', ('Load',)), [('GeneratorExp', (1, 5), ('Name', (1, 6), 'a', ('Load',)), [('comprehension', ('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 17), 'b', ('Load',)), [], 0)])], [])], None, None)], []), ('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9))], [('Call', (1, 1), ('Name', (1, 1), 'deco', ('Load',)), [('GeneratorExp', (1, 5), ('Name', (1, 6), 'a', ('Load',)), [('comprehension', ('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 17), 'b', ('Load',)), [], 0)])], [])], None, None)], []),
('Module', [('Expr', (1, 0), ('NamedExpr', (1, 1), ('Name', (1, 1), 'a', ('Store',)), ('Constant', (1, 6), 1, None)))], []), ('Module', [('Expr', (1, 0), ('NamedExpr', (1, 1), ('Name', (1, 1), 'a', ('Store',)), ('Constant', (1, 6), 1, None)))], []),
] ]
single_results = [ single_results = [
@ -1697,7 +1700,7 @@ eval_results = [
('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])), ('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))), ('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))), ('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
('Expression', ('Lambda', (1, 0), ('arguments', [], None, [], [], None, []), ('Constant', (1, 7), None, None))), ('Expression', ('Lambda', (1, 0), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7), None, None))),
('Expression', ('Dict', (1, 0), [('Constant', (1, 2), 1, None)], [('Constant', (1, 4), 2, None)])), ('Expression', ('Dict', (1, 0), [('Constant', (1, 2), 1, None)], [('Constant', (1, 4), 2, None)])),
('Expression', ('Dict', (1, 0), [], [])), ('Expression', ('Dict', (1, 0), [], [])),
('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])), ('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])),

View File

@ -9,6 +9,7 @@
>>> dump(f.__code__) >>> dump(f.__code__)
name: f name: f
argcount: 1 argcount: 1
posonlyargcount: 0
kwonlyargcount: 0 kwonlyargcount: 0
names: () names: ()
varnames: ('x', 'g') varnames: ('x', 'g')
@ -21,6 +22,7 @@ consts: ('None', '<code object g>', "'f.<locals>.g'")
>>> dump(f(4).__code__) >>> dump(f(4).__code__)
name: g name: g
argcount: 1 argcount: 1
posonlyargcount: 0
kwonlyargcount: 0 kwonlyargcount: 0
names: () names: ()
varnames: ('y',) varnames: ('y',)
@ -40,6 +42,7 @@ consts: ('None',)
>>> dump(h.__code__) >>> dump(h.__code__)
name: h name: h
argcount: 2 argcount: 2
posonlyargcount: 0
kwonlyargcount: 0 kwonlyargcount: 0
names: () names: ()
varnames: ('x', 'y', 'a', 'b', 'c') varnames: ('x', 'y', 'a', 'b', 'c')
@ -57,6 +60,7 @@ consts: ('None',)
>>> dump(attrs.__code__) >>> dump(attrs.__code__)
name: attrs name: attrs
argcount: 1 argcount: 1
posonlyargcount: 0
kwonlyargcount: 0 kwonlyargcount: 0
names: ('print', 'attr1', 'attr2', 'attr3') names: ('print', 'attr1', 'attr2', 'attr3')
varnames: ('obj',) varnames: ('obj',)
@ -75,6 +79,7 @@ consts: ('None',)
>>> dump(optimize_away.__code__) >>> dump(optimize_away.__code__)
name: optimize_away name: optimize_away
argcount: 0 argcount: 0
posonlyargcount: 0
kwonlyargcount: 0 kwonlyargcount: 0
names: () names: ()
varnames: () varnames: ()
@ -91,6 +96,7 @@ consts: ("'doc string'", 'None')
>>> dump(keywordonly_args.__code__) >>> dump(keywordonly_args.__code__)
name: keywordonly_args name: keywordonly_args
argcount: 2 argcount: 2
posonlyargcount: 0
kwonlyargcount: 1 kwonlyargcount: 1
names: () names: ()
varnames: ('a', 'b', 'k1') varnames: ('a', 'b', 'k1')
@ -100,6 +106,23 @@ nlocals: 3
flags: 67 flags: 67
consts: ('None',) consts: ('None',)
>>> def posonly_args(a,b,/,c):
... return a,b,c
...
>>> dump(posonly_args.__code__)
name: posonly_args
argcount: 1
posonlyargcount: 2
kwonlyargcount: 0
names: ()
varnames: ('a', 'b', 'c')
cellvars: ()
freevars: ()
nlocals: 3
flags: 67
consts: ('None',)
""" """
import inspect import inspect
@ -126,7 +149,8 @@ def consts(t):
def dump(co): def dump(co):
"""Print out a text representation of a code object.""" """Print out a text representation of a code object."""
for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames", for attr in ["name", "argcount", "posonlyargcount",
"kwonlyargcount", "names", "varnames",
"cellvars", "freevars", "nlocals", "flags"]: "cellvars", "freevars", "nlocals", "flags"]:
print("%s: %s" % (attr, getattr(co, "co_" + attr))) print("%s: %s" % (attr, getattr(co, "co_" + attr)))
print("consts:", tuple(consts(co.co_consts))) print("consts:", tuple(consts(co.co_consts)))
@ -157,7 +181,7 @@ class CodeTest(unittest.TestCase):
def new_code(c): def new_code(c):
'''A new code object with a __class__ cell added to freevars''' '''A new code object with a __class__ cell added to freevars'''
return CodeType( return CodeType(
c.co_argcount, c.co_kwonlyargcount, c.co_nlocals, c.co_argcount, c.co_posonlyargcount, c.co_kwonlyargcount, c.co_nlocals,
c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names, c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno, c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars) c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)

View File

@ -617,6 +617,7 @@ code_info_code_info = """\
Name: code_info Name: code_info
Filename: (.*) Filename: (.*)
Argument count: 1 Argument count: 1
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 1 Number of locals: 1
Stack size: 3 Stack size: 3
@ -631,50 +632,53 @@ Variable names:
if sys.flags.optimize < 2 else (None,)) if sys.flags.optimize < 2 else (None,))
@staticmethod @staticmethod
def tricky(x, y, z=True, *args, c, d, e=[], **kwds): def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
def f(c=c): def f(c=c):
print(x, y, z, c, d, e, f) print(a, b, x, y, z, c, d, e, f)
yield x, y, z, c, d, e, f yield a, b, x, y, z, c, d, e, f
code_info_tricky = """\ code_info_tricky = """\
Name: tricky Name: tricky
Filename: (.*) Filename: (.*)
Argument count: 3 Argument count: 3
Positional-only arguments: 2
Kw-only arguments: 3 Kw-only arguments: 3
Number of locals: 8 Number of locals: 10
Stack size: 7 Stack size: 9
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
Constants: Constants:
0: None 0: None
1: <code object f at (.*), file "(.*)", line (.*)> 1: <code object f at (.*), file "(.*)", line (.*)>
2: 'tricky.<locals>.f' 2: 'tricky.<locals>.f'
Variable names: Variable names:
0: x 0: a
1: y 1: b
2: z 2: x
3: c 3: y
4: d 4: z
5: e 5: c
6: args 6: d
7: kwds 7: e
8: args
9: kwds
Cell variables: Cell variables:
0: [edfxyz] 0: [abedfxyz]
1: [edfxyz] 1: [abedfxyz]
2: [edfxyz] 2: [abedfxyz]
3: [edfxyz] 3: [abedfxyz]
4: [edfxyz] 4: [abedfxyz]
5: [edfxyz]""" 5: [abedfxyz]"""
# NOTE: the order of the cell variables above depends on dictionary order! # NOTE: the order of the cell variables above depends on dictionary order!
co_tricky_nested_f = tricky.__func__.__code__.co_consts[1] co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
code_info_tricky_nested_f = """\ code_info_tricky_nested_f = """\
Name: f
Filename: (.*) Filename: (.*)
Argument count: 1 Argument count: 1
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 1 Number of locals: 1
Stack size: 8 Stack size: 10
Flags: OPTIMIZED, NEWLOCALS, NESTED Flags: OPTIMIZED, NEWLOCALS, NESTED
Constants: Constants:
0: None 0: None
@ -683,17 +687,18 @@ Names:
Variable names: Variable names:
0: c 0: c
Free variables: Free variables:
0: [edfxyz] 0: [abedfxyz]
1: [edfxyz] 1: [abedfxyz]
2: [edfxyz] 2: [abedfxyz]
3: [edfxyz] 3: [abedfxyz]
4: [edfxyz] 4: [abedfxyz]
5: [edfxyz]""" 5: [abedfxyz]"""
code_info_expr_str = """\ code_info_expr_str = """\
Name: <module> Name: <module>
Filename: <disassembly> Filename: <disassembly>
Argument count: 0 Argument count: 0
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 0 Number of locals: 0
Stack size: 2 Stack size: 2
@ -707,6 +712,7 @@ code_info_simple_stmt_str = """\
Name: <module> Name: <module>
Filename: <disassembly> Filename: <disassembly>
Argument count: 0 Argument count: 0
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 0 Number of locals: 0
Stack size: 2 Stack size: 2
@ -721,6 +727,7 @@ code_info_compound_stmt_str = """\
Name: <module> Name: <module>
Filename: <disassembly> Filename: <disassembly>
Argument count: 0 Argument count: 0
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 0 Number of locals: 0
Stack size: 2 Stack size: 2
@ -742,6 +749,7 @@ code_info_async_def = """\
Name: async_def Name: async_def
Filename: (.*) Filename: (.*)
Argument count: 0 Argument count: 0
Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 2 Number of locals: 2
Stack size: 10 Stack size: 10

View File

@ -581,6 +581,13 @@ class TestPartialMethod(unittest.TestCase):
for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]: for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]:
self.assertFalse(getattr(func, '__isabstractmethod__', False)) self.assertFalse(getattr(func, '__isabstractmethod__', False))
def test_positional_only(self):
def f(a, b, /):
return a + b
p = functools.partial(f, 1)
self.assertEqual(p(2), f(1, 2))
class TestUpdateWrapper(unittest.TestCase): class TestUpdateWrapper(unittest.TestCase):

View File

@ -674,7 +674,8 @@ func_filename = func.__code__.co_filename
foreign_code = importlib.import_module.__code__ foreign_code = importlib.import_module.__code__
pos = constants.index(1) pos = constants.index(1)
constants[pos] = foreign_code constants[pos] = foreign_code
code = type(code)(code.co_argcount, code.co_kwonlyargcount, code = type(code)(code.co_argcount, code.co_posonlyargcount,
code.co_kwonlyargcount,
code.co_nlocals, code.co_stacksize, code.co_nlocals, code.co_stacksize,
code.co_flags, code.co_code, tuple(constants), code.co_flags, code.co_code, tuple(constants),
code.co_names, code.co_varnames, code.co_filename, code.co_names, code.co_varnames, code.co_filename,

View File

@ -862,7 +862,7 @@ class MagicNumberTests(unittest.TestCase):
in advance. Such exceptional releases will then require an in advance. Such exceptional releases will then require an
adjustment to this test case. adjustment to this test case.
""" """
EXPECTED_MAGIC_NUMBER = 3400 EXPECTED_MAGIC_NUMBER = 3410
actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little') actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little')
msg = ( msg = (

View File

@ -763,30 +763,31 @@ class TestClassesAndFunctions(unittest.TestCase):
def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None, def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
varkw_e=None, defaults_e=None, varkw_e=None, defaults_e=None,
kwonlyargs_e=[], kwonlydefaults_e=None, posonlyargs_e=[], kwonlyargs_e=[],
kwonlydefaults_e=None,
ann_e={}, formatted=None): ann_e={}, formatted=None):
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, ann = \
inspect.getfullargspec(routine) inspect.getfullargspec(routine)
self.assertEqual(args, args_e) self.assertEqual(args, args_e)
self.assertEqual(varargs, varargs_e) self.assertEqual(varargs, varargs_e)
self.assertEqual(varkw, varkw_e) self.assertEqual(varkw, varkw_e)
self.assertEqual(defaults, defaults_e) self.assertEqual(defaults, defaults_e)
self.assertEqual(posonlyargs, posonlyargs_e)
self.assertEqual(kwonlyargs, kwonlyargs_e) self.assertEqual(kwonlyargs, kwonlyargs_e)
self.assertEqual(kwonlydefaults, kwonlydefaults_e) self.assertEqual(kwonlydefaults, kwonlydefaults_e)
self.assertEqual(ann, ann_e) self.assertEqual(ann, ann_e)
if formatted is not None: if formatted is not None:
with self.assertWarns(DeprecationWarning): with self.assertWarns(DeprecationWarning):
self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults, self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
kwonlyargs, kwonlydefaults, ann), posonlyargs, kwonlyargs,
kwonlydefaults, ann),
formatted) formatted)
def test_getargspec(self): def test_getargspec(self):
self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)') self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)')
self.assertArgSpecEquals(mod.spam, self.assertRaises(ValueError, self.assertArgSpecEquals,
['a', 'b', 'c', 'd', 'e', 'f'], mod.spam, [])
'g', 'h', (3, 4, 5),
'(a, b, c, d=3, e=4, f=5, *g, **h)')
self.assertRaises(ValueError, self.assertArgSpecEquals, self.assertRaises(ValueError, self.assertArgSpecEquals,
mod2.keyworded, []) mod2.keyworded, [])
@ -810,6 +811,26 @@ class TestClassesAndFunctions(unittest.TestCase):
kwonlyargs_e=['arg'], kwonlyargs_e=['arg'],
formatted='(*, arg)') formatted='(*, arg)')
self.assertFullArgSpecEquals(mod2.all_markers, ['c', 'd'],
posonlyargs_e=['a', 'b'],
kwonlyargs_e=['e', 'f'],
formatted='(a, b, /, c, d, *, e, f)')
self.assertFullArgSpecEquals(mod2.all_markers_with_args_and_kwargs,
['c', 'd'],
posonlyargs_e=['a', 'b'],
varargs_e='args',
varkw_e='kwargs',
kwonlyargs_e=['e', 'f'],
formatted='(a, b, /, c, d, *args, e, f, **kwargs)')
self.assertFullArgSpecEquals(mod2.all_markers_with_defaults, ['c', 'd'],
defaults_e=(1,2,3),
posonlyargs_e=['a', 'b'],
kwonlyargs_e=['e', 'f'],
kwonlydefaults_e={'e': 4, 'f': 5},
formatted='(a, b=1, /, c=2, d=3, *, e=4, f=5)')
def test_argspec_api_ignores_wrapped(self): def test_argspec_api_ignores_wrapped(self):
# Issue 20684: low level introspection API must ignore __wrapped__ # Issue 20684: low level introspection API must ignore __wrapped__
@functools.wraps(mod.spam) @functools.wraps(mod.spam)
@ -856,7 +877,7 @@ class TestClassesAndFunctions(unittest.TestCase):
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY) spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
test.__signature__ = inspect.Signature(parameters=(spam_param,)) test.__signature__ = inspect.Signature(parameters=(spam_param,))
self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)') self.assertFullArgSpecEquals(test, [], posonlyargs_e=['spam'], formatted='(spam, /)')
def test_getfullargspec_signature_annos(self): def test_getfullargspec_signature_annos(self):
def test(a:'spam') -> 'ham': pass def test(a:'spam') -> 'ham': pass
@ -870,11 +891,11 @@ class TestClassesAndFunctions(unittest.TestCase):
@unittest.skipIf(MISSING_C_DOCSTRINGS, @unittest.skipIf(MISSING_C_DOCSTRINGS,
"Signature information for builtins requires docstrings") "Signature information for builtins requires docstrings")
def test_getfullargspec_builtin_methods(self): def test_getfullargspec_builtin_methods(self):
self.assertFullArgSpecEquals(_pickle.Pickler.dump, self.assertFullArgSpecEquals(_pickle.Pickler.dump, [],
args_e=['self', 'obj'], formatted='(self, obj)') posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, [],
args_e=['self', 'obj'], formatted='(self, obj)') posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
self.assertFullArgSpecEquals( self.assertFullArgSpecEquals(
os.stat, os.stat,

View File

@ -233,6 +233,18 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase):
self.check_suite("def f(*args, a, b = 5): pass") self.check_suite("def f(*args, a, b = 5): pass")
self.check_suite("def f(*args, a, b = 5, **kwds): pass") self.check_suite("def f(*args, a, b = 5, **kwds): pass")
# positional-only arguments
self.check_suite("def f(a, /): pass")
self.check_suite("def f(a, /,): pass")
self.check_suite("def f(a, b, /): pass")
self.check_suite("def f(a, b, /, c): pass")
self.check_suite("def f(a, b, /, c = 6): pass")
self.check_suite("def f(a, b, /, c, *, d): pass")
self.check_suite("def f(a, b, /, c = 1, *, d): pass")
self.check_suite("def f(a, b, /, c, *, d = 1): pass")
self.check_suite("def f(a, b=1, /, c=2, *, d = 3): pass")
self.check_suite("def f(a=0, b=1, /, c=2, *, d = 3): pass")
# function annotations # function annotations
self.check_suite("def f(a: int): pass") self.check_suite("def f(a: int): pass")
self.check_suite("def f(a: int = 5): pass") self.check_suite("def f(a: int = 5): pass")

View File

@ -0,0 +1,403 @@
"""Unit tests for the positional only argument syntax specified in PEP 570."""
import pickle
import unittest
from test.support import check_syntax_error
def global_pos_only_f(a, b, /):
return a, b
def global_pos_only_and_normal(a, /, b):
return a, b
def global_pos_only_defaults(a=1, /, b=2):
return a, b
class PositionalOnlyTestCase(unittest.TestCase):
def assertRaisesSyntaxError(self, codestr, regex="invalid syntax"):
with self.assertRaisesRegex(SyntaxError, regex):
compile(codestr + "\n", "<test>", "single")
def test_invalid_syntax_errors(self):
check_syntax_error(self, "def f(a, b = 5, /, c): pass", "non-default argument follows default argument")
check_syntax_error(self, "def f(a = 5, b, /, c): pass", "non-default argument follows default argument")
check_syntax_error(self, "def f(a = 5, b=1, /, c, *, d=2): pass", "non-default argument follows default argument")
check_syntax_error(self, "def f(a = 5, b, /): pass", "non-default argument follows default argument")
check_syntax_error(self, "def f(*args, /): pass")
check_syntax_error(self, "def f(*args, a, /): pass")
check_syntax_error(self, "def f(**kwargs, /): pass")
check_syntax_error(self, "def f(/, a = 1): pass")
check_syntax_error(self, "def f(/, a): pass")
check_syntax_error(self, "def f(/): pass")
check_syntax_error(self, "def f(*, a, /): pass")
check_syntax_error(self, "def f(*, /, a): pass")
check_syntax_error(self, "def f(a, /, a): pass", "duplicate argument 'a' in function definition")
check_syntax_error(self, "def f(a, /, *, a): pass", "duplicate argument 'a' in function definition")
check_syntax_error(self, "def f(a, b/2, c): pass")
check_syntax_error(self, "def f(a, /, c, /): pass")
check_syntax_error(self, "def f(a, /, c, /, d): pass")
check_syntax_error(self, "def f(a, /, c, /, d, *, e): pass")
check_syntax_error(self, "def f(a, *, c, /, d, e): pass")
def test_invalid_syntax_errors_async(self):
check_syntax_error(self, "async def f(a, b = 5, /, c): pass", "non-default argument follows default argument")
check_syntax_error(self, "async def f(a = 5, b, /, c): pass", "non-default argument follows default argument")
check_syntax_error(self, "async def f(a = 5, b=1, /, c, d=2): pass", "non-default argument follows default argument")
check_syntax_error(self, "async def f(a = 5, b, /): pass", "non-default argument follows default argument")
check_syntax_error(self, "async def f(*args, /): pass")
check_syntax_error(self, "async def f(*args, a, /): pass")
check_syntax_error(self, "async def f(**kwargs, /): pass")
check_syntax_error(self, "async def f(/, a = 1): pass")
check_syntax_error(self, "async def f(/, a): pass")
check_syntax_error(self, "async def f(/): pass")
check_syntax_error(self, "async def f(*, a, /): pass")
check_syntax_error(self, "async def f(*, /, a): pass")
check_syntax_error(self, "async def f(a, /, a): pass", "duplicate argument 'a' in function definition")
check_syntax_error(self, "async def f(a, /, *, a): pass", "duplicate argument 'a' in function definition")
check_syntax_error(self, "async def f(a, b/2, c): pass")
check_syntax_error(self, "async def f(a, /, c, /): pass")
check_syntax_error(self, "async def f(a, /, c, /, d): pass")
check_syntax_error(self, "async def f(a, /, c, /, d, *, e): pass")
check_syntax_error(self, "async def f(a, *, c, /, d, e): pass")
def test_optional_positional_only_args(self):
def f(a, b=10, /, c=100):
return a + b + c
self.assertEqual(f(1, 2, 3), 6)
self.assertEqual(f(1, 2, c=3), 6)
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
f(1, b=2, c=3)
self.assertEqual(f(1, 2), 103)
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
f(1, b=2)
self.assertEqual(f(1, c=2), 13)
def f(a=1, b=10, /, c=100):
return a + b + c
self.assertEqual(f(1, 2, 3), 6)
self.assertEqual(f(1, 2, c=3), 6)
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
f(1, b=2, c=3)
self.assertEqual(f(1, 2), 103)
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
f(1, b=2)
self.assertEqual(f(1, c=2), 13)
def test_syntax_for_many_positional_only(self):
# more than 255 positional 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 test_pos_only_definition(self):
def f(a, b, c, /, d, e=1, *, f, g=2):
pass
self.assertEqual(2, f.__code__.co_argcount) # 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(3, f.__code__.co_posonlyargcount)
self.assertEqual((1, 2, 3), f.__defaults__)
def test_pos_only_call_via_unpacking(self):
def f(a, b, /):
return a + b
self.assertEqual(f(*[1, 2]), 3)
def test_use_positional_as_keyword(self):
def f(a, /):
pass
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"
with self.assertRaisesRegex(TypeError, expected):
f(a=1)
def f(a, /, b):
pass
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"
with self.assertRaisesRegex(TypeError, expected):
f(a=1, b=2)
def f(a, b, /):
pass
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a, b'"
with self.assertRaisesRegex(TypeError, expected):
f(a=1, b=2)
def test_positional_only_and_arg_invalid_calls(self):
def f(a, b, /, c):
pass
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'c'"):
f(1, 2)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'b' and 'c'"):
f(1)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 3 required positional arguments: 'a', 'b', and 'c'"):
f()
with self.assertRaisesRegex(TypeError, r"f\(\) takes 3 positional arguments but 4 were given"):
f(1, 2, 3, 4)
def test_positional_only_and_optional_arg_invalid_calls(self):
def f(a, b, /, c=3):
pass
f(1, 2) # does not raise
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'b'"):
f(1)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
f()
with self.assertRaisesRegex(TypeError, r"f\(\) takes from 2 to 3 positional arguments but 4 were given"):
f(1, 2, 3, 4)
def test_positional_only_and_kwonlyargs_invalid_calls(self):
def f(a, b, /, c, *, d, e):
pass
f(1, 2, 3, d=1, e=2) # does not raise
with self.assertRaisesRegex(TypeError, r"missing 1 required keyword-only argument: 'd'"):
f(1, 2, 3, e=2)
with self.assertRaisesRegex(TypeError, r"missing 2 required keyword-only arguments: 'd' and 'e'"):
f(1, 2, 3)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'c'"):
f(1, 2)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'b' and 'c'"):
f(1)
with self.assertRaisesRegex(TypeError, r" missing 3 required positional arguments: 'a', 'b', and 'c'"):
f()
with self.assertRaisesRegex(TypeError, r"f\(\) takes 3 positional arguments but 6 positional arguments "
r"\(and 2 keyword-only arguments\) were given"):
f(1, 2, 3, 4, 5, 6, d=7, e=8)
with self.assertRaisesRegex(TypeError, r"f\(\) got an unexpected keyword argument 'f'"):
f(1, 2, 3, d=1, e=4, f=56)
def test_positional_only_invalid_calls(self):
def f(a, b, /):
pass
f(1, 2) # does not raise
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'b'"):
f(1)
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
f()
with self.assertRaisesRegex(TypeError, r"f\(\) takes 2 positional arguments but 3 were given"):
f(1, 2, 3)
def test_positional_only_with_optional_invalid_calls(self):
def f(a, b=2, /):
pass
f(1) # does not raise
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'a'"):
f()
with self.assertRaisesRegex(TypeError, r"f\(\) takes from 1 to 2 positional arguments but 3 were given"):
f(1, 2, 3)
def test_no_standard_args_usage(self):
def f(a, b, /, *, c):
pass
f(1, 2, c=3)
with self.assertRaises(TypeError):
f(1, b=2, c=3)
def test_change_default_pos_only(self):
def f(a, b=2, /, c=3):
return a + b + c
self.assertEqual((2,3), f.__defaults__)
f.__defaults__ = (1, 2, 3)
self.assertEqual(f(1, 2, 3), 6)
def test_lambdas(self):
x = lambda a, /, b: a + b
self.assertEqual(x(1,2), 3)
self.assertEqual(x(1,b=2), 3)
x = lambda a, /, b=2: a + b
self.assertEqual(x(1), 3)
x = lambda a, b, /: a + b
self.assertEqual(x(1, 2), 3)
x = lambda a, b, /, : a + b
self.assertEqual(x(1, 2), 3)
def test_invalid_syntax_lambda(self):
check_syntax_error(self, "lambda a, b = 5, /, c: None", "non-default argument follows default argument")
check_syntax_error(self, "lambda a = 5, b, /, c: None", "non-default argument follows default argument")
check_syntax_error(self, "lambda a = 5, b, /: None", "non-default argument follows default argument")
check_syntax_error(self, "lambda *args, /: None")
check_syntax_error(self, "lambda *args, a, /: None")
check_syntax_error(self, "lambda **kwargs, /: None")
check_syntax_error(self, "lambda /, a = 1: None")
check_syntax_error(self, "lambda /, a: None")
check_syntax_error(self, "lambda /: None")
check_syntax_error(self, "lambda *, a, /: None")
check_syntax_error(self, "lambda *, /, a: None")
check_syntax_error(self, "lambda a, /, a: None", "duplicate argument 'a' in function definition")
check_syntax_error(self, "lambda a, /, *, a: None", "duplicate argument 'a' in function definition")
check_syntax_error(self, "lambda a, /, b, /: None")
check_syntax_error(self, "lambda a, /, b, /, c: None")
check_syntax_error(self, "lambda a, /, b, /, c, *, d: None")
check_syntax_error(self, "lambda a, *, b, /, c: None")
def test_posonly_methods(self):
class Example:
def f(self, a, b, /):
return a, b
self.assertEqual(Example().f(1, 2), (1, 2))
self.assertEqual(Example.f(Example(), 1, 2), (1, 2))
self.assertRaises(TypeError, Example.f, 1, 2)
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"
with self.assertRaisesRegex(TypeError, expected):
Example().f(1, b=2)
def test_mangling(self):
class X:
def f(self, *, __a=42):
return __a
self.assertEqual(X().f(), 42)
def test_module_function(self):
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
global_pos_only_f()
def test_closures(self):
def f(x,y):
def g(x2,/,y2):
return x + y + x2 + y2
return g
self.assertEqual(f(1,2)(3,4), 10)
with self.assertRaisesRegex(TypeError, r"g\(\) missing 1 required positional argument: 'y2'"):
f(1,2)(3)
with self.assertRaisesRegex(TypeError, r"g\(\) takes 2 positional arguments but 3 were given"):
f(1,2)(3,4,5)
def f(x,/,y):
def g(x2,y2):
return x + y + x2 + y2
return g
self.assertEqual(f(1,2)(3,4), 10)
def f(x,/,y):
def g(x2,/,y2):
return x + y + x2 + y2
return g
self.assertEqual(f(1,2)(3,4), 10)
with self.assertRaisesRegex(TypeError, r"g\(\) missing 1 required positional argument: 'y2'"):
f(1,2)(3)
with self.assertRaisesRegex(TypeError, r"g\(\) takes 2 positional arguments but 3 were given"):
f(1,2)(3,4,5)
def test_same_keyword_as_positional_with_kwargs(self):
def f(something,/,**kwargs):
return (something, kwargs)
self.assertEqual(f(42, something=42), (42, {'something': 42}))
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'something'"):
f(something=42)
self.assertEqual(f(42), (42, {}))
def test_mangling(self):
class X:
def f(self, __a=42, /):
return __a
def f2(self, __a=42, /, __b=43):
return (__a, __b)
def f3(self, __a=42, /, __b=43, *, __c=44):
return (__a, __b, __c)
self.assertEqual(X().f(), 42)
self.assertEqual(X().f2(), (42, 43))
self.assertEqual(X().f3(), (42, 43, 44))
def test_too_many_arguments(self):
# more than 255 positional-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 test_serialization(self):
pickled_posonly = pickle.dumps(global_pos_only_f)
pickled_optional = pickle.dumps(global_pos_only_and_normal)
pickled_defaults = pickle.dumps(global_pos_only_defaults)
unpickled_posonly = pickle.loads(pickled_posonly)
unpickled_optional = pickle.loads(pickled_optional)
unpickled_defaults = pickle.loads(pickled_defaults)
self.assertEqual(unpickled_posonly(1,2), (1,2))
expected = r"global_pos_only_f\(\) got some positional-only arguments "\
r"passed as keyword arguments: 'a, b'"
with self.assertRaisesRegex(TypeError, expected):
unpickled_posonly(a=1,b=2)
self.assertEqual(unpickled_optional(1,2), (1,2))
expected = r"global_pos_only_and_normal\(\) got some positional-only arguments "\
r"passed as keyword arguments: 'a'"
with self.assertRaisesRegex(TypeError, expected):
unpickled_optional(a=1,b=2)
self.assertEqual(unpickled_defaults(), (1,2))
expected = r"global_pos_only_defaults\(\) got some positional-only arguments "\
r"passed as keyword arguments: 'a'"
with self.assertRaisesRegex(TypeError, expected):
unpickled_defaults(a=1,b=2)
def test_async(self):
async def f(a=1, /, b=2):
return a, b
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"):
f(a=1, b=2)
def _check_call(*args, **kwargs):
try:
coro = f(*args, **kwargs)
coro.send(None)
except StopIteration as e:
result = e.value
self.assertEqual(result, (1, 2))
_check_call(1, 2)
_check_call(1, b=2)
_check_call(1)
_check_call()
def test_generator(self):
def f(a=1, /, b=2):
yield a, b
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"):
f(a=1, b=2)
gen = f(1, 2)
self.assertEqual(next(gen), (1, 2))
gen = f(1, b=2)
self.assertEqual(next(gen), (1, 2))
gen = f(1)
self.assertEqual(next(gen), (1, 2))
gen = f()
self.assertEqual(next(gen), (1, 2))
if __name__ == "__main__":
unittest.main()

View File

@ -101,7 +101,7 @@ def fab(
def fab( def fab(
a, # type: A a, # type: A
b # type: B b # type: B
): ):
pass pass

View File

@ -263,7 +263,7 @@ def coroutine(func):
# TODO: Implement this in C. # TODO: Implement this in C.
co = func.__code__ co = func.__code__
func.__code__ = CodeType( func.__code__ = CodeType(
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_argcount, co.co_posonlyargcount, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_stacksize,
co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
co.co_code, co.co_code,

View File

@ -0,0 +1,2 @@
Implement :pep:`570` (Python positional-only parameters). Patch by Pablo
Galindo.

View File

@ -320,11 +320,11 @@ _PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{ {
/* Fast paths */ /* Fast paths */
if (argdefs == NULL && co->co_argcount == nargs) { if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount == nargs) {
return function_code_fastcall(co, args, nargs, globals); return function_code_fastcall(co, args, nargs, globals);
} }
else if (nargs == 0 && argdefs != NULL else if (nargs == 0 && argdefs != NULL
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) { && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
/* function called with no arguments, but all parameters have /* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/ a default value: use default values as arguments .*/
args = _PyTuple_ITEMS(argdefs); args = _PyTuple_ITEMS(argdefs);
@ -406,11 +406,11 @@ _PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack,
if (co->co_kwonlyargcount == 0 && nkwargs == 0 && if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{ {
if (argdefs == NULL && co->co_argcount == nargs) { if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount== nargs) {
return function_code_fastcall(co, stack, nargs, globals); return function_code_fastcall(co, stack, nargs, globals);
} }
else if (nargs == 0 && argdefs != NULL else if (nargs == 0 && argdefs != NULL
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) { && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
/* function called with no arguments, but all parameters have /* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/ a default value: use default values as arguments .*/
stack = _PyTuple_ITEMS(argdefs); stack = _PyTuple_ITEMS(argdefs);

View File

@ -96,7 +96,7 @@ intern_string_constants(PyObject *tuple)
PyCodeObject * PyCodeObject *
PyCode_New(int argcount, int kwonlyargcount, PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
int nlocals, int stacksize, int flags, int nlocals, int stacksize, int flags,
PyObject *code, PyObject *consts, PyObject *names, PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *varnames, PyObject *freevars, PyObject *cellvars,
@ -108,8 +108,8 @@ PyCode_New(int argcount, int kwonlyargcount,
Py_ssize_t i, n_cellvars, n_varnames, total_args; Py_ssize_t i, n_cellvars, n_varnames, total_args;
/* Check argument types */ /* Check argument types */
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 || if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 ||
code == NULL || !PyBytes_Check(code) || nlocals < 0 || code == NULL || !PyBytes_Check(code) ||
consts == NULL || !PyTuple_Check(consts) || consts == NULL || !PyTuple_Check(consts) ||
names == NULL || !PyTuple_Check(names) || names == NULL || !PyTuple_Check(names) ||
varnames == NULL || !PyTuple_Check(varnames) || varnames == NULL || !PyTuple_Check(varnames) ||
@ -141,10 +141,12 @@ PyCode_New(int argcount, int kwonlyargcount,
} }
n_varnames = PyTuple_GET_SIZE(varnames); n_varnames = PyTuple_GET_SIZE(varnames);
if (argcount <= n_varnames && kwonlyargcount <= n_varnames) { if (posonlyargcount + argcount <= n_varnames
&& kwonlyargcount <= n_varnames) {
/* Never overflows. */ /* Never overflows. */
total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount + total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0); + (Py_ssize_t)kwonlyargcount +
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
} }
else { else {
total_args = n_varnames + 1; total_args = n_varnames + 1;
@ -193,6 +195,7 @@ PyCode_New(int argcount, int kwonlyargcount,
return NULL; return NULL;
} }
co->co_argcount = argcount; co->co_argcount = argcount;
co->co_posonlyargcount = posonlyargcount;
co->co_kwonlyargcount = kwonlyargcount; co->co_kwonlyargcount = kwonlyargcount;
co->co_nlocals = nlocals; co->co_nlocals = nlocals;
co->co_stacksize = stacksize; co->co_stacksize = stacksize;
@ -249,6 +252,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
goto failed; goto failed;
result = PyCode_New(0, /* argcount */ result = PyCode_New(0, /* argcount */
0, /* posonlyargcount */
0, /* kwonlyargcount */ 0, /* kwonlyargcount */
0, /* nlocals */ 0, /* nlocals */
0, /* stacksize */ 0, /* stacksize */
@ -274,21 +278,22 @@ failed:
#define OFF(x) offsetof(PyCodeObject, x) #define OFF(x) offsetof(PyCodeObject, x)
static PyMemberDef code_memberlist[] = { static PyMemberDef code_memberlist[] = {
{"co_argcount", T_INT, OFF(co_argcount), READONLY}, {"co_argcount", T_INT, OFF(co_argcount), READONLY},
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY}, {"co_posonlyargcount", T_INT, OFF(co_posonlyargcount), READONLY},
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY}, {"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY}, {"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
{"co_flags", T_INT, OFF(co_flags), READONLY}, {"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
{"co_code", T_OBJECT, OFF(co_code), READONLY}, {"co_flags", T_INT, OFF(co_flags), READONLY},
{"co_consts", T_OBJECT, OFF(co_consts), READONLY}, {"co_code", T_OBJECT, OFF(co_code), READONLY},
{"co_names", T_OBJECT, OFF(co_names), READONLY}, {"co_consts", T_OBJECT, OFF(co_consts), READONLY},
{"co_varnames", T_OBJECT, OFF(co_varnames), READONLY}, {"co_names", T_OBJECT, OFF(co_names), READONLY},
{"co_freevars", T_OBJECT, OFF(co_freevars), READONLY}, {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
{"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY}, {"co_freevars", T_OBJECT, OFF(co_freevars), READONLY},
{"co_filename", T_OBJECT, OFF(co_filename), READONLY}, {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
{"co_name", T_OBJECT, OFF(co_name), READONLY}, {"co_filename", T_OBJECT, OFF(co_filename), READONLY},
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, {"co_name", T_OBJECT, OFF(co_name), READONLY},
{"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
{"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@ -335,9 +340,9 @@ validate_and_copy_tuple(PyObject *tup)
} }
PyDoc_STRVAR(code_doc, PyDoc_STRVAR(code_doc,
"code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n\ "code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\
constants, names, varnames, filename, name, firstlineno,\n\ flags, codestring, constants, names, varnames, filename, name,\n\
lnotab[, freevars[, cellvars]])\n\ firstlineno, lnotab[, freevars[, cellvars]])\n\
\n\ \n\
Create a code object. Not for the faint of heart."); Create a code object. Not for the faint of heart.");
@ -345,6 +350,7 @@ static PyObject *
code_new(PyTypeObject *type, PyObject *args, PyObject *kw) code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{ {
int argcount; int argcount;
int posonlyargcount;
int kwonlyargcount; int kwonlyargcount;
int nlocals; int nlocals;
int stacksize; int stacksize;
@ -361,8 +367,8 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
int firstlineno; int firstlineno;
PyObject *lnotab; PyObject *lnotab;
if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!UUiS|O!O!:code", if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code",
&argcount, &kwonlyargcount, &argcount, &posonlyargcount, &kwonlyargcount,
&nlocals, &stacksize, &flags, &nlocals, &stacksize, &flags,
&code, &code,
&PyTuple_Type, &consts, &PyTuple_Type, &consts,
@ -381,6 +387,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
goto cleanup; goto cleanup;
} }
if (posonlyargcount < 0) {
PyErr_SetString(
PyExc_ValueError,
"code: posonlyargcount must not be negative");
goto cleanup;
}
if (kwonlyargcount < 0) { if (kwonlyargcount < 0) {
PyErr_SetString( PyErr_SetString(
PyExc_ValueError, PyExc_ValueError,
@ -413,7 +426,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
if (ourcellvars == NULL) if (ourcellvars == NULL)
goto cleanup; goto cleanup;
co = (PyObject *)PyCode_New(argcount, kwonlyargcount, co = (PyObject *)PyCode_New(argcount, posonlyargcount, kwonlyargcount,
nlocals, stacksize, flags, nlocals, stacksize, flags,
code, consts, ournames, ourvarnames, code, consts, ournames, ourvarnames,
ourfreevars, ourcellvars, filename, ourfreevars, ourcellvars, filename,
@ -645,9 +658,11 @@ code_richcompare(PyObject *self, PyObject *other, int op)
cp = (PyCodeObject *)other; cp = (PyCodeObject *)other;
eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ); eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
if (eq <= 0) goto unequal; if (!eq) goto unequal;
eq = co->co_argcount == cp->co_argcount; eq = co->co_argcount == cp->co_argcount;
if (!eq) goto unequal; if (!eq) goto unequal;
eq = co->co_posonlyargcount == cp->co_posonlyargcount;
if (!eq) goto unequal;
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount; eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
if (!eq) goto unequal; if (!eq) goto unequal;
eq = co->co_nlocals == cp->co_nlocals; eq = co->co_nlocals == cp->co_nlocals;
@ -720,7 +735,7 @@ code_hash(PyCodeObject *co)
h6 = PyObject_Hash(co->co_cellvars); h6 = PyObject_Hash(co->co_cellvars);
if (h6 == -1) return -1; if (h6 == -1) return -1;
h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
co->co_argcount ^ co->co_kwonlyargcount ^ co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
co->co_nlocals ^ co->co_flags; co->co_nlocals ^ co->co_flags;
if (h == -1) h = -2; if (h == -1) h = -2;
return h; return h;

View File

@ -1139,7 +1139,7 @@ static PYC_MAGIC magic_values[] = {
{ 3320, 3351, L"3.5" }, { 3320, 3351, L"3.5" },
{ 3360, 3379, L"3.6" }, { 3360, 3379, L"3.6" },
{ 3390, 3399, L"3.7" }, { 3390, 3399, L"3.7" },
{ 3400, 3409, L"3.8" }, { 3400, 3410, L"3.8" },
{ 0 } { 0 }
}; };

View File

@ -111,8 +111,8 @@ module Python
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, arguments = (arg* args, arg* posonlyargs, arg? vararg, arg* kwonlyargs,
arg? kwarg, expr* defaults) expr* kw_defaults, arg? kwarg, expr* defaults)
arg = (identifier arg, expr? annotation, string? type_comment) arg = (identifier arg, expr? annotation, string? type_comment)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

50
Python/Python-ast.c generated
View File

@ -469,6 +469,7 @@ static char *ExceptHandler_fields[]={
}; };
static PyTypeObject *arguments_type; static PyTypeObject *arguments_type;
static PyObject* ast2obj_arguments(void*); static PyObject* ast2obj_arguments(void*);
_Py_IDENTIFIER(posonlyargs);
_Py_IDENTIFIER(vararg); _Py_IDENTIFIER(vararg);
_Py_IDENTIFIER(kwonlyargs); _Py_IDENTIFIER(kwonlyargs);
_Py_IDENTIFIER(kw_defaults); _Py_IDENTIFIER(kw_defaults);
@ -476,6 +477,7 @@ _Py_IDENTIFIER(kwarg);
_Py_IDENTIFIER(defaults); _Py_IDENTIFIER(defaults);
static char *arguments_fields[]={ static char *arguments_fields[]={
"args", "args",
"posonlyargs",
"vararg", "vararg",
"kwonlyargs", "kwonlyargs",
"kw_defaults", "kw_defaults",
@ -1141,7 +1143,7 @@ static int init_types(void)
ExceptHandler_type = make_type("ExceptHandler", excepthandler_type, ExceptHandler_type = make_type("ExceptHandler", excepthandler_type,
ExceptHandler_fields, 3); ExceptHandler_fields, 3);
if (!ExceptHandler_type) return 0; if (!ExceptHandler_type) return 0;
arguments_type = make_type("arguments", &AST_type, arguments_fields, 6); arguments_type = make_type("arguments", &AST_type, arguments_fields, 7);
if (!arguments_type) return 0; if (!arguments_type) return 0;
if (!add_attributes(arguments_type, NULL, 0)) return 0; if (!add_attributes(arguments_type, NULL, 0)) return 0;
arg_type = make_type("arg", &AST_type, arg_fields, 3); arg_type = make_type("arg", &AST_type, arg_fields, 3);
@ -2569,14 +2571,16 @@ ExceptHandler(expr_ty type, identifier name, asdl_seq * body, int lineno, int
} }
arguments_ty arguments_ty
arguments(asdl_seq * args, arg_ty vararg, asdl_seq * kwonlyargs, asdl_seq * arguments(asdl_seq * args, asdl_seq * posonlyargs, arg_ty vararg, asdl_seq *
kw_defaults, arg_ty kwarg, asdl_seq * defaults, PyArena *arena) kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, asdl_seq *
defaults, PyArena *arena)
{ {
arguments_ty p; arguments_ty p;
p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p) if (!p)
return NULL; return NULL;
p->args = args; p->args = args;
p->posonlyargs = posonlyargs;
p->vararg = vararg; p->vararg = vararg;
p->kwonlyargs = kwonlyargs; p->kwonlyargs = kwonlyargs;
p->kw_defaults = kw_defaults; p->kw_defaults = kw_defaults;
@ -3954,6 +3958,11 @@ ast2obj_arguments(void* _o)
if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) if (_PyObject_SetAttrId(result, &PyId_args, value) == -1)
goto failed; goto failed;
Py_DECREF(value); Py_DECREF(value);
value = ast2obj_list(o->posonlyargs, ast2obj_arg);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_posonlyargs, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_arg(o->vararg); value = ast2obj_arg(o->vararg);
if (!value) goto failed; if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1) if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1)
@ -8267,6 +8276,7 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
{ {
PyObject* tmp = NULL; PyObject* tmp = NULL;
asdl_seq* args; asdl_seq* args;
asdl_seq* posonlyargs;
arg_ty vararg; arg_ty vararg;
asdl_seq* kwonlyargs; asdl_seq* kwonlyargs;
asdl_seq* kw_defaults; asdl_seq* kw_defaults;
@ -8303,6 +8313,36 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
} }
Py_CLEAR(tmp); Py_CLEAR(tmp);
} }
if (_PyObject_LookupAttrId(obj, &PyId_posonlyargs, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"posonlyargs\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"posonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
posonlyargs = _Py_asdl_seq_new(len, arena);
if (posonlyargs == NULL) goto failed;
for (i = 0; i < len; i++) {
arg_ty val;
res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &val, arena);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"posonlyargs\" changed size during iteration");
goto failed;
}
asdl_seq_SET(posonlyargs, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttrId(obj, &PyId_vararg, &tmp) < 0) { if (_PyObject_LookupAttrId(obj, &PyId_vararg, &tmp) < 0) {
return 1; return 1;
} }
@ -8419,8 +8459,8 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
} }
Py_CLEAR(tmp); Py_CLEAR(tmp);
} }
*out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, defaults, *out = arguments(args, posonlyargs, vararg, kwonlyargs, kw_defaults, kwarg,
arena); defaults, arena);
return 0; return 0;
failed: failed:
Py_XDECREF(tmp); Py_XDECREF(tmp);

View File

@ -110,8 +110,9 @@ expr_context_name(expr_context_ty ctx)
static int static int
validate_arguments(arguments_ty args) validate_arguments(arguments_ty args)
{ {
if (!validate_args(args->args)) if (!validate_args(args->posonlyargs) || !validate_args(args->args)) {
return 0; return 0;
}
if (args->vararg && args->vararg->annotation if (args->vararg && args->vararg->annotation
&& !validate_expr(args->vararg->annotation, Load)) { && !validate_expr(args->vararg->annotation, Load)) {
return 0; return 0;
@ -1431,31 +1432,73 @@ ast_for_arguments(struct compiling *c, const node *n)
and varargslist (lambda definition). and varargslist (lambda definition).
parameters: '(' [typedargslist] ')' parameters: '(' [typedargslist] ')'
typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [
'*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] The following definition for typedarglist is equivalent to this set of rules:
| '**' tfpdef [',']]]
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] arguments = argument (',' [TYPE_COMMENT] argument)*
| '**' tfpdef [',']) argument = tfpdef ['=' test]
kwargs = '**' tfpdef [','] [TYPE_COMMENT]
args = '*' [tfpdef]
kwonly_kwargs = (',' [TYPE_COMMENT] argument)* (TYPE_COMMENT | [','
[TYPE_COMMENT] [kwargs]])
args_kwonly_kwargs = args kwonly_kwargs | kwargs
poskeyword_args_kwonly_kwargs = arguments ( TYPE_COMMENT | [','
[TYPE_COMMENT] [args_kwonly_kwargs]])
typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
typedarglist = (arguments ',' [TYPE_COMMENT] '/' [',' [[TYPE_COMMENT]
typedargslist_no_posonly]])|(typedargslist_no_posonly)"
typedargslist: ( (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])*
',' [TYPE_COMMENT] '/' [',' [ [TYPE_COMMENT] tfpdef ['=' test] ( ','
[TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [ '*'
[tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [','
[TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) | '**' tfpdef [',']
[TYPE_COMMENT]]]) | '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])*
(TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) |
'**' tfpdef [','] [TYPE_COMMENT]]] ) | (tfpdef ['=' test] (','
[TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [ '*'
[tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [','
[TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) | '**' tfpdef [',']
[TYPE_COMMENT]]]) | '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])*
(TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) |
'**' tfpdef [','] [TYPE_COMMENT]))
tfpdef: NAME [':' test] tfpdef: NAME [':' test]
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] The following definition for varargslist is equivalent to this set of rules:
| '**' vfpdef [',']]]
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] arguments = argument (',' argument )*
| '**' vfpdef [','] argument = vfpdef ['=' test]
) kwargs = '**' vfpdef [',']
args = '*' [vfpdef]
kwonly_kwargs = (',' argument )* [',' [kwargs]]
args_kwonly_kwargs = args kwonly_kwargs | kwargs
poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] |
(vararglist_no_posonly)
varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ (vfpdef ['='
test] (',' vfpdef ['=' test])* [',' [ '*' [vfpdef] (',' vfpdef ['=' test])* [','
['**' vfpdef [',']]] | '**' vfpdef [',']]] | '*' [vfpdef] (',' vfpdef ['=' test])*
[',' ['**' vfpdef [',']]] | '**' vfpdef [',']) ]] | (vfpdef ['=' test] (',' vfpdef
['=' test])* [',' [ '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef
[',']]] | '**' vfpdef [','])
vfpdef: NAME vfpdef: NAME
*/ */
int i, j, k, nposargs = 0, nkwonlyargs = 0; int i, j, k, l, nposonlyargs=0, nposargs = 0, nkwonlyargs = 0;
int nposdefaults = 0, found_default = 0; int nposdefaults = 0, found_default = 0;
asdl_seq *posargs, *posdefaults, *kwonlyargs, *kwdefaults; asdl_seq *posonlyargs, *posargs, *posdefaults, *kwonlyargs, *kwdefaults;
arg_ty vararg = NULL, kwarg = NULL; arg_ty vararg = NULL, kwarg = NULL;
arg_ty arg = NULL; arg_ty arg = NULL;
node *ch; node *ch;
if (TYPE(n) == parameters) { if (TYPE(n) == parameters) {
if (NCH(n) == 2) /* () as argument list */ if (NCH(n) == 2) /* () as argument list */
return arguments(NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena); return arguments(NULL, NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
n = CHILD(n, 1); n = CHILD(n, 1);
} }
assert(TYPE(n) == typedargslist || TYPE(n) == varargslist); assert(TYPE(n) == typedargslist || TYPE(n) == varargslist);
@ -1479,6 +1522,10 @@ ast_for_arguments(struct compiling *c, const node *n)
if (TYPE(ch) == DOUBLESTAR) break; if (TYPE(ch) == DOUBLESTAR) break;
if (TYPE(ch) == vfpdef || TYPE(ch) == tfpdef) nposargs++; if (TYPE(ch) == vfpdef || TYPE(ch) == tfpdef) nposargs++;
if (TYPE(ch) == EQUAL) nposdefaults++; if (TYPE(ch) == EQUAL) nposdefaults++;
if (TYPE(ch) == SLASH ) {
nposonlyargs = nposargs;
nposargs = 0;
}
} }
/* count the number of keyword only args & /* count the number of keyword only args &
defaults for keyword only args */ defaults for keyword only args */
@ -1487,6 +1534,10 @@ ast_for_arguments(struct compiling *c, const node *n)
if (TYPE(ch) == DOUBLESTAR) break; if (TYPE(ch) == DOUBLESTAR) break;
if (TYPE(ch) == tfpdef || TYPE(ch) == vfpdef) nkwonlyargs++; if (TYPE(ch) == tfpdef || TYPE(ch) == vfpdef) nkwonlyargs++;
} }
posonlyargs = (nposonlyargs ? _Py_asdl_seq_new(nposonlyargs, c->c_arena) : NULL);
if (!posonlyargs && nposonlyargs) {
return NULL;
}
posargs = (nposargs ? _Py_asdl_seq_new(nposargs, c->c_arena) : NULL); posargs = (nposargs ? _Py_asdl_seq_new(nposargs, c->c_arena) : NULL);
if (!posargs && nposargs) if (!posargs && nposargs)
return NULL; return NULL;
@ -1512,6 +1563,7 @@ ast_for_arguments(struct compiling *c, const node *n)
i = 0; i = 0;
j = 0; /* index for defaults */ j = 0; /* index for defaults */
k = 0; /* index for args */ k = 0; /* index for args */
l = 0; /* index for posonlyargs */
while (i < NCH(n)) { while (i < NCH(n)) {
ch = CHILD(n, i); ch = CHILD(n, i);
switch (TYPE(ch)) { switch (TYPE(ch)) {
@ -1537,11 +1589,23 @@ ast_for_arguments(struct compiling *c, const node *n)
arg = ast_for_arg(c, ch); arg = ast_for_arg(c, ch);
if (!arg) if (!arg)
return NULL; return NULL;
asdl_seq_SET(posargs, k++, arg); if (l < nposonlyargs) {
asdl_seq_SET(posonlyargs, l++, arg);
} else {
asdl_seq_SET(posargs, k++, arg);
}
i += 1; /* the name */ i += 1; /* the name */
if (i < NCH(n) && TYPE(CHILD(n, i)) == COMMA) if (i < NCH(n) && TYPE(CHILD(n, i)) == COMMA)
i += 1; /* the comma, if present */ i += 1; /* the comma, if present */
break; break;
case SLASH:
/* Advance the slash and the comma. If there are more names
* after the slash there will be a comma so we are advancing
* the correct number of nodes. If the slash is the last item,
* we will be advancing an extra token but then * i > NCH(n)
* and the enclosing while will finish correctly. */
i += 2;
break;
case STAR: case STAR:
if (i+1 >= NCH(n) || if (i+1 >= NCH(n) ||
(i+2 == NCH(n) && (TYPE(CHILD(n, i+1)) == COMMA (i+2 == NCH(n) && (TYPE(CHILD(n, i+1)) == COMMA
@ -1621,7 +1685,7 @@ ast_for_arguments(struct compiling *c, const node *n)
return NULL; return NULL;
} }
} }
return arguments(posargs, vararg, kwonlyargs, kwdefaults, kwarg, posdefaults, c->c_arena); return arguments(posargs, posonlyargs, vararg, kwonlyargs, kwdefaults, kwarg, posdefaults, c->c_arena);
} }
static expr_ty static expr_ty
@ -1909,7 +1973,7 @@ ast_for_lambdef(struct compiling *c, const node *n)
expr_ty expression; expr_ty expression;
if (NCH(n) == 3) { if (NCH(n) == 3) {
args = arguments(NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena); args = arguments(NULL, NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
if (!args) if (!args)
return NULL; return NULL;
expression = ast_for_expr(c, CHILD(n, 2)); expression = ast_for_expr(c, CHILD(n, 2));

View File

@ -3694,10 +3694,10 @@ missing_arguments(PyCodeObject *co, Py_ssize_t missing, Py_ssize_t defcount,
return; return;
if (positional) { if (positional) {
start = 0; start = 0;
end = co->co_argcount - defcount; end = co->co_posonlyargcount + co->co_argcount - defcount;
} }
else { else {
start = co->co_argcount; start = co->co_posonlyargcount + co->co_argcount;
end = start + co->co_kwonlyargcount; end = start + co->co_kwonlyargcount;
} }
for (i = start; i < end; i++) { for (i = start; i < end; i++) {
@ -3724,23 +3724,25 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
Py_ssize_t kwonly_given = 0; Py_ssize_t kwonly_given = 0;
Py_ssize_t i; Py_ssize_t i;
PyObject *sig, *kwonly_sig; PyObject *sig, *kwonly_sig;
Py_ssize_t co_posonlyargcount = co->co_posonlyargcount;
Py_ssize_t co_argcount = co->co_argcount; Py_ssize_t co_argcount = co->co_argcount;
Py_ssize_t total_positional = co_argcount + co_posonlyargcount;
assert((co->co_flags & CO_VARARGS) == 0); assert((co->co_flags & CO_VARARGS) == 0);
/* Count missing keyword-only args. */ /* Count missing keyword-only args. */
for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) { for (i = total_positional; i < total_positional + co->co_kwonlyargcount; i++) {
if (GETLOCAL(i) != NULL) { if (GETLOCAL(i) != NULL) {
kwonly_given++; kwonly_given++;
} }
} }
if (defcount) { if (defcount) {
Py_ssize_t atleast = co_argcount - defcount; Py_ssize_t atleast = total_positional - defcount;
plural = 1; plural = 1;
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount); sig = PyUnicode_FromFormat("from %zd to %zd", atleast, total_positional);
} }
else { else {
plural = (co_argcount != 1); plural = (total_positional != 1);
sig = PyUnicode_FromFormat("%zd", co_argcount); sig = PyUnicode_FromFormat("%zd", total_positional);
} }
if (sig == NULL) if (sig == NULL)
return; return;
@ -3772,6 +3774,67 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
Py_DECREF(kwonly_sig); Py_DECREF(kwonly_sig);
} }
static int
positional_only_passed_as_keyword(PyCodeObject *co, Py_ssize_t kwcount,
PyObject* const* kwnames)
{
int posonly_conflicts = 0;
PyObject* posonly_names = PyList_New(0);
for(int k=0; k < co->co_posonlyargcount; k++){
PyObject* posonly_name = PyTuple_GET_ITEM(co->co_varnames, k);
for (int k2=0; k2<kwcount; k2++){
/* Compare the pointers first and fallback to PyObject_RichCompareBool*/
PyObject* kwname = kwnames[k2];
if (kwname == posonly_name){
if(PyList_Append(posonly_names, kwname) != 0) {
goto fail;
}
posonly_conflicts++;
continue;
}
int cmp = PyObject_RichCompareBool(posonly_name, kwname, Py_EQ);
if ( cmp > 0) {
if(PyList_Append(posonly_names, kwname) != 0) {
goto fail;
}
posonly_conflicts++;
} else if (cmp < 0) {
goto fail;
}
}
}
if (posonly_conflicts) {
PyObject* comma = PyUnicode_FromString(", ");
if (comma == NULL) {
goto fail;
}
PyObject* error_names = PyUnicode_Join(comma, posonly_names);
Py_DECREF(comma);
if (error_names == NULL) {
goto fail;
}
PyErr_Format(PyExc_TypeError,
"%U() got some positional-only arguments passed"
" as keyword arguments: '%U'",
co->co_name, error_names);
Py_DECREF(error_names);
goto fail;
}
Py_DECREF(posonly_names);
return 0;
fail:
Py_XDECREF(posonly_names);
return 1;
}
/* This is gonna seem *real weird*, but if you put some other code between /* This is gonna seem *real weird*, but if you put some other code between
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
the test in the if statements in Misc/gdbinit (pystack and pystackv). */ the test in the if statements in Misc/gdbinit (pystack and pystackv). */
@ -3791,8 +3854,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **fastlocals, **freevars; PyObject **fastlocals, **freevars;
PyThreadState *tstate; PyThreadState *tstate;
PyObject *x, *u; PyObject *x, *u;
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
Py_ssize_t i, n; Py_ssize_t i, j, n;
PyObject *kwdict; PyObject *kwdict;
if (globals == NULL) { if (globals == NULL) {
@ -3826,14 +3889,28 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
kwdict = NULL; kwdict = NULL;
} }
/* Copy positional arguments into local variables */ /* Copy positional only arguments into local variables */
if (argcount > co->co_argcount) { if (argcount > co->co_argcount + co->co_posonlyargcount) {
n = co->co_argcount; n = co->co_posonlyargcount;
} }
else { else {
n = argcount; n = argcount;
} }
for (i = 0; i < n; i++) { for (j = 0; j < n; j++) {
x = args[j];
Py_INCREF(x);
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]; x = args[i];
Py_INCREF(x); Py_INCREF(x);
SETLOCAL(i, x); SETLOCAL(i, x);
@ -3866,7 +3943,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
/* Speed hack: do raw pointer compares. As names are /* Speed hack: do raw pointer compares. As names are
normally interned this should almost always hit. */ normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item; co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = 0; j < total_args; j++) { for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *name = co_varnames[j]; PyObject *name = co_varnames[j];
if (name == keyword) { if (name == keyword) {
goto kw_found; goto kw_found;
@ -3874,7 +3951,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
} }
/* Slow fallback, just in case */ /* Slow fallback, just in case */
for (j = 0; j < total_args; j++) { for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *name = co_varnames[j]; PyObject *name = co_varnames[j];
int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ); int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ);
if (cmp > 0) { if (cmp > 0) {
@ -3887,6 +3964,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
assert(j >= total_args); assert(j >= total_args);
if (kwdict == NULL) { if (kwdict == NULL) {
if (co->co_posonlyargcount && positional_only_passed_as_keyword(co, kwcount, kwnames)) {
goto fail;
}
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%U() got an unexpected keyword argument '%S'", "%U() got an unexpected keyword argument '%S'",
co->co_name, keyword); co->co_name, keyword);
@ -3910,14 +3992,14 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
} }
/* Check the number of positional arguments */ /* Check the number of positional arguments */
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) { if ((argcount > co->co_argcount + co->co_posonlyargcount) && !(co->co_flags & CO_VARARGS)) {
too_many_positional(co, argcount, defcount, fastlocals); too_many_positional(co, argcount, defcount, fastlocals);
goto fail; goto fail;
} }
/* Add missing positional arguments (copy default values from defs) */ /* Add missing positional arguments (copy default values from defs) */
if (argcount < co->co_argcount) { if (argcount < co->co_posonlyargcount + co->co_argcount) {
Py_ssize_t m = co->co_argcount - defcount; Py_ssize_t m = co->co_posonlyargcount + co->co_argcount - defcount;
Py_ssize_t missing = 0; Py_ssize_t missing = 0;
for (i = argcount; i < m; i++) { for (i = argcount; i < m; i++) {
if (GETLOCAL(i) == NULL) { if (GETLOCAL(i) == NULL) {
@ -3944,7 +4026,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
/* Add missing keyword arguments (copy default values from kwdefs) */ /* Add missing keyword arguments (copy default values from kwdefs) */
if (co->co_kwonlyargcount > 0) { if (co->co_kwonlyargcount > 0) {
Py_ssize_t missing = 0; Py_ssize_t missing = 0;
for (i = co->co_argcount; i < total_args; i++) { for (i = co->co_posonlyargcount + co->co_argcount; i < total_args; i++) {
PyObject *name; PyObject *name;
if (GETLOCAL(i) != NULL) if (GETLOCAL(i) != NULL)
continue; continue;

View File

@ -122,6 +122,7 @@ struct compiler_unit {
PyObject *u_private; /* for private name mangling */ PyObject *u_private; /* for private name mangling */
Py_ssize_t u_argcount; /* number of arguments for block */ Py_ssize_t u_argcount; /* number of arguments for block */
Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */
Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
/* Pointer to the most recently allocated block. By following b_list /* Pointer to the most recently allocated block. By following b_list
members, you can reach all early allocated blocks. */ members, you can reach all early allocated blocks. */
@ -552,6 +553,7 @@ compiler_enter_scope(struct compiler *c, identifier name,
memset(u, 0, sizeof(struct compiler_unit)); memset(u, 0, sizeof(struct compiler_unit));
u->u_scope_type = scope_type; u->u_scope_type = scope_type;
u->u_argcount = 0; u->u_argcount = 0;
u->u_posonlyargcount = 0;
u->u_kwonlyargcount = 0; u->u_kwonlyargcount = 0;
u->u_ste = PySymtable_Lookup(c->c_st, key); u->u_ste = PySymtable_Lookup(c->c_st, key);
if (!u->u_ste) { if (!u->u_ste) {
@ -2127,6 +2129,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
} }
c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_argcount = asdl_seq_LEN(args->args);
c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
VISIT_SEQ_IN_SCOPE(c, stmt, body); VISIT_SEQ_IN_SCOPE(c, stmt, body);
co = assemble(c, 1); co = assemble(c, 1);
@ -2507,6 +2510,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
return 0; return 0;
c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_argcount = asdl_seq_LEN(args->args);
c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body); VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
if (c->u->u_ste->ste_generator) { if (c->u->u_ste->ste_generator) {
@ -5742,7 +5746,7 @@ makecode(struct compiler *c, struct assembler *a)
Py_ssize_t nlocals; Py_ssize_t nlocals;
int nlocals_int; int nlocals_int;
int flags; int flags;
int argcount, kwonlyargcount, maxdepth; int argcount, posonlyargcount, kwonlyargcount, maxdepth;
consts = consts_dict_keys_inorder(c->u->u_consts); consts = consts_dict_keys_inorder(c->u->u_consts);
names = dict_keys_inorder(c->u->u_names, 0); names = dict_keys_inorder(c->u->u_names, 0);
@ -5787,12 +5791,13 @@ makecode(struct compiler *c, struct assembler *a)
} }
argcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int); argcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
posonlyargcount = Py_SAFE_DOWNCAST(c->u->u_posonlyargcount, Py_ssize_t, int);
kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int); kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
maxdepth = stackdepth(c); maxdepth = stackdepth(c);
if (maxdepth < 0) { if (maxdepth < 0) {
goto error; goto error;
} }
co = PyCode_New(argcount, kwonlyargcount, co = PyCode_New(argcount, posonlyargcount, kwonlyargcount,
nlocals_int, maxdepth, flags, nlocals_int, maxdepth, flags,
bytecode, consts, names, varnames, bytecode, consts, names, varnames,
freevars, cellvars, freevars, cellvars,

View File

@ -15,15 +15,15 @@
the appropriate bytes from M___main__.c. */ the appropriate bytes from M___main__.c. */
static unsigned char M___hello__[] = { static unsigned char M___hello__[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, 227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,64,0,0,0,115,16,0,0,0,100,0,90,0,101,1, 0,2,0,0,0,64,0,0,0,115,16,0,0,0,100,0,
100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72, 90,0,101,1,100,1,131,1,1,0,100,2,83,0,41,3,
101,108,108,111,32,119,111,114,108,100,33,78,41,2,218,11, 84,122,12,72,101,108,108,111,32,119,111,114,108,100,33,78,
105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105, 41,2,218,11,105,110,105,116,105,97,108,105,122,101,100,218,
110,116,169,0,114,3,0,0,0,114,3,0,0,0,250,22, 5,112,114,105,110,116,169,0,114,3,0,0,0,114,3,0,
46,47,84,111,111,108,115,47,102,114,101,101,122,101,47,102, 0,0,250,20,84,111,111,108,115,47,102,114,101,101,122,101,
108,97,103,46,112,121,218,8,60,109,111,100,117,108,101,62, 47,102,108,97,103,46,112,121,218,8,60,109,111,100,117,108,
1,0,0,0,115,2,0,0,0,4,1, 101,62,1,0,0,0,115,2,0,0,0,4,1,
}; };
#define SIZE (int)sizeof(M___hello__) #define SIZE (int)sizeof(M___hello__)

File diff suppressed because it is too large Load Diff

2781
Python/importlib.h generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -530,6 +530,7 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
PyCodeObject *co = (PyCodeObject *)v; PyCodeObject *co = (PyCodeObject *)v;
W_TYPE(TYPE_CODE, p); W_TYPE(TYPE_CODE, p);
w_long(co->co_argcount, p); w_long(co->co_argcount, p);
w_long(co->co_posonlyargcount, p);
w_long(co->co_kwonlyargcount, p); w_long(co->co_kwonlyargcount, p);
w_long(co->co_nlocals, p); w_long(co->co_nlocals, p);
w_long(co->co_stacksize, p); w_long(co->co_stacksize, p);
@ -1322,6 +1323,7 @@ r_object(RFILE *p)
case TYPE_CODE: case TYPE_CODE:
{ {
int argcount; int argcount;
int posonlyargcount;
int kwonlyargcount; int kwonlyargcount;
int nlocals; int nlocals;
int stacksize; int stacksize;
@ -1347,6 +1349,10 @@ r_object(RFILE *p)
argcount = (int)r_long(p); argcount = (int)r_long(p);
if (PyErr_Occurred()) if (PyErr_Occurred())
goto code_error; goto code_error;
posonlyargcount = (int)r_long(p);
if (PyErr_Occurred()) {
goto code_error;
}
kwonlyargcount = (int)r_long(p); kwonlyargcount = (int)r_long(p);
if (PyErr_Occurred()) if (PyErr_Occurred())
goto code_error; goto code_error;
@ -1391,7 +1397,7 @@ r_object(RFILE *p)
goto code_error; goto code_error;
v = (PyObject *) PyCode_New( v = (PyObject *) PyCode_New(
argcount, kwonlyargcount, argcount, posonlyargcount, kwonlyargcount,
nlocals, stacksize, flags, nlocals, stacksize, flags,
code, consts, names, varnames, code, consts, names, varnames,
freevars, cellvars, filename, name, freevars, cellvars, filename, name,

View File

@ -1653,6 +1653,8 @@ symtable_visit_arguments(struct symtable *st, arguments_ty a)
/* skip default arguments inside function block /* skip default arguments inside function block
XXX should ast be different? XXX should ast be different?
*/ */
if (a->posonlyargs && !symtable_visit_params(st, a->posonlyargs))
return 0;
if (a->args && !symtable_visit_params(st, a->args)) if (a->args && !symtable_visit_params(st, a->args))
return 0; return 0;
if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs)) if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs))

View File

@ -592,14 +592,18 @@ class Unparser:
def _arguments(self, t): def _arguments(self, t):
first = True first = True
# normal arguments # normal arguments
defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults all_args = t.posonlyargs + t.args
for a, d in zip(t.args, defaults): defaults = [None] * (len(all_args) - len(t.defaults)) + t.defaults
for index, elements in enumerate(zip(all_args, defaults), 1):
a, d = elements
if first:first = False if first:first = False
else: self.write(", ") else: self.write(", ")
self.dispatch(a) self.dispatch(a)
if d: if d:
self.write("=") self.write("=")
self.dispatch(d) self.dispatch(d)
if index == len(t.posonlyargs):
self.write(", /")
# varargs, or bare '*' if no varargs but keyword-only arguments present # varargs, or bare '*' if no varargs but keyword-only arguments present
if t.vararg or t.kwonlyargs: if t.vararg or t.kwonlyargs: