Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

recordCall and CallStack/CallLocation #35

Merged
merged 2 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions python/selfie-lib/selfie_lib/WriteTracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from typing import List, Optional
from selfie_lib.CommentTracker import SnapshotFileLayout
import inspect
from functools import total_ordering


@total_ordering
class CallLocation:
nedtwigg marked this conversation as resolved.
Show resolved Hide resolved
def __init__(self, file_name: Optional[str], line: int):
self._file_name = file_name
self._line = line

@property
def file_name(self) -> Optional[str]:
return self._file_name

@property
def line(self) -> int:
return self._line

def with_line(self, line: int) -> "CallLocation":
return CallLocation(self._file_name, line)

def ide_link(self, layout: "SnapshotFileLayout") -> str:
return f"File: {self._file_name}, Line: {self._line}"

def same_path_as(self, other: "CallLocation") -> bool:
if not isinstance(other, CallLocation):
return False
return self._file_name == other.file_name

def source_filename_without_extension(self) -> str:
if self._file_name is not None:
return self._file_name.rsplit(".", 1)[0]
return ""

def __lt__(self, other) -> bool:
if not isinstance(other, CallLocation):
return NotImplemented
return (self._file_name, self._line) < (other.file_name, other.line)

def __eq__(self, other) -> bool:
if not isinstance(other, CallLocation):
return NotImplemented
return (self._file_name, self._line) == (other.file_name, other.line)


class CallStack:
def __init__(self, location: CallLocation, rest_of_stack: List[CallLocation]):
self.location = location
self.rest_of_stack = rest_of_stack

def ide_link(self, layout: "SnapshotFileLayout") -> str:
links = [self.location.ide_link(layout)] + [
loc.ide_link(layout) for loc in self.rest_of_stack
]
return "\n".join(links)


def recordCall(callerFileOnly: bool = False) -> CallStack:
stack_frames = inspect.stack()[1:]

if callerFileOnly:
caller_file = stack_frames[0].filename
stack_frames = [
frame for frame in stack_frames if frame.filename == caller_file
]

call_locations = [
CallLocation(frame.filename, frame.lineno) for frame in stack_frames
]

location = call_locations[0]
rest_of_stack = call_locations[1:]

return CallStack(location, rest_of_stack)
50 changes: 50 additions & 0 deletions python/selfie-lib/tests/RecordCall_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from unittest.mock import Mock
from selfie_lib.WriteTracker import CallLocation, CallStack, recordCall
import os


def test_call_location_ide_link():
layout = Mock()
location = CallLocation(file_name="example.py", line=10)
expected_link = "File: example.py, Line: 10"

assert location.ide_link(layout) == expected_link


def test_call_stack_ide_link():
layout = Mock()
location1 = CallLocation(file_name="example1.py", line=10)
location2 = CallLocation(file_name="example2.py", line=20)
call_stack = CallStack(location=location1, rest_of_stack=[location2])

expected_links = "File: example1.py, Line: 10\nFile: example2.py, Line: 20"
assert call_stack.ide_link(layout) == expected_links


def test_record_call_with_caller_file_only_false():
call_stack = recordCall(False)
nedtwigg marked this conversation as resolved.
Show resolved Hide resolved

assert (
len(call_stack.rest_of_stack) > 0
), "Expected the rest of stack to contain more than one CallLocation"

expected_call_location_str = "File: RecordCall_test.py, Line: 25"

if call_stack.location.file_name is not None:
actual_file_name = os.path.basename(call_stack.location.file_name)
actual_call_location_str = (
f"File: {actual_file_name}, Line: {call_stack.location.line}"
)
else:
actual_call_location_str = "File name is None"

assert (
actual_call_location_str == expected_call_location_str
), f"Expected call location to be '{expected_call_location_str}' but was '{actual_call_location_str}'"


def test_record_call_with_caller_file_only_true():
call_stack = recordCall(True)
assert (
len(call_stack.rest_of_stack) >= 0
), "Expected the rest of stack to potentially contain only the caller's file location"