Alex G.P.
Alex G.P.

Reputation: 10028

Python import lib analogue to "import * from XXX"

I have following structure of configuration files:

app
  \config
     \development
        \__init__.py
        \settings.py
        \app_config.py
     \production
        \__init__.py
        \settings.py
        \app_config.py
     \testingpy
        \settings.py
        \app_config.py
     \settinngs.py
     \app_config.py

Actually app.config.settings just check environment variable RUNTIME_ENV (which could be development|production|testing, equivalent to one of config's subfolders) and load corresponding settings.

I know only about importing with importlib which return to me module as local variable and I forced to write something like that:

SCALA_URL = imported_settings.SCALA_URL
REDIS_URL = imported_settings.REDIS_URL
SOME_SETTINGS_VAR = imported_settings.REDIS_URL
.... tons of duplicated strings here, i.e. variables names are the same ...

Is there way to do something similar to python's expression: from config.${RUNTIME_ENV}.settings import *?

Upvotes: 2

Views: 391

Answers (1)

Kevin
Kevin

Reputation: 30181

The return value of globals() is mutable. You could do something like this:

imported_foo = importlib.import_module('foo')
globals().update(vars(imported_foo))

Note that this imports underscore-prefixed things into the global namespace. If you want to exclude those, write a dictionary comprehension that only includes the things you want. For example:

globals().update({name: value 
                  for name, value in vars(imported_foo).items()
                  if not name.startswith('_')})

This does not work with locals(), which returns a read-only value. It is not reasonably possible to do that (import * into a non-global namespace), because Python has to know the names of all local variables at compile time in order to generate the correct LOAD_FOO instructions in the bytecode (along with a variety of other interesting problems such as identifying the variables captured by a closure). You will find that import * is illegal inside a function or class:

>>> def foo():
...     from foo import *
... 
  File "<stdin>", line 1
SyntaxError: import * only allowed at module level
>>> 

That's not just a matter of "import * is bad design." It's a fundamental language limitation and can't be worked around with importlib.

Upvotes: 2

Related Questions