Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added several systems-swamp + __file__ dunders #24

Closed
wants to merge 17 commits into from
Closed
3 changes: 3 additions & 0 deletions src/module-mesa/file/assets/haiku.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I am a haiku
Inside of a small text file
Waiting to be read
7 changes: 7 additions & 0 deletions src/module-mesa/file/file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Sets a directory relative to _this_ file"""
from pathlib import Path

ASSETS = (Path(__file__) / ".." / "assets").resolve()
James-Ansley marked this conversation as resolved.
Show resolved Hide resolved

with (ASSETS / "haiku.txt").open() as f:
print(f.read())
84 changes: 84 additions & 0 deletions src/systems-swamp/breakpointhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import contextlib
import linecache
import reprlib
import sys
from pathlib import Path
from pdb import Pdb
from pprint import pformat
from textwrap import indent


class PdbLocals(Pdb):
"""
Adds locals + extra formatting to default Pdb debugger at `breakpoint()`
"""

def _short_path(self, filename):
try:
return Path(filename).resolve().relative_to(Path.cwd())
except ValueError:
return Path(filename).resolve()

def _header(self, lineno):
name = self.curframe.f_code.co_name or "<lambda>"
filename = self._short_path(self.curframe.f_code.co_filename)
return f'File "{filename}" line {lineno} in {name}'

def _code_line(self, lineno):
if lineno is not None:
path = self.canonic(self.curframe.f_code.co_filename)
if line := linecache.getline(path, lineno, self.curframe.f_globals):
return indent(line.strip(), " " * 4)

def _return_value(self):
if "__return__" in self.curframe.f_locals:
rv = self.curframe.f_locals["__return__"]
return "Returning -> " + reprlib.repr(rv)

def _locals(self):
local_values = {
k: v for k, v in self.curframe_locals.items() if k != "__return__"
}
result = f"Locals: {pformat(local_values)}"
if return_value := self._return_value():
result += "\n" + return_value
return result

def format_stack_entry(self, frame_lineno, lprefix=": "):
_, lineno = frame_lineno
lines = [self._header(lineno)]
if line := self._code_line(lineno):
lines.append(line)
lines.append(self._locals())
return "\n\n".join(lines) + "\n"


def set_trace(*, header=None):
pdb = PdbLocals()
if header is not None:
pdb.message(header)
pdb.set_trace(sys._getframe().f_back)


@contextlib.contextmanager
def debug_with_locals():
sys.breakpointhook = set_trace
yield
sys.breakpointhook = sys.__breakpointhook__


# Example
def foo(x, y):
z = x + y
return z
James-Ansley marked this conversation as resolved.
Show resolved Hide resolved


def main():
breakpoint()
result = foo(1, 1)
print(result)


if __name__ == "__main__":
with debug_with_locals():
main()
24 changes: 24 additions & 0 deletions src/systems-swamp/displayhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Run in interactive mode (-i) or import this in an interactive session to
pretty print the result of all expressions
"""

import builtins
import sys
from pprint import pprint


def activate_pretty():
def hook(value):
if value is not None:
pprint(value)
builtins._ = value

sys.displayhook = hook


def deactivate_pretty():
sys.displayhook = sys.__displayhook__


activate_pretty()
22 changes: 22 additions & 0 deletions src/systems-swamp/excepthook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sys
from contextlib import redirect_stderr
from io import StringIO


def memeify(value: str) -> str:
return "".join(
c.upper() if i % 2 == 0 else c.lower() for i, c in enumerate(value)
)


def sarcastic_excepthook(type, value, traceback):
"""Makes error messages sArCaStIc"""
with redirect_stderr(StringIO()) as f:
sys.__excepthook__(type, value, traceback)
message = memeify(f.getvalue())
print(message, file=sys.stderr)


sys.excepthook = sarcastic_excepthook

1 / 0
100 changes: 100 additions & 0 deletions src/systems-swamp/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
SUPPRESSED_HEADER = "(But the context was suppressed (__suppress_context__))"
CONTEXT_HEADER = (
"- The above error happened while handling this error (__context__):"
)
CAUSE_HEADER = (
"- The above error was caused by the following error (__cause__):"
)


def print_context(exception: BaseException, pad: int = 0):
print(" " * (pad - 2) + CONTEXT_HEADER)
if exception.__suppress_context__:
print(" " * pad + SUPPRESSED_HEADER)
print_error(exception.__context__, pad=pad + 4)


def print_cause(exception: BaseException, pad: int = 0):
print(" " * (pad - 2) + CAUSE_HEADER)
print_error(exception.__cause__, pad=pad + 4)


def print_error(exception: BaseException, pad: int = 0):
print(f"{' ' * pad}{type(exception).__name__}: {exception}")
if exception.__context__ is not None:
print_context(exception, pad=pad + 4)
if exception.__cause__ is not None:
print_cause(exception, pad=pad + 4)


class ExplainErrors:
"""Explains and suppresses any exceptions raised"""

def __enter__(self):
...

def __exit__(self, exc_type, exc_val, exc_tb):
print_error(exc_val, pad=4)
print()
return True


print("Regular Exception:")
with ExplainErrors():
result = 1 / 0

print("Exception with context:")
with ExplainErrors():
try:
result = 1 / 0
except ZeroDivisionError:
raise ValueError("Can't use 0")

print("Exception with suppressed context:")
with ExplainErrors():
try:
result = 1 / 0
except ZeroDivisionError:
raise ValueError("Can't use 0") from None

print("Exception with cause (and suppressed context)")
with ExplainErrors():
try:
result = 1 / 0
except ZeroDivisionError as e:
raise ValueError("Can't use 0") from e

print("Exception with cause (and different suppressed context):")
with ExplainErrors():
try:
result = 1 / 0
except ZeroDivisionError:
raise ValueError("Can't use 0") from Exception("Another exception")

print("Exception with cause and context (unsuppressed):")
with ExplainErrors():
try:
result = 1 / 0
except ZeroDivisionError:
err = ValueError("Can't use 0")
err.__cause__ = Exception("Another exception")
err.__suppress_context__ = False
raise err

print("Manually creating an error with cause and context:")
with ExplainErrors():
err = Exception("The exception")
err.__context__ = Exception("The context")
err.__cause__ = Exception("The cause")
err.__suppress_context__ = False
raise err

print("Nested Errors Example:")
with ExplainErrors():
try:
try:
raise Exception("The initial Exception")
except Exception as e:
raise Exception("Inside the inner try") from e
except Exception:
raise Exception("Inside the outer try") from None
32 changes: 32 additions & 0 deletions src/systems-swamp/interactivehook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
This file needs to be set as a PYTHONSTARTUP environment variable:

export PYTHONSTARTUP=src/systems-swamp/interactivehook.py

It will then run when an interactive session is started.

Sets all outputs to be pretty printed + adds an introductory message
"""
import builtins
import sys
from pprint import pprint

BANNER = """
********************************************************************************
*********************** Remember to like and subscribe *************************
********************************************************************************
"""


def displayhook(value):
if value is not None:
pprint(value)
builtins._ = value


def interactivehook():
print(BANNER)
sys.displayhook = displayhook


sys.__interactivehook__ = interactivehook
61 changes: 61 additions & 0 deletions src/systems-swamp/stdio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import builtins
import contextlib
import sys
from collections.abc import Iterator
from io import StringIO
from textwrap import indent
from typing import TextIO, TypeVar

T = TypeVar("T", bound=TextIO)

SAVED_INPUT = input


def _input(prompt: object) -> str:
result = SAVED_INPUT(prompt)
print(result)
return result


@contextlib.contextmanager
def redirect_stdin(
target: TextIO, *, write_to_stdout: bool = False
) -> Iterator[None]:
sys.stdin = target
if write_to_stdout:
builtins.input = _input
yield
sys.stdin = sys.__stdin__
if write_to_stdout:
builtins.input = SAVED_INPUT


@contextlib.contextmanager
def redirect_stdout(target: T) -> Iterator[T]:
"""Example only, use contextlib.redirect_stdout instead"""
sys.stdout = target
yield target
sys.stdout = sys.__stdout__


@contextlib.contextmanager
def redirect_stderr(target: T) -> Iterator[T]:
"""Example only, use contextlib.redirect_stderr instead"""
sys.stderr = target
yield target
sys.stderr = sys.__stderr__


with (
redirect_stdin(StringIO("Some redirected stdin\n")),
redirect_stdout(StringIO()) as stdout,
redirect_stderr(StringIO()) as stderr,
):
value = input("Input: ")
print(f"Some stdout, with the input value of `{value}`")
print("Some stderr", file=sys.stderr)
print("Some more stdout")
print("Some more stderr", file=sys.stderr)

print("The stdout:", indent(stdout.getvalue(), "> "), sep="\n")
print("The stderr:", indent(stderr.getvalue(), "> "), sep="\n")
28 changes: 28 additions & 0 deletions src/systems-swamp/unraisablehook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""A context manager to ignore unraiseable errors"""
import contextlib
import sys


@contextlib.contextmanager
def silence_unraiseables():
sys.unraisablehook = lambda *args, **kwargs: None
yield
sys.unraisablehook = sys.__unraisablehook__


class Foo:
def __del__(self):
raise Exception("Whoops!")


with silence_unraiseables():
# stderr to keep error messages in order
print("Making Foo with silenced unraisables:", file=sys.stderr)
Foo()
print("Done", file=sys.stderr)

print(file=sys.stderr)

print("Making Foo with regular hook:", file=sys.stderr)
Foo()
print("Done", file=sys.stderr)