Last active
May 22, 2019 15:23
-
-
Save GoldsteinE/f60601063ee90252f1f5c5b8ab51b691 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fuck | |
fuck('Какой-то', 'текст') # Вывести какой-то текст, плюс название модуля и номер строки | |
fuck() # Вывести трейсбек | |
a = 1 | |
fuck.a # Вывести текст "a = 1", плюс название модуля и номер строки | |
b = fuck.a + 2 # В b будет лежать 3, на экран попадёт то же, что и в предыдущем примере | |
@fuck.ing | |
def function(a, b): # Все вызовы функции и их результаты будут логироваться | |
return a * b | |
fuck.fuck_to_stdout() # Переключить вывод на STDOUT | |
fuck.fuck_to_stderr() # Переключить вывод на STDERR (default) | |
fuck.fuck_to_file() # Переключить вывод в файл /tmp/fuck (Linux), C:\Temp\Fuck (Windows) | |
s = fuck.ing('test') # Все операции с переменной s будут логироваться | |
s = fuck.ing(s='test') # Можно использовать такой синтаксис, чтобы сделать сообщения информативнее | |
s.replace('s', 'x') # Это залогируется, как если бы на replace() висел декоратор | |
s + 'a' # И это | |
repr(s) # И даже это | |
fuck.ing(1j).imag # Также будет логироваться сам факт доступа к параметру |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# pylint: skip-file | |
import os | |
import sys | |
import types | |
import inspect | |
import tempfile | |
import functools | |
import traceback | |
def _function(): | |
pass | |
function = type(_function) | |
def make_fucker_debug_proxy_meta(base_type): | |
def fucker_debug_proxy_meta(name, bases, dct): | |
def make_wrapper(name): | |
def wrapper(self, *args): | |
object.__getattribute__(self, "_hook")(wrapper, *args) | |
result = getattr(object.__getattribute__(self, "_obj"), name)(*args) | |
object.__getattribute__(self, "_return_hook")(wrapper, result) | |
return result | |
wrapper.__name__ = name | |
return wrapper | |
do_not_proxy = { | |
"__class__", | |
"__mro__", | |
"__new__", | |
"__init__", | |
"__setattr__", | |
"__getattr__", | |
"__getattribute__", | |
"__dict__", | |
"__name__", | |
} | |
cls = type(name, bases, dct) | |
for field in dir(base_type): | |
if ( | |
field.startswith("__") | |
and field.endswith("__") | |
and field not in do_not_proxy | |
and field not in dct | |
): | |
setattr(cls, field, make_wrapper(field)) | |
return cls | |
return fucker_debug_proxy_meta | |
class Fucker(types.ModuleType): | |
def __init__(self): | |
filename = os.path.join(tempfile.gettempdir(), "fuck") | |
self._file = open(filename, "a", encoding="utf-8") | |
self._out = sys.stderr | |
def fuck_to_file(self): | |
self._out = self._file | |
def fuck_to_stdout(self): | |
self._out = sys.stdout | |
def fuck_to_stderr(self): | |
self._out = sys.stderr | |
def _fuck_print(self, *args, _fuck_frame=None, **kwargs): | |
try: | |
if _fuck_frame is None: | |
caller_frame = sys._getframe(1) | |
else: | |
caller_frame = _fuck_frame | |
module = caller_frame.f_globals.get("__name__", None) | |
if module: | |
module += "." | |
args = ( | |
"[" | |
+ module | |
+ caller_frame.f_code.co_name | |
+ ":" | |
+ str(caller_frame.f_lineno) | |
+ "] ", | |
) + args | |
except: | |
pass | |
print(*args, **kwargs, file=self._out) | |
def _fuck_format_args(self, func, args, kwargs): | |
kwargs = tuple(str(key) + "=" + repr(value) for key, value in kwargs.items()) | |
args = tuple(map(repr, args)) | |
return func.__name__ + "(" + ", ".join(args + kwargs) + ")" | |
def __getattr__(self, key): | |
caller_frame = sys._getframe(1) | |
try: | |
variables = dict(caller_frame.f_globals, **caller_frame.f_locals) | |
self._fuck_print(key, "=", variables[key], _fuck_frame=caller_frame) | |
return variables[key] | |
except KeyError: | |
raise NameError("No variable " + key + " found in caller frame") from None | |
def __call__(self, *args): | |
caller_frame = sys._getframe(1) | |
if args: | |
self._fuck_print(*args, _fuck_frame=caller_frame) | |
else: | |
traceback.print_stack(caller_frame, file=self._out) | |
def ing(self, obj=None, **kwargs): | |
name = None | |
if obj is None: | |
if len(kwargs) != 1: | |
raise ValueError( | |
"fuck.ing kwargs must have 1 key if obj is not specified" | |
) | |
name = next(iter(kwargs)) | |
obj = kwargs[name] | |
else: | |
if kwargs: | |
raise ValueError("fuck.ing kwargs must be empty if obj is specified") | |
if hasattr(obj, "__call__") and not kwargs: | |
@functools.wraps(obj) | |
def decorated(*args, **kwargs): | |
caller_frame = sys._getframe(1) | |
self._fuck_print( | |
"function called: ", | |
self._fuck_format_args(obj, args, kwargs), | |
_fuck_frame=caller_frame, | |
) | |
result = obj(*args, **kwargs) | |
self._fuck_print( | |
"function", | |
obj.__name__, | |
"returned", | |
repr(result), | |
_fuck_frame=caller_frame, | |
) | |
return result | |
return decorated | |
else: | |
meta = make_fucker_debug_proxy_meta(type(obj)) | |
fuck = self | |
class FuckerDebugProxy(metaclass=meta): | |
def __init__(self, obj): | |
object.__setattr__(self, "_obj", obj) | |
def __getattribute__(self, key): | |
fuck._fuck_print( | |
"someone accessed", | |
(name or repr(obj)) + "." + key, | |
_fuck_frame=sys._getframe(1), | |
) | |
ans = getattr(object.__getattribute__(self, "_obj"), key) | |
if hasattr(ans, "__call__"): | |
return fuck.ing(ans) | |
return ans | |
def __setattr__(self, key, val): | |
fuck._fuck_print( | |
"someone set", | |
(name or repr(obj)) + "." + key, | |
"to", | |
val, | |
_fuck_frame=sys.getframe(1), | |
) | |
setattr(object.__getattribute__(self, "_obj"), key, val) | |
def _hook(self, func, *args, **kwargs): | |
fuck._fuck_print( | |
"method called:", | |
(name or repr(obj)) | |
+ "." | |
+ fuck._fuck_format_args(func, args, kwargs), | |
_fuck_frame=sys._getframe(2), | |
) | |
def _return_hook(self, func, result): | |
fuck._fuck_print( | |
"method", | |
(name or repr(obj)) + "." + func.__name__, | |
"returned", | |
repr(result), | |
_fuck_frame=sys._getframe(2), | |
) | |
return FuckerDebugProxy(obj) | |
sys.modules[__name__] = Fucker() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment