From d73055cc3ef589a9c6c5d72b24a2a23dccd034ff Mon Sep 17 00:00:00 2001 From: wassname Date: Sun, 7 May 2023 15:38:34 +0800 Subject: [PATCH 01/10] Update doc_reqs.sh --- {{ cookiecutter.repo_name }}/requirements/doc_reqs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/{{ cookiecutter.repo_name }}/requirements/doc_reqs.sh b/{{ cookiecutter.repo_name }}/requirements/doc_reqs.sh index b87161d..95a3fc4 100644 --- a/{{ cookiecutter.repo_name }}/requirements/doc_reqs.sh +++ b/{{ cookiecutter.repo_name }}/requirements/doc_reqs.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e -x # This script will document the requirements for multiple conda environments, see ./readme.md for more +# Sometimes I like to do relaxed and strict requirements. The strict requirements lets you debug subtle version errors by asking "gee what exact version did they use". +# The relaxed versioning makes it easy to upgrade # inputs PROJECT_NAMES='{{ cookiecutter.python_interpreter }}' From 63dd6f602d6559567251a43342fe8a701e1621f3 Mon Sep 17 00:00:00 2001 From: wassname Date: Sun, 28 Apr 2024 13:35:31 +0800 Subject: [PATCH 02/10] fix --- {{ cookiecutter.repo_name }}/justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.repo_name }}/justfile b/{{ cookiecutter.repo_name }}/justfile index b758d30..99abd83 100644 --- a/{{ cookiecutter.repo_name }}/justfile +++ b/{{ cookiecutter.repo_name }}/justfile @@ -1,4 +1,4 @@ -package := "{{cookiecutter.package_name}}" +package := "{{cookiecutter.project_name.lower().replace(' ', '_')}}" # put your run commands here app: From 10b39d0e7ded354ccf936f3e4c7d2baaf674afc2 Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Fri, 10 May 2024 15:03:18 +0800 Subject: [PATCH 03/10] Update pyproject.toml --- {{ cookiecutter.repo_name }}/pyproject.toml | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/{{ cookiecutter.repo_name }}/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml index 1e540be..d6e396a 100644 --- a/{{ cookiecutter.repo_name }}/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -8,18 +8,18 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.10,<3.13" -torch = {version = "^2.1.0+cu124", source = "pytorch"} -simple-parsing = "^0.1.4" +# simple-parsing = "^0.1.4" tqdm = "^4.66.1" numpy = "^1.26.1" pandas = "^2.1.1" -lightning = "^2.1.0" matplotlib = "^3.8.0" loguru = "^0.7.2" einops = "^0.7.0" scikit-learn = "^1.3.1" -pytorch-optimizer = "^2.12.0" -torchinfo = "^1.8.0" +# torch = {version = "^2.1.0+cu124", source = "pytorch"} +# lightning = "^2.1.0" +# pytorch-optimizer = "^2.12.0" +# torchinfo = "^1.8.0" # accelerate = "^0.24.1" # transformers = "4.34.0" # accelerate = "^0.24.1" @@ -27,17 +27,19 @@ torchinfo = "^1.8.0" # loguru = "^0.7.2" # einops = "^0.3.1" +[tool.poetry.group.dev.dependencies] +ipykernel = "^6.25.2" +ruff = "^0.1.3" + [[tool.poetry.source]] name = "pytorch" url = "https://download.pytorch.org/whl/cu124" priority = "explicit" - -[tool.poetry.group.dev.dependencies] -ipykernel = "^6.25.2" -ruff = "^0.1.3" -pylama = "^8.4.1" - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[virtualenvs] +create = true +in-project = true From b0008772b145e8d84394b2c19bc6a5be9787cdc3 Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Fri, 10 May 2024 15:03:46 +0800 Subject: [PATCH 04/10] Update pyproject.toml --- {{ cookiecutter.repo_name }}/pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/{{ cookiecutter.repo_name }}/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml index d6e396a..cd64e67 100644 --- a/{{ cookiecutter.repo_name }}/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -8,14 +8,14 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.10,<3.13" -# simple-parsing = "^0.1.4" -tqdm = "^4.66.1" numpy = "^1.26.1" pandas = "^2.1.1" matplotlib = "^3.8.0" -loguru = "^0.7.2" -einops = "^0.7.0" scikit-learn = "^1.3.1" +loguru = "^0.7.2" +tqdm = "^4.66.1" +# einops = "^0.7.0" +# simple-parsing = "^0.1.4" # torch = {version = "^2.1.0+cu124", source = "pytorch"} # lightning = "^2.1.0" # pytorch-optimizer = "^2.12.0" From 379857070b91626795457d3a13f2d4a5f3c0786a Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Sun, 9 Jun 2024 15:51:45 +0800 Subject: [PATCH 05/10] Update README.md --- README.md | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3f707fc..1498d97 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Cookiecutter Data Science - Conda +# Cookiecutter Data Science - using poetry and justfiles _A logical, reasonably standardized, but flexible project structure for doing and sharing data science work._ @@ -8,21 +8,13 @@ _A logical, reasonably standardized, but flexible project structure for doing an ### Requirements to use the cookiecutter template: ----------- - - Python 2.7 or 3.5 + - Python 3.9+ - [Cookiecutter Python package](http://cookiecutter.readthedocs.org/en/latest/installation.html) >= 1.4.0: This can be installed with pip by or conda depending on how you manage your Python packages: ``` bash $ pip install cookiecutter ``` -or - -``` bash -$ conda config --add channels conda-forge -$ conda install cookiecutter -``` - - ### To start a new project, run: ------------ @@ -38,7 +30,7 @@ $ conda install cookiecutter The directory structure of your new project looks like this: ``` -├── Makefile <- Makefile with commands like `make data` or `make train` +├── justfile <- justfile with commands like `just data` or `just train` ├── README.md <- The top-level README for developers using this project. ├── data │ ├── interim <- Intermediate data that has been transformed. @@ -47,11 +39,11 @@ The directory structure of your new project looks like this: │ ├── models <- Trained and serialized models, model predictions, or model summaries │ -├── notebooks <- Jupyter notebooks. Naming convention is a number (for ordering), +├── nbs <- Jupyter notebooks. Naming convention is a number (for ordering), │ the creator's initials, and a short `-` delimited description, e.g. │ `1.0-jqp-initial-data-exploration`. │ -├── requirements <- The requirements directory for reproducing the analysis environment +├── pypoetry.toml <- The requirements directory for reproducing the analysis environment │ ├── src <- Source code for use in this project. │ ├── __init__.py <- Makes src a Python module @@ -79,9 +71,4 @@ We welcome contributions! [See the docs for guidelines](https://drivendata.githu ### Installing development requirements ------------ - pip install -r requirements.txt - -### Running the tests ------------- - - py.test tests + poetry install From bb1644ff645ea43c94fc4df7e0ac68d59db4cb4c Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Sun, 9 Jun 2024 16:10:28 +0800 Subject: [PATCH 06/10] tidy --- data/.gitkeep | 0 tests/conftest.py | 47 -------- tests/test_creation.py | 119 ------------------- {{ cookiecutter.repo_name }}/.gitignore | 14 ++- {{ cookiecutter.repo_name }}/README.md | 1 - {{ cookiecutter.repo_name }}/justfile | 10 ++ {{ cookiecutter.repo_name }}/pyproject.toml | 3 +- {{ cookiecutter.repo_name }}/research_log.md | 3 + 8 files changed, 23 insertions(+), 174 deletions(-) create mode 100644 data/.gitkeep delete mode 100644 tests/conftest.py delete mode 100644 tests/test_creation.py create mode 100644 {{ cookiecutter.repo_name }}/research_log.md diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 8acbfb2..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import pytest -import shutil -from pathlib import Path -from cookiecutter import main - -CCDS_ROOT = Path(__file__).parents[1].resolve() - -args = { - 'project_name': 'DrivenData', - 'author_name': 'DrivenData', - 'open_source_license': 'BSD-3-Clause', - 'python_interpreter': 'python' - } - - -def system_check(basename): - platform = sys.platform - if 'linux' in platform: - basename = basename.lower() - return basename - - -@pytest.fixture(scope='class', params=[{}, args]) -def default_baked_project(tmpdir_factory, request): - temp = tmpdir_factory.mktemp('data-project') - out_dir = Path(temp).resolve() - - pytest.param = request.param - main.cookiecutter( - str(CCDS_ROOT), - no_input=True, - extra_context=pytest.param, - output_dir=out_dir - ) - - pn = pytest.param.get('project_name') or 'project_name' - - # project name gets converted to lower case on Linux but not Mac - pn = system_check(pn) - - proj = out_dir / pn - request.cls.path = proj - yield - - # cleanup after - shutil.rmtree(out_dir) \ No newline at end of file diff --git a/tests/test_creation.py b/tests/test_creation.py deleted file mode 100644 index 59bbc75..0000000 --- a/tests/test_creation.py +++ /dev/null @@ -1,119 +0,0 @@ -import os -import pytest -from subprocess import check_output -from conftest import system_check - - -def no_curlies(filepath): - """ Utility to make sure no curly braces appear in a file. - That is, was Jinja able to render everything? - """ - with open(filepath, 'r') as f: - data = f.read() - - template_strings = [ - '{{', - '}}', - '{%', - '%}' - ] - - template_strings_in_file = [s in data for s in template_strings] - return not any(template_strings_in_file) - - -@pytest.mark.usefixtures("default_baked_project") -class TestCookieSetup(object): - def test_project_name(self): - project = self.path - if pytest.param.get('project_name'): - name = system_check('DrivenData') - assert project.name == name - else: - assert project.name == 'project_name' - - def test_author(self): - setup_ = self.path / 'setup.py' - args = ['python', str(setup_), '--author'] - p = check_output(args).decode('ascii').strip() - if pytest.param.get('author_name'): - assert p == 'DrivenData' - else: - assert p == 'Your name (or your organization/company/team)' - - def test_readme(self): - readme_path = self.path / 'README.md' - assert readme_path.exists() - assert no_curlies(readme_path) - # if pytest.param.get('project_name'): - # with open(readme_path) as fin: - # assert 'DrivenData' == next(fin).strip() - - def test_setup(self): - setup_ = self.path / 'setup.py' - args = ['python', str(setup_), '--version'] - p = check_output(args).decode('ascii').strip() - assert p == '0.1.0' - - # def test_license(self): - # license_path = self.path / 'LICENSE' - # assert license_path.exists() - # assert no_curlies(license_path) - - # def test_license_type(self): - # setup_ = self.path / 'setup.py' - # args = ['python', str(setup_), '--license'] - # p = check_output(args).decode('ascii').strip() - # if pytest.param.get('open_source_license'): - # assert p == 'BSD-3' - # else: - # assert p == 'MIT' - - def test_requirements(self): - reqs_path = self.path / 'requirements'/ 'environment.yaml' - assert reqs_path.exists() - assert no_curlies(reqs_path) - # if pytest.param.get('python_interpreter'): - # with open(reqs_path) as fin: - # lines = list(map(lambda x: x.strip(), fin.readlines())) - # assert 'pathlib2' in lines - - def test_makefile(self): - makefile_path = self.path / 'Makefile' - assert makefile_path.exists() - assert no_curlies(makefile_path) - - def test_folders(self): - expected_dirs = [ - 'data', - # 'data/external', - 'data/interim', - 'data/processed', - 'data/raw', - # 'docs', - 'outputs', - 'notebooks', - # 'references', - # 'reports', - # 'reports/figures', - 'drivendata', - 'drivendata/data', - 'drivendata/features', - 'drivendata/models', - 'drivendata/visualization', - ] - - ignored_dirs = [ - str(self.path) - ] - - abs_expected_dirs = [str(self.path / d) for d in expected_dirs] - abs_dirs, _, _ = list(zip(*os.walk(self.path))) - # if pytest.param.get('project_name'): - # print('proj', pytest.param.get('project_name', 'project_name')) - # print(abs_dirs) - # print(set(abs_expected_dirs + ignored_dirs)) - # 1/0 - # print(set(abs_expected_dirs + ignored_dirs) - set(abs_dirs)) - assert len(set(abs_expected_dirs + ignored_dirs) - set(abs_dirs)) == 0 - diff --git a/{{ cookiecutter.repo_name }}/.gitignore b/{{ cookiecutter.repo_name }}/.gitignore index d7c9832..83ff7b0 100644 --- a/{{ cookiecutter.repo_name }}/.gitignore +++ b/{{ cookiecutter.repo_name }}/.gitignore @@ -1,3 +1,11 @@ + +# exclude data from source control by default +/data/ +/outputs/ + +# DotEnv configuration +.env + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -56,9 +64,6 @@ docs/_build/ # PyBuilder target/ -# DotEnv configuration -.env - # Database *.db *.rdb @@ -75,9 +80,6 @@ target/ # Jupyter NB Checkpoints .ipynb_checkpoints/ -# exclude data from source control by default -/data/ - # Mac OS-specific storage files .DS_Store diff --git a/{{ cookiecutter.repo_name }}/README.md b/{{ cookiecutter.repo_name }}/README.md index b2228c2..8a3e3a3 100644 --- a/{{ cookiecutter.repo_name }}/README.md +++ b/{{ cookiecutter.repo_name }}/README.md @@ -11,7 +11,6 @@ │   ├── 20_interim <- Intermediate data that has been transformed. │   └── 10_raw <- The original, immutable data dump. │ - │ ├── nbs <- Jupyter notebooks. Namiwith creator's initials, a number (for ordering), and short `-` delimited description, e.g. │ `jqp-1.0-initial-data-exploration`. │ diff --git a/{{ cookiecutter.repo_name }}/justfile b/{{ cookiecutter.repo_name }}/justfile index 99abd83..982e1f3 100644 --- a/{{ cookiecutter.repo_name }}/justfile +++ b/{{ cookiecutter.repo_name }}/justfile @@ -1,5 +1,15 @@ +# see https://cheatography.com/linux-china/cheat-sheets/justfile/ + +set dotenv-load + +# Export all just variables as environment variables. +set export + package := "{{cookiecutter.project_name.lower().replace(' ', '_')}}" +[private] +default: @just --list + # put your run commands here app: echo "hello world" diff --git a/{{ cookiecutter.repo_name }}/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml index cd64e67..36cc6fe 100644 --- a/{{ cookiecutter.repo_name }}/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -7,7 +7,7 @@ license = "MIT" readme = "README.md" [tool.poetry.dependencies] -python = ">=3.10,<3.13" +python = ">=3.10" numpy = "^1.26.1" pandas = "^2.1.1" matplotlib = "^3.8.0" @@ -32,6 +32,7 @@ ipykernel = "^6.25.2" ruff = "^0.1.3" [[tool.poetry.source]] +# pytorch cuda needs to compe from another source https://python-poetry.org/docs/dependency-specification/#source-dependencies name = "pytorch" url = "https://download.pytorch.org/whl/cu124" priority = "explicit" diff --git a/{{ cookiecutter.repo_name }}/research_log.md b/{{ cookiecutter.repo_name }}/research_log.md new file mode 100644 index 0000000..cf787de --- /dev/null +++ b/{{ cookiecutter.repo_name }}/research_log.md @@ -0,0 +1,3 @@ +# 2024-06-09 16:05:45 + +Started project using cookiecutter data science project template. From 19d792d686a80993783772c7a6723618dae706e5 Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Thu, 13 Jun 2024 07:41:30 +0800 Subject: [PATCH 07/10] cite and rewrite --- {{ cookiecutter.repo_name }}/README.md | 73 +++++++++++++++----------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/{{ cookiecutter.repo_name }}/README.md b/{{ cookiecutter.repo_name }}/README.md index 8a3e3a3..2074780 100644 --- a/{{ cookiecutter.repo_name }}/README.md +++ b/{{ cookiecutter.repo_name }}/README.md @@ -2,48 +2,29 @@ {{cookiecutter.description}} -## Project Organization - ├── Justfile <- Makefile with commands like `make data` or `make train` - ├── README.md <- The top-level README for developers using this project. - ├── data - │   ├── 30_processed <- The final, canonical data sets for modeling. - │   ├── 20_interim <- Intermediate data that has been transformed. - │   └── 10_raw <- The original, immutable data dump. - │ - ├── nbs <- Jupyter notebooks. Namiwith creator's initials, a number (for ordering), and short `-` delimited description, e.g. - │ `jqp-1.0-initial-data-exploration`. - │ - ├── pyproject.toml <- defines project dependencies and build configuration - ├── src <- Source code for use in this project. - │   ├── __init__.py <- Makes src a Python module - │ │ - │   ├── data <- Scripts to download or generate data - │   │   └── make_dataset.py - │ │ - │   ├── features <- Scripts to turn raw data into features for modeling - │   │   └── build_features.py - │ │ - │   ├── models <- Scripts to train models and then use trained models to make - │ │ │ predictions - │   │   ├── predict_model.py - │   │   └── train_model.py - │ │ - │   └── visualization <- Scripts to create exploratory and results oriented visualizations -    └── visualize.py +Project status: TODO + +Project plan: + +- [x] Init +- [ ] Fill out README +- [ ] ??? +- [ ] Profit ## Install requirements -This project uses poetry for requirement and is set up for torch using cuda. -``` +This project uses [poetry](https://python-poetry.org/) for requirement and is set up for torch using cuda. +~~~ poetry install -``` +~~~ ## How to get data TODO document how to get the data + ## How to run This project uses [just](https://github.com/casey/just) @@ -52,6 +33,36 @@ This project uses [just](https://github.com/casey/just) just --list ~~~ + +## Project Organization + +Note this project uses + +- [Justfile](https://github.com/casey/just): Command runner with commands like `just data` or `just train` +- data: [data directory ](https://cookiecutter-data-science.drivendata.org/#directory-structure) + - ./10_raw <- The original, immutable data dump. + - ./20_interim <- Intermediate data that has been transformed. + - ./30_processed <- The final, canonical data sets for modeling. +- nbs: upyter notebooks. Name with creator's initials, a number (for ordering), and short `-` delimited description, e.g. `jqp-1.0-initial-data-exploration`. +- pyproject.toml: defines poetry project dependencies and build configuration +- {{cookiecutter.project_name}}: Source code for use in this project. + + +## How to cite + +~~~bibtext +@software{wassname2024{{ cookiecutter.project_name.lower().replace(' ', '_') }, + author = {Clark, M.J.}, + title = { {{cookiecutter.project_name}} }, + year = {2024}, + publisher = {GitHub}, + journal = {GitHub repository}, + url = {https://github.com/wassname/{{ cookiecutter.project_name.lower().replace(' ', '_') }} }, + commit = {} +} +~~~ + + --------

Project based on the cookiecutter data science project template. #cookiecutterdatascience

From 91c82208680378422c32972ea377c49a8d81b920 Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Sat, 15 Jun 2024 20:21:55 +0800 Subject: [PATCH 08/10] mv --- .../{research_log.md => research_journal.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {{ cookiecutter.repo_name }}/{research_log.md => research_journal.md} (100%) diff --git a/{{ cookiecutter.repo_name }}/research_log.md b/{{ cookiecutter.repo_name }}/research_journal.md similarity index 100% rename from {{ cookiecutter.repo_name }}/research_log.md rename to {{ cookiecutter.repo_name }}/research_journal.md From f01894707202bc96c6b95b986b233de4d5579c9d Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Sat, 15 Jun 2024 20:23:22 +0800 Subject: [PATCH 09/10] dl --- .../features/.gitkeep | 0 .../features/__init__.py | 0 .../features/build_features.py | 0 .../models/predict_model.py | 0 .../models/train_model.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 {{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/.gitkeep delete mode 100644 {{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/__init__.py delete mode 100644 {{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/build_features.py delete mode 100644 {{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/predict_model.py delete mode 100644 {{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/train_model.py diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/.gitkeep b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/__init__.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/build_features.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/features/build_features.py deleted file mode 100644 index e69de29..0000000 diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/predict_model.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/predict_model.py deleted file mode 100644 index e69de29..0000000 diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/train_model.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name.lower().replace(' ', '_') }}/models/train_model.py deleted file mode 100644 index e69de29..0000000 From 46c361d012ac0a86d5853ddb27d3f5803d932895 Mon Sep 17 00:00:00 2001 From: Michael J Clark Date: Fri, 21 Jun 2024 09:43:05 +0800 Subject: [PATCH 10/10] fix syntx --- {{ cookiecutter.repo_name }}/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.repo_name }}/README.md b/{{ cookiecutter.repo_name }}/README.md index 2074780..d6ff058 100644 --- a/{{ cookiecutter.repo_name }}/README.md +++ b/{{ cookiecutter.repo_name }}/README.md @@ -51,7 +51,7 @@ Note this project uses ## How to cite ~~~bibtext -@software{wassname2024{{ cookiecutter.project_name.lower().replace(' ', '_') }, +@software{wassname2024{{ cookiecutter.project_name.lower().replace(' ', '_') }}, author = {Clark, M.J.}, title = { {{cookiecutter.project_name}} }, year = {2024},