Source code for pennylane.configuration

# Copyright 2018-2021 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""
This module contains the :class:`Configuration` class, which is used to
load, store, save, and modify configuration options for PennyLane and all
supported plugins and devices.
"""

import contextlib
import os

import toml
from appdirs import user_config_dir


[docs]class Configuration: """Configuration class. This class is responsible for loading, saving, and storing PennyLane and plugin/device configurations. Args: name (str): filename of the configuration file. This should be a valid TOML file. You may also pass an absolute or a relative file path to the configuration file. """ def __init__(self, name): # Look for an existing configuration file self._config = {} self._filepath = None self._name = name self._user_config_dir = user_config_dir("pennylane", "Xanadu") self._env_config_dir = os.environ.get("PENNYLANE_CONF", "") # search the current directory the directory under environment # variable PENNYLANE_CONF, and default user config directory, in that order. directories = [os.curdir, self._env_config_dir, self._user_config_dir, ""] for directory in directories: with contextlib.suppress(FileNotFoundError): self._filepath = os.path.join(directory, self._name) self.load(self._filepath) break def __str__(self): if self._config: return f"{self._config}" return "" def __repr__(self): return f"PennyLane Configuration <{self._filepath}>" @property def path(self): """Return the path of the loaded configuration file. Returns: str: If no configuration is loaded, this returns ``None``.""" return self._filepath
[docs] def load(self, filepath): """Load a configuration file. Args: filepath (str): path to the configuration file. """ with open(filepath, "r", encoding="utf8") as f: self._config = toml.load(f)
[docs] def save(self, filepath): """Save a configuration file. Args: filepath (str): path to the configuration file. """ with open(filepath, "w", encoding="utf8") as f: toml.dump(self._config, f)
def __getitem__(self, key): keys = key.split(".") return self.safe_get(self._config, *keys) def __setitem__(self, key, value): keys = key.split(".") self.safe_set(self._config, value, *keys) def __bool__(self): return bool(self._config)
[docs] @staticmethod def safe_set(dct, value, *keys): """Safely set the value of a key from a nested dictionary. If any key provided does not exist, a dictionary containing the remaining keys is dynamically created and set to the required value. Args: dct (dict): the dictionary to set the value of. value: the value to set. Can be any valid type. *keys: each additional argument corresponds to a nested key. """ for key in keys[:-1]: dct = dct.setdefault(key, {}) dct[keys[-1]] = value
[docs] @staticmethod def safe_get(dct, *keys): """Safely return value from a nested dictionary. If any key provided does not exist, an empty dictionary is returned. Args: dct (dict): the dictionary to set the value of. *keys: each additional argument corresponds to a nested key. Returns: value corresponding to ``dct[keys[0]][keys[1]]`` etc. """ for key in keys: try: dct = dct[key] except KeyError: return {} return dct