Skip to content

Commit

Permalink
Improve StackFrame type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
tysmith committed May 9, 2024
1 parent adf48c4 commit e3c1042
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
23 changes: 18 additions & 5 deletions grizzly/common/stack_hasher.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
crash id (1st hash) and a bug id (2nd hash). This is not perfect but works very
well in most cases.
"""
from abc import ABC, abstractmethod
from hashlib import sha1
from logging import DEBUG, INFO, basicConfig, getLogger
from os.path import basename
from re import compile as re_compile
from re import match as re_match
from typing import List, Optional
from typing import List, Optional, Type

__all__ = ("Stack",)
__author__ = "Tyson Smith"
Expand All @@ -37,7 +38,7 @@
_RE_FUNC_NAME = re_compile(r"(?P<func>.+?)[\(|\s|\<]{1}")


class StackFrame:
class StackFrame(ABC):
__slots__ = ("function", "location", "offset", "stack_line")

def __init__(
Expand All @@ -64,6 +65,18 @@ def __str__(self) -> str:
out.append(f"offset: {self.offset!r}")
return " - ".join(out)

@classmethod
@abstractmethod
def from_line(cls, input_line: str) -> Optional["StackFrame"]:
"""Parse stack frame details.
Args:
input_line: A single line of text.
Returns:
StackFrame
"""


class MinidumpStackFrame(StackFrame):
@classmethod
Expand Down Expand Up @@ -402,13 +415,13 @@ def from_text(cls, input_text: str, major_depth: int = MAJOR_DEPTH) -> "Stack":
"""

frames: List[StackFrame] = []
parser_class = None
parser_class: Optional[Type[StackFrame]] = None
for line in input_text.split("\n"):
line = line.rstrip()
if not line:
# skip empty lines
continue
frame = None
frame: Optional[StackFrame] = None
try:
# only use a single StackFrame type
if parser_class is None:
Expand All @@ -424,8 +437,8 @@ def from_text(cls, input_text: str, major_depth: int = MAJOR_DEPTH) -> "Stack":
):
frame = frame_parser.from_line(line)
if frame is not None:
LOG.debug("frame parser: %s", frame_parser.__name__)
parser_class = frame_parser
LOG.debug("frame parser: %s", parser_class.__name__)
break
else:
frame = parser_class.from_line(line)
Expand Down
23 changes: 16 additions & 7 deletions grizzly/common/test_stack_hasher.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
)


class BasicStackFrame(StackFrame):
@classmethod
def from_line(cls, input_line):
# unused
pass


def test_stack_01():
"""test creating an empty Stack"""
stack = Stack([])
Expand All @@ -27,7 +34,7 @@ def test_stack_01():

def test_stack_02():
"""test creating a Stack with 1 generic frame"""
frames = [StackFrame(function="a", location="b", offset="c", stack_line="0")]
frames = [BasicStackFrame(function="a", location="b", offset="c", stack_line="0")]
stack = Stack(frames)
assert stack.minor is not None
assert stack.major is not None
Expand All @@ -44,7 +51,7 @@ def test_stack_02():
def test_stack_03():
"""test creating a Stack with 2 frames"""
frames = [
StackFrame(function="a", location="b", offset="c", stack_line="0")
BasicStackFrame(function="a", location="b", offset="c", stack_line="0")
for _ in range(2)
]
stack = Stack(frames, major_depth=2)
Expand All @@ -59,7 +66,7 @@ def test_stack_03():
def test_stack_04():
"""test creating a Stack with 2 frames with a major depth of 0"""
frames = [
StackFrame(function="a", location="b", offset="c", stack_line=str(line))
BasicStackFrame(function="a", location="b", offset="c", stack_line=str(line))
for line in range(2)
]
stack = Stack(frames, major_depth=0)
Expand All @@ -74,7 +81,7 @@ def test_stack_04():
def test_stack_05():
"""test creating a Stack with 10 frames exceeding major depth"""
frames = [
StackFrame(function="a", location="b", offset="c", stack_line=str(line))
BasicStackFrame(function="a", location="b", offset="c", stack_line=str(line))
for line in range(10)
]
stack = Stack(frames, major_depth=5)
Expand Down Expand Up @@ -284,7 +291,9 @@ def test_stack_13():
def test_stack_14():
"""test Stack.height_limit"""
frames = [
StackFrame(function=str(num), location="b", offset="c", stack_line=str(num))
BasicStackFrame(
function=str(num), location="b", offset="c", stack_line=str(num)
)
for num in range(10)
]
stack = Stack(frames, major_depth=3)
Expand Down Expand Up @@ -379,8 +388,8 @@ def test_stack_18():


def test_stackframe_01():
"""test creating an empty generic StackFrame"""
stack = StackFrame()
"""test creating an empty generic BasicStackFrame"""
stack = BasicStackFrame()
assert not str(stack)


Expand Down

0 comments on commit e3c1042

Please sign in to comment.