From 6f474bb9cedd81a91ae32d6eb787a8d3f67a310d Mon Sep 17 00:00:00 2001 From: Ivan Ruiz Manuel <72193617+irm-codebase@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:56:20 +0200 Subject: [PATCH 1/4] add authors and maintainers --- copier.yaml | 60 ++++++++++++--- template/AUTHORS.jinja | 4 +- template/CITATION.cff.jinja | 6 +- ...== 'Apache-2.0' %}LICENSE{% endif %}.jinja | 2 +- tests/template_test.py | 74 +++++++++++++++++++ tests/utils/simple_answers.yaml | 13 +++- 6 files changed, 140 insertions(+), 19 deletions(-) diff --git a/copier.yaml b/copier.yaml index d404f8f..4b10d81 100644 --- a/copier.yaml +++ b/copier.yaml @@ -51,18 +51,56 @@ module_long_name: module_description: type: str help: "Please provide a description of your module." -author_given_name: - type: str - help: "Please provide your given name (e.g., Ursula)." -author_family_name: - type: str - help: "Please provide your family name (e.g., Le Guin)." -author_email: - type: str - help: Please provide your email address. +authors: + type: yaml + multiline: true + help: |- + Please provide a list of module authors (i.e., the people that wrote the software). + These will be listed in licensing files and referenced when citing the software. + + Each author needs given_name, family_name, and email fields: + - given_name: Ursula + family_name: Le Guin + email: ursula.leguin@example.com + validator: >- - {% if not (author_email | regex_search('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+[.][a-zA-Z0-9-.]+$')) %} - "Invalid email address." + {% if authors is not sequence or authors is string or authors | length == 0 %} + Please provide at least one author as a YAML list. + {% else %} + {% for author in authors %} + {% if author is not mapping %} + Author {{ loop.index }} must be a mapping with given_name, family_name, and email. + {% elif not author.given_name or not author.family_name or not author.email %} + Author {{ loop.index }} must include given_name, family_name, and email. + {% elif not (author.email | regex_search('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+[.][a-zA-Z0-9-.]+$')) %} + Invalid email address for author {{ loop.index }}. + {% endif %} + {% endfor %} + {% endif %} +maintainers: + type: yaml + multiline: true + help: |- + Please provide the module maintainers (i.e., the people currently responsible for the software). + + Similar to authors, each needs given_name, family_name, and email: + - given_name: Juan + family_name: Rulfo + email: j.rulfo@example.com + + validator: >- + {% if maintainers is not sequence or maintainers is string or maintainers | length == 0 %} + Please provide at least one maintainer as a YAML list. + {% else %} + {% for maintainer in maintainers %} + {% if maintainer is not mapping %} + Maintainer {{ loop.index }} must be a mapping with given_name, family_name, and email. + {% elif not maintainer.given_name or not maintainer.family_name or not maintainer.email %} + Maintainer {{ loop.index }} must include given_name, family_name, and email. + {% elif not (maintainer.email | regex_search('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+[.][a-zA-Z0-9-.]+$')) %} + Invalid email address for maintainer {{ loop.index }}. + {% endif %} + {% endfor %} {% endif %} github_org: type: str diff --git a/template/AUTHORS.jinja b/template/AUTHORS.jinja index 400f351..72d0956 100644 --- a/template/AUTHORS.jinja +++ b/template/AUTHORS.jinja @@ -2,6 +2,8 @@ This is the list of contributors for copyright purposes. This does not necessarily list everyone who has contributed to this software's code or documentation. For a full contributor list, see: + -{{author_given_name}} {{author_family_name}}, <{{author_email}}> +{% for author in authors %}{{ author.given_name }} {{ author.family_name }}, <{{ author.email }}> +{% endfor %} diff --git a/template/CITATION.cff.jinja b/template/CITATION.cff.jinja index 0e1de2c..a34b6ec 100644 --- a/template/CITATION.cff.jinja +++ b/template/CITATION.cff.jinja @@ -7,5 +7,7 @@ title: "Modelblocks - {{module_short_name}}: {{module_long_name}}" repository: "https://github.com/{{github_org}}/{{module_short_name}}" license: {{license}} authors: - - given-names: {{author_given_name}} - family-names: {{author_family_name}} +{% for author in authors %} - given-names: {{ author.given_name | tojson }} + family-names: {{ author.family_name | tojson }} + email: {{ author.email | tojson }} +{% endfor %} diff --git a/template/{% if license == 'Apache-2.0' %}LICENSE{% endif %}.jinja b/template/{% if license == 'Apache-2.0' %}LICENSE{% endif %}.jinja index 9205df5..261eeb9 100644 --- a/template/{% if license == 'Apache-2.0' %}LICENSE{% endif %}.jinja +++ b/template/{% if license == 'Apache-2.0' %}LICENSE{% endif %}.jinja @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {{ '%Y' | strftime }} AUTHORS + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/tests/template_test.py b/tests/template_test.py index 67b502b..18cb4f9 100644 --- a/tests/template_test.py +++ b/tests/template_test.py @@ -5,9 +5,83 @@ from pathlib import Path import pytest +import yaml from copier import run_copy +class TestTemplateAuthors: + """Build and check author metadata rendering.""" + + def test_multiple_authors_are_rendered( + self, tmp_path, template_path, simple_answers + ): + """Multiple author answers should render in metadata files.""" + answers = deepcopy(simple_answers) + answers["authors"] = [ + { + "given_name": "Ursula", + "family_name": "Le Guin", + "email": "ursula.leguin@example.com", + }, + { + "given_name": "Stanislaw", + "family_name": "Lem", + "email": "s.lem@example.com", + }, + ] + + run_copy( + src_path=str(template_path), + dst_path=str(tmp_path), + data=answers, + vcs_ref="HEAD", + ) + + copier_answers = yaml.safe_load((tmp_path / ".copier-answers.yml").read_text()) + assert copier_answers["authors"] == answers["authors"] + + authors = (tmp_path / "AUTHORS").read_text() + assert "Ursula Le Guin, " in authors + assert "Stanislaw Lem, " in authors + + citation = (tmp_path / "CITATION.cff").read_text() + assert 'given-names: "Ursula"' in citation + assert 'family-names: "Lem"' in citation + assert 'email: "s.lem@example.com"' in citation + + +class TestTemplateMaintainers: + """Build and check maintainer answer rendering.""" + + def test_multiple_maintainers_are_stored( + self, tmp_path, template_path, simple_answers + ): + """Multiple maintainer answers should be stored for documentation.""" + answers = deepcopy(simple_answers) + answers["maintainers"] = [ + { + "given_name": "Juan", + "family_name": "Rulfo", + "email": "j.rulfo@example.com", + }, + { + "given_name": "Toni", + "family_name": "Morrison", + "email": "toni.morrison@example.com", + }, + ] + + run_copy( + src_path=str(template_path), + dst_path=str(tmp_path), + data=answers, + vcs_ref="HEAD", + ) + + copier_answers = yaml.safe_load((tmp_path / ".copier-answers.yml").read_text()) + assert copier_answers["maintainers"] == answers["maintainers"] + + class TestBuiltTemplate: """Build and check the resulting template.""" diff --git a/tests/utils/simple_answers.yaml b/tests/utils/simple_answers.yaml index aab13c1..157081e 100644 --- a/tests/utils/simple_answers.yaml +++ b/tests/utils/simple_answers.yaml @@ -1,8 +1,13 @@ module_short_name: test_module module_long_name: Test module module_description: A simple module to test the template -author_given_name: Tester -author_family_name: McTest -author_email: tester.mctest@example.com +authors: + - given_name: Tester + family_name: McTest + email: tester.mctest@example.com +maintainers: + - given_name: Maintain + family_name: McMaintainer + email: maintain.mcmaintainer@example.com github_org: modelblocks-org -license: +license: "Apache-2.0" From 8e6043d6d97a9a47035541483bdab690261a5cfa Mon Sep 17 00:00:00 2001 From: Ivan Ruiz Manuel <72193617+irm-codebase@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:56:44 +0200 Subject: [PATCH 2/4] rename module names to code and human --- copier.yaml | 10 +++++----- template/.all-contributorsrc.jinja | 2 +- template/AUTHORS.jinja | 4 ++-- template/CITATION.cff.jinja | 4 ++-- template/README.md.jinja | 6 +++--- template/pixi.toml.jinja | 2 +- template/tests/integration/test_config.yaml.jinja | 2 +- .../{% if true %}Snakefile{% endif %}.jinja | 6 +++--- tests/utils/simple_answers.yaml | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/copier.yaml b/copier.yaml index 4b10d81..bed4455 100644 --- a/copier.yaml +++ b/copier.yaml @@ -38,16 +38,16 @@ _templates_suffix: .jinja _answers_file: .copier-answers.yml # === copier user provided === -module_short_name: +module_code_name: type: str - help: Please enter your module's short name as used in snakemake (should be in `snake_case`). This will be folder name within which your module lives. + help: Please enter your module's name as used in code (should be in `snake_case`). This will be used for GitHub and Snakemake access. validator: >- - {% if not (module_short_name | regex_search('^[a-z][a-z0-9_]*$')) %} + {% if not (module_code_name | regex_search('^[a-z][a-z0-9_]*$')) %} "Only lowercase letters, digits and underscores are valid." {% endif %} -module_long_name: +module_human_name: type: str - help: Please enter your module's long name (e.g., PV capacity factors, Hydropower, Heat-pump profiles, etc). + help: Please enter your module's human readable name (e.g., PV capacity factors, Hydropower, Heat-pump profiles, etc). module_description: type: str help: "Please provide a description of your module." diff --git a/template/.all-contributorsrc.jinja b/template/.all-contributorsrc.jinja index 16e4443..3ac1bdf 100644 --- a/template/.all-contributorsrc.jinja +++ b/template/.all-contributorsrc.jinja @@ -1,5 +1,5 @@ { - "projectName": "{{module_short_name}}", + "projectName": "{{module_code_name}}", "projectOwner": "{{github_org}}", "repoType": "github", "repoHost": "https://github.com", diff --git a/template/AUTHORS.jinja b/template/AUTHORS.jinja index 72d0956..fa5f5f2 100644 --- a/template/AUTHORS.jinja +++ b/template/AUTHORS.jinja @@ -2,8 +2,8 @@ This is the list of contributors for copyright purposes. This does not necessarily list everyone who has contributed to this software's code or documentation. For a full contributor list, see: - - + + {% for author in authors %}{{ author.given_name }} {{ author.family_name }}, <{{ author.email }}> {% endfor %} diff --git a/template/CITATION.cff.jinja b/template/CITATION.cff.jinja index a34b6ec..eeb9e09 100644 --- a/template/CITATION.cff.jinja +++ b/template/CITATION.cff.jinja @@ -3,8 +3,8 @@ # https://citation-file-format.github.io/ cff-version: 1.2.0 message: If you use this software or data produced by it, please cite it using the metadata from this file. -title: "Modelblocks - {{module_short_name}}: {{module_long_name}}" -repository: "https://github.com/{{github_org}}/{{module_short_name}}" +title: "Modelblocks - {{module_code_name}}: {{module_human_name}}" +repository: "https://github.com/{{github_org}}/{{module_code_name}}" license: {{license}} authors: {% for author in authors %} - given-names: {{ author.given_name | tojson }} diff --git a/template/README.md.jinja b/template/README.md.jinja index d6cb8fa..ecbd48e 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -1,4 +1,4 @@ -# {{module_long_name}} +# {{module_human_name}} {{module_description}} @@ -39,8 +39,8 @@ We use [`pixi`](https://pixi.sh/) as our package manager for development. Once installed, run the following to clone this repository and install all dependencies. ```shell -git clone git@github.com:{{github_org}}/{{module_short_name}}.git -cd {{module_short_name}} +git clone git@github.com:{{github_org}}/{{module_code_name}}.git +cd {{module_code_name}} pixi install --all ``` diff --git a/template/pixi.toml.jinja b/template/pixi.toml.jinja index 64f4a12..a2e14a3 100644 --- a/template/pixi.toml.jinja +++ b/template/pixi.toml.jinja @@ -1,5 +1,5 @@ [workspace] -name = "{{ module_short_name }}" +name = "{{ module_code_name }}" authors = ["See AUTHORS file"] description = "{{ module_description }}" license = "{{ license }}" diff --git a/template/tests/integration/test_config.yaml.jinja b/template/tests/integration/test_config.yaml.jinja index 0ac4327..df6d354 100644 --- a/template/tests/integration/test_config.yaml.jinja +++ b/template/tests/integration/test_config.yaml.jinja @@ -1,4 +1,4 @@ -{{module_short_name}}: +{{module_code_name}}: dummy_text: >- Configuration values (like this one) are also external to the module! This gives users a lot of flexibility in how they apply your methodology to solve their particular needs. diff --git a/template/tests/integration/{% if true %}Snakefile{% endif %}.jinja b/template/tests/integration/{% if true %}Snakefile{% endif %}.jinja index 1317149..617c374 100644 --- a/template/tests/integration/{% if true %}Snakefile{% endif %}.jinja +++ b/template/tests/integration/{% if true %}Snakefile{% endif %}.jinja @@ -21,9 +21,9 @@ rule create_external_input: # `snakefile:` specifies the module. It can use file paths and special github(...) / gitlab(...) markers # `config`: specifies the module configuration. # `pathvars:` helps you re-wire where the module places files. -module {{module_short_name}}: +module {{module_code_name}}: snakefile: "../../workflow/Snakefile" - config: config["{{module_short_name}}"] + config: config["{{module_code_name}}"] pathvars: # Redirect specific user resources (inputs) user_message=rules.create_external_input.output.text_file, @@ -36,7 +36,7 @@ module {{module_short_name}}: # rename all module rules with a prefix, to avoid naming conflicts. -use rule * from {{module_short_name}} as {{module_short_name}}_* +use rule * from {{module_code_name}} as {{module_code_name}}_* # Request something from the module rule all: diff --git a/tests/utils/simple_answers.yaml b/tests/utils/simple_answers.yaml index 157081e..f045241 100644 --- a/tests/utils/simple_answers.yaml +++ b/tests/utils/simple_answers.yaml @@ -1,5 +1,5 @@ -module_short_name: test_module -module_long_name: Test module +module_code_name: test_module +module_human_name: Test module module_description: A simple module to test the template authors: - given_name: Tester From b0f9ba339ece51c851b283dcb2d870c4459c4b11 Mon Sep 17 00:00:00 2001 From: Ivan Ruiz Manuel <72193617+irm-codebase@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:04:17 +0200 Subject: [PATCH 3/4] Add image HTML example --- template/README.md.jinja | 3 +++ template/figures/module.png | Bin 0 -> 14569 bytes 2 files changed, 3 insertions(+) create mode 100644 template/figures/module.png diff --git a/template/README.md.jinja b/template/README.md.jinja index ecbd48e..b21af00 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -3,6 +3,9 @@ {{module_description}} +

+ +

## About diff --git a/template/figures/module.png b/template/figures/module.png new file mode 100644 index 0000000000000000000000000000000000000000..1a83735d93f8f33f2e447dcb4623138a2d2ca121 GIT binary patch literal 14569 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 Date: Fri, 3 Jul 2026 17:46:14 +0200 Subject: [PATCH 4/4] Improve copier text helpers --- copier.yaml | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/copier.yaml b/copier.yaml index bed4455..c841a71 100644 --- a/copier.yaml +++ b/copier.yaml @@ -40,29 +40,36 @@ _answers_file: .copier-answers.yml # === copier user provided === module_code_name: type: str - help: Please enter your module's name as used in code (should be in `snake_case`). This will be used for GitHub and Snakemake access. + help: | + Please enter your module's name as used in code in `snake_case`. This will be used for GitHub and Snakemake access. + 💡 Core modules should start with "module_" as a convention. + default: module_ validator: >- {% if not (module_code_name | regex_search('^[a-z][a-z0-9_]*$')) %} "Only lowercase letters, digits and underscores are valid." {% endif %} module_human_name: type: str - help: Please enter your module's human readable name (e.g., PV capacity factors, Hydropower, Heat-pump profiles, etc). + help: | + Please enter your module's human readable name (e.g., PV capacity factors, Hydropower, Heat-pump profiles, etc). + 💡 This name will be used in the Modelblocks website, citation files and README documentation. module_description: type: str - help: "Please provide a description of your module." + help: | + Please provide a description of your module. + 💡 These will be used as the README's introduction. authors: type: yaml multiline: true - help: |- + help: | Please provide a list of module authors (i.e., the people that wrote the software). - These will be listed in licensing files and referenced when citing the software. - - Each author needs given_name, family_name, and email fields: + 💡 These will be listed in licensing files and referenced when citing the software. + 💡 Each author needs a given_name, family_name, and email fields. + 💡 Multiple authors are possible (separate them with '-'). + default: - given_name: Ursula family_name: Le Guin email: ursula.leguin@example.com - validator: >- {% if authors is not sequence or authors is string or authors | length == 0 %} Please provide at least one author as a YAML list. @@ -80,14 +87,14 @@ authors: maintainers: type: yaml multiline: true - help: |- + help: | Please provide the module maintainers (i.e., the people currently responsible for the software). - - Similar to authors, each needs given_name, family_name, and email: + 💡 Similar to authors, each needs a given_name, family_name, and email. + 💡 The same person can be both an author and a maintainer. + default: - given_name: Juan family_name: Rulfo email: j.rulfo@example.com - validator: >- {% if maintainers is not sequence or maintainers is string or maintainers | length == 0 %} Please provide at least one maintainer as a YAML list. @@ -104,17 +111,19 @@ maintainers: {% endif %} github_org: type: str - help: >- - Please provide the name of the github account or organisation where - this module will be created (e.g., 'modelblocks-org' in 'github.com/modelblocks-org'). + help: | + Please provide the name of the github account or organisation where this module will be created. + 💡 For example: 'modelblocks-org' in 'github.com/modelblocks-org'. + default: "modelblocks-org" validator: >- {% if not (github_org | regex_search('^[a-zA-Z0-9][a-zA-Z0-9-]*$')) %} "Only lowercase letters, digits, hyphens and underscores are valid." {% endif %} - default: "modelblocks-org" license: type: str - help: "Please choose a license." + help: | + Please choose a license. + 💡 Core modules must use Apache-2.0 as a standard. choices: - "Apache-2.0" - "MIT"