|
| 1 | +# -*- encoding: utf8 -*- |
1 | 2 | """Top-level package for unasync."""
|
2 | 3 |
|
3 | 4 | from __future__ import print_function
|
4 | 5 |
|
5 | 6 | import collections
|
6 | 7 | import errno
|
| 8 | +import io |
7 | 9 | import os
|
8 | 10 | import sys
|
9 | 11 | import tokenize as std_tokenize
|
|
34 | 36 | "StopAsyncIteration": "StopIteration",
|
35 | 37 | }
|
36 | 38 |
|
| 39 | +_TYPE_COMMENT_PREFIX = "# type: " |
| 40 | + |
| 41 | + |
| 42 | +if sys.version_info[0] == 2: # PY2 |
| 43 | + |
| 44 | + def isidentifier(s): |
| 45 | + return all([c.isalnum() or c == "_" for c in s]) |
| 46 | + |
| 47 | + StringIO = io.BytesIO |
| 48 | +else: # PY3 |
| 49 | + |
| 50 | + def isidentifier(s): |
| 51 | + return s.isidentifier() |
| 52 | + |
| 53 | + StringIO = io.StringIO |
| 54 | + |
37 | 55 |
|
38 | 56 | class Rule:
|
39 | 57 | """A single set of rules for 'unasync'ing file(s)"""
|
@@ -95,6 +113,31 @@ def _unasync_tokens(self, tokens):
|
95 | 113 | elif toknum == std_tokenize.STRING:
|
96 | 114 | left_quote, name, right_quote = tokval[0], tokval[1:-1], tokval[-1]
|
97 | 115 | tokval = left_quote + self._unasync_name(name) + right_quote
|
| 116 | + elif toknum == std_tokenize.COMMENT and tokval.startswith( |
| 117 | + _TYPE_COMMENT_PREFIX |
| 118 | + ): |
| 119 | + type_decl, suffix = tokval[len(_TYPE_COMMENT_PREFIX) :], "" |
| 120 | + if "#" in type_decl: |
| 121 | + type_decl, suffix = type_decl.split("#", 1) |
| 122 | + suffix = "#" + suffix |
| 123 | + type_decl_stripped = type_decl.strip() |
| 124 | + |
| 125 | + # Do not process `type: ignore` or `type: ignore[…]` as these aren't actual identifiers |
| 126 | + is_type_ignore = type_decl_stripped == "ignore" |
| 127 | + is_type_ignore |= type_decl_stripped.startswith( |
| 128 | + "ignore" |
| 129 | + ) and not isidentifier(type_decl_stripped[0:7]) |
| 130 | + if not is_type_ignore: |
| 131 | + # Preserve trailing whitespace since the tokenizer won't |
| 132 | + trailing_space_len = len(type_decl) - len(type_decl.rstrip()) |
| 133 | + if trailing_space_len > 0: |
| 134 | + suffix = type_decl[-trailing_space_len:] + suffix |
| 135 | + type_decl = type_decl[:-trailing_space_len] |
| 136 | + type_decl = _untokenize( |
| 137 | + self._unasync_tokens(_tokenize(StringIO(type_decl))) |
| 138 | + ) |
| 139 | + |
| 140 | + tokval = _TYPE_COMMENT_PREFIX + type_decl + suffix |
98 | 141 | if used_space is None:
|
99 | 142 | used_space = space
|
100 | 143 | yield (used_space, tokval)
|
@@ -133,7 +176,11 @@ def _get_tokens(f):
|
133 | 176 | type_, string, start, end, line = tok
|
134 | 177 | yield Token(type_, string, start, end, line)
|
135 | 178 | else: # PY3
|
136 |
| - for tok in std_tokenize.tokenize(f.readline): |
| 179 | + if isinstance(f, io.TextIOBase): |
| 180 | + gen = std_tokenize.generate_tokens(f.readline) |
| 181 | + else: |
| 182 | + gen = std_tokenize.tokenize(f.readline) |
| 183 | + for tok in gen: |
137 | 184 | if tok.type == std_tokenize.ENCODING:
|
138 | 185 | continue
|
139 | 186 | yield tok
|
|
0 commit comments