-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-116022: Improve repr()
of AST nodes
#117046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7461655
447261b
74759bc
4ffc1fb
6094100
5cde4fc
00133b8
e1b7643
0308982
3f2bf3f
4386a5a
af3b2a3
1aaa1c0
06e4657
df70943
ed89975
d8b3bff
cfd6cdf
f022378
0f916cc
e2b0415
9f405ac
b06c8a4
32a5169
7603910
74c57a6
ddd7e71
132932a
a341c57
d03c3d1
44b3303
0b52a65
0b19d2e
2ed3f99
c94c197
6ca6b5b
df34a04
ab823cc
abd35b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Improve the :meth:`~object.__repr__` output of :class:`~ast.AST` nodes. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1435,8 +1435,230 @@ def visitModule(self, mod): | |
{NULL} | ||
}; | ||
|
||
static PyObject * | ||
ast_repr_max_depth(AST_object *self, int depth); | ||
|
||
/* Format list and tuple properties of AST nodes. | ||
Note that, only the first and last elements are shown. | ||
Anything in between is represented with an ellipsis ('...'). | ||
For example, the list [1, 2, 3] is formatted as | ||
'List(elts=[Constant(1), ..., Constant(3)])'. */ | ||
static PyObject * | ||
ast_repr_list(PyObject *list, int depth) | ||
{ | ||
assert(PyList_Check(list) || PyTuple_Check(list)); | ||
|
||
struct ast_state *state = get_ast_state(); | ||
if (state == NULL) { | ||
return NULL; | ||
} | ||
|
||
Py_ssize_t length = PySequence_Size(list); | ||
if (length < 0) { | ||
return NULL; | ||
} | ||
else if (length == 0) { | ||
return PyObject_Repr(list); | ||
} | ||
|
||
_PyUnicodeWriter writer; | ||
picnixz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_PyUnicodeWriter_Init(&writer); | ||
writer.overallocate = 1; | ||
PyObject *items[2] = {NULL, NULL}; | ||
|
||
items[0] = PySequence_GetItem(list, 0); | ||
tomasr8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!items[0]) { | ||
goto error; | ||
} | ||
if (length > 1) { | ||
items[1] = PySequence_GetItem(list, length - 1); | ||
if (!items[1]) { | ||
goto error; | ||
} | ||
} | ||
|
||
bool is_list = PyList_Check(list); | ||
if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) { | ||
goto error; | ||
} | ||
|
||
for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) { | ||
PyObject *item = items[i]; | ||
PyObject *item_repr; | ||
|
||
if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) { | ||
item_repr = ast_repr_max_depth((AST_object*)item, depth - 1); | ||
} else { | ||
item_repr = PyObject_Repr(item); | ||
} | ||
if (!item_repr) { | ||
goto error; | ||
} | ||
if (i > 0) { | ||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { | ||
goto error; | ||
} | ||
} | ||
if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) { | ||
Py_DECREF(item_repr); | ||
goto error; | ||
} | ||
if (i == 0 && length > 2) { | ||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) { | ||
Py_DECREF(item_repr); | ||
goto error; | ||
} | ||
} | ||
Py_DECREF(item_repr); | ||
} | ||
|
||
if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) { | ||
goto error; | ||
} | ||
|
||
Py_XDECREF(items[0]); | ||
Py_XDECREF(items[1]); | ||
return _PyUnicodeWriter_Finish(&writer); | ||
|
||
error: | ||
Py_XDECREF(items[0]); | ||
Py_XDECREF(items[1]); | ||
_PyUnicodeWriter_Dealloc(&writer); | ||
return NULL; | ||
} | ||
|
||
static PyObject * | ||
ast_repr_max_depth(AST_object *self, int depth) | ||
{ | ||
struct ast_state *state = get_ast_state(); | ||
if (state == NULL) { | ||
return NULL; | ||
} | ||
|
||
if (depth <= 0) { | ||
return PyUnicode_FromFormat("%s(...)", Py_TYPE(self)->tp_name); | ||
} | ||
|
||
int status = Py_ReprEnter((PyObject *)self); | ||
if (status != 0) { | ||
if (status < 0) { | ||
return NULL; | ||
} | ||
return PyUnicode_FromFormat("%s(...)", Py_TYPE(self)->tp_name); | ||
} | ||
|
||
PyObject *fields; | ||
if (PyObject_GetOptionalAttr((PyObject *)Py_TYPE(self), state->_fields, &fields) < 0) { | ||
Py_ReprLeave((PyObject *)self); | ||
return NULL; | ||
} | ||
|
||
Py_ssize_t numfields = PySequence_Size(fields); | ||
tomasr8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (numfields < 0) { | ||
Py_ReprLeave((PyObject *)self); | ||
Py_DECREF(fields); | ||
return NULL; | ||
} | ||
|
||
if (numfields == 0) { | ||
Py_ReprLeave((PyObject *)self); | ||
Py_DECREF(fields); | ||
return PyUnicode_FromFormat("%s()", Py_TYPE(self)->tp_name); | ||
} | ||
|
||
const char* tp_name = Py_TYPE(self)->tp_name; | ||
_PyUnicodeWriter writer; | ||
tomasr8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_PyUnicodeWriter_Init(&writer); | ||
writer.overallocate = 1; | ||
|
||
if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) { | ||
goto error; | ||
} | ||
if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { | ||
goto error; | ||
} | ||
|
||
for (Py_ssize_t i = 0; i < numfields; i++) { | ||
PyObject *name = PySequence_GetItem(fields, i); | ||
if (!name) { | ||
goto error; | ||
} | ||
|
||
PyObject *value = PyObject_GetAttr((PyObject *)self, name); | ||
if (!value) { | ||
Py_DECREF(name); | ||
goto error; | ||
} | ||
|
||
PyObject *value_repr; | ||
if (PyList_Check(value) || PyTuple_Check(value)) { | ||
value_repr = ast_repr_list(value, depth); | ||
} | ||
else if (PyType_IsSubtype(Py_TYPE(value), (PyTypeObject *)state->AST_type)) { | ||
value_repr = ast_repr_max_depth((AST_object*)value, depth - 1); | ||
} | ||
else { | ||
value_repr = PyObject_Repr(value); | ||
} | ||
|
||
Py_DECREF(value); | ||
|
||
if (!value_repr) { | ||
Py_DECREF(name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can DECREF name and value earlier so you don't have to repeat this. Looks like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, I move those DECREFs up |
||
Py_DECREF(value); | ||
goto error; | ||
} | ||
|
||
if (i > 0) { | ||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { | ||
Py_DECREF(name); | ||
Py_DECREF(value_repr); | ||
goto error; | ||
} | ||
} | ||
if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { | ||
Py_DECREF(name); | ||
Py_DECREF(value_repr); | ||
goto error; | ||
} | ||
|
||
Py_DECREF(name); | ||
|
||
if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { | ||
Py_DECREF(value_repr); | ||
goto error; | ||
} | ||
if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) { | ||
Py_DECREF(value_repr); | ||
goto error; | ||
} | ||
|
||
Py_DECREF(value_repr); | ||
} | ||
|
||
if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { | ||
goto error; | ||
} | ||
Py_ReprLeave((PyObject *)self); | ||
Py_DECREF(fields); | ||
return _PyUnicodeWriter_Finish(&writer); | ||
|
||
error: | ||
Py_ReprLeave((PyObject *)self); | ||
Py_DECREF(fields); | ||
_PyUnicodeWriter_Dealloc(&writer); | ||
return NULL; | ||
} | ||
|
||
static PyObject * | ||
ast_repr(AST_object *self) | ||
{ | ||
return ast_repr_max_depth(self, 3); | ||
} | ||
|
||
static PyType_Slot AST_type_slots[] = { | ||
{Py_tp_dealloc, ast_dealloc}, | ||
{Py_tp_repr, ast_repr}, | ||
{Py_tp_getattro, PyObject_GenericGetAttr}, | ||
{Py_tp_setattro, PyObject_GenericSetAttr}, | ||
{Py_tp_traverse, ast_traverse}, | ||
|
Uh oh!
There was an error while loading. Please reload this page.