def test_config_load_multiple_configfiles(self): """Test more specific config overrides less specific one, on a key by key basis.""" config_system = u""" [alpha] endpoint = alpha solver = DW_2000Q_1 """ config_user = u""" [alpha] solver = DW_2000Q_2 [beta] endpoint = beta """ with mock.patch("dwave.cloud.config.get_configfile_paths", lambda: ['config_system', 'config_user']): # 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)()] 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)()] section = load_config(profile='beta') self.assertEqual(section['endpoint'], 'beta')
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 test_config_load_configfile_env_profile_env_key_arg(self): """Explicitly provided values should override env/file.""" with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=['myfile'])): with mock.patch.dict(os.environ, {'DWAVE_CONFIG_FILE': 'myfile', 'DWAVE_PROFILE': 'alpha'}): self.assertEqual(load_config(endpoint='manual')['endpoint'], 'manual') self.assertEqual(load_config(token='manual')['token'], 'manual') self.assertEqual(load_config(client='manual')['client'], 'manual') self.assertEqual(load_config(solver='manual')['solver'], 'manual') self.assertEqual(load_config(proxy='manual')['proxy'], 'manual')
def test_config_load_skip_configfiles(self): with mock.patch("dwave.cloud.config.load_config_from_files", self._load_config_from_files): # don't load from file, use arg or env self.assertEqual(load_config(config_file=False)['endpoint'], None) with mock.patch.dict(os.environ, {'DWAVE_API_ENDPOINT': 'test'}): self.assertEqual(load_config(config_file=False)['endpoint'], 'test') # specifying a profile doesn't affect outcome self.assertEqual(load_config(config_file=False, profile='alpha')['endpoint'], None) with mock.patch.dict(os.environ, {'DWAVE_API_ENDPOINT': 'test'}): self.assertEqual(load_config(config_file=False, profile='alpha')['endpoint'], 'test') with mock.patch.dict(os.environ, {'DWAVE_PROFILE': 'profile'}): self.assertEqual(load_config(config_file=False, endpoint='test')['endpoint'], 'test')
def test_config_load_configfile_env(self): with mock.patch( "dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=['myfile'])): with mock.patch.dict(os.environ, {'DWAVE_CONFIG_FILE': 'myfile'}): self._assert_config_valid( load_config(config_file=None, profile='alpha'))
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 = """ [alpha] endpoint = alpha solver = DW_2000Q_1 """ file2 = """ [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')
def test_config_load_configfile_arg_profile_default(self): """Check the right profile is loaded when `profile` specified only in [defaults] section. """ with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=['myfile'])): profile = load_config(config_file='myfile') self.assertEqual(profile['solver'], 'c4-sw_sample')
def test_config_load_force_autodetection(self): with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=None)): # load from file self._assert_config_valid(load_config(config_file=True, profile='alpha')) # load from file, even when config_file overridden in env (to path) with mock.patch.dict(os.environ, {'DWAVE_CONFIG_FILE': 'nonexisting'}): self._assert_config_valid(load_config(config_file=True, profile='alpha')) with mock.patch.dict(os.environ, {'DWAVE_PROFILE': 'alpha'}): self._assert_config_valid(load_config(config_file=True)) # load from file, even when config_file overridden in env (to None) with mock.patch.dict(os.environ, {'DWAVE_CONFIG_FILE': ''}): self._assert_config_valid(load_config(config_file=True, profile='alpha')) with mock.patch.dict(os.environ, {'DWAVE_PROFILE': 'alpha'}): self._assert_config_valid(load_config(config_file=True))
def test_config_load_configfile_env_profile_env(self): with mock.patch( "dwave.cloud.config.load_config_from_file", partial(self._load_config_from_file, provided='myfile')): with mock.patch.dict(os.environ, { 'DWAVE_CONFIG_FILE': 'myfile', 'DWAVE_PROFILE': 'alpha' }): self._assert_config_valid(load_config())
def test_config_load_env_override(self): with mock.patch( "dwave.cloud.config.load_config_from_files", 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') with mock.patch.dict(os.environ, {'DWAVE_API_ENDPOINT': 'test'}): self.assertEqual( load_config(config_file='myfile')['endpoint'], 'test') with mock.patch.dict(os.environ, {'DWAVE_API_TOKEN': 'test'}): self.assertEqual( load_config(config_file='myfile')['token'], 'test') with mock.patch.dict(os.environ, {'DWAVE_API_SOLVER': 'test'}): self.assertEqual( load_config(config_file='myfile')['solver'], 'test') with mock.patch.dict(os.environ, {'DWAVE_API_PROXY': 'test'}): self.assertEqual( load_config(config_file='myfile')['proxy'], 'test') with mock.patch.dict(os.environ, {'DWAVE_API_HEADERS': 'test'}): self.assertEqual( load_config(config_file='myfile')['headers'], 'test')
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""" [first] solver = DW_2000Q_1 """ with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=None, data=myconfig)): profile = load_config() self.assertIn('solver', profile) self.assertEqual(profile['solver'], 'DW_2000Q_1')
def test_update(self, name, extra_opts, inputs): config_file = 'dwave.conf' profile = 'profile' runner = CliRunner(mix_stderr=False) with runner.isolated_filesystem(): # create config config_body = '\n'.join(f"{k} = old-{v}" for k, v in inputs.items()) with open(config_file, 'w') as fp: fp.write(f"[{profile}]\n{config_body}") # verify config before update with isolated_environ(remove_dwave=True): config = load_config(config_file=config_file) for var, val in inputs.items(): self.assertEqual(config.get(var), f"old-{val}") # update config result = runner.invoke(cli, [ 'config', 'create', '-f', config_file, '-p', profile, ] + extra_opts, input='\n'.join('' if v is None else v for v in inputs.values())) self.assertEqual(result.exit_code, 0) # verify config updated with isolated_environ(remove_dwave=True): config = load_config(config_file=config_file) for var, val in inputs.items(): self.assertEqual(config.get(var), val)
def test_config_load__profile_from_defaults(self): """load_config should promote [defaults] section to profile, if profile is nowhere else specified *and* not even a single non-[defaults] section exists. """ myconfig = u""" [defaults] solver = DW_2000Q_1 """ with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=None, data=myconfig)): profile = load_config() self.assertIn('solver', profile) self.assertEqual(profile['solver'], 'DW_2000Q_1')
def test_configure(self): config_file = 'dwave.conf' profile = 'profile' values = 'endpoint token client solver proxy'.split() with mock.patch("six.moves.input", side_effect=values, create=True): runner = CliRunner() with runner.isolated_filesystem(): touch(config_file) result = runner.invoke(cli, [ 'configure', '--config-file', config_file, '--profile', profile ], input='\n'.join(values)) self.assertEqual(result.exit_code, 0) config = load_config(config_file, profile=profile) for val in values: self.assertEqual(config.get(val), val)
def test_default_flows(self, name, extra_opts, inputs): runner = CliRunner(mix_stderr=False) with runner.isolated_filesystem(): with mock.patch("dwave.cloud.config.get_configfile_paths", lambda: ['dwave.conf']): with mock.patch("dwave.cloud.utils.input", side_effect=inputs): result = runner.invoke( cli, ['config', 'create'] + extra_opts, input='\n'.join('' if v is None else v for v in inputs.values())) self.assertEqual(result.exit_code, 0) # load and verify config with isolated_environ(remove_dwave=True): config = load_config() for var, val in inputs.items(): if val: # skip empty default confirmations self.assertEqual(config.get(var), val)
def test_create(self, name, extra_opts, inputs): config_file = 'path/to/dwave.conf' profile = 'profile' runner = CliRunner(mix_stderr=False) with runner.isolated_filesystem(): result = runner.invoke(cli, [ 'config', 'create', '--config-file', config_file, '--profile', profile ] + extra_opts, input='\n'.join('' if v is None else v for v in inputs.values())) self.assertEqual(result.exit_code, 0) # load and verify config with isolated_environ(remove_dwave=True): config = load_config(config_file, profile=profile) for var, val in inputs.items(): self.assertEqual(config.get(var), val)
def test_config_create(self): config_file = 'dwave.conf' profile = 'profile' values = 'endpoint token client solver'.split() runner = CliRunner() with runner.isolated_filesystem(): # create config file through simulated user input in `dwave configure` touch(config_file) with mock.patch("dwave.cloud.utils.input", side_effect=values): result = runner.invoke(cli, [ 'config', 'create', '--config-file', config_file, '--profile', profile ], input='\n'.join(values)) self.assertEqual(result.exit_code, 0) # load and verify config with isolated_environ(remove_dwave=True): config = load_config(config_file, profile=profile) for val in values: self.assertEqual(config.get(val), val)
import os import warnings from dwave.cloud.config import load_config from dwave.cloud.exceptions import CanceledFutureError, ConfigFileError # try to load client config needed for live tests on SAPI web service try: # by default, use `test` profile from `tests/dwave.conf`, # with secrets (token) read from env default_config_path = os.path.join(os.path.dirname(__file__), 'dwave.conf') default_config_profile = 'test' # allow manual override of config file and profile used for tests test_config_path = os.getenv('DWAVE_CONFIG_FILE', default_config_path) test_config_profile = os.getenv('DWAVE_PROFILE', default_config_profile) config = load_config(config_file=test_config_path, profile=test_config_profile) # ensure config is complete for var in 'endpoint token solver'.split(): if not config[var]: raise ValueError("Config incomplete, missing: {!r}".format(var)) except (ConfigFileError, ValueError) as e: config = None warnings.warn("Skipping live tests due to: {!s}".format(e))
def from_config(cls, config_file=None, profile=None, client=None, endpoint=None, token=None, solver=None, proxy=None, legacy_config_fallback=True, **kwargs): """Client factory method which loads configuration from file(s), process environment variables and explicitly provided values, creating and returning the appropriate client instance (:class:`dwave.cloud.qpu.Client` or :class:`dwave.cloud.sw.Client`). Note: For details on config loading from files and environment, please see :func:`~dwave.cloud.config.load_config`. Args: config_file (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 for config file. profile (str, default=None): Profile name (config file section name). If undefined it is taken from ``DWAVE_PROFILE`` environment variable, or config file, or first section, or defaults. For details, see :func:`~dwave.cloud.config.load_config`. client (str, default=None): Client class (selected by name) to use for accessing the API. Use ``qpu`` to specify the :class:`dwave.cloud.qpu.Client` and ``sw`` for :class:`dwave.cloud.sw.Client`. endpoint (str, default=None): API endpoint URL. token (str, default=None): API authorization token. solver (str, default=None): Default solver to use in :meth:`~dwave.cloud.client.Client.get_solver`. If undefined, you'll have to explicitly specify the solver name/id in all calls to :meth:`~dwave.cloud.client.Client.get_solver`. proxy (str, default=None): URL for proxy to use in connections to D-Wave API. Can include username/password, port, scheme, etc. If undefined, client will connect directly to the API (unless you use a system-level proxy). legacy_config_fallback (bool, default=True): If loading from a ``dwave.conf`` config file fails, try loading the ``.dwrc`` legacy config. **kwargs: All remaining keyword arguments are passed-through as-is to the chosen `Client` constructor method. A notable custom argument is `permissive_ssl`. Note: all user-defined keys from config files are propagated to the `Client` constructor too, and can be overridden with these keyword arguments. Example: Create ``dwave.conf`` in your current directory or ``~/.config/dwave/dwave.conf``:: [prod] endpoint = https://cloud.dwavesys.com/sapi token = DW-123123-secret solver = DW_2000Q_1 Run:: from dwave.cloud import Client with Client.from_config(profile='prod') as client: solver = client.get_solver() computation = solver.sample_ising({}, {}) samples = computation.result() Raises: :exc:`~dwave.cloud.exceptions.ConfigFileReadError`: Config file specified or detected could not be opened or read. :exc:`~dwave.cloud.exceptions.ConfigFileParseError`: Config file parse failed. """ # try loading configuration from a preferred new config subsystem # (`./dwave.conf`, `~/.config/dwave/dwave.conf`, etc) config = load_config(config_file=config_file, profile=profile, client=client, endpoint=endpoint, token=token, solver=solver, proxy=proxy) # fallback to legacy `.dwrc` if key variables missing if legacy_config_fallback and (not config.get('token') or not config.get('endpoint')): config = legacy_load_config(profile=profile, client=client, endpoint=endpoint, token=token, solver=solver, proxy=proxy) # manual override of other (client-custom) arguments config.update(kwargs) from dwave.cloud import qpu, sw _clients = {'qpu': qpu.Client, 'sw': sw.Client} _client = config.pop('client', None) or 'qpu' return _clients[_client](**config)
def test_config_load_configfile_detect_profile_env(self): with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=None)): with mock.patch.dict(os.environ, {'DWAVE_PROFILE': 'alpha'}): self._assert_config_valid(load_config())
def test_config_load_configfile_detect(self): with mock.patch("dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=None)): self._assert_config_valid( load_config(config_file=None, profile='alpha'))
def test_config_load_configfile_arg(self): with mock.patch( "dwave.cloud.config.load_config_from_files", partial(self._load_config_from_files, provided=['myfile'])): self._assert_config_valid( load_config(config_file='myfile', profile='alpha'))
def from_config(cls, config_file=None, profile=None, client=None, endpoint=None, token=None, solver=None, proxy=None): """Client factory method which loads configuration from file(s), process environment variables and explicitly provided values, creating and returning the appropriate client instance (:class:`dwave.cloud.qpu.Client` or :class:`dwave.cloud.sw.Client`). Usage example: Create ``dwave.conf`` in your current directory or ``~/.config/dwave/dwave.conf``:: [prod] endpoint = https://cloud.dwavesys.com/sapi token = DW-123123-secret solver = DW_2000Q_1 Run: >>> from dwave.cloud import Client >>> client = Client.from_config(profile='prod') >>> solver = client.get_solver() >>> computation = solver.submit({}, {}) >>> samples = computation.result() TODO: describe config loading, new config in broad strokes, refer to actual loaders' doc; include examples for config and usage. """ # try loading configuration from a preferred new config subsystem # (`./dwave.conf`, `~/.config/dwave/dwave.conf`, etc) try: config = load_config(config_file=config_file, profile=profile, client=client, endpoint=endpoint, token=token, solver=solver, proxy=proxy) except ValueError: config = dict(endpoint=endpoint, token=token, solver=solver, proxy=proxy, client=client) # and failback to the legacy `.dwrc` if config.get('token') is None or config.get('endpoint') is None: try: _endpoint, _token, _proxy, _solver = legacy_load_config( key=profile, endpoint=endpoint, token=token, solver=solver, proxy=proxy) config = dict(endpoint=_endpoint, token=_token, solver=_solver, proxy=_proxy, client=client) except (ValueError, IOError): pass from dwave.cloud import qpu, sw _clients = {'qpu': qpu.Client, 'sw': sw.Client} _client = config.pop('client') or 'qpu' return _clients[_client](**config)
def from_config(cls, config_file=None, profile=None, client=None, endpoint=None, token=None, solver=None, proxy=None, legacy_config_fallback=True, **kwargs): """Client factory method to instantiate a client instance from configuration. Configuration files comply with standard Windows INI-like format, parsable with Python's :mod:`configparser`. An optional ``defaults`` section provides default key-value pairs for all other sections. User-defined key-value pairs (unrecognized keys) are passed through to the client. Configuration values can be specified in multiple ways, ranked in the following order (with 1 the highest ranked): 1. Values specified as keyword arguments in :func:`from_config()` 2. Values specified as environment variables 3. Values specified in the configuration file If the location of the configuration file is not specified, auto-detection searches for existing configuration files in the standard directories of :func:`get_configfile_paths`. If a configuration file explicitly specified, via an argument or environment variable, does not exist or is unreadable, loading fails with :exc:`~dwave.cloud.exceptions.ConfigFileReadError`. Loading fails with :exc:`~dwave.cloud.exceptions.ConfigFileParseError` if the file is readable but invalid as a configuration file. Similarly, if a profile explicitly specified, via an argument or environment variable, is not present in the loaded configuration, loading fails with :exc:`ValueError`. Explicit profile selection also fails if the configuration file is not explicitly specified, detected on the system, or defined via an environment variable. Environment variables: ``DWAVE_CONFIG_FILE``: Configuration file path used if no configuration file is specified. ``DWAVE_PROFILE``: Name of profile (section) to use if no profile is specified. ``DWAVE_API_CLIENT``: API client class used if no client is specified. Supported values are ``qpu`` or ``sw``. ``DWAVE_API_ENDPOINT``: API endpoint URL used if no endpoint is specified. ``DWAVE_API_TOKEN``: API authorization token used if no token is specified. ``DWAVE_API_SOLVER``: Default solver used if no solver is specified. ``DWAVE_API_PROXY``: URL for proxy connections to D-Wave API used if no proxy is specified. Args: config_file (str/[str]/None/False/True, default=None): Path to configuration file. If ``None``, the value is taken from ``DWAVE_CONFIG_FILE`` environment variable if defined. If the environment variable is undefined or empty, auto-detection searches for existing configuration files in the standard directories of :func:`get_configfile_paths`. If ``False``, loading from file is skipped. If ``True``, forces auto-detection (regardless of the ``DWAVE_CONFIG_FILE`` environment variable). profile (str, default=None): Profile name (name of the profile section in the configuration file). If undefined, inferred from ``DWAVE_PROFILE`` environment variable if defined. If the environment variable is undefined or empty, a profile is selected in the following order: 1. From the default section if it includes a profile key. 2. The first section (after the default section). 3. If no other section is defined besides ``[defaults]``, the defaults section is promoted and selected. client (str, default=None): Client type used for accessing the API. Supported values are ``qpu`` for :class:`dwave.cloud.qpu.Client` and ``sw`` for :class:`dwave.cloud.sw.Client`. endpoint (str, default=None): API endpoint URL. token (str, default=None): API authorization token. solver (str, default=None): Default :term:`solver` to use in :meth:`~dwave.cloud.client.Client.get_solver`. If undefined, :meth:`~dwave.cloud.client.Client.get_solver` will return the first solver available. proxy (str, default=None): URL for proxy to use in connections to D-Wave API. Can include username/password, port, scheme, etc. If undefined, client uses the system-level proxy, if defined, or connects directly to the API. legacy_config_fallback (bool, default=True): If True (the default) and loading from a standard D-Wave Cloud Client configuration file (``dwave.conf``) fails, tries loading a legacy configuration file (``~/.dwrc``). Other Parameters: Unrecognized keys (str): All unrecognized keys are passed through to the appropriate client class constructor as string keyword arguments. An explicit key value overrides an identical user-defined key value loaded from a configuration file. Returns: :class:`~dwave.cloud.client.Client` (:class:`dwave.cloud.qpu.Client` or :class:`dwave.cloud.sw.Client`, default=:class:`dwave.cloud.qpu.Client`): Appropriate instance of a QPU or software client. Raises: :exc:`~dwave.cloud.exceptions.ConfigFileReadError`: Config file specified or detected could not be opened or read. :exc:`~dwave.cloud.exceptions.ConfigFileParseError`: Config file parse failed. Examples: This first example initializes :class:`~dwave.cloud.client.Client` from an explicitly specified configuration file, "~/jane/my_path_to_config/my_cloud_conf.conf":: [defaults] endpoint = https://url.of.some.dwavesystem.com/sapi client = qpu token = ABC-123456789123456789123456789 [dw2000] solver = EXAMPLE_2000Q_SYSTEM token = DEF-987654321987654321987654321 The example code below creates a client object that connects to a D-Wave QPU, using :class:`dwave.cloud.qpu.Client` and ``EXAMPLE_2000Q_SYSTEM`` as a default solver. >>> from dwave.cloud import Client >>> client = Client.from_config(config_file='~/jane/my_path_to_config/my_cloud_conf.conf') # doctest: +SKIP >>> # code that uses client >>> client.close() This second example auto-detects a configuration file on the local system following the user/system configuration paths of :func:`get_configfile_paths`. It passes through to the instantiated client an unrecognized key-value pair my_param=`my_value`. >>> from dwave.cloud import Client >>> client = Client.from_config(my_param=`my_value`) >>> # code that uses client >>> client.close() This third example instantiates two clients, for managing both QPU and software solvers. Common key-value pairs are taken from the defaults section of a shared configuration file:: [defaults] endpoint = https://url.of.some.dwavesystem.com/sapi client = qpu [dw2000A] solver = EXAMPLE_2000Q_SYSTEM_A token = ABC-123456789123456789123456789 [sw_solver] client = sw solver = c4-sw_sample endpoint = https://url.of.some.software.resource.com/my_if token = DEF-987654321987654321987654321 [dw2000B] solver = EXAMPLE_2000Q_SYSTEM_B proxy = http://user:[email protected]:8080/ token = XYZ-0101010100112341234123412341234 The example code below creates client objects for two QPU solvers (at the same URL but each with its own solver ID and token) and one software solver. >>> from dwave.cloud import Client >>> client_qpu1 = Client.from_config(profile='dw2000A') # doctest: +SKIP >>> client_qpu1 = Client.from_config(profile='dw2000B') # doctest: +SKIP >>> client_sw1 = Client.from_config(profile='sw_solver') # doctest: +SKIP >>> client_qpu1.default_solver # doctest: +SKIP u'EXAMPLE_2000Q_SYSTEM_A' >>> client_qpu2.endpoint # doctest: +SKIP u'https://url.of.some.dwavesystem.com/sapi' >>> # code that uses client >>> client_qpu1.close() # doctest: +SKIP >>> client_qpu2.close() # doctest: +SKIP >>> client_sw1.close() # doctest: +SKIP This fourth example loads configurations auto-detected in more than one configuration file, with the higher priority file (in the current working directory) supplementing and overriding values from the lower priority user-local file. After instantiation, an endpoint from the default section and client from the profile section is provided from the user-local ``/usr/local/share/dwave/dwave.conf`` file:: [defaults] endpoint = https://int.se.dwavesystems.com/sapi [dw2000] client = qpu token = ABC-123456789123456789123456789 A solver is supplemented from the file in the current working directory, which also overrides the token value. ``./dwave.conf`` is the file in the current directory:: [dw2000] solver = EXAMPLE_2000Q_SYSTEM_A token = DEF-987654321987654321987654321 >>> from dwave.cloud import Client >>> client = Client.from_config() >>> client.default_solver # doctest: +SKIP u'EXAMPLE_2000Q_SYSTEM_A' >>> client.endpoint # doctest: +SKIP u'https://int.se.dwavesystems.com/sapi' >>> client.token # doctest: +SKIP u'DEF-987654321987654321987654321' >>> # code that uses client >>> client.close() # doctest: +SKIP """ # try loading configuration from a preferred new config subsystem # (`./dwave.conf`, `~/.config/dwave/dwave.conf`, etc) config = load_config(config_file=config_file, profile=profile, client=client, endpoint=endpoint, token=token, solver=solver, proxy=proxy) _LOGGER.debug("Config loaded: %r", config) # fallback to legacy `.dwrc` if key variables missing if legacy_config_fallback and (not config.get('token') or not config.get('endpoint')): config = legacy_load_config(profile=profile, client=client, endpoint=endpoint, token=token, solver=solver, proxy=proxy) _LOGGER.debug("Legacy config loaded: %r", config) # manual override of other (client-custom) arguments config.update(kwargs) from dwave.cloud import qpu, sw _clients = {'qpu': qpu.Client, 'sw': sw.Client, 'base': cls} _client = config.pop('client', None) or 'base' _LOGGER.debug("Final config used for %s.Client(): %r", _client, config) return _clients[_client](**config)