Skip to content

Instantly share code, notes, and snippets.

@mangecoeur
Created February 27, 2018 13:37
Show Gist options
  • Save mangecoeur/25a4658ea9a8d5dbe7dd5373f5537426 to your computer and use it in GitHub Desktop.
Save mangecoeur/25a4658ea9a8d5dbe7dd5373f5537426 to your computer and use it in GitHub Desktop.
Dummy config module for importing a master shared config file from a parent folder.
"""
Background
----------
One of the simplest configuration approaches in python is to just use python files,
giving you the full power of python - the least hassle approach in a trusted environment.
However, importing config modules can be problematic in interactive environments.
For example, when using jupyter notebooks organised into sub-folders,
we want to access a common config file in the overall project root.
However, when using the jupyter notebook, the current working directory
is the directory of the notebook and the parent project folder is ignored.
Attempting to import a module from the parent directory would raise the error
`attempted relative import beyond top-level package`.
Instead of copying the config file into every sub-folder and trying to
keep them all up to date, copy this module which will find the master
config file and import the variables from it.
Description
-----------
This is a dummy config module that loads the real config from the first file called
'config.py' found in the parent directories of the current directory. Searches
each parent folder in turn for a file of the right name, aborting when it
reaches to filesystem root.
All non-underscore-prefixed names will be imported from the found config file
into this module's global namespace.
Usage
-----
Place a copy of this in every folder where you need to be able to import the config directly,
when the parent folders are not part of your current working directory.
"""
# rename imports to hide from calling module
import os as _os
import sys as _sys
if _os.getcwd() not in _sys.path:
_sys.path.append(_os.getcwd())
def _search_for_config(config_name='config.py'):
to_scan = _os.path.abspath('..')
while True:
files = _os.scandir(to_scan)
conf_search = [f for f in files if f.name == config_name]
if len(conf_search) == 1:
conf_dat = conf_search[0]
return _os.path.abspath(conf_dat.path)
else:
# Check if we are in the file system root by checking if trying to going up one level
# doesn't change the current path
new_path = _os.path.abspath(_os.path.join(to_scan, '..'))
if new_path == to_scan:
raise RuntimeError(f'No file "{config_name}" found in the parent folders of this folder.'
' Config could not be loaded.')
else:
to_scan = new_path
def _load_config_to_current_module():
import runpy
conf_path = _search_for_config()
config = runpy.run_path(conf_path)
for name, value in config.items():
if not name.startswith('_'):
globals()[name] = value
_load_config_to_current_module()
@Moondra
Copy link

Moondra commented Apr 15, 2019

I don't quite understand why you are renaming os to _os.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment