Skip to content

Commit

Permalink
Merge pull request #267 from sbillinge/configupdate
Browse files Browse the repository at this point in the history
Config updater workflow
  • Loading branch information
sbillinge authored Dec 26, 2024
2 parents 969ca54 + 8d0bf06 commit 40c3446
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 98 deletions.
4 changes: 4 additions & 0 deletions doc/source/examples/tools_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ After receiving the inputs, the function will write the information to
the `diffpyconfig.json` file in your home directory.


``check_and_build_global_config()`` returns ``True`` if the config file exists (whether it created it or not)
and ``False`` if the config file does not exist in the user's home allowing you to develop your own
workflow for handling missing config files after running it with ``skip_config_creation=True``.

I entered the wrong information in my config file so it always loads incorrect information, how do I fix that?
--------------------------------------------------------------------------------------------------------------

Expand Down
23 changes: 23 additions & 0 deletions news/configupdate.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Added:**

* no news added: covered in the news from the get_user_info work

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
83 changes: 72 additions & 11 deletions src/diffpy/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def get_user_info(owner_name=None, owner_email=None, owner_orcid=None):
"owner_email": "<your_associated_email>>@email.com",
"owner_orcid": "<your_associated_orcid if you would like this stored with your data>>"
}
You may also store any other gloabl-level information that you would like associated with your
You may also store any other global-level information that you would like associated with your
diffraction data in this file
Parameters
Expand All @@ -103,22 +103,83 @@ def get_user_info(owner_name=None, owner_email=None, owner_orcid=None):
del runtime_info[key]
global_config = _load_config(Path().home() / "diffpyconfig.json")
local_config = _load_config(Path().cwd() / "diffpyconfig.json")
# if global_config is None and local_config is None:
# print(
# "No global configuration file was found containing "
# "information about the user to associate with the data.\n"
# "By following the prompts below you can add your name and email to this file on the current "
# "computer and your name will be automatically associated with subsequent diffpy data by default.\n"
# "This is not recommended on a shared or public computer. "
# "You will only have to do that once.\n"
# "For more information, please refer to www.diffpy.org/diffpy.utils/examples/toolsexample.html"
# )
user_info = global_config
user_info.update(local_config)
user_info.update(runtime_info)
return user_info


def check_and_build_global_config(skip_config_creation=False):
"""Checks for a global diffpu config file in user's home directory and
creates one if it is missing.
The file it looks for is called diffpyconfig.json. This can contain anything in json format, but
minimally contains information about the computer owner. The information is used
when diffpy objects are created and saved to files or databases to retain ownership information
of datasets. For example, it is used by diffpy.utils.tools.get_user_info().
If the function finds no config file in the user's home directory it interrupts execution
and prompts the user for name, email, and orcid information. It then creates the config file
with this information inside it.
The function returns True if the file exists and False otherwise.
If you would like to check for a file but not run the file creation workflow you can set
the optional argument skip_config_creation to True.
Parameters
----------
skip_config_creation: bool, optional, Default is False
The bool that will override the creation workflow even if no config file exists.
Returns
-------
bool: True if the file exists and False otherwise.
"""
config_exists = False
config_path = Path().home() / "diffpyconfig.json"
if config_path.is_file():
config_exists = True
return config_exists
if skip_config_creation:
return config_exists
intro_text = (
"No global configuration file was found containing information about the user to "
"associate with the data.\n By following the prompts below you can add your name "
"and email to this file on the current "
"computer and your name will be automatically associated with subsequent diffpy data by default.\n"
"This is not recommended on a shared or public computer. "
"You will only have to do that once.\n"
"For more information, please refer to www.diffpy.org/diffpy.utils/examples/toolsexample.html"
)
print(intro_text)
username = input("Please enter the name you would want future work to be credited to: ").strip()
email = input("Please enter your email: ").strip()
orcid = input("Please enter your orcid ID if you know it: ").strip()
config = {
"owner_name": _stringify(username),
"owner_email": _stringify(email),
"owner_orcid": _stringify(orcid),
}
if email != "" or orcid != "" or username != "":
config["owner_orcid"] = _stringify(orcid)
with open(config_path, "w") as f:
f.write(json.dumps(config))
outro_text = (
f"The config file at {Path().home() / 'diffpyconfig.json'} has been created. "
f"The values {config} were entered.\n"
f"These values will be inserted as metadata with your data in apps that use "
f"diffpy.get_user_info(). If you would like to update these values, either "
f"delete the config file and this workflow will rerun next time you run this "
f"program. Or you may open the config file in a text editor and manually edit the"
f"entries. For more information, see: "
f"https://diffpy.github.io/diffpy.utils/examples/tools_example.html"
)
print(outro_text)
config_exists = True
return config_exists


def get_package_info(package_names, metadata=None):
"""Fetches package version and updates it into (given) metadata.
Expand Down
145 changes: 58 additions & 87 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,7 @@

import pytest

from diffpy.utils.tools import get_package_info, get_user_info

# def _setup_dirs(monkeypatch, user_filesystem):
# home_dir, cwd_dir = user_filesystem.home_dir, user_filesystem.cwd_dir
# os.chdir(cwd_dir)
# return home_dir
#


def _run_tests(inputs, expected):
args = {"username": inputs[0], "email": inputs[1]}
expected_username, expected_email = expected
config = get_user_info(args)
assert config.get("username") == expected_username
assert config.get("email") == expected_email


params_user_info_with_local_conf_file = [
(["", ""], ["cwd_username", "[email protected]"]),
(["cli_username", ""], ["cli_username", "[email protected]"]),
(["", "[email protected]"], ["cwd_username", "[email protected]"]),
([None, None], ["cwd_username", "[email protected]"]),
(["cli_username", None], ["cli_username", "[email protected]"]),
([None, "[email protected]"], ["cwd_username", "[email protected]"]),
(["cli_username", "[email protected]"], ["cli_username", "[email protected]"]),
]
params_user_info_with_no_home_conf_file = [
(
[None, None],
["input_username", "[email protected]"],
["input_username", "[email protected]"],
),
(
["cli_username", None],
["", "[email protected]"],
["cli_username", "[email protected]"],
),
(
[None, "[email protected]"],
["input_username", ""],
["input_username", "[email protected]"],
),
(
["", ""],
["input_username", "[email protected]"],
["input_username", "[email protected]"],
),
(
["cli_username", ""],
["", "[email protected]"],
["cli_username", "[email protected]"],
),
(
["", "[email protected]"],
["input_username", ""],
["input_username", "[email protected]"],
),
(
["cli_username", "[email protected]"],
["input_username", "[email protected]"],
["cli_username", "[email protected]"],
),
]
params_user_info_no_conf_file_no_inputs = [
([None, None], ["", ""], ["", ""]),
]
from diffpy.utils.tools import check_and_build_global_config, get_package_info, get_user_info


@pytest.mark.parametrize(
Expand Down Expand Up @@ -149,27 +84,63 @@ def test_get_user_info_with_local_conf_file(runtime_inputs, expected, user_files
assert actual == expected


# @pytest.mark.parametrize("inputsa, inputsb, expected", params_user_info_with_no_home_conf_file)
# def test_get_user_info_with_no_home_conf_file(monkeypatch, inputsa, inputsb, expected, user_filesystem):
# _setup_dirs(monkeypatch, user_filesystem)
# os.remove(Path().home() / "diffpyconfig.json")
# inp_iter = iter(inputsb)
# monkeypatch.setattr("builtins.input", lambda _: next(inp_iter))
# _run_tests(inputsa, expected)
# confile = Path().home() / "diffpyconfig.json"
# assert confile.is_file()
#
#
# @pytest.mark.parametrize("inputsa, inputsb, expected", params_user_info_no_conf_file_no_inputs)
# def test_get_user_info_no_conf_file_no_inputs(monkeypatch, inputsa, inputsb, expected, user_filesystem):
# _setup_dirs(monkeypatch, user_filesystem)
# os.remove(Path().home() / "diffpyconfig.json")
# inp_iter = iter(inputsb)
# monkeypatch.setattr("builtins.input", lambda _: next(inp_iter))
# _run_tests(inputsa, expected)
# confile = Path().home() / "diffpyconfig.json"
# assert confile.exists() is False
#
@pytest.mark.parametrize(
"test_inputs,expected",
[ # Check check_and_build_global_config() builds correct config when config is found missing
( # C1: user inputs valid name, email and orcid
{"user_inputs": ["input_name", "[email protected]", "input_orcid"]},
{"owner_email": "[email protected]", "owner_orcid": "input_orcid", "owner_name": "input_name"},
),
({"user_inputs": ["", "", ""]}, None), # C2: empty strings passed in, expect no config file created
( # C3: just username input, expect config file but with some empty values
{"user_inputs": ["input_name", "", ""]},
{"owner_email": "", "owner_orcid": "", "owner_name": "input_name"},
),
],
)
def test_check_and_build_global_config(test_inputs, expected, user_filesystem, mocker):
# user_filesystem[0] is tmp_dir/home_dir with the global config file in it, user_filesystem[1]
# is tmp_dir/cwd_dir
mocker.patch.object(Path, "home", return_value=user_filesystem[0])
os.chdir(user_filesystem[1])
confile = user_filesystem[0] / "diffpyconfig.json"
# remove the config file from home that came with user_filesystem
os.remove(confile)
mocker.patch("builtins.input", side_effect=test_inputs["user_inputs"])
actual_bool = check_and_build_global_config()
try:
with open(confile, "r") as f:
actual = json.load(f)
expected_bool = True
except FileNotFoundError:
expected_bool = False
actual = None
assert actual == expected
assert actual_bool == expected_bool


def test_check_and_build_global_config_file_exists(user_filesystem, mocker):
mocker.patch.object(Path, "home", return_value=user_filesystem[0])
os.chdir(user_filesystem[1])
confile = user_filesystem[0] / "diffpyconfig.json"
expected = {"owner_name": "home_ownername", "owner_email": "[email protected]", "owner_orcid": "home_orcid"}
actual_bool = check_and_build_global_config()
assert actual_bool is True
with open(confile, "r") as f:
actual = json.load(f)
assert actual == expected


def test_check_and_build_global_config_skipped(user_filesystem, mocker):
mocker.patch.object(Path, "home", return_value=user_filesystem[0])
os.chdir(user_filesystem[1])
confile = user_filesystem[0] / "diffpyconfig.json"
# remove the config file from home that came with user_filesystem
os.remove(confile)
actual_bool = check_and_build_global_config(skip_config_creation=True)
assert actual_bool is False
assert not confile.exists()


params_package_info = [
(["diffpy.utils", None], {"package_info": {"diffpy.utils": "3.3.0"}}),
Expand Down

0 comments on commit 40c3446

Please sign in to comment.