I've created a 'Django style' settings files for different environments. The settings files define some variables, and also serves as dependency injection for other modules.
So the structure is:
settings/
___init__.py
base.py
dev.py
dev2.py
prod.py
service/
__init__.py
service.py
service_mock.py
And in settings/__init__.py I write:
settings_env = os.environ.get('PROJECT_SETTINGS', '')
if settings_env == 'prod':
from .prod import *
elif settings_env == 'dev':
from .dev import *
Each settings file define different some variables, and also import a class from service.py or service_mock.py, depends on the environment variable.
This works mostly fine.
Now, the problem is that the service.py cannot import the settings package, because the settings files import the service.py, so that will become a circular import.
As I see in Django it is solved by using import strings in the settings files, instead of actual imports. I don't really like the idea as I lose some of the IDE autocomplete features, also I'm not sure how to actually create the settings object that Django provides.
What are the solutions to this problem? Having a settings file that serves as a dependency injection container that imports modules, and get imported by the same modules? Preferably a simple solution.
A very common, and certainly easiest solution to circular imports, is to defer imports until you actually need them. For example, change
import settings
def func():
settings.things
to
def func():
import settings
settings.things
If you absolutely must have module-global imports, there are various tricks you could use, such as
settings = None
def import_stuff():
global settings
import settings as s
settings = s
or have a class
class Settings():
mod = None
def __getattr__(self, attr):
if self.mod is None:
import settings
self.mod = settings
return getattr(self.mod, attr)
settings = Settings()
(or generalise for any module name)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With