Last active
May 10, 2019 15:35
-
-
Save benmezger/9cdc67a20792c213d2e08888681bf7df to your computer and use it in GitHub Desktop.
This file contains hidden or 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 sys | |
| import time | |
| import dis | |
| import cProfile | |
| import pstats | |
| try: | |
| from django.conf import settings | |
| is_django = True | |
| except ImportError: | |
| settings = {} | |
| is_django = False | |
| try: | |
| from ipdb import runcall | |
| except ImportError: | |
| from pdb import runcall | |
| # TODO: Change print to respect logger | |
| # https://stackoverflow.com/questions/10294014/python-decorator-best-practice-using-a-class-vs-a-function | |
| class _Decorator: | |
| def __init__(self, func, logger=None): | |
| self.logger = logger | |
| if not self.logger: | |
| self.logger = logging.getLogger() | |
| self.func = func | |
| self.sys_version = sys.executable | |
| def __call__(self, *args, **kwargs): | |
| raise NotImplemented() | |
| class ObjectInfoDebug(_Decorator): | |
| def __init__(self, func, logger=None): | |
| super().__init__(func, logger) | |
| functools.update_wrapper(self, func) | |
| def __call__(self, *args, **kwargs): | |
| args_repr = (repr(a) for a in args) | |
| kwargs_repr = (f"{k}={v!r}" for k, v in kwargs.items()) | |
| signature = ", ".join(list(args_repr) + list(kwargs_repr)) | |
| print(f"Calling {self.func.__name__}({signature})") | |
| perf_start = time.perf_counter() | |
| proc_start = time.process_time() | |
| ret = self.func(*args, **kwargs) | |
| total_perf = (time.perf_counter() - perf_start) / 60 | |
| total_proc = (time.process_time() - proc_start) / 60 | |
| print(f"{self.func.__name__!r} Elapsed time: {total_perf} [min]") | |
| print(f"{self.func.__name__!r} CPU process time: {total_proc} [min]") | |
| print(f"{self.func.__name__!r} returned {ret!r}") | |
| return ret | |
| class PDBDebugger(_Decorator): | |
| def __init__(self, func, logger=None): | |
| super().__init__(func, logger) | |
| functools.update_wrapper(self, func) | |
| def __call__(self, *args, **kwargs): | |
| ret = runcall(self.func, *args, **kwargs) | |
| return ret | |
| class DisassembleDebug(_Decorator): | |
| def __init__(self, func, logger=None): | |
| super().__init__(func, logger) | |
| functools.update_wrapper(self, func) | |
| def __call__(self, *args, **kwargs): | |
| print(dis.dis(self.func)) | |
| return self.func(*args, **kwargs) | |
| class ProfilerDebug(_Decorator): | |
| def __init__(self, func, logger=None, profiler_log="profiler.out"): | |
| super().__init__(func, logger) | |
| functools.update_wrapper(self, func) | |
| self.profiler_log = profiler_log | |
| self.prof = cProfile.Profile() | |
| def __call__(self, *args, **kwargs): | |
| self.prof.enable() | |
| try: | |
| ret = self.func(*args, **kwargs) | |
| finally: | |
| self.prof.disable() | |
| with open(self.profiler_log, 'w') as profile_file: | |
| stats = pstats.Stats(self.prof, stream=profile_file) | |
| stats.print_stats() | |
| stats.print_callers() | |
| return ret | |
| @ProfilerDebug(profiler_log="foo.log") | |
| def hello(a, b): | |
| for i in range(10000): | |
| pass | |
| x = 12 | |
| return (a, b) | |
| hello(1, 2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment