Tokenize a series of lines and group tokens by line. The tokens for a multiline Python string or expression are grouped as one line. All lines except the last lines should keep their line ending ('\\n', '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)` for
(lines:List[str])
| 596 | return lines_before + [new_line] + lines_after |
| 597 | |
| 598 | def make_tokens_by_line(lines:List[str]): |
| 599 | """Tokenize a series of lines and group tokens by line. |
| 600 | |
| 601 | The tokens for a multiline Python string or expression are grouped as one |
| 602 | line. All lines except the last lines should keep their line ending ('\\n', |
| 603 | '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)` |
| 604 | for example when passing block of text to this function. |
| 605 | |
| 606 | """ |
| 607 | # NL tokens are used inside multiline expressions, but also after blank |
| 608 | # lines or comments. This is intentional - see https://bugs.python.org/issue17061 |
| 609 | # We want to group the former case together but split the latter, so we |
| 610 | # track parentheses level, similar to the internals of tokenize. |
| 611 | |
| 612 | # reexported from token on 3.7+ |
| 613 | NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore |
| 614 | tokens_by_line: List[List[Any]] = [[]] |
| 615 | if len(lines) > 1 and not lines[0].endswith(("\n", "\r", "\r\n", "\x0b", "\x0c")): |
| 616 | warnings.warn( |
| 617 | "`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified", |
| 618 | stacklevel=2, |
| 619 | ) |
| 620 | parenlev = 0 |
| 621 | try: |
| 622 | for token in tokenutil.generate_tokens_catch_errors( |
| 623 | iter(lines).__next__, extra_errors_to_catch=["expected EOF"] |
| 624 | ): |
| 625 | tokens_by_line[-1].append(token) |
| 626 | if (token.type == NEWLINE) \ |
| 627 | or ((token.type == NL) and (parenlev <= 0)): |
| 628 | tokens_by_line.append([]) |
| 629 | elif token.string in {'(', '[', '{'}: |
| 630 | parenlev += 1 |
| 631 | elif token.string in {')', ']', '}'}: |
| 632 | if parenlev > 0: |
| 633 | parenlev -= 1 |
| 634 | except tokenize.TokenError: |
| 635 | # Input ended in a multiline string or expression. That's OK for us. |
| 636 | pass |
| 637 | |
| 638 | |
| 639 | if not tokens_by_line[-1]: |
| 640 | tokens_by_line.pop() |
| 641 | |
| 642 | |
| 643 | return tokens_by_line |
| 644 | |
| 645 | |
| 646 | def has_sunken_brackets(tokens: List[tokenize.TokenInfo]): |
searching dependent graphs…