-
-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
362 additions
and
188 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Removed `crashtest` dependency and vendored part of it into `cleo` |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from __future__ import annotations | ||
|
||
import operator | ||
|
||
from functools import reduce | ||
from pathlib import Path | ||
from typing import TYPE_CHECKING | ||
from typing import ClassVar | ||
|
||
|
||
if TYPE_CHECKING: | ||
import inspect | ||
|
||
from types import FrameType | ||
|
||
|
||
class Frame: | ||
_content_cache: ClassVar[dict[str, str]] = {} | ||
|
||
def __init__(self, frame_info: inspect.FrameInfo) -> None: | ||
self._frame = frame_info.frame | ||
self._frame_info = frame_info | ||
self._lineno = frame_info.lineno | ||
self._filename = frame_info.filename | ||
self._function = frame_info.function | ||
self._lines = None | ||
self._file_content: str | None = None | ||
|
||
@property | ||
def frame(self) -> FrameType: | ||
return self._frame | ||
|
||
@property | ||
def lineno(self) -> int: | ||
return self._lineno | ||
|
||
@property | ||
def filename(self) -> str: | ||
return self._filename | ||
|
||
@property | ||
def function(self) -> str: | ||
return self._function | ||
|
||
@property | ||
def line(self) -> str: | ||
if not self._frame_info.code_context: | ||
return "" | ||
|
||
return self._frame_info.code_context[0] | ||
|
||
@property | ||
def _key(self) -> tuple[str, str, int]: | ||
return self._filename, self._function, self._lineno | ||
|
||
@property | ||
def file_content(self) -> str: | ||
if self._file_content is not None: | ||
return self._file_content | ||
if not self._filename: | ||
self._file_content = "" | ||
return "" | ||
if self._filename not in self.__class__._content_cache: | ||
try: | ||
file_content = Path(self._filename).read_text() | ||
except OSError: | ||
file_content = "" | ||
self.__class__._content_cache[self._filename] = file_content | ||
self._file_content = self.__class__._content_cache[self._filename] | ||
return self._file_content | ||
|
||
def __hash__(self) -> int: | ||
return reduce(operator.xor, map(hash, self._key)) | ||
|
||
def __eq__(self, other: object) -> bool: | ||
if not isinstance(other, Frame): | ||
return NotImplemented | ||
return self._key == other._key | ||
|
||
def __repr__(self) -> str: | ||
return f"<Frame {self._filename}, {self._function}, {self._lineno}>" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
from __future__ import annotations | ||
|
||
from typing import List | ||
|
||
from cleo.ui.exception_trace.frame import Frame | ||
|
||
|
||
class FrameCollection(List[Frame]): | ||
def __init__(self, frames: list[Frame] | None = None, count: int = 0) -> None: | ||
if frames is None: | ||
frames = [] | ||
|
||
super().__init__(frames) | ||
|
||
self._count = count | ||
|
||
@property | ||
def repetitions(self) -> int: | ||
return self._count - 1 | ||
|
||
@property | ||
def is_repeated(self) -> bool: | ||
return self._count > 1 | ||
|
||
def increment_count(self, increment: int = 1) -> FrameCollection: | ||
self._count += increment | ||
|
||
return self | ||
|
||
def compact(self) -> list[FrameCollection]: | ||
""" | ||
Compacts the frames to deduplicate recursive calls. | ||
""" | ||
collections = [] | ||
current_collection = FrameCollection() | ||
|
||
i = 0 | ||
while i < len(self) - 1: | ||
frame = self[i] | ||
if frame in self[i + 1 :]: | ||
duplicate_indices = [] | ||
for sub_index, sub_frame in enumerate(self[i + 1 :]): | ||
if frame == sub_frame: | ||
duplicate_indices.append(sub_index + i + 1) | ||
|
||
found_duplicate = False | ||
for duplicate_index in duplicate_indices: | ||
collection = FrameCollection(self[i:duplicate_index]) | ||
if collection == current_collection: | ||
current_collection.increment_count() | ||
i = duplicate_index | ||
found_duplicate = True | ||
break | ||
|
||
if found_duplicate: | ||
continue | ||
|
||
collections.append(current_collection) | ||
current_collection = FrameCollection(self[i : duplicate_indices[0]]) | ||
|
||
i = duplicate_indices[0] | ||
|
||
continue | ||
|
||
if current_collection.is_repeated: | ||
collections.append(current_collection) | ||
current_collection = FrameCollection() | ||
|
||
current_collection.append(frame) | ||
i += 1 | ||
|
||
collections.append(current_collection) | ||
|
||
return collections |
Oops, something went wrong.