Return a line number of the given object's docstring. Returns `None` if the given object does not have a docstring.
(self, obj, source_lines)
| 1108 | filename, lineno) |
| 1109 | |
| 1110 | def _find_lineno(self, obj, source_lines): |
| 1111 | """ |
| 1112 | Return a line number of the given object's docstring. |
| 1113 | |
| 1114 | Returns `None` if the given object does not have a docstring. |
| 1115 | """ |
| 1116 | lineno = None |
| 1117 | docstring = getattr(obj, '__doc__', None) |
| 1118 | |
| 1119 | # Find the line number for modules. |
| 1120 | if inspect.ismodule(obj) and docstring is not None: |
| 1121 | lineno = 0 |
| 1122 | |
| 1123 | # Find the line number for classes. |
| 1124 | # Note: this could be fooled if a class is defined multiple |
| 1125 | # times in a single file. |
| 1126 | if inspect.isclass(obj) and docstring is not None: |
| 1127 | if source_lines is None: |
| 1128 | return None |
| 1129 | pat = re.compile(r'^\s*class\s*%s\b' % |
| 1130 | re.escape(getattr(obj, '__name__', '-'))) |
| 1131 | for i, line in enumerate(source_lines): |
| 1132 | if pat.match(line): |
| 1133 | lineno = i |
| 1134 | break |
| 1135 | |
| 1136 | # Find the line number for functions & methods. |
| 1137 | if inspect.ismethod(obj): obj = obj.__func__ |
| 1138 | if isinstance(obj, property): |
| 1139 | obj = obj.fget |
| 1140 | if isinstance(obj, functools.cached_property): |
| 1141 | obj = obj.func |
| 1142 | if inspect.isroutine(obj) and getattr(obj, '__doc__', None): |
| 1143 | # We don't use `docstring` var here, because `obj` can be changed. |
| 1144 | obj = inspect.unwrap(obj) |
| 1145 | try: |
| 1146 | obj = obj.__code__ |
| 1147 | except AttributeError: |
| 1148 | # Functions implemented in C don't necessarily |
| 1149 | # have a __code__ attribute. |
| 1150 | # If there's no code, there's no lineno |
| 1151 | return None |
| 1152 | if inspect.istraceback(obj): obj = obj.tb_frame |
| 1153 | if inspect.isframe(obj): obj = obj.f_code |
| 1154 | if inspect.iscode(obj): |
| 1155 | lineno = obj.co_firstlineno - 1 |
| 1156 | |
| 1157 | # Find the line number where the docstring starts. Assume |
| 1158 | # that it's the first line that begins with a quote mark. |
| 1159 | # Note: this could be fooled by a multiline function |
| 1160 | # signature, where a continuation line begins with a quote |
| 1161 | # mark. |
| 1162 | if lineno is not None: |
| 1163 | if source_lines is None: |
| 1164 | return lineno+1 |
| 1165 | pat = re.compile(r'(^|.*:)\s*\w*("|\')') |
| 1166 | for lineno in range(lineno, len(source_lines)): |
| 1167 | if pat.match(source_lines[lineno]): |