diff --git a/dwave/cloud/config.py b/dwave/cloud/config.py index 9067215f..87971a4d 100644 --- a/dwave/cloud/config.py +++ b/dwave/cloud/config.py @@ -462,6 +462,7 @@ def load_config_from_files(filenames=None): config = configparser.ConfigParser(default_section="defaults") for filename in filenames: try: + filename = os.path.expandvars(os.path.expanduser(filename)) with open(filename, 'r') as f: config.read_file(f, filename) except (IOError, OSError): diff --git a/tests/test_config.py b/tests/test_config.py index 44ad05d8..ed150ae4 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -27,7 +27,7 @@ class TestConfig(unittest.TestCase): - config_body = u""" + config_body = """ [defaults] endpoint = https://cloud.dwavesys.com/sapi client = qpu @@ -72,7 +72,7 @@ def setUp(self): def test_config_load_from_file__invalid_format__duplicate_sections(self): """Config loading should fail with ``ConfigFileParseError`` for invalid config files.""" - myconfig = u""" + myconfig = """ [section] key = val [section] @@ -122,6 +122,34 @@ def test_config_file_detection_nonexisting(self): with mock.patch("os.path.exists", lambda path: False): self.assertEqual(get_configfile_paths(), []) + def test_config_file_path_expansion(self): + """Home dir and env vars are expanded when resolving config path.""" + + env = {"var": "val"} + config_file = "~/path/${var}/to/$var/my.conf" + expected_path = os.path.expanduser("~/path/val/to/val/my.conf") + profile = "profile" + + conf_content = """ + [{}] + valid = yes + """.format(profile) + + def mock_open(filename, *pa, **kw): + self.assertEqual(filename, expected_path) + return iterable_mock_open(conf_content)() + + # config file via kwarg + with mock.patch.dict(os.environ, env): + with mock.patch('dwave.cloud.config.open', mock_open) as m: + conf = load_config(config_file=config_file, profile=profile) + self.assertEqual(conf['valid'], 'yes') + + # config file via env var + with mock.patch.dict(os.environ, env, DWAVE_CONFIG_FILE=config_file): + with mock.patch('dwave.cloud.config.open', mock_open) as m: + conf = load_config(profile=profile) + self.assertEqual(conf['valid'], 'yes') def _assert_config_valid(self, config): # profile 'alpha' is loaded @@ -238,7 +266,7 @@ def test_config_load__profile_first_section(self): """load_config should load the first section for profile, if profile is nowhere else specified. """ - myconfig = u""" + myconfig = """ [first] solver = DW_2000Q_1 """ @@ -254,7 +282,7 @@ def test_config_load__profile_from_defaults(self): is nowhere else specified *and* not even a single non-[defaults] section exists. """ - myconfig = u""" + myconfig = """ [defaults] solver = DW_2000Q_1 """ @@ -269,7 +297,7 @@ def test_config_load_configfile_arg_profile_default_nonexisting(self): """load_config should fail if the profile specified in the defaults section is non-existing. """ - myconfig = u""" + myconfig = """ [defaults] profile = nonexisting @@ -285,12 +313,12 @@ def test_config_load_multiple_autodetected_configfiles(self): """Test more specific config overrides less specific one, on a key by key basis, in a list of auto-detected config files.""" - config_system = u""" + config_system = """ [alpha] endpoint = alpha solver = DW_2000Q_1 """ - config_user = u""" + config_user = """ [alpha] solver = DW_2000Q_2 [beta] @@ -302,16 +330,16 @@ def test_config_load_multiple_autodetected_configfiles(self): # test per-key override with mock.patch('dwave.cloud.config.open', create=True) as m: - m.side_effect=[iterable_mock_open(config_system)(), - iterable_mock_open(config_user)()] + m.side_effect = [iterable_mock_open(config_system)(), + iterable_mock_open(config_user)()] section = load_config(profile='alpha') self.assertEqual(section['endpoint'], 'alpha') self.assertEqual(section['solver'], 'DW_2000Q_2') # test per-section override (section addition) with mock.patch('dwave.cloud.config.open', create=True) as m: - m.side_effect=[iterable_mock_open(config_system)(), - iterable_mock_open(config_user)()] + m.side_effect = [iterable_mock_open(config_system)(), + iterable_mock_open(config_user)()] section = load_config(profile='beta') self.assertEqual(section['endpoint'], 'beta') @@ -319,12 +347,12 @@ def test_config_load_multiple_explicit_configfiles(self): """Test more specific config overrides less specific one, on a key by key basis, in a list of explicitly given files.""" - file1 = u""" + file1 = """ [alpha] endpoint = alpha solver = DW_2000Q_1 """ - file2 = u""" + file2 = """ [alpha] solver = DW_2000Q_2 """ @@ -339,7 +367,7 @@ def test_config_load_multiple_explicit_configfiles(self): def test_config_load_env_override(self): with mock.patch("dwave.cloud.config.load_config_from_files", - partial(self._load_config_from_files, data=u"", provided=['myfile'])): + partial(self._load_config_from_files, data="", provided=['myfile'])): with mock.patch.dict(os.environ, {'DWAVE_API_CLIENT': 'test'}): self.assertEqual(load_config(config_file='myfile')['client'], 'test')