0

I have several 'app'-modules (which are being started by a main-application) and a utility module with some functionality:

my_utility/
    ├── __init__.py
    └── __main__.py
apps/
    ├── app1/
    │   ├── __init__.py
    │   └── __main__.py
    ├── app2/
    │   ├── __init__.py
    │   └── __main__.py
    ...
main_app.py

The apps are being started like this (by the main application):

python3 -m <app-name>

I need to provide some meta information (tied to the module) about each app which is readable by the main_app and the apps themselves:

apps/app1/__init__.py:

meta_info = {'min_platform_version': '1.0',
             'logger_name': 'mm1'}

... and use it like this:

apps/app1/__main__.py:

from my_utility import handle_meta_info
# does something with meta_info (checking, etc.)
handle_meta_info()

main_app.py:

mod = importlib.import_module('app1')
meta_inf = getattr(mod, 'meta_info')
do_something(meta_inf)

The Problem

I don't know how to access meta_info from within the apps. I know I can import the module itself and access meta_info:

apps/app1/__main__.py:

import app1
do_something(app1.meta_info)

But this is only possible if I know the name of the module. From inside another module - e.g. my_utility I don't know how to access the module which has been started in the first place (or it's name).

my_utility/__main__.py:

def handle_meta_info():
    import MAIN_MODULE        <-- don't know, what to import here
    do_something(MAIN_MODULE.meta_info)

In other words

I don't know how to access meta_info from within an app's process (being started via python3 -m <name> but from another module which does not know the name of the 'root' module which has been started

Approaches

  • Always provide the module name when calling meta-info-functions (bad, because it's verbose and redundant)

    from my_utility import handle_meta_info
    handle_meta_info('app1')
    
  • add meta_info to __builtins__ (generally bad to pollute global space)

  • Parse the command line (ugly)

  • Analyze the call stack on import my_utility (dangerous, ugly)

The solution I'd like to see

It would be nice to be able to either access the "main" modules global space OR know it's name (to import)

my_utility/__main__.py:

def handle_meta_info():
    do_something(__main_module__.meta_info)

OR

def handle_meta_info():
    if process_has_been_started_as_module():
        mod = importlib.import_module(name_of_main_module())
        meta_inf = getattr(mod, 'meta_info')
        do_something(meta_inf)

Any ideas?

My current (bloody) solution:

Inside my_utility I use psutil to get the command line the module has been started with (why not sys.argv? Because). There I extract the module name. This way I attach the desired meta information to my_utility (so I have to load it only once).

my_utility/__init__.py:

def __get_executed_modules_meta_info__() -> dict:
    def get_executed_module_name()
        from psutil import Process
        from os import getpid
        _cmdline = Process(getpid()).cmdline
        try:
            # normal case: app has been started via 'python3 -m <app>'
            return _cmdline[_cmdline.index('-m') + 1]
        except ValueError:
            return None
    from importlib import import_module
    try:
        _main_module = import_module(get_module_name())
        return import_module(get_executed_module_name()).meta_info
    except AttributeError:
        return {}

__executed_modules_meta_info__ = __get_executed_modules_meta_info__()
Community
  • 1
  • 1
frans
  • 8,868
  • 11
  • 58
  • 132
  • So `main_app.py` is using e.g. `subprocess` to run these other modules "from the command line"? Why? And presumably it must know their names to do so - are you really asking *"how can you import a module by name"*? In which case see e.g. http://stackoverflow.com/q/37808866/3001761 – jonrsharpe Nov 15 '16 at 10:01
  • I'm not asking how to import a module by name (I'm using `import_module` in my examples already) - `main_app.py` imports the modules just to access their `meta_info` attribute. What I don't know is how to access `meta_info` from within the app's process *but from another module which does not know the name of the 'root' module which has been started* – frans Nov 15 '16 at 10:24
  • So you want to access the `meta_info` from `app1/__init__.py` in `app1/__main__.py`? What's the *"main module"*? What *"other module"*? Better yet, could you give some more context about what you're really trying to achieve? – jonrsharpe Nov 15 '16 at 10:28
  • very close :). I want to access `meta_info` from `app1/__init__.py` but not *directly* from `app1/__main__.py` but from a function called inside `app1/__main__.py` which itself is located inside another module (`my_utility` in my example) – frans Nov 15 '16 at 10:35
  • Why not just make the `meta_info` an argument to that function, then? – jonrsharpe Nov 15 '16 at 10:35
  • because actually there are lots of functions/classes which want to access the "meta info about the module being executed" and I would have to provide it all the time. – frans Nov 15 '16 at 10:38
  • To what end? Again, could you give some more context? And if you have to pass it to several different things, so what? – jonrsharpe Nov 15 '16 at 10:42
  • The `my_utility` module is just an example. Actually I have a bunch of modules with lot's of classes which all have to access the meta info of the currently executed module. Theoretically I can implement dependency injection for all classes but that would not be very readable or reusable. – frans Nov 15 '16 at 11:25

0 Answers0