Advertisement
manageryzy

Untitled

Jan 12th, 2025
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.75 KB | None | 0 0
  1. import importlib
  2. import importlib.abc
  3. import importlib.util
  4. import sys
  5. import inspect
  6. import functools
  7. import time
  8. import atexit
  9.  
  10. function_call_info = {}
  11.  
  12. ORIGINAL_FIND_SPEC = importlib.util.find_spec
  13.  
  14.  
  15. def filter_basic_types(obj):
  16.     """Return only basic types or a placeholder for others."""
  17.     BASIC_TYPES = (type(None), bool, int, float, complex, str)
  18.  
  19.     max_container_len = 5
  20.  
  21.     if isinstance(obj, BASIC_TYPES):
  22.         return obj
  23.     elif isinstance(obj, (list, tuple)):
  24.         # return [filter_basic_types(x) for x in obj]
  25.  
  26.         return  [filter_basic_types(x) for x in obj][:max_container_len]
  27.     elif isinstance(obj, dict):
  28.         # return {filter_basic_types(k): filter_basic_types(v) for k, v in obj.items()}
  29.         return {filter_basic_types(k): filter_basic_types(v) for k, v in list(obj.items())[:max_container_len]}
  30.     else:
  31.         return f"<{type(obj).__name__}>"
  32.  
  33. def safe_repr(obj):
  34.     """Attempt repr; return placeholder if it fails."""
  35.     try:
  36.         return repr(obj)
  37.     except Exception:
  38.         return f"<unprintable {type(obj).__name__} object>"
  39.  
  40. def log_function_call(func):
  41.     """Decorator to wrap and track function/method calls."""
  42.     @functools.wraps(func)
  43.     def wrapper(*args, **kwargs):
  44.         full_name = f"{func.__module__}.{func.__qualname__}"
  45.  
  46.         start_time = time.time()
  47.         result = func(*args, **kwargs)
  48.         duration = time.time() - start_time
  49.  
  50.         do_print = True
  51.         if 'parse_' in full_name:
  52.             do_print = False
  53.         if 'on_' in full_name:
  54.             do_print = False
  55.         if 'safe_' in full_name:
  56.             do_print = False
  57.         if 'is_defined' in full_name:
  58.             do_print = False
  59.         if 'throttle' in full_name:
  60.             do_print = False
  61.         if 'handle_' in full_name:
  62.             do_print = False
  63.         if 'get_default' in full_name:
  64.             do_print = False
  65.         if 'ccxt.base.precise' in full_name:
  66.             do_print = False
  67.         if 'describe' in full_name:
  68.             do_print = False
  69.         if 'omit_zero' in full_name:
  70.             do_print = False
  71.         if 'check_conflicting_proxies' in full_name:
  72.             do_print = False
  73.  
  74.         if do_print:
  75.             # Filter args and kwargs to basic types
  76.             filtered_args = filter_basic_types(args)
  77.             filtered_kwargs = filter_basic_types(kwargs)
  78.  
  79.             # Convert args/kwargs to safe repr to avoid TypeError
  80.             args_str = ", ".join(safe_repr(a) for a in filtered_args)
  81.             kwargs_str = ", ".join(
  82.                 f"{k}={safe_repr(v)}" for k, v in filtered_kwargs.items()
  83.             )
  84.  
  85.             print(f"[CALL] {full_name}")
  86.             print(f"       args:   ({args_str})")
  87.             print(f"       kwargs: {{{kwargs_str}}}")
  88.             # import traceback
  89.             # traceback.print_stack(limit=10)
  90.  
  91.  
  92.         if full_name not in function_call_info:
  93.             function_call_info[full_name] = {
  94.                 "count": 0,
  95.                 "total_time": 0.0,
  96.             }
  97.         function_call_info[full_name]["count"] += 1
  98.         function_call_info[full_name]["total_time"] += duration
  99.         return result
  100.     return wrapper
  101.  
  102.  
  103. wrapped_modules = set()
  104. wrapped_classes = set()
  105. wrapped_functions = set()
  106.  
  107. class HookLoader(importlib.abc.Loader):
  108.     def __init__(self, original_loader):
  109.         self.original_loader = original_loader
  110.  
  111.     def create_module(self, spec):
  112.         return self.original_loader.create_module(spec)
  113.  
  114.     def exec_module(self, module):
  115.         self.original_loader.exec_module(module)
  116.         self._wrap_module_functions(module)
  117.  
  118.     def _wrap_module_functions(self, module):
  119.         if module.__name__ in wrapped_modules:
  120.             return
  121.         wrapped_modules.add(module.__name__)
  122.         print(f"Wrapping module: {module.__name__}")
  123.         for attr_name in dir(module):
  124.             # skip private if you wish
  125.             if attr_name.startswith('_'):
  126.                 continue
  127.             attr = getattr(module, attr_name)
  128.             if inspect.isfunction(attr) or inspect.ismethod(attr):
  129.                 # print(f"Wrapping function: {attr_name} in module: {module.__name__} {attr}")
  130.                 full_name = f"{module.__name__}.{attr_name}"
  131.                 if full_name in wrapped_functions:
  132.                     continue
  133.                 wrapped_functions.add(full_name)
  134.  
  135.                 if 'test.py' in inspect.getsourcefile(attr):
  136.                     print(
  137.                         f"Wrapping function: {attr_name} in module: {module.__name__} {inspect.getsourcefile(attr)}"
  138.                     )
  139.                     continue
  140.                 setattr(module, attr_name, log_function_call(attr))
  141.             elif inspect.isclass(attr):
  142.                 self._wrap_class_methods(attr)
  143.  
  144.     def _wrap_class_methods(self, cls):
  145.         full_name = f"{cls.__module__}.{cls.__qualname__}"
  146.         if full_name in wrapped_classes:
  147.             return
  148.         wrapped_classes.add(full_name)
  149.  
  150.         for attr_name, attr_value in cls.__dict__.items():
  151.             if attr_name.startswith('_'):
  152.                 continue
  153.             if inspect.isfunction(attr_value) or inspect.ismethod(attr_value):
  154.                 if 'test.py' in inspect.getsourcefile(attr_value):
  155.                     print(
  156.                         f"Wrapping function: {attr_name} in module: {cls.__name__} {inspect.getsourcefile(attr_value)}"
  157.                     )
  158.  
  159.                     continue
  160.                 setattr(cls, attr_name, log_function_call(attr_value))
  161.  
  162. class HookFinder(importlib.abc.MetaPathFinder):
  163.     def __init__(self, package_name):
  164.         self.package_name = package_name
  165.         self._processing = False
  166.  
  167.     def find_spec(self, fullname, path=None, target=None):
  168.         if not fullname.startswith(self.package_name):
  169.             return None
  170.         if self._processing:
  171.             return None
  172.         if 'ccxt.static_dependencies' in fullname:
  173.             return None
  174.         try:
  175.             self._processing = True
  176.             spec = ORIGINAL_FIND_SPEC(fullname)
  177.         finally:
  178.             self._processing = False
  179.         if spec and spec.loader:
  180.             spec.loader = HookLoader(spec.loader)
  181.         return spec
  182.  
  183. def install_hook(package_name):
  184.     sys.meta_path.insert(0, HookFinder(package_name))
  185.  
  186. def print_aggregated_call_info():
  187.     print("\n[Function/Method Call Summary]")
  188.     for func_name, info in function_call_info.items():
  189.         print(f"{func_name} => calls: {info['count']}, total time: {info['total_time']:.6f} s")
  190.  
  191. atexit.register(print_aggregated_call_info)
  192.  
  193. install_hook("ccxt")
  194.  
  195. import ccxt
  196.  
  197.  
  198. if __name__ == '__main__':
  199.     exchange = ccxt.binance()
  200.     ticker = exchange.fetch_ticker('BTC/USDT')
  201.     print(ticker)
  202.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement