From 589bc0b5f12f65358dcde01379ebbbb2ea39bec7 Mon Sep 17 00:00:00 2001
From: Athanasius <github@miggy.org>
Date: Tue, 28 Jul 2020 08:51:18 +0100
Subject: [PATCH] Cover all cases with `inspect`

* <module> works.
* top-level function in <module> works, presumably also any other file.
* Call from within classes works.
* Extra, commented out, test cases in EDMarketConnector.py
---
 EDMCLogging.py       | 37 +++++++++++++++----------------------
 EDMarketConnector.py | 13 +++++++++----
 2 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/EDMCLogging.py b/EDMCLogging.py
index 00cf504d..a8fb45df 100644
--- a/EDMCLogging.py
+++ b/EDMCLogging.py
@@ -152,32 +152,25 @@ class EDMCContextFilter(logging.Filter):
             args, _, _, value_dict = inspect.getargvalues(frame)
             if len(args) and args[0] == 'self':
                 frame_class = value_dict['self']
-                # Find __qualname__ of the caller
-                fn = getattr(frame_class, frame_info.function)
 
-                if fn and fn.__qualname__:
-                    caller_qualname = fn.__qualname__
+                if frame_class:
+                    # Find __qualname__ of the caller
+                    fn = getattr(frame_class, frame_info.function)
+                    if fn and fn.__qualname__:
+                        caller_qualname = fn.__qualname__
 
-                # Find containing class name(s) of caller, if any
-                if frame_class and frame_class.__qualname__:
-                    caller_class_names = frame_class.__qualname__
+                    # Find containing class name(s) of caller, if any
+                    if frame_class.__class__ and frame_class.__class__.__qualname__:
+                        caller_class_names = frame_class.__class__.__qualname__
 
-            # If the frame caller is a bare function then there's no 'self'
-            elif frame.f_code.co_name and frame.f_code.co_name in frame.f_globals:
-                fn = frame.f_globals[frame.f_code.co_name]
-                if fn and fn.__qualname__:
-                    caller_qualname = fn.__qualname__
+            # It's a call from the top level module file
+            elif frame_info.function == '<module>':
+                caller_class_names = '<none>'
+                caller_qualname = value_dict['__name__']
 
-                frame_class = getattr(fn, '__class__', None)
-                if frame_class and frame_class.__qualname__:
-                    caller_class_names = frame_class.__qualname__
-
-                    # 'class' __qualname__ of 'function' means it's a bare
-                    # function for sure.  You *can* have a class called
-                    # 'function', so let's make this 100% obvious what it is.
-                    if caller_class_names == 'function':
-                        # In case the condition above tests a tuple of values
-                        caller_class_names = f'<{caller_class_names}>'
+            elif frame_info.function != '':
+                caller_class_names = '<none>'
+                caller_qualname = frame_info.function
 
             # https://docs.python.org/3.7/library/inspect.html#the-interpreter-stack
             del frame
diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index 9bf7496d..d953e819 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -1014,6 +1014,9 @@ def enforce_single_instance() -> None:
         EnumWindows(enumwindowsproc, 0)
 
 
+def test_logging():
+    logger.debug('Test from EDMarketConnector.py top-level test_logging()')
+
 # Run the app
 if __name__ == "__main__":
 
@@ -1026,10 +1029,9 @@ if __name__ == "__main__":
 
     logger = EDMCLogging.Logger(appname).get_logger()
 
-    # Plain, not via `logger`
-    print(f'{applongname} {appversion}')
-
-    # TODO: unittest in place of this
+    # TODO: unittests in place of these
+    # logger.debug('Test from __main__')
+    # test_logging()
     class A(object):
         class B(object):
             def __init__(self):
@@ -1037,6 +1039,9 @@ if __name__ == "__main__":
 
     # abinit = A.B()
 
+    # Plain, not via `logger`
+    print(f'{applongname} {appversion}')
+
     Translations.install(config.get('language') or None)  # Can generate errors so wait til log set up
 
     root = tk.Tk(className=appname.lower())