Skip to content
This repository was archived by the owner on Jul 5, 2023. It is now read-only.

Commit 6222c24

Browse files
authored
Support text appearing after "# type: ignore" (#116)
This is to allow things like `# type: ignore[E1000]`. Essentially a backport of GH-13238, GH-13479, and GH-13504 from cpython.
1 parent 7b9cbb6 commit 6222c24

File tree

15 files changed

+219
-67
lines changed

15 files changed

+219
-67
lines changed

.gitattributes

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Generated files
2+
# https://github.com/github/linguist#generated-code
3+
ast3/Include/graminit.h linguist-generated=true
4+
ast3/Python/graminit.h linguist-generated=true
5+
ast3/Include/Python-ast.h linguist-generated=true
6+
ast3/Python/Python-ast.c linguist-generated=true
7+
ast3/Include/token.h linguist-generated=true
8+
ast3/Lib/token.py linguist-generated=true
9+
ast3/Parser/token.c linguist-generated=true
10+
ast27/Include/graminit.h linguist-generated=true
11+
ast27/Python/graminit.h linguist-generated=true
12+
ast27/Include/Python-ast.h linguist-generated=true
13+
ast27/Python/Python-ast.c linguist-generated=true
14+
ast27/Include/token.h linguist-generated=true
15+
ast27/Lib/token.py linguist-generated=true
16+
ast27/Parser/token.c linguist-generated=true

ast27/Include/Python-ast.h

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ast27/Parser/Python.asdl

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Python version "$Revision$"
1010
-- not really an actual node but useful in Jython's typesystem.
1111
| Suite(stmt* body)
1212

13-
stmt = FunctionDef(identifier name, arguments args,
13+
stmt = FunctionDef(identifier name, arguments args,
1414
stmt* body, expr* decorator_list, string? type_comment)
1515
| ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)
1616
| Return(expr? value)
@@ -78,21 +78,21 @@ module Python version "$Revision$"
7878
| Attribute(expr value, identifier attr, expr_context ctx)
7979
| Subscript(expr value, slice slice, expr_context ctx)
8080
| Name(identifier id, expr_context ctx)
81-
| List(expr* elts, expr_context ctx)
81+
| List(expr* elts, expr_context ctx)
8282
| Tuple(expr* elts, expr_context ctx)
8383

8484
-- col_offset is the byte offset in the utf8 string the parser uses
8585
attributes (int lineno, int col_offset)
8686

8787
expr_context = Load | Store | Del | AugLoad | AugStore | Param
8888

89-
slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step)
90-
| ExtSlice(slice* dims)
91-
| Index(expr value)
89+
slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step)
90+
| ExtSlice(slice* dims)
91+
| Index(expr value)
9292

93-
boolop = And | Or
93+
boolop = And | Or
9494

95-
operator = Add | Sub | Mult | Div | Mod | Pow | LShift
95+
operator = Add | Sub | Mult | Div | Mod | Pow | LShift
9696
| RShift | BitOr | BitXor | BitAnd | FloorDiv
9797

9898
unaryop = Invert | Not | UAdd | USub
@@ -109,7 +109,7 @@ module Python version "$Revision$"
109109
-- It is either an empty list or a list with length equal to the number of
110110
-- args (including varargs and kwargs, if present) and with members set to the
111111
-- string of each arg's type comment, if present, or None otherwise.
112-
arguments = (expr* args, identifier? vararg,
112+
arguments = (expr* args, identifier? vararg,
113113
identifier? kwarg, expr* defaults, string* type_comments)
114114

115115
-- keyword arguments supplied to call
@@ -118,5 +118,5 @@ module Python version "$Revision$"
118118
-- import name with optional 'as' alias.
119119
alias = (identifier name, identifier? asname)
120120

121-
type_ignore = TypeIgnore(int lineno)
121+
type_ignore = TypeIgnore(int lineno, string tag)
122122
}

ast27/Parser/parsetok.c

+33-13
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,16 @@ warn(const char *msg, const char *filename, int lineno)
152152

153153

154154
typedef struct {
155-
int *items;
155+
struct {
156+
int lineno;
157+
char *comment;
158+
} *items;
156159
size_t size;
157160
size_t num_items;
158-
} growable_int_array;
161+
} growable_comment_array;
159162

160-
int growable_int_array_init(growable_int_array *arr, size_t initial_size) {
163+
static int
164+
growable_comment_array_init(growable_comment_array *arr, size_t initial_size) {
161165
assert(initial_size > 0);
162166
arr->items = malloc(initial_size * sizeof(*arr->items));
163167
arr->size = initial_size;
@@ -166,20 +170,28 @@ int growable_int_array_init(growable_int_array *arr, size_t initial_size) {
166170
return arr->items != NULL;
167171
}
168172

169-
int growable_int_array_add(growable_int_array *arr, int item) {
173+
static int
174+
growable_comment_array_add(growable_comment_array *arr, int lineno, char *comment) {
170175
if (arr->num_items >= arr->size) {
171176
arr->size *= 2;
172177
arr->items = realloc(arr->items, arr->size * sizeof(*arr->items));
173-
if (!arr->items)
178+
if (!arr->items) {
174179
return 0;
180+
}
175181
}
176182

177-
arr->items[arr->num_items] = item;
183+
arr->items[arr->num_items].lineno = lineno;
184+
arr->items[arr->num_items].comment = comment;
178185
arr->num_items++;
179186
return 1;
180187
}
181188

182-
void growable_int_array_deallocate(growable_int_array *arr) {
189+
static void
190+
growable_comment_array_deallocate(growable_comment_array *arr) {
191+
unsigned i;
192+
for (i = 0; i < arr->num_items; i++) {
193+
PyObject_FREE(arr->items[i].comment);
194+
}
183195
free(arr->items);
184196
}
185197

@@ -195,8 +207,8 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
195207
node *n;
196208
int started = 0;
197209

198-
growable_int_array type_ignores;
199-
if (!growable_int_array_init(&type_ignores, 10)) {
210+
growable_comment_array type_ignores;
211+
if (!growable_comment_array_init(&type_ignores, 10)) {
200212
err_ret->error = E_NOMEM;
201213
Ta27Tokenizer_Free(tok);
202214
return NULL;
@@ -264,7 +276,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
264276
col_offset = -1;
265277

266278
if (type == TYPE_IGNORE) {
267-
if (!growable_int_array_add(&type_ignores, tok->lineno)) {
279+
if (!growable_comment_array_add(&type_ignores, tok->lineno, str)) {
268280
err_ret->error = E_NOMEM;
269281
break;
270282
}
@@ -297,15 +309,23 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
297309
REQ(ch, ENDMARKER);
298310

299311
for (i = 0; i < type_ignores.num_items; i++) {
300-
Ta27Node_AddChild(ch, TYPE_IGNORE, NULL, type_ignores.items[i], 0);
312+
int res = Ta27Node_AddChild(ch, TYPE_IGNORE, type_ignores.items[i].comment,
313+
type_ignores.items[i].lineno, 0);
314+
if (res != 0) {
315+
err_ret->error = res;
316+
Ta27Node_Free(n);
317+
n = NULL;
318+
break;
319+
}
320+
type_ignores.items[i].comment = NULL;
301321
}
302322
}
303-
growable_int_array_deallocate(&type_ignores);
304-
305323
}
306324
else
307325
n = NULL;
308326

327+
growable_comment_array_deallocate(&type_ignores);
328+
309329
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
310330
*flags = ps->p_flags;
311331
#endif

ast27/Parser/tokenizer.c

+10-8
Original file line numberDiff line numberDiff line change
@@ -1400,20 +1400,22 @@ tok_get(register struct tok_state *tok, char **p_start, char **p_end)
14001400
/* This is a type comment if we matched all of type_comment_prefix. */
14011401
if (!*prefix) {
14021402
int is_type_ignore = 1;
1403+
const char *ignore_end = p + 6;
14031404
tok_backup(tok, c); /* don't eat the newline or EOF */
14041405

14051406
type_start = p;
14061407

1407-
is_type_ignore = tok->cur >= p + 6 && memcmp(p, "ignore", 6) == 0;
1408-
p += 6;
1409-
while (is_type_ignore && p < tok->cur) {
1410-
if (*p == '#')
1411-
break;
1412-
is_type_ignore = is_type_ignore && (*p == ' ' || *p == '\t');
1413-
p++;
1414-
}
1408+
/* A TYPE_IGNORE is "type: ignore" followed by the end of the token
1409+
* or anything ASCII and non-alphanumeric. */
1410+
is_type_ignore = (
1411+
tok->cur >= ignore_end && memcmp(p, "ignore", 6) == 0
1412+
&& !(tok->cur > ignore_end
1413+
&& ((unsigned char)ignore_end[0] >= 128 || Py_ISALNUM(ignore_end[0]))));
14151414

14161415
if (is_type_ignore) {
1416+
*p_start = (char *) ignore_end;
1417+
*p_end = tok->cur;
1418+
14171419
/* If this type ignore is the only thing on the line, consume the newline also. */
14181420
if (blankline) {
14191421
tok_nextc(tok);

ast27/Python/Python-ast.c

+28-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ast27/Python/ast.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,10 @@ Ta27AST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename,
297297
goto error;
298298

299299
for (i = 0; i < num; i++) {
300-
type_ignore_ty ti = TypeIgnore(LINENO(CHILD(ch, i)), arena);
300+
string type_comment = new_type_comment(STR(CHILD(ch, i)), &c);
301+
if (!type_comment)
302+
goto error;
303+
type_ignore_ty ti = TypeIgnore(LINENO(CHILD(ch, i)), type_comment, arena);
301304
if (!ti)
302305
goto error;
303306
asdl_seq_SET(type_ignores, i, ti);
@@ -2431,7 +2434,7 @@ ast_for_print_stmt(struct compiling *c, const node *n)
24312434
dest = ast_for_expr(c, CHILD(n, 2));
24322435
if (!dest)
24332436
return NULL;
2434-
start = 4;
2437+
start = 4;
24352438
}
24362439
values_count = (NCH(n) + 1 - start) / 2;
24372440
if (values_count) {

ast3/Include/Python-ast.h

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ast3/Parser/Python.asdl

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,5 @@ module Python
130130

131131
withitem = (expr context_expr, expr? optional_vars)
132132

133-
type_ignore = TypeIgnore(int lineno)
133+
type_ignore = TypeIgnore(int lineno, string tag)
134134
}

0 commit comments

Comments
 (0)