Skip to content

Instantly share code, notes, and snippets.

@GoldsteinE
Last active May 22, 2019 15:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GoldsteinE/f60601063ee90252f1f5c5b8ab51b691 to your computer and use it in GitHub Desktop.
Save GoldsteinE/f60601063ee90252f1f5c5b8ab51b691 to your computer and use it in GitHub Desktop.
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 # Также будет логироваться сам факт доступа к параметру
# 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