From 5726c6985fc8fc0746db111b3e3ee0279f8f13fb Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Tue, 10 Oct 2023 01:35:01 +0200 Subject: [PATCH] Added utility function to get the defining class of a method. --- platypush/utils/__init__.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/platypush/utils/__init__.py b/platypush/utils/__init__.py index 2bcd6ff87..29a8500b2 100644 --- a/platypush/utils/__init__.py +++ b/platypush/utils/__init__.py @@ -1,6 +1,7 @@ import ast import contextlib import datetime +import functools import hashlib import importlib import inspect @@ -705,4 +706,36 @@ def import_file(path: str, name: Optional[str] = None): return mod +def get_defining_class(meth) -> Optional[type]: + """ + See https://stackoverflow.com/a/25959545/622364. + + This is the best way I could find of answering the question "given a bound + method, get the class that defined it", + """ + if isinstance(meth, functools.partial): + return get_defining_class(meth.func) + + if inspect.ismethod(meth) or ( + inspect.isbuiltin(meth) + and getattr(meth, '__self__', None) is not None + and getattr(meth.__self__, '__class__', None) + ): + for cls in inspect.getmro(meth.__self__.__class__): + if meth.__name__ in cls.__dict__: + return cls + meth = getattr(meth, '__func__', meth) # fallback to __qualname__ parsing + + if inspect.isfunction(meth): + cls = getattr( + inspect.getmodule(meth), + meth.__qualname__.split('.', 1)[0].rsplit('.', 1)[0], + None, + ) + if isinstance(cls, type): + return cls + + return getattr(meth, '__objclass__', None) # handle special descriptor objects + + # vim:sw=4:ts=4:et: