Convert module to dict
Asked Answered
L

6

9

I would like to do the following (python3):

In module settings.py:

message = 'Hello'

In module __main__.py:

from . import settings


def dict_from_module(module):
    ...
    return d

print(dict_from_module(settings))

Running this should produce:

{'message': 'hello'}

Is there a canonical way of converting a module to a dictionary?

EDIT

Using vars(settings) gives lots of internal information:

{   
    '__builtins__': {
        ...
    },
    '__cached__': 'xxx/__pycache__/settings.cpython-34.pyc',
    '__doc__': None,
    '__file__': 'xxx/settings.py',
    '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f87fc192518>,
    '__name__': 'xxx.settings',
    '__package__': 'xxx',
    '__spec__': ModuleSpec(...),
    'message': 'bye'
}

Which I do not want / need. I can filter that out (by removing keys starting with __), but I would like to avoid hacking around if there is an accepted way of doing this.

Leffert answered 24/2, 2016 at 9:44 Comment(2)
@vaultah: thanks, but that gives lots of internal attributes, which I do not want / needLeffert
I don't think there's a solution that doesn't include filtering out the predefined values in some way or another. Plus you need to resolve borderline cases, like what to do when module declares a variable __doc__.Timbre
N
10

Hope this helps!

def dict_from_module(module):
    context = {}
    for setting in dir(module):
        # you can write your filter here
        if setting.islower() and setting.isalpha():
            context[setting] = getattr(module, setting)

    return context
Nystatin answered 17/9, 2017 at 11:40 Comment(1)
My way: module_to_dict = lambda module: {k: getattr(module, k) for k in dir(module) if not k.startswith('_')}Adoration
A
3

Anothoer option is to use __all__ with module you with to convert to dict. For example, my exported module is

# mylib.py

__all__ = ['square']

def square(x):
    return x ** 2

And you can easily convert this module to dict like this:

def module_to_dict(module):
    return {key: getattr(module, key) for key in module.__all__}

Giving the following output:

>>> import mylib
>>> module_to_dict(mylib)
{'square': <function square at 0x03C39B28>}
Ashla answered 3/7, 2019 at 16:16 Comment(0)
C
1

I'm using a python file as a config file where I have constants and computable properties. And to interface with some web service I need it to be serializable (eg like a dictionary). Based on @heykarimoff 's solution, I used startswith("_") and isinstance(v, ModuleType): to filter out imported modules so that they won't show up in the dictionary.

def dict_from_module(module):
    context = {}
    for setting in dir(module):
        if not setting.startswith("_"):
            v = getattr(module, setting)
            if not isinstance(v, ModuleType):
                context[setting] = getattr(module, setting)
    return context
Calypso answered 14/12, 2020 at 2:41 Comment(0)
E
1
import inspect
from itertools import takewhile

import .settings

dict(takewhile(lambda i: i[0] != '__builtins__', inspect.getmembers(settings)))
Erda answered 24/8, 2021 at 0:29 Comment(0)
S
0

This is improved @heykarimoff answer, that I personally use.

# firstly I make a class attribute dict
class Ad(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__dict__ = self

# and now I make this function:
def m2d(module):
    return Ad({val: getattr(module, val) for val in dir(module) if '__' not in val})

import myModule

myDict = m2d(myModule) #our dictionary

As a result i receive a dictionary that acts like a module. In opposite to a module though you can pass it easily to functions avoiding "Can't pickle module objects" error. Hope it helps!

Sachet answered 15/1, 2023 at 6:34 Comment(0)
V
0

if settings.py content variable only:

settings.py:

   var1 = 'val1'
   var2 = 2

main.py:

from pprint import pprint
import settings
v={var:vars(settings)[var] for var in dir(settings) if not var.startswith('_')}
pprint(v)
{'var1': 'val1',
 'var2': 2}
Valorize answered 21/1, 2023 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.