#πŸ”’ code review, a traceback filtering script

88 messages Β· Page 1 of 1 (latest)

chilly helm
#
from __future__ import annotations

from typing import (
    Any  # constants
    , overload  # functions
)

from types import TracebackType, ModuleType, FunctionType

import sys
import traceback


class traceback_frame_info:
    def __init__(
        self
        , frame_module: ModuleType | str
        , frame_class: type | str
        , frame_function: FunctionType | str
    ) -> None:
        self.frame_module_name = (
            frame_module
            if isinstance(frame_module, str)
            else frame_module.__name__
        )

        self.frame_class_name = (
            frame_class
            if isinstance(frame_class, str)
            else frame_class.__name__
        )

        self.frame_function_name = (
            frame_function
            if isinstance(frame_function, str)
            else frame_function.__name__
        )

    def __eq__(self, value: object) -> bool:  # a == b
        return (
            value is not None
            and isinstance(value, traceback_frame_info) is True
            and self.frame_module_name == value.frame_module_name
            and self.frame_class_name == value.frame_class_name
            and self.frame_function_name == value.frame_function_name
        )

    def __hash__(self) -> int:  # hash(a)
        return hash((self.frame_module_name, self.frame_class_name, self.frame_function_name))
ivory joltBOT
#

@chilly helm

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

chilly helm
#
filtered_tracebacks_frames: set[traceback_frame_info] = set()

original_sys_excepthook = sys.excepthook


def filtered_sys_excepthook(
    exception_type: type[BaseException]
    , exception: BaseException
    , exception_traceback: TracebackType | None
) -> Any:
    # global filtered_tracebacks_frames  # not changing its value

    # global original_sys_excepthook  # not changing its value

    function_result: Any

    filtered_exception_traceback = []

    for frame, line_number in traceback.walk_tb(exception_traceback):
        frame_module_name = frame.f_globals.get("__name__")
        frame_class_name = (
            type(
                frame.f_locals.get("self")
                or frame.f_locals.get("cls")
                or frame.f_locals.get("mcs")
            ).__name__
        )

        frame_function_name = frame.f_code.co_name
        frame_info = traceback_frame_info(frame_module_name, frame_class_name, frame_function_name)

        if frame_info in filtered_tracebacks_frames:
            break

        filtered_exception_traceback.append((frame, line_number))

    current_traceback = None

    if filtered_exception_traceback:
        next_traceback = None

        for frame, line_number in reversed(filtered_exception_traceback):
            tb_next = next_traceback
            tb_frame = frame
            tb_lasti = frame.f_lasti
            tb_lineno = line_number

            current_traceback = TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)
            next_traceback = current_traceback

    function_result = (
        original_sys_excepthook(
            exception_type
            , exception.with_traceback(current_traceback)
            , current_traceback
        )
    )
    
    return function_result


sys.excepthook = filtered_sys_excepthook
#

example of usage:

class Row:
    def __init__(self) -> None:
        self._dict = {"a": 5}

    def __getattr__(self, name: str) -> Any:
        if name in self._dict:
            return self._dict[name]

        raise AttributeError(f"row has no column '{name}'")


filtered_tracebacks_frames.add(traceback_frame_info(__name__, Row, Row.__getattr__))


def a():
    b = Row()

    print(b.a)

    return b.c


d = a()
#

@bleak viper

#

took me like 3 hours to work on this sht not gonna lie

#

i dont know if i've got everything right

#

the idea is to remove tracebacks the user wants to remove

bleak viper
#

bruh

#

crazy

chilly helm
#

added eq dunder, since hash is not enough

#

with sys.excepthook = filtered_sys_excepthook:

5
Traceback (most recent call last):
  File "***.py", line 130, in <module>
    d = a()
  File "***.py", line 127, in a
    return b.c
           ^^^
AttributeError: row has no column 'c'
#

without sys.excepthook = filtered_sys_excepthook:

5
Traceback (most recent call last):
  File "***.py", line 130, in <module>
    d = a()
  File "***.py", line 127, in a
    return b.c
           ^^^
  File "***.py", line 116, in __getattr__
    raise AttributeError(f"row has no column '{name}'")
AttributeError: row has no column 'c'
bleak viper
#

nice

chilly helm
#

i dont know if i would use it, but its up to u

bleak viper
#

same

lunar quarry
#

seems intresting... ill certenly use a customized version of it. never thought to hook the global execution handler like that before/

chilly helm
#

if u're interested in sharing it of course

lunar quarry
chilly helm
#

uh i see

chilly helm
#

i wanna make a change to traceback_frame_info

lunar quarry
#

more so adding in the first and last 50 some lines of code from where the error originated;

#

apologies im more so self taught learned back in 2010 i use ai in some ways to speed up my development cycle.

lunar quarry
#

not yet. its untested... just a concept for now.

chilly helm
#

alright, i'm making a small change right now

lunar quarry
#

heres something blursed tho


def obfuscate_python_code_safe(pycode):
    # Safely encode Python code as ASCII values and reconstruct with exec()
    encoded = [str(ord(c)) for c in pycode]
    # Remove any leading zeros from integer literals
    encoded_clean = [str(int(num)) for num in encoded]
    encoded_str = ",".join(encoded_clean)
    payload = f"exec(''.join(map(chr,[{encoded_str}])))"
    return payload

def python_to_safe_bf(pycode):
    obf_code = obfuscate_python_code_safe(pycode)
    bf = ""
    indices = list(range(1, len(obf_code) + 1))
    random.shuffle(indices)
    tape_map = dict(zip(indices, obf_code))

    for i in sorted(tape_map.keys()):
        c = tape_map[i]
        bf += bf_write_char(ord(c), i)
        bf += "+" * random.randint(0, 3)
        bf += ">" * random.randint(0, 2)
        bf += "<" * random.randint(0, 2)

    return bf
chilly helm
#

to also accept modules classes and functions as well as their names

chilly helm
#

i've added these overloads in my code:


    @overload
    def __init__(self, frame_module_name: str, frame_class_name: str, frame_function_name: str) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module_name: str, frame_class_name: str, frame_function: FunctionType) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module_name: str, frame_class: type, frame_function_name: str) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module_name: str, frame_class: type, frame_function: FunctionType) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module: ModuleType, frame_class_name: str, frame_function_name: str) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module: ModuleType, frame_class_name: str, frame_function: FunctionType) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module: ModuleType, frame_class: type, frame_function_name: str) -> traceback_frame_info:
        pass

    @overload
    def __init__(self, frame_module: ModuleType, frame_class: type, frame_function: FunctionType) -> traceback_frame_info:
        pass
lunar quarry
#

heres what i have for output....

#

@chilly helm

chilly helm
#

um

lunar quarry
#

πŸ‘ πŸ‘Ž

chilly helm
#

i've added some more boilerplate

lunar quarry
#

that is it...

#

the bottom pices are just error cases im using for testing.

chilly helm
#

oh i see lol

#

u've added prints

#

thats cool

#

cool concept i like it

lunar quarry
#

just fancy formating

chilly helm
#

yea pretty cool

#

u can even go through the frames in filtered_exception_traceback

#

like i did in here:


        for frame, line_number in reversed(filtered_exception_traceback):
            tb_next = next_traceback
            tb_frame = frame
            tb_lasti = frame.f_lasti
            tb_lineno = line_number
#

and add custom prints

#

pretty cool concept, haven't thought of this

lunar quarry
#

yea i just grab the file header and toss anything that isnt in my local files.

chilly helm
#

uh i see what u did there

lunar quarry
#

yup... stupid and dead simple. i assume my code is the problem even when its not

#

for rather obvious reasons i wouldnt use this.

chilly helm
#

i should add "" in _traceback_frame_info

#

if NoneType then ""

#
(
            frame_class_name
            if frame_class_name != "NoneType"
            else ""
        )
lunar quarry
#

heres a bunch of random test cases you can use

def error_attribute():
    r = Row()
    return r.banana


def error_zero_division():
    return 1 / 0


def error_name():
    return undefined_variable + 5


def error_index():
    lst = [1, 2, 3]
    return lst[99]


def error_key():
    d = {"x": 1}
    return d["banana"]


def error_type():
    return "hello" + 5


def error_assert():
    assert False, "You messed up bad, champ."


def error_import():
    import this_module_doesnt_exist


def error_file():
    with open("definitely_not_a_file.txt") as f:
        return f.read()


def error_recursion():
    def recurse(): return recurse()
    return recurse()


def error_module_call():
    import math
    return math()


def error_bytes():
    b = b"hello"
    return b.index(300)  # byte out of range


def error_custom():
    class Boom(Exception): pass
    raise Boom("Custom error time :bomb:")


def error_generator():
    def bad_gen():
        raise StopIteration("whoops")
        yield
    next(bad_gen())


def error_unpacking():
    a, b = (1,)  # too few values


def error_math_domain():
    import math
    return math.sqrt(-1)


def error_encoding():
    ":bomb:".encode("ascii")


def error_lambda():
    (lambda x: x.does_not_exist)(42)


def error_slice():
    s = slice("a", 3)
    return [1, 2, 3][s]


def error_property():
    class BadProp:
        @property
        def boom(self):
            raise RuntimeError("Property exploded")
    return BadProp().boom
chilly helm
#

cool

lunar quarry
#

mind if i dm you?

#

@chilly helm

chilly helm
#

i just did this:



        if frame_class_name == "NoneType":
            frame_class_name = ""
#

import test

filter_traceback_frame(test, test.Row, test.Row.__getattr__)


def a():
    b = test.Row()

    print(b.a)

    return b.c


d = a()
#

test.py:

from typing import Any
class Row:
    def __init__(self) -> None:
        self._dict = {"a": 5}

    def __getattr__(self, name: str) -> Any:
        if name in self._dict:
            return self._dict[name]

        raise AttributeError(f"row has no column '{name}'")
#

also works

#

cool stuff

lunar quarry
#

yee

chilly helm
#

        frame_class = (
            frame_locals.get("self")
            or frame_locals.get("cls")
            or frame_locals.get("mcs")
        )
        
        frame_class_name = (
            type(frame_class).__name__
            if frame_class is not None
            else ""
        )
lunar quarry
#
import sys

def global_fuck_you_handler(exc_type, exc_value, exc_traceback):
    print("fuck you", flush=True)

sys.excepthook = global_fuck_you_handler
#

πŸ‘

#

certified.

chilly helm
#

lol

#

!paste

ivory joltBOT
#
Pasting large amounts of code

If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/

After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.

chilly helm
#

filtered_traceback.py

#

filtered_traceback_test.py

#

to run it use run_test()

#

alright, for now its finished i guess

lunar quarry
#

new idea for a feature... logging! current working directory/logs/run-log-{filename}-{run number}.txt

ivory joltBOT
#
Python help channel closed for inactivity

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.