Spaces:
Running
Running
File size: 1,807 Bytes
c61ccee |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import tokenize
from typing import Dict, List, Optional
cache: Dict[str, Dict[int, str]] = {}
def clearcache() -> None:
cache.clear()
def _add_file(filename: str) -> None:
try:
with open(filename) as f:
tokens = list(tokenize.generate_tokens(f.readline))
except OSError:
cache[filename] = {}
return
# NOTE: undefined behavior if file is not valid Python source,
# since tokenize will have undefined behavior.
result: Dict[int, str] = {}
# current full funcname, e.g. xxx.yyy.zzz
cur_name = ""
cur_indent = 0
significant_indents: List[int] = []
for i, token in enumerate(tokens):
if token.type == tokenize.INDENT:
cur_indent += 1
elif token.type == tokenize.DEDENT:
cur_indent -= 1
# possible end of function or class
if significant_indents and cur_indent == significant_indents[-1]:
significant_indents.pop()
# pop the last name
cur_name = cur_name.rpartition(".")[0]
elif (
token.type == tokenize.NAME
and i + 1 < len(tokens)
and tokens[i + 1].type == tokenize.NAME
and (token.string == "class" or token.string == "def")
):
# name of class/function always follows class/def token
significant_indents.append(cur_indent)
if cur_name:
cur_name += "."
cur_name += tokens[i + 1].string
result[token.start[0]] = cur_name
cache[filename] = result
def get_funcname(filename: str, lineno: int) -> Optional[str]:
if filename not in cache:
_add_file(filename)
return cache[filename].get(lineno, None)
|