Trying to robustly patch func.__globals__

Yes, that’s why I characterized my solution as a workaround and why I put the word “module” in quotes.

Regarding your good point about the missing subtle things that may be expected from ModuleType:

  1. __file__ does not come from ModuleType. It is set by a file-based loader, which the InspectLoader I used in my example is not. It would be set if you use a loader inherited from SourceFileLoader instead for example.
  2. Support for a user-defined __getattr__ (not __getitem__ by the way) can be easily implemented by overloading __getattr__ for our “module”.
  3. For code that explicitly checks if our “module” is a ModuleType, we can work around it by setting the __class__ attribute.

And here’s our updated “module” type to support points 2. and 3.:

class LoggingModule:
    __class__ = ModuleType

    def __init__(self):
        self.__dict__ = LoggingDict()

    def __getattr__(self, name):
        if __getattr__ := self.__dict__.get('__getattr__'):
            return __getattr__(name)
        raise AttributeError

Demo here, which shows that it correctly supports a user-defined __getattr__ and passes both of the following tests:

assert isinstance(foo, ModuleType)
assert inspect.ismodule(foo)