"""
Utilities for path handling
Provides server-specific paths, configured in a server configuration file.
"""
import sys
import os
import yaml
SHAREDDIR_SHELLVAR = "IMPERICS_SHAREDDIR"
default_server_config_path = "../server.yml"
shareddir_key = "shareddir"
server_config = None # filled in upon first call to sharedpath
# Path-handling functions
[docs]
def sharedpath(subpath):
"""Return a subpath of the configured shareddir
``shareddir`` is path to the root directory containing the support/data
files needed to run impact projections. ``shareddir`` is found first by
looking for the ``IMPERICS_SHAREDDIR`` shell/environment variable. If
this is not defined, it looks for a "shareddir" entry in a "../server.yml"
file.
Parameters
----------
subpath : str
Subdirectory path joined onto ``shareddir``.
"""
if server_config is None:
default_path = os.environ.get(SHAREDDIR_SHELLVAR)
if default_path is None:
# No shell (environment) variable set. Old behavior.
default_path = str(default_server_config_path)
msg = f"Cannot find configuration file at {default_path}"
assert os.path.exists(default_path), msg
server_config_dict = get_file_config(default_path)
else:
# Use shell (environment) variable to get "shareddir".
server_config_dict = {shareddir_key: str(default_path)}
use_config(server_config_dict)
return os.path.join(server_config[shareddir_key], subpath)
[docs]
def configpath(path):
"""Return an configured absolute path. If the path is absolute, it
will be left alone; otherwise, it is assumed to be a subpath of the
configured `shareddir`."""
if path[:2] == './':
return path[2:]
if path[0] == '/':
return path
return sharedpath(path)
# Configuration-file handling functions
[docs]
def use_config(config):
"""Use the given configuration for path functions."""
global server_config
# Add values from server_config only if not in config
if server_config is not None:
for key in server_config:
if key not in config:
config[key] = server_config[key]
server_config = config
[docs]
def get_file_config(filepath):
"""Load a configuration file from a given path."""
with open(filepath) as fp:
config = yaml.load(fp, Loader=yaml.FullLoader)
return config
[docs]
def get_argv_config(index=1):
"""
Load a configuration file specified as the `index` argv argument.
In the future, this should also load specific configurable options from the
command-line.
"""
with open(sys.argv[index]) as fp:
config = yaml.load(fp, Loader=yaml.FullLoader)
return config
[docs]
def get_allargv_config():
"""
Load a configuration from the command line, merging all arguments into a
single configuration dictionary.
Handles the following kinds of command-line arguments:
- `*.yml`: a full configuration YaML file, merged into the result dictionary
- `--config=VALUE`: a full configuration YaML file, as above
- `--KEY=VALUE`: a single configuration value to be set
- anything else: sets an entry in the config file for that anything to
have a value of True.
Later command-line arguments always overide earlier ones.
"""
config = {}
for arg in sys.argv:
if arg[-4:] == '.yml':
config.update(get_file_config(arg))
continue
# Add --key=value arguments one at a time
if arg[0:2] == '--':
if '=' in arg:
chunks = arg[2:].split('=')
if chunks[0] == 'config':
config = get_file_config(chunks[1])
else:
config[chunks[0]] = yaml.safe_load(chunks[1])
else:
config[arg[2:]] = True
continue
config[arg] = True
return config
if __name__ == '__main__':
print(configpath('testing'))