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))
#π code review, a traceback filtering script
88 messages Β· Page 1 of 1 (latest)
@chilly helm
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.
Closes after a period of inactivity, or when you send !close.
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
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'
nice
same
seems intresting... ill certenly use a customized version of it. never thought to hook the global execution handler like that before/
would be interesting to see your version
if u're interested in sharing it of course
ehh. the only customization i did was adding in context frames for use in ai.
uh i see
to filtered_tracebacks_frames?
i wanna make a change to traceback_frame_info
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.
can u show what u did
not yet. its untested... just a concept for now.
alright, i'm making a small change right now
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
editted the original
to also accept modules classes and functions as well as their names
interesting...
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
um
π π
no clue what it does
i've added some more boilerplate
just fancy formating
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
uh i see what u did there
yup... stupid and dead simple. i assume my code is the problem even when its not
for rather obvious reasons i wouldnt use this.
i should add "" in _traceback_frame_info
if NoneType then ""
(
frame_class_name
if frame_class_name != "NoneType"
else ""
)
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
cool
ok
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()
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
yee
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 ""
)
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.
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.
filtered_traceback.py
filtered_traceback_test.py
to run it use run_test()
alright, for now its finished i guess
new idea for a feature... logging! current working directory/logs/run-log-{filename}-{run number}.txt
very cool
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.