Goal
My program takes a yaml config file as parameter python myprogram.py cfg.yml.
- all modules can access the cfg content with a simple module import
- the imported configbehaves like the loaded top-level yaml dictionary for reading operations
# module_a.py
from config_module import cfg_class as config
print(config['pi'])
Reasoning
I wanted to follow the official python FAQ to share config global variables across modules but I could only define the parameters in a pre-defined file that cannot be changed by the user:
# config_module.py
pi = 3.14
To let the user choose a yaml config file, I changed config.py to:
# config_module.py
class cfg_class:
    pass
and the very top of myprogram.py to
# myprogram.py
from config_module import cfg_class as config
import yaml
if __name__=='__main__':
    with open(sys.argv[1], 'r') as f:
        cfg_dict = yaml.safe_load(f)
    config.cfg_dict = cfg_dict
As a result all modules have access to the config content
# module_a.py
from config_module import cfg_class as config
print(config.cfg_dict['pi'])
Instead of using config.cfg_dict['pi'] I wanted to use config['pi']. To do that I defined the __getitem__ for the cfg_class:
class cfg_class:
    def __getitem__(self, x):
        return self.cfg_dict[x]
It failed with TypeError: 'type' object is not subscriptable. An explanation to this problem is given here. It indicates that we need a metaclass for cfg_class:
# config.py
class Meta(type):
    def __getitem__(self, x):
        return cfg_class.cfg_dict[x]
class cfg_class(metaclass=Meta):
    pass
And now it works. Below is the code for
config_module.py
myprogram.py
module_a.py
module_b.py
cfg.yml
Any feedback?
Working code
# config_module.py
class Meta(type):
    def __getitem__(self, x):
        return cfg_class.cfg_dict[x]
class cfg_class(metaclass=Meta):
    pass
# myprogram.py
import sys
import yaml
from config_module import cfg_class as config
import module_a
import module_b
if __name__=='__main__':
    with open(sys.argv[1], 'r') as f:
        cfg_dict = yaml.safe_load(f)
    config.cfg_dict = cfg_dict
    module_a.a_class_from_module_a()
    module_b.a_class_from_module_b()
# module_a.py
from config_module import cfg_class as config
class a_class_from_module_a:
    def __init__(self):
        print(
            'I am an instance of a_class_from_module_a'
            ' and I have access to config: ',
            config['pi']
        )
# module_b.py
from config_module import cfg_class as config
class a_class_from_module_b:
    def __init__(self):
        print(
            'I am an instance of a_class_from_module_b'
            ' and I have access to config: ',
            config['pi']
        )
# cfg.yml
---
pi: 3.14
...
Result:
$ python myprogram.py cfg.yml
>> I am an instance of a_class_from_module_a and I have access to config:  3.14
>> I am an instance of a_class_from_module_b and I have access to config:  3.14
Edit: simpler solution thanks to @MiguelAlorda who almost got it all right and @RootTwo who fixed the problem
# config_module.py
import yaml
config = {}
def load_config(file_str: str) -> None:
    global config
    with open(file_str) as f:
        # config = yaml.safe_load(f) # does not work because it unbinds config, see comment from @RootTwo
        config.update(yaml.safe_load(f))
# myprogram.py
import sys
import config_module
import module_a
import module_b
if __name__=='__main__':
    config_module.load_config(sys.argv[1])
    
    x = module_a.a_class_from_module_a()
    y = module_b.a_class_from_module_b()
    print(x,y)
# module_a.py
from config_module import config
class a_class_from_module_a:
    def __init__(self):
        print(
            'I am an instance of a_class_from_module_a'
            ' and I have access to config: ',
            config['pi']
        )
# module_b.py
from config_module import config
class a_class_from_module_b:
    def __init__(self):
        print(
            'I am an instance of a_class_from_module_b'
            ' and I have access to config: ',
            config['pi']
        )
#cfg.yml
---
pi: 3.14
...
Output:
$ python myprogram.py cfg.yml
I am an instance of a_class_from_module_a and I have access to config:  3.14
I am an instance of a_class_from_module_b and I have access to config:  3.14
<module_a.a_class_from_module_a object at 0x000002391D5F8F48> <module_b.a_class_from_module_b object at 0x000002391D5FB288>


