# Path: pymatgen/db/dbconfig.py
# class DBConfig:
#     """Database configuration."""
# 
#     DEFAULT_PORT = 27017
#     DEFAULT_FILE = "db.json"
#     ALL_SETTINGS = [
#         HOST_KEY,
#         PORT_KEY,
#         DB_KEY,
#         COLL_KEY,
#         ALIASES_KEY,
#     ]
#     DEFAULT_SETTINGS = [
#         (HOST_KEY, "localhost"),
#         (PORT_KEY, DEFAULT_PORT),
#         (DB_KEY, "vasp"),
#         (ALIASES_KEY, {}),
#     ]
# 
#     def __init__(self, config_file=None, config_dict=None):
#         """
#         Constructor.
# 
#         Settings are created from config_dict, if given,
#         or parsed config_file, if given, otherwise
#         the DEFAULT_FILE is tried and if that is not present
#         the DEFAULT_SETTINGS are used without modification.
# 
#         :param config_file: Read configuration from this file.
#         :type config_file: file or str path
#         :param config_dict: Set configuration from this dictionary.
#         :raises: ConfigurationFileError if cannot read/parse config_file
#         """
#         self._cfg = dict(self.DEFAULT_SETTINGS)
#         settings = {}
#         if config_dict:
#             settings = config_dict.copy()
#             auth_aliases(settings)
#         else:
#             # Try to use DEFAULT_FILE if no config_file
#             if config_file is None:
#                 if os.path.exists(self.DEFAULT_FILE):
#                     config_file = self.DEFAULT_FILE
#             # If there was a config_file, parse it
#             if config_file is not None:
#                 try:
#                     settings = get_settings(config_file)
#                 except Exception as err:
#                     path = _as_file(config_file).name
#                     raise ConfigurationFileError(path, err)
#         self._cfg.update(settings)
#         normalize_auth(self._cfg)
# 
#     def __str__(self):
#         return str(self._cfg)
# 
#     def copy(self):
#         """Return a copy of self (internal settings are copied)."""
#         return DBConfig(config_dict=self._cfg.copy())
# 
#     @property
#     def settings(self):
#         return self._cfg
# 
#     @property
#     def host(self):
#         return self._cfg.get(HOST_KEY, None)
# 
#     @property
#     def port(self):
#         return self._cfg.get(PORT_KEY, self.DEFAULT_PORT)
# 
#     @property
#     def dbname(self):
#         """Name of the database."""
#         return self._cfg.get(DB_KEY, None)
# 
#     @dbname.setter
#     def dbname(self, value):
#         self._cfg[DB_KEY] = value
# 
#     @property
#     def collection(self):
#         return self._cfg.get(COLL_KEY, None)
# 
#     @collection.setter
#     def collection(self, value):
#         self._cfg[COLL_KEY] = value
# 
#     @property
#     def user(self):
#         return self._cfg.get(USER_KEY, None)
# 
#     @property
#     def password(self):
#         return self._cfg.get(PASS_KEY, None)
# 
# def normalize_auth(settings, admin=True, readonly=True, readonly_first=False):
#     """Transform the readonly/admin user and password to simple user/password,
#     as expected by QueryEngine. If return value is true, then
#     admin or readonly password will be in keys "user" and "password".
# 
#     :param settings: Connection settings
#     :type settings: dict
#     :param admin: Check for admin password
#     :param readonly: Check for readonly password
#     :param readonly_first: Check for readonly password before admin
#     :return: Whether user/password were found
#     :rtype: bool
#     """
#     U, P = USER_KEY, PASS_KEY
#     # If user/password, un-prefixed, exists, do nothing.
#     if U in settings and P in settings:
#         return True
# 
#     # Set prefixes
#     prefixes = []
#     if readonly_first:
#         if readonly:
#             prefixes.append("readonly_")
#         if admin:
#             prefixes.append("admin_")
#     else:
#         if admin:
#             prefixes.append("admin_")
#         if readonly:
#             prefixes.append("readonly_")
# 
#     # Look for first user/password matching.
#     found = False
#     for pfx in prefixes:
#         ukey, pkey = pfx + U, pfx + P
#         if ukey in settings and pkey in settings:
#             settings[U] = settings[ukey]
#             settings[P] = settings[pkey]
#             found = True
#             break
# 
#     return found
# 
# Path: pymatgen/db/dbconfig.py
# class ConfigurationFileError(Exception):
#     def __init__(self, filename, err):
#         msg = f"reading '{filename}': {err}"
#         Exception.__init__(self, msg)


import json
import tempfile
import unittest
from pymatgen.db.dbconfig import DBConfig, normalize_auth
from pymatgen.db.dbconfig import ConfigurationFileError
        """Imitate authorization de-aliasing."""
        cfg = self.cfg.copy()
        cfg["readonly_password"] = cfg["password"]
        cfg["readonly_user"] = cfg["user"]
        return cfg

    def test_init_file(self):
        """Create DBConfig from file or path."""
        # sending file obj, or its path, should have same effect
        tmp = "dbconfigtest.json"
        with open(tmp, "w") as f:
            json.dump(self.cfg, f)
            f.flush()
            # reset file to beginning
        with open(tmp) as f:
            d1 = DBConfig(config_file=f)
        d2 = DBConfig(config_file=tmp)
        self.assertEqual(d1.settings, d2.settings)
        self.assertEqual(d2.settings, self._aliased_cfg())

    def test_init_dict(self):
        """Create DBConfig from dict object."""
        d1 = DBConfig(config_dict=self.cfg)
        self.assertEqual(d1.settings, self._aliased_cfg())

    def test_init_junk_file(self):
        """Check error when creating DBConfig from bad input file."""
        tf = tempfile.NamedTemporaryFile("w", delete=False)
        tf.write("JUNK")
        tf.close()

# Path: pymatgen/db/dbconfig.py
# class DBConfig:
#     """Database configuration."""
# 
#     DEFAULT_PORT = 27017
#     DEFAULT_FILE = "db.json"
#     ALL_SETTINGS = [
#         HOST_KEY,
#         PORT_KEY,
#         DB_KEY,
#         COLL_KEY,
#         ALIASES_KEY,
#     ]
#     DEFAULT_SETTINGS = [
#         (HOST_KEY, "localhost"),
#         (PORT_KEY, DEFAULT_PORT),
#         (DB_KEY, "vasp"),
#         (ALIASES_KEY, {}),
#     ]
# 
#     def __init__(self, config_file=None, config_dict=None):
#         """
#         Constructor.
# 
#         Settings are created from config_dict, if given,
#         or parsed config_file, if given, otherwise
#         the DEFAULT_FILE is tried and if that is not present
#         the DEFAULT_SETTINGS are used without modification.
# 
#         :param config_file: Read configuration from this file.
#         :type config_file: file or str path
#         :param config_dict: Set configuration from this dictionary.
#         :raises: ConfigurationFileError if cannot read/parse config_file
#         """
#         self._cfg = dict(self.DEFAULT_SETTINGS)
#         settings = {}
#         if config_dict:
#             settings = config_dict.copy()
#             auth_aliases(settings)
#         else:
#             # Try to use DEFAULT_FILE if no config_file
#             if config_file is None:
#                 if os.path.exists(self.DEFAULT_FILE):
#                     config_file = self.DEFAULT_FILE
#             # If there was a config_file, parse it
#             if config_file is not None:
#                 try:
#                     settings = get_settings(config_file)
#                 except Exception as err:
#                     path = _as_file(config_file).name
#                     raise ConfigurationFileError(path, err)
#         self._cfg.update(settings)
#         normalize_auth(self._cfg)
# 
#     def __str__(self):
#         return str(self._cfg)
# 
#     def copy(self):
#         """Return a copy of self (internal settings are copied)."""
#         return DBConfig(config_dict=self._cfg.copy())
# 
#     @property
#     def settings(self):
#         return self._cfg
# 
#     @property
#     def host(self):
#         return self._cfg.get(HOST_KEY, None)
# 
#     @property
#     def port(self):
#         return self._cfg.get(PORT_KEY, self.DEFAULT_PORT)
# 
#     @property
#     def dbname(self):
#         """Name of the database."""
#         return self._cfg.get(DB_KEY, None)
# 
#     @dbname.setter
#     def dbname(self, value):
#         self._cfg[DB_KEY] = value
# 
#     @property
#     def collection(self):
#         return self._cfg.get(COLL_KEY, None)
# 
#     @collection.setter
#     def collection(self, value):
#         self._cfg[COLL_KEY] = value
# 
#     @property
#     def user(self):
#         return self._cfg.get(USER_KEY, None)
# 
#     @property
#     def password(self):
#         return self._cfg.get(PASS_KEY, None)
# 
# def normalize_auth(settings, admin=True, readonly=True, readonly_first=False):
#     """Transform the readonly/admin user and password to simple user/password,
#     as expected by QueryEngine. If return value is true, then
#     admin or readonly password will be in keys "user" and "password".
# 
#     :param settings: Connection settings
#     :type settings: dict
#     :param admin: Check for admin password
#     :param readonly: Check for readonly password
#     :param readonly_first: Check for readonly password before admin
#     :return: Whether user/password were found
#     :rtype: bool
#     """
#     U, P = USER_KEY, PASS_KEY
#     # If user/password, un-prefixed, exists, do nothing.
#     if U in settings and P in settings:
#         return True
# 
#     # Set prefixes
#     prefixes = []
#     if readonly_first:
#         if readonly:
#             prefixes.append("readonly_")
#         if admin:
#             prefixes.append("admin_")
#     else:
#         if admin:
#             prefixes.append("admin_")
#         if readonly:
#             prefixes.append("readonly_")
# 
#     # Look for first user/password matching.
#     found = False
#     for pfx in prefixes:
#         ukey, pkey = pfx + U, pfx + P
#         if ukey in settings and pkey in settings:
#             settings[U] = settings[ukey]
#             settings[P] = settings[pkey]
#             found = True
#             break
# 
#     return found
# 
# Path: pymatgen/db/dbconfig.py
# class ConfigurationFileError(Exception):
#     def __init__(self, filename, err):
#         msg = f"reading '{filename}': {err}"
#         Exception.__init__(self, msg)


# Path: pymatgen/db/tests/test_dbconfig.py
import json
import tempfile
import unittest
from pymatgen.db.dbconfig import DBConfig, normalize_auth
from pymatgen.db.dbconfig import ConfigurationFileError

        """Imitate authorization de-aliasing."""
        cfg = self.cfg.copy()
        cfg["readonly_password"] = cfg["password"]
        cfg["readonly_user"] = cfg["user"]
        return cfg

    def test_init_file(self):
        """Create DBConfig from file or path."""
        # sending file obj, or its path, should have same effect
        tmp = "dbconfigtest.json"
        with open(tmp, "w") as f:
            json.dump(self.cfg, f)
            f.flush()
            # reset file to beginning
        with open(tmp) as f:
            d1 = DBConfig(config_file=f)
        d2 = DBConfig(config_file=tmp)
        self.assertEqual(d1.settings, d2.settings)
        self.assertEqual(d2.settings, self._aliased_cfg())

    def test_init_dict(self):
        """Create DBConfig from dict object."""
        d1 = DBConfig(config_dict=self.cfg)
        self.assertEqual(d1.settings, self._aliased_cfg())

    def test_init_junk_file(self):
        """Check error when creating DBConfig from bad input file."""
        tf = tempfile.NamedTemporaryFile("w", delete=False)
        tf.write("JUNK")
        tf.close()

        self.assertRaises(ConfigurationFileError, DBConfig, config_file=tf.name)