Repository: dwavesystems/dwave-cloud-client
Pull request #145 (2018-04-27 00:20:20)

Support explicit list of config files in Client.from_config
Closes  #135.


Patch:
diff --git a/dwave/cloud/client.py b/dwave/cloud/client.py
index 13c4ce5..d488d3c 100644
--- a/dwave/cloud/client.py
+++ b/dwave/cloud/client.py
@@ -127,7 +127,7 @@ class Client(object):
             see :func:`~dwave.cloud.config.load_config`.
 
         Args:
-            config_file (str/None/False/True, default=None):
+            config_file (str/[str]/None/False/True, default=None):
                 Path to config file. ``None`` for auto-detect, ``False`` to
                 skip loading from any file (including auto-detection), and
                 ``True`` to force auto-detection, disregarding environment value
diff --git a/dwave/cloud/config.py b/dwave/cloud/config.py
index 70d1d6b..fcb5104 100644
--- a/dwave/cloud/config.py
+++ b/dwave/cloud/config.py
@@ -17,6 +17,7 @@ import os
 import configparser
 from collections import OrderedDict
 
+import six
 import homebase
 
 from dwave.cloud.utils import uniform_get
@@ -466,7 +467,7 @@ def load_config(config_file=None, profile=None, client=None,
 
     Args:
 
-        config_file (str/None/False/True, default=None):
+        config_file (str/[str]/None/False/True, default=None):
             Path to configuration file.
 
             If ``None``, the value is taken from ``DWAVE_CONFIG_FILE`` environment
@@ -599,8 +600,16 @@ def load_config(config_file=None, profile=None, client=None,
         if config_file is None:
             # note: both empty and undefined DWAVE_CONFIG_FILE treated as None
             config_file = os.getenv("DWAVE_CONFIG_FILE")
-        section = load_profile_from_files(
-            [config_file] if config_file else None, profile)
+
+        # handle ''/None/str/[str] for `config_file` (after env)
+        filenames = None
+        if config_file:
+            if isinstance(config_file, six.string_types):
+                filenames = [config_file]
+            else:
+                filenames = config_file
+
+        section = load_profile_from_files(filenames, profile)
 
     # override a selected subset of values via env or kwargs,
     # pass-through the rest unmodified


Test patch:
diff --git a/tests/test_config.py b/tests/test_config.py
index 11d26ff..1b1c8ee 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -265,9 +265,9 @@ class TestConfig(unittest.TestCase):
                                 provided=['myfile'], data=myconfig)):
             self.assertRaises(ValueError, load_config, config_file='myfile')
 
-    def test_config_load_multiple_configfiles(self):
+    def test_config_load_multiple_autodetected_configfiles(self):
         """Test more specific config overrides less specific one,
-        on a key by key basis."""
+        on a key by key basis, in a list of auto-detected config files."""
 
         config_system = u"""
             [alpha]
@@ -298,3 +298,25 @@ class TestConfig(unittest.TestCase):
                                iterable_mock_open(config_user)()]
                 section = load_config(profile='beta')
                 self.assertEqual(section['endpoint'], 'beta')
+
+    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"""
+            [alpha]
+            endpoint = alpha
+            solver = DW_2000Q_1
+        """
+        file2 = u"""
+            [alpha]
+            solver = DW_2000Q_2
+        """
+
+        with mock.patch('dwave.cloud.config.open', create=True) as m:
+            m.side_effect=[iterable_mock_open(file1)(),
+                           iterable_mock_open(file2)()]
+            section = load_config(config_file=['file1', 'file2'], profile='alpha')
+            m.assert_has_calls([mock.call('file1', 'r'), mock.call('file2', 'r')])
+            self.assertEqual(section['endpoint'], 'alpha')
+            self.assertEqual(section['solver'], 'DW_2000Q_2')