Skip to content

Commit e6d5e63

Browse files
miss-islingtonJelleZijlstraAlexWaygood
authored
[3.12] gh-104799: Default missing lists in AST to the empty list (GH-104834) (#105213)
(cherry picked from commit 77d2579) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent d57ee81 commit e6d5e63

File tree

4 files changed

+400
-239
lines changed

4 files changed

+400
-239
lines changed

Lib/test/test_ast.py

+2
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,8 @@ def test_funcdef(self):
15911591
f = ast.FunctionDef("x", a, [ast.Pass()], [],
15921592
ast.Name("x", ast.Store()), None, [])
15931593
self.stmt(f, "must have Load context")
1594+
f = ast.FunctionDef("x", ast.arguments(), [ast.Pass()])
1595+
self.stmt(f)
15941596
def fac(args):
15951597
return ast.FunctionDef("x", args, [ast.Pass()], [], None, None, [])
15961598
self._check_arguments(fac, self.stmt)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Attributes of :mod:`ast` nodes that are lists now default to the empty list
2+
if omitted. This means that some code that previously raised
3+
:exc:`TypeError` when the AST node was used will now proceed with the empty
4+
list instead. Patch by Jelle Zijlstra.

Parser/asdl_c.py

+29-20
Original file line numberDiff line numberDiff line change
@@ -632,29 +632,38 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
632632
self.emit(line % field.name, depth)
633633
self.emit("return 1;", depth+1)
634634
self.emit("}", depth)
635-
if not field.opt:
635+
if field.seq:
636636
self.emit("if (tmp == NULL) {", depth)
637-
message = "required field \\\"%s\\\" missing from %s" % (field.name, name)
638-
format = "PyErr_SetString(PyExc_TypeError, \"%s\");"
639-
self.emit(format % message, depth+1, reflow=False)
640-
self.emit("return 1;", depth+1)
637+
self.emit("tmp = PyList_New(0);", depth+1)
638+
self.emit("if (tmp == NULL) {", depth+1)
639+
self.emit("return 1;", depth+2)
640+
self.emit("}", depth+1)
641+
self.emit("}", depth)
642+
self.emit("{", depth)
641643
else:
642-
self.emit("if (tmp == NULL || tmp == Py_None) {", depth)
643-
self.emit("Py_CLEAR(tmp);", depth+1)
644-
if self.isNumeric(field):
645-
if field.name in self.attribute_special_defaults:
646-
self.emit(
647-
"%s = %s;" % (field.name, self.attribute_special_defaults[field.name]),
648-
depth+1,
649-
)
650-
else:
651-
self.emit("%s = 0;" % field.name, depth+1)
652-
elif not self.isSimpleType(field):
653-
self.emit("%s = NULL;" % field.name, depth+1)
644+
if not field.opt:
645+
self.emit("if (tmp == NULL) {", depth)
646+
message = "required field \\\"%s\\\" missing from %s" % (field.name, name)
647+
format = "PyErr_SetString(PyExc_TypeError, \"%s\");"
648+
self.emit(format % message, depth+1, reflow=False)
649+
self.emit("return 1;", depth+1)
654650
else:
655-
raise TypeError("could not determine the default value for %s" % field.name)
656-
self.emit("}", depth)
657-
self.emit("else {", depth)
651+
self.emit("if (tmp == NULL || tmp == Py_None) {", depth)
652+
self.emit("Py_CLEAR(tmp);", depth+1)
653+
if self.isNumeric(field):
654+
if field.name in self.attribute_special_defaults:
655+
self.emit(
656+
"%s = %s;" % (field.name, self.attribute_special_defaults[field.name]),
657+
depth+1,
658+
)
659+
else:
660+
self.emit("%s = 0;" % field.name, depth+1)
661+
elif not self.isSimpleType(field):
662+
self.emit("%s = NULL;" % field.name, depth+1)
663+
else:
664+
raise TypeError("could not determine the default value for %s" % field.name)
665+
self.emit("}", depth)
666+
self.emit("else {", depth)
658667

659668
self.emit("int res;", depth+1)
660669
if field.seq:

0 commit comments

Comments
 (0)