(funcname, filename)
| 134 | return code.co_firstlineno |
| 135 | |
| 136 | def find_function(funcname, filename): |
| 137 | cre = re.compile(r'(?:async\s+)?def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname)) |
| 138 | try: |
| 139 | fp = tokenize.open(filename) |
| 140 | except OSError: |
| 141 | lines = linecache.getlines(filename) |
| 142 | if not lines: |
| 143 | return None |
| 144 | fp = io.StringIO(''.join(lines)) |
| 145 | funcdef = "" |
| 146 | funcstart = 0 |
| 147 | # consumer of this info expects the first line to be 1 |
| 148 | with fp: |
| 149 | for lineno, line in enumerate(fp, start=1): |
| 150 | if cre.match(line): |
| 151 | funcstart, funcdef = lineno, line |
| 152 | elif funcdef: |
| 153 | funcdef += line |
| 154 | |
| 155 | if funcdef: |
| 156 | try: |
| 157 | code = compile(funcdef, filename, 'exec') |
| 158 | except SyntaxError: |
| 159 | continue |
| 160 | # We should always be able to find the code object here |
| 161 | funccode = next(c for c in code.co_consts if |
| 162 | isinstance(c, CodeType) and c.co_name == funcname) |
| 163 | lineno_offset = find_first_executable_line(funccode) |
| 164 | return funcname, filename, funcstart + lineno_offset - 1 |
| 165 | return None |
| 166 | |
| 167 | def lasti2lineno(code, lasti): |
| 168 | linestarts = list(dis.findlinestarts(code)) |
no test coverage detected
searching dependent graphs…