|
29 | 29 | import py |
30 | 30 |
|
31 | 31 | import _pytest |
| 32 | +from _pytest._code.source import findsource |
| 33 | +from _pytest._code.source import getrawcode |
| 34 | +from _pytest._code.source import getstatementrange_ast |
| 35 | +from _pytest._code.source import Source |
32 | 36 | from _pytest._io import TerminalWriter |
33 | 37 | from _pytest._io.saferepr import safeformat |
34 | 38 | from _pytest._io.saferepr import saferepr |
35 | 39 | from _pytest.compat import ATTRS_EQ_FIELD |
| 40 | +from _pytest.compat import get_real_func |
36 | 41 | from _pytest.compat import overload |
37 | 42 | from _pytest.compat import TYPE_CHECKING |
38 | 43 |
|
|
41 | 46 | from typing_extensions import Literal |
42 | 47 | from weakref import ReferenceType # noqa: F401 |
43 | 48 |
|
44 | | - from _pytest._code import Source |
45 | | - |
46 | 49 | _TracebackStyle = Literal["long", "short", "line", "no", "native"] |
47 | 50 |
|
48 | 51 |
|
@@ -90,18 +93,14 @@ def path(self) -> Union[py.path.local, str]: |
90 | 93 | def fullsource(self) -> Optional["Source"]: |
91 | 94 | """ return a _pytest._code.Source object for the full source file of the code |
92 | 95 | """ |
93 | | - from _pytest._code import source |
94 | | - |
95 | | - full, _ = source.findsource(self.raw) |
| 96 | + full, _ = findsource(self.raw) |
96 | 97 | return full |
97 | 98 |
|
98 | 99 | def source(self) -> "Source": |
99 | 100 | """ return a _pytest._code.Source object for the code object's source only |
100 | 101 | """ |
101 | 102 | # return source only for that part of code |
102 | | - import _pytest._code |
103 | | - |
104 | | - return _pytest._code.Source(self.raw) |
| 103 | + return Source(self.raw) |
105 | 104 |
|
106 | 105 | def getargs(self, var: bool = False) -> Tuple[str, ...]: |
107 | 106 | """ return a tuple with the argument names for the code object |
@@ -132,10 +131,8 @@ def __init__(self, frame: FrameType) -> None: |
132 | 131 | @property |
133 | 132 | def statement(self) -> "Source": |
134 | 133 | """ statement this frame is at """ |
135 | | - import _pytest._code |
136 | | - |
137 | 134 | if self.code.fullsource is None: |
138 | | - return _pytest._code.Source("") |
| 135 | + return Source("") |
139 | 136 | return self.code.fullsource.getstatement(self.lineno) |
140 | 137 |
|
141 | 138 | def eval(self, code, **vars): |
@@ -231,8 +228,6 @@ def getsource(self, astcache=None) -> Optional["Source"]: |
231 | 228 | """ return failing source code. """ |
232 | 229 | # we use the passed in astcache to not reparse asttrees |
233 | 230 | # within exception info printing |
234 | | - from _pytest._code.source import getstatementrange_ast |
235 | | - |
236 | 231 | source = self.frame.code.fullsource |
237 | 232 | if source is None: |
238 | 233 | return None |
@@ -703,11 +698,9 @@ def get_source( |
703 | 698 | short: bool = False, |
704 | 699 | ) -> List[str]: |
705 | 700 | """ return formatted and marked up source lines. """ |
706 | | - import _pytest._code |
707 | | - |
708 | 701 | lines = [] |
709 | 702 | if source is None or line_index >= len(source.lines): |
710 | | - source = _pytest._code.Source("???") |
| 703 | + source = Source("???") |
711 | 704 | line_index = 0 |
712 | 705 | if line_index < 0: |
713 | 706 | line_index += len(source) |
@@ -769,11 +762,9 @@ def repr_locals(self, locals: Dict[str, object]) -> Optional["ReprLocals"]: |
769 | 762 | def repr_traceback_entry( |
770 | 763 | self, entry: TracebackEntry, excinfo: Optional[ExceptionInfo] = None |
771 | 764 | ) -> "ReprEntry": |
772 | | - import _pytest._code |
773 | | - |
774 | 765 | source = self._getentrysource(entry) |
775 | 766 | if source is None: |
776 | | - source = _pytest._code.Source("???") |
| 767 | + source = Source("???") |
777 | 768 | line_index = 0 |
778 | 769 | else: |
779 | 770 | line_index = entry.lineno - entry.getfirstlinesource() |
@@ -1150,19 +1141,37 @@ def toterminal(self, tw: TerminalWriter) -> None: |
1150 | 1141 | tw.line("") |
1151 | 1142 |
|
1152 | 1143 |
|
1153 | | -def getrawcode(obj, trycall: bool = True): |
1154 | | - """ return code object for given function. """ |
| 1144 | +def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]: |
| 1145 | + """ Return source location (path, lineno) for the given object. |
| 1146 | + If the source cannot be determined return ("", -1). |
| 1147 | +
|
| 1148 | + The line number is 0-based. |
| 1149 | + """ |
| 1150 | + # xxx let decorators etc specify a sane ordering |
| 1151 | + # NOTE: this used to be done in _pytest.compat.getfslineno, initially added |
| 1152 | + # in 6ec13a2b9. It ("place_as") appears to be something very custom. |
| 1153 | + obj = get_real_func(obj) |
| 1154 | + if hasattr(obj, "place_as"): |
| 1155 | + obj = obj.place_as |
| 1156 | + |
1155 | 1157 | try: |
1156 | | - return obj.__code__ |
1157 | | - except AttributeError: |
1158 | | - obj = getattr(obj, "f_code", obj) |
1159 | | - obj = getattr(obj, "__code__", obj) |
1160 | | - if trycall and not hasattr(obj, "co_firstlineno"): |
1161 | | - if hasattr(obj, "__call__") and not inspect.isclass(obj): |
1162 | | - x = getrawcode(obj.__call__, trycall=False) |
1163 | | - if hasattr(x, "co_firstlineno"): |
1164 | | - return x |
1165 | | - return obj |
| 1158 | + code = Code(obj) |
| 1159 | + except TypeError: |
| 1160 | + try: |
| 1161 | + fn = inspect.getsourcefile(obj) or inspect.getfile(obj) |
| 1162 | + except TypeError: |
| 1163 | + return "", -1 |
| 1164 | + |
| 1165 | + fspath = fn and py.path.local(fn) or "" |
| 1166 | + lineno = -1 |
| 1167 | + if fspath: |
| 1168 | + try: |
| 1169 | + _, lineno = findsource(obj) |
| 1170 | + except OSError: |
| 1171 | + pass |
| 1172 | + return fspath, lineno |
| 1173 | + else: |
| 1174 | + return code.path, code.firstlineno |
1166 | 1175 |
|
1167 | 1176 |
|
1168 | 1177 | # relative paths that we use to filter traceback entries from appearing to the user; |
|
0 commit comments