Commit 73cbe7a0 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-32911: Revert bpo-29463. (GH-7121) (GH-7197)

Remove the docstring attribute of AST types and restore docstring
expression as a first stmt in their body.
Co-authored-by: default avatarINADA Naoki <methane@users.noreply.github.com>
parent 2179022d
...@@ -151,10 +151,6 @@ and classes for traversing abstract syntax trees: ...@@ -151,10 +151,6 @@ and classes for traversing abstract syntax trees:
.. versionchanged:: 3.5 .. versionchanged:: 3.5
:class:`AsyncFunctionDef` is now supported. :class:`AsyncFunctionDef` is now supported.
.. versionchanged:: 3.7
The docstring is now exported from the node docstring field, instead of
the first body statement.
.. function:: fix_missing_locations(node) .. function:: fix_missing_locations(node)
......
...@@ -2161,13 +2161,6 @@ Changes in Python Behavior ...@@ -2161,13 +2161,6 @@ Changes in Python Behavior
Changes in the Python API Changes in the Python API
------------------------- -------------------------
* ``Module``, ``FunctionDef``, ``AsyncFunctionDef``, and
``ClassDef`` AST nodes now have the new ``docstring`` attribute.
The first statement in their body is not considered as a docstring
anymore. ``co_firstlineno`` and ``co_lnotab`` of code object for class
and module are affected by this change. (Contributed by INADA Naoki and
Eugene Toder in :issue:`29463`.)
* :meth:`socketserver.ThreadingMixIn.server_close` now waits until all * :meth:`socketserver.ThreadingMixIn.server_close` now waits until all
non-daemon threads complete. Set the new non-daemon threads complete. Set the new
:attr:`socketserver.ThreadingMixIn.block_on_close` class attribute to :attr:`socketserver.ThreadingMixIn.block_on_close` class attribute to
......
...@@ -46,7 +46,6 @@ struct _mod { ...@@ -46,7 +46,6 @@ struct _mod {
union { union {
struct { struct {
asdl_seq *body; asdl_seq *body;
string docstring;
} Module; } Module;
struct { struct {
...@@ -81,7 +80,6 @@ struct _stmt { ...@@ -81,7 +80,6 @@ struct _stmt {
asdl_seq *body; asdl_seq *body;
asdl_seq *decorator_list; asdl_seq *decorator_list;
expr_ty returns; expr_ty returns;
string docstring;
} FunctionDef; } FunctionDef;
struct { struct {
...@@ -90,7 +88,6 @@ struct _stmt { ...@@ -90,7 +88,6 @@ struct _stmt {
asdl_seq *body; asdl_seq *body;
asdl_seq *decorator_list; asdl_seq *decorator_list;
expr_ty returns; expr_ty returns;
string docstring;
} AsyncFunctionDef; } AsyncFunctionDef;
struct { struct {
...@@ -99,7 +96,6 @@ struct _stmt { ...@@ -99,7 +96,6 @@ struct _stmt {
asdl_seq *keywords; asdl_seq *keywords;
asdl_seq *body; asdl_seq *body;
asdl_seq *decorator_list; asdl_seq *decorator_list;
string docstring;
} ClassDef; } ClassDef;
struct { struct {
...@@ -443,27 +439,26 @@ struct _withitem { ...@@ -443,27 +439,26 @@ struct _withitem {
}; };
#define Module(a0, a1, a2) _Py_Module(a0, a1, a2) #define Module(a0, a1) _Py_Module(a0, a1)
mod_ty _Py_Module(asdl_seq * body, string docstring, PyArena *arena); mod_ty _Py_Module(asdl_seq * body, PyArena *arena);
#define Interactive(a0, a1) _Py_Interactive(a0, a1) #define Interactive(a0, a1) _Py_Interactive(a0, a1)
mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena);
#define Expression(a0, a1) _Py_Expression(a0, a1) #define Expression(a0, a1) _Py_Expression(a0, a1)
mod_ty _Py_Expression(expr_ty body, PyArena *arena); mod_ty _Py_Expression(expr_ty body, PyArena *arena);
#define Suite(a0, a1) _Py_Suite(a0, a1) #define Suite(a0, a1) _Py_Suite(a0, a1)
mod_ty _Py_Suite(asdl_seq * body, PyArena *arena); mod_ty _Py_Suite(asdl_seq * body, PyArena *arena);
#define FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) #define FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7)
stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body,
asdl_seq * decorator_list, expr_ty returns, string asdl_seq * decorator_list, expr_ty returns, int lineno,
docstring, int lineno, int col_offset, PyArena *arena); int col_offset, PyArena *arena);
#define AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) #define AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7)
stmt_ty _Py_AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq * stmt_ty _Py_AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq *
body, asdl_seq * decorator_list, expr_ty returns, body, asdl_seq * decorator_list, expr_ty returns,
string docstring, int lineno, int col_offset, int lineno, int col_offset, PyArena *arena);
PyArena *arena); #define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7)
#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8)
stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords,
asdl_seq * body, asdl_seq * decorator_list, string asdl_seq * body, asdl_seq * decorator_list, int lineno,
docstring, int lineno, int col_offset, PyArena *arena); int col_offset, PyArena *arena);
#define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) #define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3)
stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena);
#define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3) #define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3)
......
...@@ -206,7 +206,15 @@ def get_docstring(node, clean=True): ...@@ -206,7 +206,15 @@ def get_docstring(node, clean=True):
""" """
if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)): if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)):
raise TypeError("%r can't have docstrings" % node.__class__.__name__) raise TypeError("%r can't have docstrings" % node.__class__.__name__)
text = node.docstring if not node.body:
return None
node = node.body[0].value
if isinstance(node, Str):
text = node.s
elif isinstance(node, Constant) and isinstance(node.value, str):
text = node.value
else:
return None
if clean and text: if clean and text:
import inspect import inspect
text = inspect.cleandoc(text) text = inspect.cleandoc(text)
......
This diff is collapsed.
...@@ -27,7 +27,7 @@ class OpcodeTest(unittest.TestCase): ...@@ -27,7 +27,7 @@ class OpcodeTest(unittest.TestCase):
with open(ann_module.__file__) as f: with open(ann_module.__file__) as f:
txt = f.read() txt = f.read()
co = compile(txt, ann_module.__file__, 'exec') co = compile(txt, ann_module.__file__, 'exec')
self.assertEqual(co.co_firstlineno, 8) self.assertEqual(co.co_firstlineno, 6)
except OSError: except OSError:
pass pass
......
...@@ -788,7 +788,7 @@ objects. ...@@ -788,7 +788,7 @@ objects.
Add ``docstring`` field to Module, ClassDef, FunctionDef, and Add ``docstring`` field to Module, ClassDef, FunctionDef, and
AsyncFunctionDef ast nodes. docstring is not first stmt in their body AsyncFunctionDef ast nodes. docstring is not first stmt in their body
anymore. It affects ``co_firstlineno`` and ``co_lnotab`` of code object for anymore. It affects ``co_firstlineno`` and ``co_lnotab`` of code object for
module and class. module and class. (Reverted in :issue:`32911`.)
.. ..
......
Due to unexpected compatibility issues discovered during downstream beta
testing, reverted :issue:`29463`. ``docstring`` field is removed from Module,
ClassDef, FunctionDef, and AsyncFunctionDef ast nodes which was added in
3.7a1. Docstring expression is restored as a first statement in their body.
Based on patch by Inada Naoki.
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
module Python module Python
{ {
mod = Module(stmt* body, string? docstring) mod = Module(stmt* body)
| Interactive(stmt* body) | Interactive(stmt* body)
| Expression(expr body) | Expression(expr body)
...@@ -14,18 +14,15 @@ module Python ...@@ -14,18 +14,15 @@ module Python
| Suite(stmt* body) | Suite(stmt* body)
stmt = FunctionDef(identifier name, arguments args, stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns, stmt* body, expr* decorator_list, expr? returns)
string? docstring)
| AsyncFunctionDef(identifier name, arguments args, | AsyncFunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns, stmt* body, expr* decorator_list, expr? returns)
string? docstring)
| ClassDef(identifier name, | ClassDef(identifier name,
expr* bases, expr* bases,
keyword* keywords, keyword* keywords,
stmt* body, stmt* body,
expr* decorator_list, expr* decorator_list)
string? docstring)
| Return(expr? value) | Return(expr? value)
| Delete(expr* targets) | Delete(expr* targets)
......
This diff is collapsed.
This diff is collapsed.
...@@ -467,12 +467,51 @@ static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int opti ...@@ -467,12 +467,51 @@ static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int opti
} \ } \
} }
static int
isdocstring(stmt_ty s)
{
if (s->kind != Expr_kind)
return 0;
if (s->v.Expr.value->kind == Str_kind)
return 1;
if (s->v.Expr.value->kind == Constant_kind)
return PyUnicode_CheckExact(s->v.Expr.value->v.Constant.value);
return 0;
}
static int
astfold_body(asdl_seq *stmts, PyArena *ctx_, int optimize_)
{
if (!asdl_seq_LEN(stmts)) {
return 1;
}
int docstring = isdocstring((stmt_ty)asdl_seq_GET(stmts, 0));
CALL_SEQ(astfold_stmt, stmt_ty, stmts);
if (docstring) {
return 1;
}
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0);
if (isdocstring(st)) {
asdl_seq *values = _Py_asdl_seq_new(1, ctx_);
if (!values) {
return 0;
}
asdl_seq_SET(values, 0, st->v.Expr.value);
expr_ty expr = _Py_JoinedStr(values, st->lineno, st->col_offset, ctx_);
if (!expr) {
return 0;
}
st->v.Expr.value = expr;
}
return 1;
}
static int static int
astfold_mod(mod_ty node_, PyArena *ctx_, int optimize_) astfold_mod(mod_ty node_, PyArena *ctx_, int optimize_)
{ {
switch (node_->kind) { switch (node_->kind) {
case Module_kind: case Module_kind:
CALL_SEQ(astfold_stmt, stmt_ty, node_->v.Module.body); CALL(astfold_body, asdl_seq, node_->v.Module.body);
break; break;
case Interactive_kind: case Interactive_kind:
CALL_SEQ(astfold_stmt, stmt_ty, node_->v.Interactive.body); CALL_SEQ(astfold_stmt, stmt_ty, node_->v.Interactive.body);
...@@ -657,20 +696,20 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_) ...@@ -657,20 +696,20 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_)
switch (node_->kind) { switch (node_->kind) {
case FunctionDef_kind: case FunctionDef_kind:
CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args); CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args);
CALL_SEQ(astfold_stmt, stmt_ty, node_->v.FunctionDef.body); CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body);
CALL_SEQ(astfold_expr, expr_ty, node_->v.FunctionDef.decorator_list); CALL_SEQ(astfold_expr, expr_ty, node_->v.FunctionDef.decorator_list);
CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns); CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns);
break; break;
case AsyncFunctionDef_kind: case AsyncFunctionDef_kind:
CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args); CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args);
CALL_SEQ(astfold_stmt, stmt_ty, node_->v.AsyncFunctionDef.body); CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body);
CALL_SEQ(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.decorator_list); CALL_SEQ(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.decorator_list);
CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns); CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns);
break; break;
case ClassDef_kind: case ClassDef_kind:
CALL_SEQ(astfold_expr, expr_ty, node_->v.ClassDef.bases); CALL_SEQ(astfold_expr, expr_ty, node_->v.ClassDef.bases);
CALL_SEQ(astfold_keyword, keyword_ty, node_->v.ClassDef.keywords); CALL_SEQ(astfold_keyword, keyword_ty, node_->v.ClassDef.keywords);
CALL_SEQ(astfold_stmt, stmt_ty, node_->v.ClassDef.body); CALL(astfold_body, asdl_seq, node_->v.ClassDef.body);
CALL_SEQ(astfold_expr, expr_ty, node_->v.ClassDef.decorator_list); CALL_SEQ(astfold_expr, expr_ty, node_->v.ClassDef.decorator_list);
break; break;
case Return_kind: case Return_kind:
......
...@@ -1392,6 +1392,18 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) ...@@ -1392,6 +1392,18 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
} \ } \
} }
static int
compiler_isdocstring(stmt_ty s)
{
if (s->kind != Expr_kind)
return 0;
if (s->v.Expr.value->kind == Str_kind)
return 1;
if (s->v.Expr.value->kind == Constant_kind)
return PyUnicode_CheckExact(s->v.Expr.value->v.Constant.value);
return 0;
}
static int static int
is_const(expr_ty e) is_const(expr_ty e)
{ {
...@@ -1587,27 +1599,37 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ...@@ -1587,27 +1599,37 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
and for annotations. */ and for annotations. */
static int static int
compiler_body(struct compiler *c, asdl_seq *stmts, string docstring) compiler_body(struct compiler *c, asdl_seq *stmts)
{ {
int i = 0;
stmt_ty st;
/* Set current line number to the line number of first statement. /* Set current line number to the line number of first statement.
This way line number for SETUP_ANNOTATIONS will always This way line number for SETUP_ANNOTATIONS will always
coincide with the line number of first "real" statement in module. coincide with the line number of first "real" statement in module.
If body is empy, then lineno will be set later in assemble. */ If body is empy, then lineno will be set later in assemble. */
if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && if (c->u->u_scope_type == COMPILER_SCOPE_MODULE &&
!c->u->u_lineno && asdl_seq_LEN(stmts)) { !c->u->u_lineno && asdl_seq_LEN(stmts)) {
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0); st = (stmt_ty)asdl_seq_GET(stmts, 0);
c->u->u_lineno = st->lineno; c->u->u_lineno = st->lineno;
} }
/* Every annotated class and module should have __annotations__. */ /* Every annotated class and module should have __annotations__. */
if (find_ann(stmts)) { if (find_ann(stmts)) {
ADDOP(c, SETUP_ANNOTATIONS); ADDOP(c, SETUP_ANNOTATIONS);
} }
if (!asdl_seq_LEN(stmts))
return 1;
st = (stmt_ty)asdl_seq_GET(stmts, 0);
/* if not -OO mode, set docstring */ /* if not -OO mode, set docstring */
if (c->c_optimize < 2 && docstring) { if (compiler_isdocstring(st) && c->c_optimize < 2) {
ADDOP_LOAD_CONST(c, docstring); /* don't generate docstrings if -OO */
ADDOP_NAME(c, STORE_NAME, __doc__, names); i = 1;
VISIT(c, expr, st->v.Expr.value);
if (!compiler_nameop(c, __doc__, Store))
return 0;
} }
VISIT_SEQ(c, stmt, stmts); for (; i < asdl_seq_LEN(stmts); i++)
VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i));
return 1; return 1;
} }
...@@ -1627,7 +1649,7 @@ compiler_mod(struct compiler *c, mod_ty mod) ...@@ -1627,7 +1649,7 @@ compiler_mod(struct compiler *c, mod_ty mod)
return NULL; return NULL;
switch (mod->kind) { switch (mod->kind) {
case Module_kind: case Module_kind:
if (!compiler_body(c, mod->v.Module.body, mod->v.Module.docstring)) { if (!compiler_body(c, mod->v.Module.body)) {
compiler_exit_scope(c); compiler_exit_scope(c);
return 0; return 0;
} }
...@@ -1957,13 +1979,15 @@ static int ...@@ -1957,13 +1979,15 @@ static int
compiler_function(struct compiler *c, stmt_ty s, int is_async) compiler_function(struct compiler *c, stmt_ty s, int is_async)
{ {
PyCodeObject *co; PyCodeObject *co;
PyObject *qualname, *docstring = Py_None; PyObject *qualname, *first_const = Py_None;
arguments_ty args; arguments_ty args;
expr_ty returns; expr_ty returns;
identifier name; identifier name;
asdl_seq* decos; asdl_seq* decos;
asdl_seq *body; asdl_seq *body;
stmt_ty st;
Py_ssize_t i, funcflags; Py_ssize_t i, funcflags;
int docstring;
int annotations; int annotations;
int scope_type; int scope_type;
...@@ -2010,16 +2034,21 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) ...@@ -2010,16 +2034,21 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
} }
/* if not -OO mode, add docstring */ /* if not -OO mode, add docstring */
if (c->c_optimize < 2 && s->v.FunctionDef.docstring) st = (stmt_ty)asdl_seq_GET(body, 0);
docstring = s->v.FunctionDef.docstring; docstring = compiler_isdocstring(st);
if (compiler_add_const(c, docstring) < 0) { if (docstring && c->c_optimize < 2) {
if (st->v.Expr.value->kind == Constant_kind)
first_const = st->v.Expr.value->v.Constant.value;
else
first_const = st->v.Expr.value->v.Str.s;
}
if (compiler_add_const(c, first_const) < 0) {
compiler_exit_scope(c); compiler_exit_scope(c);
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_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
/* if there was a docstring, we need to skip the first statement */
VISIT_SEQ_IN_SCOPE(c, stmt, body); VISIT_SEQ_IN_SCOPE(c, stmt, body);
co = assemble(c, 1); co = assemble(c, 1);
qualname = c->u->u_qualname; qualname = c->u->u_qualname;
...@@ -2101,7 +2130,7 @@ compiler_class(struct compiler *c, stmt_ty s) ...@@ -2101,7 +2130,7 @@ compiler_class(struct compiler *c, stmt_ty s)
} }
Py_DECREF(str); Py_DECREF(str);
/* compile the body proper */ /* compile the body proper */
if (!compiler_body(c, s->v.ClassDef.body, s->v.ClassDef.docstring)) { if (!compiler_body(c, s->v.ClassDef.body)) {
compiler_exit_scope(c); compiler_exit_scope(c);
return 0; return 0;
} }
......
...@@ -63,6 +63,7 @@ static int ...@@ -63,6 +63,7 @@ static int
future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename) future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
{ {
int i, done = 0, prev_line = 0; int i, done = 0, prev_line = 0;
stmt_ty first;
if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
return 1; return 1;
...@@ -78,7 +79,15 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename) ...@@ -78,7 +79,15 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
but is preceded by a regular import. but is preceded by a regular import.
*/ */
for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) { i = 0;
first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
if (first->kind == Expr_kind
&& (first->v.Expr.value->kind == Str_kind
|| (first->v.Expr.value->kind == Constant_kind
&& PyUnicode_CheckExact(first->v.Expr.value->v.Constant.value))))
i++;
for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
if (done && s->lineno > prev_line) if (done && s->lineno > prev_line)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -71,8 +71,6 @@ class Unparser: ...@@ -71,8 +71,6 @@ class Unparser:
######################################################## ########################################################
def _Module(self, tree): def _Module(self, tree):
if tree.docstring is not None:
self.fill(repr(tree.docstring))
for stmt in tree.body: for stmt in tree.body:
self.dispatch(stmt) self.dispatch(stmt)
...@@ -237,8 +235,6 @@ class Unparser: ...@@ -237,8 +235,6 @@ class Unparser:
self.write(")") self.write(")")
self.enter() self.enter()
if t.docstring is not None:
self.fill(repr(t.docstring))
self.dispatch(t.body) self.dispatch(t.body)
self.leave() self.leave()
...@@ -261,8 +257,6 @@ class Unparser: ...@@ -261,8 +257,6 @@ class Unparser:
self.write(" -> ") self.write(" -> ")
self.dispatch(t.returns) self.dispatch(t.returns)
self.enter() self.enter()
if t.docstring is not None:
self.fill(repr(t.docstring))
self.dispatch(t.body) self.dispatch(t.body)
self.leave() self.leave()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment