From 913c8b2409cb796164bc1a84b5e78cffc4c54dc5 Mon Sep 17 00:00:00 2001 From: Peter Bull Date: Thu, 30 May 2024 11:48:11 -0400 Subject: [PATCH 1/3] Update config imports and test --- HISTORY.md | 9 +++ ccds/__main__.py | 6 +- tests/conda_harness.sh | 3 +- tests/pipenv_harness.sh | 9 +++ tests/test_creation.py | 62 +++++++++---------- tests/test_functions.sh | 7 +++ tests/virtualenv_harness.sh | 4 +- .../__init__.py | 1 - 8 files changed, 63 insertions(+), 38 deletions(-) create mode 100644 HISTORY.md diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 000000000..d9b38d22c --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,9 @@ +# cookiecutter-data-science Changelog + +## UNRELEASED + +- Fixes issue with scaffold code that import of config did not work. Adds testing of imports to test suite. (Issue [#370](https://github.com/drivendataorg/cookiecutter-data-science/issues/370)) + +## v2.0.0 (2024-05-22) + +- Released version 2.0.0! :tada: See [docs](https://cookiecutter-data-science.drivendata.org/) and [announcement blog post](https://drivendata.co/blog/ccds-v2) for more information. \ No newline at end of file diff --git a/ccds/__main__.py b/ccds/__main__.py index f9262d172..2f50dfadd 100644 --- a/ccds/__main__.py +++ b/ccds/__main__.py @@ -28,9 +28,9 @@ def default_ccds_main(f): """Set the default for the cookiecutter template argument to the CCDS template.""" def _main(*args, **kwargs): - f.params[1].default = ( - "https://github.com/drivendataorg/cookiecutter-data-science" - ) + f.params[ + 1 + ].default = "https://github.com/drivendataorg/cookiecutter-data-science" return f(*args, **kwargs) return _main diff --git a/tests/conda_harness.sh b/tests/conda_harness.sh index b43c1ee77..0d5a2f6dc 100644 --- a/tests/conda_harness.sh +++ b/tests/conda_harness.sh @@ -6,6 +6,7 @@ eval "$(conda shell.bash hook)" PROJECT_NAME=$(basename $1) CCDS_ROOT=$(dirname $0) +MODULE_NAME=$2 # configure exit / teardown behavior function finish { @@ -34,4 +35,4 @@ make create_environment conda activate $PROJECT_NAME make requirements -run_tests $PROJECT_NAME +run_tests $PROJECT_NAME $MODULE_NAME diff --git a/tests/pipenv_harness.sh b/tests/pipenv_harness.sh index 463756e5b..2726b9907 100644 --- a/tests/pipenv_harness.sh +++ b/tests/pipenv_harness.sh @@ -3,6 +3,7 @@ set -ex PROJECT_NAME=$(basename $1) CCDS_ROOT=$(dirname $0) +MODULE_NAME=$2 # configure exit / teardown behavior function finish { @@ -27,3 +28,11 @@ make requirements # test with pipenv run pipenv run python -c "import sys; assert \"$PROJECT_NAME\" in sys.executable" + +# test importable +pipenv run python -c "import $MODULE_NAME" + +# test config importable if scaffolded +if [ -f "$MODULE_NAME/config.py" ]; then + pipenv run python -c "from $MODULE_NAME import config" +fi diff --git a/tests/test_creation.py b/tests/test_creation.py index 322c00ed3..1dee39845 100644 --- a/tests/test_creation.py +++ b/tests/test_creation.py @@ -9,6 +9,26 @@ BASH_EXECUTABLE = os.getenv("BASH_EXECUTABLE", "bash") +def _decode_print_stdout_stderr(result): + """Print command stdout and stderr to console to use when debugging failing tests + Normally hidden by pytest except in failure we want this displayed + """ + encoding = sys.stdout.encoding + + if encoding is None: + encoding = "utf-8" + + print("\n======================= STDOUT ======================") + stdout = result.stdout.decode(encoding) + print(stdout) + + print("\n======================= STDERR ======================") + stderr = result.stderr.decode(encoding) + print(stderr) + + return stdout, stderr + + def no_curlies(filepath): """Utility to make sure no curly braces appear in a file. That is, was Jinja able to render everything? @@ -154,31 +174,23 @@ def verify_makefile_commands(root, config): ) result = run( - [BASH_EXECUTABLE, str(harness_path), str(root.resolve())], + [ + BASH_EXECUTABLE, + str(harness_path), + str(root.resolve()), + str(config["module_name"]), + ], stderr=PIPE, stdout=PIPE, ) - result_returncode = result.returncode - encoding = sys.stdout.encoding - - if encoding is None: - encoding = "utf-8" - - # normally hidden by pytest except in failure we want this displayed - print("PATH=", os.getenv("PATH")) - print("\n======================= STDOUT ======================") - stdout_output = result.stdout.decode(encoding) - print(stdout_output) - - print("\n======================= STDERR ======================") - print(result.stderr.decode(encoding)) + stdout_output, _ = _decode_print_stdout_stderr(result) # Check that makefile help ran successfully assert "Available rules:" in stdout_output assert "clean Delete all compiled Python files" in stdout_output - assert result_returncode == 0 + assert result.returncode == 0 def lint(root): @@ -189,20 +201,6 @@ def lint(root): stderr=PIPE, stdout=PIPE, ) - result_returncode = result.returncode - - encoding = sys.stdout.encoding - - if encoding is None: - encoding = "utf-8" - - # normally hidden by pytest except in failure we want this displayed - print("PATH=", os.getenv("PATH")) - print("\n======================= STDOUT ======================") - stdout_output = result.stdout.decode(encoding) - print(stdout_output) - - print("\n======================= STDERR ======================") - print(result.stderr.decode(encoding)) + _, _ = _decode_print_stdout_stderr(result) - assert result_returncode == 0 + assert result.returncode == 0 diff --git a/tests/test_functions.sh b/tests/test_functions.sh index 96c19f447..4bb6a4a6c 100644 --- a/tests/test_functions.sh +++ b/tests/test_functions.sh @@ -9,4 +9,11 @@ function run_tests () { exit 99 fi + # test importable + python -c "import $2" + + # test config importable if scaffolded + if [ -f "$2/config.py" ]; then + python -c "from $2 import config" + fi } \ No newline at end of file diff --git a/tests/virtualenv_harness.sh b/tests/virtualenv_harness.sh index cdc1231c6..d03462581 100644 --- a/tests/virtualenv_harness.sh +++ b/tests/virtualenv_harness.sh @@ -3,6 +3,7 @@ set -e PROJECT_NAME=$(basename $1) CCDS_ROOT=$(dirname $0) +MODULE_NAME=$2 # configure exit / teardown behavior function finish { @@ -55,4 +56,5 @@ fi make requirements -run_tests $PROJECT_NAME +run_tests $PROJECT_NAME $MODULE_NAME + diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py index 9680e9410..e69de29bb 100644 --- a/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py +++ b/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py @@ -1 +0,0 @@ -import config # noqa: F401 From 1039ac9120cfd5045657feb34364a5da2943e33f Mon Sep 17 00:00:00 2001 From: Peter Bull Date: Thu, 30 May 2024 11:53:46 -0400 Subject: [PATCH 2/3] reformat with latest black --- ccds/__main__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ccds/__main__.py b/ccds/__main__.py index 2f50dfadd..f9262d172 100644 --- a/ccds/__main__.py +++ b/ccds/__main__.py @@ -28,9 +28,9 @@ def default_ccds_main(f): """Set the default for the cookiecutter template argument to the CCDS template.""" def _main(*args, **kwargs): - f.params[ - 1 - ].default = "https://github.com/drivendataorg/cookiecutter-data-science" + f.params[1].default = ( + "https://github.com/drivendataorg/cookiecutter-data-science" + ) return f(*args, **kwargs) return _main From 7b3b29a181f61cc56a77844cd29f061d020b7531 Mon Sep 17 00:00:00 2001 From: Peter Bull Date: Thu, 30 May 2024 12:49:05 -0400 Subject: [PATCH 3/3] Add config back in --- hooks/post_gen_project.py | 3 +++ .../{{ cookiecutter.module_name }}/__init__.py | 1 + 2 files changed, 4 insertions(+) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index e7ac204d7..2e0bc89b6 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -76,4 +76,7 @@ shutil.rmtree(generated_path) elif generated_path.name != "__init__.py": generated_path.unlink() + elif generated_path.name == "__init__.py": + # remove any content in __init__.py since it won't be available + generated_path.write_text("") # {% endif %} diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py index e69de29bb..8884c8ebe 100644 --- a/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py +++ b/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/__init__.py @@ -0,0 +1 @@ +from {{ cookiecutter.module_name }} import config # noqa: F401