diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7c1e3f33..094b67b1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -59,8 +59,8 @@ repos: - --wrap-descriptions - '88' - --blank - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.289 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.292 hooks: - id: ruff # args: @@ -76,7 +76,10 @@ repos: rev: 1.7.0 hooks: - id: nbqa-black + additional_dependencies: [black==23.9.1] - id: nbqa-ruff + additional_dependencies: [ruff==v0.0.292] + args: ['--ignore=B018,T201'] - repo: https://github.com/executablebooks/mdformat rev: 0.7.17 hooks: @@ -92,7 +95,7 @@ repos: args: [--wrap, '88'] files: (docs/.) - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell args: [--skip="**.ipynb"] diff --git a/CHANGES.md b/CHANGES.md index ba19302d..b35db7a1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,12 @@ # Release Notes -## v0.6.4 -- March 2023 +## v0.7.0 -- October 2023 + +- Update required pytask to version 0.4 and adjust code accordingly (only Python + example). +- Pre-commit autoupdate / fix ruff complaints. + +## v0.6.5 -- March 2023 Incorporate more feedback from EPP students, @janosg: @@ -48,7 +54,7 @@ Incorporate feedback from EPP students, @janosg, @tobiasraabe. - Much improved documentation (@raholler) - Extensive instructions for use on Windows (@raholler) -- Re-use previously-entered data when cookiecutter fails +- Reuse previously-entered data when cookiecutter fails (@tobiasraabe, @raholler) - Fix Stata template by setting --shell-escape=1 (#63, @raholler) diff --git a/cookiecutter.json b/cookiecutter.json index 0c702701..d0c39228 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -24,16 +24,16 @@ "no" ], "add_r_example": [ - "yes", - "no" + "no", + "yes" ], "add_julia_example": [ - "yes", - "no" + "no", + "yes" ], "add_stata_example": [ - "yes", - "no" + "no", + "yes" ], "add_linters": [ "no", diff --git a/docs/source/background/design_rationale.md b/docs/source/background/design_rationale.md index 3ab6f25b..0b636c44 100644 --- a/docs/source/background/design_rationale.md +++ b/docs/source/background/design_rationale.md @@ -3,7 +3,7 @@ The design of the project templates is guided by the following main thoughts: 1. **Separation of logical chunks:** A minimal requirement for a project to scale. 1. **Only execute required tasks, automatically:** Again required for scalability. It means that the machine needs to know what is meant by a "required task". -1. **Re-use of code and data instead of copying and pasting:** Else you will forget the +1. **Reuse of code and data instead of copying and pasting:** Else you will forget the copy & paste step at some point down the road. At best, this leads to errors; at worst, to misinterpreting the results. 1. **Be as language-agnostic as possible:** Make it easy to use the best tool for a diff --git a/docs/source/conf.py b/docs/source/conf.py index 47c5b03c..8d074098 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -107,8 +107,8 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -release = "0.6.5" -version = "0.6.5" +release = "0.7.0" +version = "0.7.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/development/changes.md b/docs/source/development/changes.md deleted file mode 100644 index 5569a397..00000000 --- a/docs/source/development/changes.md +++ /dev/null @@ -1,3 +0,0 @@ -```{eval-rst} -.. include:: ../../../CHANGES.md -``` diff --git a/docs/source/development/index.md b/docs/source/development/index.md index cb005096..b0a1a596 100644 --- a/docs/source/development/index.md +++ b/docs/source/development/index.md @@ -7,6 +7,3 @@ parser: myst_parser.sphinx_ --- ``` - -```{include} changes.md -``` diff --git a/docs/source/faq.md b/docs/source/faq.md index 0084c182..2ea1c838 100644 --- a/docs/source/faq.md +++ b/docs/source/faq.md @@ -118,7 +118,7 @@ but it is precise...). Then type: ```bash -$ code ~/.cookiecutter_replay/econ-project-templates-0.6.5.json +$ code ~/.cookiecutter_replay/econ-project-templates-0.7.0.json ``` If you are not using VS Code as your editor of choice, adjust the line accordingly. @@ -130,7 +130,7 @@ you have spaces or special characters in your path, you need to adjust your path When done, launch a new shell if necessary and type: ```bash -$ cookiecutter --replay https://github.com/OpenSourceEconomics/econ-project-templates/archive/v0.6.5.zip +$ cookiecutter --replay https://github.com/OpenSourceEconomics/econ-project-templates/archive/v0.7.0.zip ``` (stata_failure_check_erase_log_file)= diff --git a/docs/source/getting_started/cookiecutter_dialogue.md b/docs/source/getting_started/cookiecutter_dialogue.md index e77f2d05..b1f09aff 100644 --- a/docs/source/getting_started/cookiecutter_dialogue.md +++ b/docs/source/getting_started/cookiecutter_dialogue.md @@ -1,11 +1,17 @@ 1. If you are on Windows, please open the Windows Powershell. On Mac or Linux, open a terminal. - Navigate to the parent folder of your future project and type (i.e., copy & paste): + 1. Navigate to the parent folder of your future project. - ```console - $ cookiecutter https://github.com/OpenSourceEconomics/econ-project-templates/archive/v0.6.5.zip - ``` + 1. If you are using conda environments, make sure that you are in the base + environment before proceeding. If in doubt, type `conda deactivate`, possibly + multiple times. + + 1. Type (i.e., copy & paste): + + ```console + cookiecutter https://github.com/OpenSourceEconomics/econ-project-templates/archive/v0.7.0.zip + ``` 1. The dialogue will move you through the installation. **Make sure to keep this page side-by-side during the process because if something is invalid, the whole process @@ -42,14 +48,14 @@ **version** -- The version of your project. - **python_version** -- The python version, tested with 3.9 - 3.11. + **python_version** -- The python version, min 3.10, tested with 3.10 - 3.11. **conda_environment_name** -- Name of your conda environment. This should not be too - long, since you need to type it often. + long, since you need to type it often. Typically just the same as *project_slug*. - **create_conda_environment_at_finish** -- Just accept the default. If you don't, the - same caveat applies as for the *project_slug*. If you really do not want a conda - environment, type "x". + **create_conda_environment_at_finish** -- You can do so for convenience, but often it + is useful to add packages to the environment file first so that it will serve your + needs. **add_python_example** -- Whether to set up the example project in the Python programming language. diff --git a/docs/source/getting_started/preparing_your_system.md b/docs/source/getting_started/preparing_your_system.md index 84be953d..1e41b60e 100644 --- a/docs/source/getting_started/preparing_your_system.md +++ b/docs/source/getting_started/preparing_your_system.md @@ -126,6 +126,11 @@ enable personalized installations. Before you start, install cookiecutter on your system. + ```{warning} If you are using conda environments, make sure that you are in the base + environment before installing cookiecutter (`conda deactivate`, possibly multiple + times). Else you may get a nested environment later on, this can be annoying. + ``` + ```console $ pip install cookiecutter ``` diff --git a/docs/source/index.md b/docs/source/index.md index b90d7481..6a3a685a 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -58,5 +58,6 @@ guides_explanations/index programming_languages/index faq development/index +release_notes zreferences ``` diff --git a/docs/source/release_notes.md b/docs/source/release_notes.md new file mode 100644 index 00000000..ae803bd4 --- /dev/null +++ b/docs/source/release_notes.md @@ -0,0 +1,7 @@ +# Release Notes + +```{include} ../../CHANGES.md +--- +start-line: 1 +--- +``` diff --git a/environment.yml b/environment.yml index b22a5697..9b8ca6ed 100644 --- a/environment.yml +++ b/environment.yml @@ -13,16 +13,14 @@ dependencies: - myst-parser - nbsphinx - pandas - - pdbpp - pip - plotly>=5.13.0 - pre-commit - pydata-sphinx-theme>=0.3.0 - - pytask>=0.2 - pytest - pytest-cookies - pytest-cov - - python + - python=3.11 - setuptools_scm - sphinx - sphinx-autoapi @@ -31,4 +29,4 @@ dependencies: - sphinx-panels - sphinxcontrib-bibtex - toml - - pip: [kaleido] + - pip: [kaleido, pdbp] diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 26d06ab4..efe3a35b 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -92,6 +92,9 @@ def main() -> None: conda_exe = shutil.which("conda") if conda_exe: + print( + "\nStarting to create conda environment, might take a while.", + ) subprocess.run( ( conda_exe, @@ -104,6 +107,7 @@ def main() -> None: check=True, capture_output=True, ) + print("Finished creating conda environment.") else: warnings.warn( "conda environment could not be created since no conda or mamba " diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index ce621361..df7b36e3 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -3,46 +3,65 @@ MODULE_REGEX = r"^[_a-zA-Z][_a-zA-Z0-9]*$" ENVIRON_REGEX = r"^[-_a-zA-Z0-9]*$" -PYTHONVERSION_REGEX = r"^(3)\.(9|10|11)" -PYTHONVERSION_MIN = "3.9" +PYTHON_VERSION_REGEX = r"^(3)\.(11)" +# If bumping this, also bump the version in "test_invalid_python_version" +PYTHON_VERSION_MIN = "3.11" -EXCEPTION_MSG_MODULE_NAME = """ -ERROR: The project slug ({module_name}) is not a valid Python module name. + +class InvalidModuleNameError(Exception): + """Raised when the module name is invalid.""" + + def __init__(self: Exception, module_name: str) -> None: + """Initialize the exception.""" + self.message = f""" + +The project slug ({module_name}) is not a valid Python module name. Please do not use anything other than letters, numbers, and underscores '_'. The first character must not be a number. + """ + super().__init__(self.message) + + +class InvalidEnvironmentNameError(Exception): + """Raised when the environment name is invalid.""" -EXCEPTION_MSG_ENVIRON_NAME = """ -ERROR: The project slug ({environment_name}) is not a valid conda environment name. + def __init__(self: Exception, environment_name: str) -> None: + """Initialize the exception.""" + self.message = f""" +ERROR: The environment name ({environment_name}) is not a valid conda environment name. Please do not use anything other than letters, numbers, underscores '_', and minus signs '-'. """ + super().__init__(self.message) -EXCEPTION_MSG_PYTHONVERSION = """ -ERROR: The python version must be >= {PYTHONVERSION_MIN}, got {pythonversion}. + +class InvalidPythonVersionError(Exception): + """Raised when the Python version not supported.""" + + def __init__(self: Exception, python_version: str) -> None: + """Initialize the exception.""" + self.message = f""" +ERROR: The python version must be >= {PYTHON_VERSION_MIN}, got {python_version}. """ + super().__init__(self.message) def main() -> None: """Apply pre-generation hooks.""" module_name = "{{ cookiecutter.project_slug }}" - if not re.match(MODULE_REGEX, module_name): - raise ValueError(EXCEPTION_MSG_MODULE_NAME.format(module_name)) + raise InvalidModuleNameError(module_name) environment_name = "{{ cookiecutter.conda_environment_name }}" - if not re.match(ENVIRON_REGEX, environment_name): - raise ValueError(EXCEPTION_MSG_ENVIRON_NAME.format(environment_name)) + raise InvalidEnvironmentNameError(environment_name) python_version = "{{ cookiecutter.python_version }}" - - if not re.match(PYTHONVERSION_REGEX, python_version): - raise ValueError( - EXCEPTION_MSG_PYTHONVERSION.format(PYTHONVERSION_MIN, python_version), - ) + if not re.match(PYTHON_VERSION_REGEX, python_version): + raise InvalidPythonVersionError(python_version) if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index d658c8f0..c9501767 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ exclude = [ [tool.ruff.per-file-ignores] "tests/*" = ["S101", "ANN", "D100", "D103"] -"hooks/post_gen_project.py" = ["C901", "PLR0912"] +"hooks/post_gen_project.py" = ["C901", "PLR0912", "T201"] "docs/source/conf.py" = ["DTZ005", "D100"] "docs/source/__init__.py" = ["D104"] "hooks/__init__.py" = ["D104"] diff --git a/tests/test_cookie.py b/tests/test_cookie.py index 10e5e0e5..9c13c52b 100644 --- a/tests/test_cookie.py +++ b/tests/test_cookie.py @@ -8,6 +8,22 @@ conda_exe = _mamba if (_mamba := shutil.which("mamba")) else shutil.which("conda") +def test_invalid_module_name(cookies): + result = cookies.bake(extra_context={"project_slug": "hello-world"}) + assert str(result.exception).startswith("Hook script failed") + + +def test_invalid_environment_name(cookies): + result = cookies.bake(extra_context={"project_slug": "hello-world"}) + assert str(result.exception).startswith("Hook script failed") + + +def test_invalid_python_version(cookies): + result = cookies.bake(extra_context={"python_version": "3.10"}) + assert result.exception is not None + assert str(result.exception).startswith("Hook script failed") + + @pytest.mark.end_to_end() def test_bake_project(cookies): major, minor = sys.version_info[:2] @@ -119,19 +135,14 @@ def test_check_conda_environment_creation_for_all_examples_and_run_all_checks( check=True, ) - # Check linting, but not on the first try since formatters fix stuff. - subprocess.run( - (conda_exe, "run", "-n", env_name, "pre-commit", "run", "--all-files"), - cwd=result.project_path, - check=False, - env={}, - ) - subprocess.run( - (conda_exe, "run", "-n", env_name, "pre-commit", "run", "--all-files"), - cwd=result.project_path, - check=True, - env={}, - ) + # Check linting, but not on the first two tries since formatters fix stuff. + for check in False, False, True: + subprocess.run( + (conda_exe, "run", "-n", env_name, "pre-commit", "run", "--all-files"), + cwd=result.project_path, + check=check, + env={}, + ) subprocess.run( (conda_exe, "run", "-n", env_name, "pytask", "-x"), diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml index 65396f15..ca3d879c 100644 --- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -56,8 +56,8 @@ repos: - --wrap-descriptions - '88' - --blank - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.289 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.292 hooks: - id: ruff # args: @@ -75,7 +75,7 @@ repos: - id: nbqa-black additional_dependencies: [black==23.9.1] - id: nbqa-ruff - additional_dependencies: [ruff==v0.0.289] + additional_dependencies: [ruff==v0.0.292] args: ['--ignore=B018,T201'] - repo: https://github.com/executablebooks/mdformat rev: 0.7.17 @@ -92,7 +92,7 @@ repos: args: [--wrap, '88'] files: (docs/.) - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell args: [--skip="**.ipynb"] diff --git a/{{cookiecutter.project_slug}}/environment.yml b/{{cookiecutter.project_slug}}/environment.yml index de55f330..6d36edb8 100644 --- a/{{cookiecutter.project_slug}}/environment.yml +++ b/{{cookiecutter.project_slug}}/environment.yml @@ -13,18 +13,20 @@ dependencies: - plotly>=5.13.0 - pre-commit{% if cookiecutter.add_julia_example == 'yes' %} - pytask-julia{% endif %} - - pytask-latex - - pytask-parallel{% if cookiecutter.add_r_example == 'yes' %} + - pytask-latex>=0.4.0 + - pytask-parallel>=0.4.0{% if cookiecutter.add_r_example == 'yes' %} - pytask-r{% endif %}{% if cookiecutter.add_stata_example == 'yes' %} - pytask-stata{% endif %} - - pytask>=0.2 + - pytask>=0.4.0 - pytest - pytest-cov - pytest-xdist - python-graphviz - python={{ cookiecutter.python_version }} - pyyaml{% if cookiecutter.add_r_example == 'yes' %} + - plotly-orca - r-plotly + - r-processx - r-reshape2 - r-reticulate - r-webshot diff --git a/{{cookiecutter.project_slug}}/inst/WORDLIST b/{{cookiecutter.project_slug}}/inst/WORDLIST index 91a80e32..6bb4261b 100644 --- a/{{cookiecutter.project_slug}}/inst/WORDLIST +++ b/{{cookiecutter.project_slug}}/inst/WORDLIST @@ -68,7 +68,7 @@ gsppi Hatton Helmut Hennenfent -hhttps +https Hoxby hoxby Hoyt diff --git a/{{cookiecutter.project_slug}}/paper/refs.bib b/{{cookiecutter.project_slug}}/paper/refs.bib index 085159f1..d04e8e66 100644 --- a/{{cookiecutter.project_slug}}/paper/refs.bib +++ b/{{cookiecutter.project_slug}}/paper/refs.bib @@ -129,9 +129,9 @@ @book{Friedl06 @unpublished{GaudeckerEconProjectTemplates, author = {Hans-Martin von Gaudecker}, - note = {\url{https://doi.org/10.5281/zenodo.2533241}}, + note = {\url{https://doi.org/10.5281/zenodo.7780520}}, title = {Templates for Reproducible Research Projects in Economics}, - year = {2019} + year = {2023} } @article{GaudeckerSoestWengstrom11prefhet, diff --git a/{{cookiecutter.project_slug}}/paper/task_paper.py b/{{cookiecutter.project_slug}}/paper/task_paper.py index d2579b1a..35d7070a 100644 --- a/{{cookiecutter.project_slug}}/paper/task_paper.py +++ b/{{cookiecutter.project_slug}}/paper/task_paper.py @@ -16,7 +16,7 @@ options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd"), ), ) - @pytask.mark.task(id=document) + @pytask.task(id=document) def task_compile_document(): """Compile the document specified in the latex decorator.""" @@ -25,7 +25,7 @@ def task_compile_document(): "produces": BLD.parent.resolve() / f"{document}.pdf", } - @pytask.mark.task(id=document, kwargs=kwargs) + @pytask.task(id=document, kwargs=kwargs) def task_copy_to_root(depends_on, produces): """Copy a document to the root directory for easier retrieval.""" shutil.copy(depends_on, produces) diff --git a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/analysis/task_analysis.py b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/analysis/task_analysis.py index e77542d8..591aece6 100644 --- a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/analysis/task_analysis.py +++ b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/analysis/task_analysis.py @@ -1,5 +1,7 @@ """Tasks running the core analyses.""" +from pathlib import Path + {% if cookiecutter.add_python_example == 'yes' %}import pandas as pd {% endif %}import pytask @@ -8,16 +10,17 @@ {% endif %}from {{cookiecutter.project_slug}}.config import BLD, GROUPS, SRC{% if cookiecutter.add_python_example == 'yes' %} from {{cookiecutter.project_slug}}.utilities import read_yaml +fit_model_deps = { + "scripts": [Path("model.py"), Path("predict.py")], + "data": BLD / "python" / "data" / "data_clean.csv", + "data_info": SRC / "data_management" / "data_info.yaml", +} -@pytask.mark.depends_on( - { - "scripts": ["model.py", "predict.py"], - "data": BLD / "python" / "data" / "data_clean.csv", - "data_info": SRC / "data_management" / "data_info.yaml", - }, -) -@pytask.mark.produces(BLD / "python" / "models" / "model.pickle") -def task_fit_model_python(depends_on, produces): + +def task_fit_model_python( + depends_on=fit_model_deps, + produces=BLD / "python" / "models" / "model.pickle", +): """Fit a logistic regression model (Python version).""" data_info = read_yaml(depends_on["data_info"]) data = pd.read_csv(depends_on["data"]) @@ -26,19 +29,17 @@ def task_fit_model_python(depends_on, produces): for group in GROUPS: - kwargs = { - "group": group, - "produces": BLD / "python" / "predictions" / f"{group}.csv", + predict_deps = { + "data": BLD / "python" / "data" / "data_clean.csv", + "model": BLD / "python" / "models" / "model.pickle", } - @pytask.mark.depends_on( - { - "data": BLD / "python" / "data" / "data_clean.csv", - "model": BLD / "python" / "models" / "model.pickle", - }, - ) - @pytask.mark.task(id=group, kwargs=kwargs) - def task_predict_python(depends_on, group, produces): + @pytask.task(id=group) + def task_predict_python( + group=group, + depends_on=predict_deps, + produces=BLD / "python" / "predictions" / f"{group}.csv", + ): """Predict based on the model estimates (Python version).""" model = load_model(depends_on["model"]) data = pd.read_csv(depends_on["data"]) @@ -71,7 +72,7 @@ def task_fit_model_r(): "model": BLD / "r" / "models" / "model.rds", }, ) - @pytask.mark.task(id=group, kwargs=kwargs) + @pytask.task(id=group, kwargs=kwargs) @pytask.mark.r(script=SRC / "analysis" / "predict.r", serializer="yaml") def task_predict_r(): """Predict based on the model estimates (R version)."""{% endif %} diff --git a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/data_management/task_data_management.py b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/data_management/task_data_management.py index 034238b5..b28352d2 100644 --- a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/data_management/task_data_management.py +++ b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/data_management/task_data_management.py @@ -1,22 +1,25 @@ """Tasks for managing the data.""" -{% if cookiecutter.add_python_example == 'yes' %}import pandas as pd -{% endif %}import pytask +from pathlib import Path +{% if cookiecutter.add_python_example == 'yes' %}import pandas as pd +{% endif %}{% if cookiecutter.add_r_example == 'yes' %}import pytask +{% endif %} from {{cookiecutter.project_slug}}.config import BLD, SRC{% if cookiecutter.add_python_example == 'yes' %} from {{cookiecutter.project_slug}}.data_management import clean_data from {{cookiecutter.project_slug}}.utilities import read_yaml +clean_data_deps = { + "scripts": Path("clean_data.py"), + "data_info": SRC / "data_management" / "data_info.yaml", + "data": SRC / "data" / "data.csv", +} -@pytask.mark.depends_on( - { - "scripts": ["clean_data.py"], - "data_info": SRC / "data_management" / "data_info.yaml", - "data": SRC / "data" / "data.csv", - }, -) -@pytask.mark.produces(BLD / "python" / "data" / "data_clean.csv") -def task_clean_data_python(depends_on, produces): + +def task_clean_data_python( + depends_on=clean_data_deps, + produces=BLD / "python" / "data" / "data_clean.csv", +): """Clean the data (Python version).""" data_info = read_yaml(depends_on["data_info"]) data = pd.read_csv(depends_on["data"]) diff --git a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/final/task_final.py b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/final/task_final.py index 46f1f907..3b4cbb0b 100644 --- a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/final/task_final.py +++ b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/final/task_final.py @@ -9,20 +9,18 @@ from {{cookiecutter.project_slug}}.utilities import read_yaml for group in GROUPS: - kwargs = { - "group": group, - "depends_on": {"predictions": BLD / "python" / "predictions" / f"{group}.csv"}, - "produces": BLD / "python" / "figures" / f"smoking_by_{group}.png", + deps = { + "predictions": BLD / "python" / "predictions" / f"{group}.csv", + "data_info": SRC / "data_management" / "data_info.yaml", + "data": BLD / "python" / "data" / "data_clean.csv", } - @pytask.mark.depends_on( - { - "data_info": SRC / "data_management" / "data_info.yaml", - "data": BLD / "python" / "data" / "data_clean.csv", - }, - ) - @pytask.mark.task(id=group, kwargs=kwargs) - def task_plot_results_by_age_python(depends_on, group, produces): + @pytask.task(id=group) + def task_plot_results_by_age_python( + group=group, + depends_on=deps, + produces=BLD / "python" / "figures" / f"smoking_by_{group}.png", + ): """Plot the regression results by age (Python version).""" data_info = read_yaml(depends_on["data_info"]) data = pd.read_csv(depends_on["data"]) @@ -31,9 +29,10 @@ def task_plot_results_by_age_python(depends_on, group, produces): fig.write_image(produces) -@pytask.mark.depends_on(BLD / "python" / "models" / "model.pickle") -@pytask.mark.produces(BLD / "python" / "tables" / "estimation_results.tex") -def task_create_results_table_python(depends_on, produces): +def task_create_results_table_python( + depends_on=BLD / "python" / "models" / "model.pickle", + produces=BLD / "python" / "tables" / "estimation_results.tex", +): """Store a table in LaTeX format with the estimation results (Python version).""" model = load_model(depends_on) table = model.summary().as_latex() @@ -54,7 +53,7 @@ def task_create_results_table_python(depends_on, produces): "data": BLD / "r" / "data" / "data_clean.csv", }, ) - @pytask.mark.task(id=group, kwargs=kwargs) + @pytask.task(id=group, kwargs=kwargs) @pytask.mark.r(script=SRC / "final" / "plot_regression.r", serializer="yaml") def task_plot_results_by_age_r(): """Plot the regression results by age (R version)."""