Return the entire source file and starting line number for an object.
(obj)
| 121 | |
| 122 | |
| 123 | def findsource(obj): |
| 124 | """Return the entire source file and starting line number for an object.""" |
| 125 | import linecache # pylint: disable=import-outside-toplevel |
| 126 | |
| 127 | if not inspect.isclass(obj): |
| 128 | return _findsource(obj) |
| 129 | |
| 130 | file = inspect.getsourcefile(obj) |
| 131 | if file: |
| 132 | linecache.checkcache(file) |
| 133 | else: |
| 134 | file = inspect.getfile(obj) |
| 135 | if not (file.startswith("<") and file.endswith(">")): |
| 136 | raise OSError("source code not available") |
| 137 | |
| 138 | module = inspect.getmodule(obj, file) |
| 139 | if module: |
| 140 | lines = linecache.getlines(file, module.__dict__) |
| 141 | else: |
| 142 | lines = linecache.getlines(file) |
| 143 | if not lines: |
| 144 | raise OSError("could not get source code") |
| 145 | qual_names = obj.__qualname__.replace(".<locals>", "<locals>").split(".") |
| 146 | in_comment = 0 |
| 147 | scope_stack = [] |
| 148 | indent_info = {} |
| 149 | for i, line in enumerate(lines): |
| 150 | n_comment = line.count('"""') |
| 151 | if n_comment: |
| 152 | # update multi-line comments status |
| 153 | in_comment = in_comment ^ (n_comment & 1) |
| 154 | continue |
| 155 | if in_comment: |
| 156 | # skip lines within multi-line comments |
| 157 | continue |
| 158 | indent = len(line) - len(line.lstrip()) |
| 159 | tokens = line.split() |
| 160 | if len(tokens) > 1: |
| 161 | name = None |
| 162 | if tokens[0] == "def": |
| 163 | name = tokens[1].split(":")[0].split("(")[0] + "<locals>" |
| 164 | elif tokens[0] == "class": |
| 165 | name = tokens[1].split(":")[0].split("(")[0] |
| 166 | # pop scope if we are less indented |
| 167 | while scope_stack and indent_info[scope_stack[-1]] >= indent: |
| 168 | scope_stack.pop() |
| 169 | if name: |
| 170 | scope_stack.append(name) |
| 171 | indent_info[name] = indent |
| 172 | if scope_stack == qual_names: |
| 173 | return lines, i |
| 174 | |
| 175 | raise OSError("could not find class definition") |
| 176 | |
| 177 | |
| 178 | def getsourcelines(obj): |
no test coverage detected
searching dependent graphs…