From b5db20016556c225086c0bcc8b87dd0a319457db Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Mon, 12 Jul 2021 13:58:52 +0200
Subject: [PATCH 01/11] add author information (#78)

---
 tests/input_files/config.mutliple_lanes.yml | 2 ++
 tests/input_files/config.yaml               | 2 ++
 tests/input_files/config_alfa.yaml          | 2 ++
 workflow/Snakefile                          | 4 ++++
 4 files changed, 10 insertions(+)

diff --git a/tests/input_files/config.mutliple_lanes.yml b/tests/input_files/config.mutliple_lanes.yml
index 3d04a01..ada2c6b 100644
--- a/tests/input_files/config.mutliple_lanes.yml
+++ b/tests/input_files/config.mutliple_lanes.yml
@@ -10,4 +10,6 @@
   report_description: "No description provided by user"
   report_logo: "../../images/logo.128px.png"
   report_url: "https://zavolan.biozentrum.unibas.ch/"
+  author_name: "NA"
+  author_email: "NA"
 ...
diff --git a/tests/input_files/config.yaml b/tests/input_files/config.yaml
index 853a8a7..f7a7410 100644
--- a/tests/input_files/config.yaml
+++ b/tests/input_files/config.yaml
@@ -10,4 +10,6 @@
   report_description: "No description provided by user"
   report_logo: "../../images/logo.128px.png"
   report_url: "https://zavolan.biozentrum.unibas.ch/"
+  author_name: "NA"
+  author_email: "NA"
 ...
diff --git a/tests/input_files/config_alfa.yaml b/tests/input_files/config_alfa.yaml
index cdcfb8b..60c1e0a 100644
--- a/tests/input_files/config_alfa.yaml
+++ b/tests/input_files/config_alfa.yaml
@@ -9,4 +9,6 @@
   report_description: "No description provided by user"
   report_logo: "../../images/logo.128px.png"
   report_url: "https://zavolan.biozentrum.unibas.ch/"
+  author_name: "NA"
+  author_email: "NA"
 ...
diff --git a/workflow/Snakefile b/workflow/Snakefile
index d46c511..5f2434e 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -1547,6 +1547,8 @@ rule prepare_multiqc_config:
         logo_path = config['report_logo'],
         multiqc_intro_text = config['report_description'],
         url = config['report_url'],
+        author_name = config['author_name'],
+        author_email = config['author_email'],
         additional_params = parse_rule_config(
             rule_config,
             current_rule=current_rule,
@@ -1572,6 +1574,8 @@ rule prepare_multiqc_config:
         --intro-text '{params.multiqc_intro_text}' \
         --custom-logo {params.logo_path} \
         --url '{params.url}' \
+        --author-name {params.author_name} \
+        --author-email {params.author_email} \
         {params.additional_params}) \
         1> {log.stdout} 2> {log.stderr}"
 
-- 
GitLab


From ef68b7658b99c69e52f8a51736e0af03e2e969db Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Tue, 13 Jul 2021 11:58:31 +0200
Subject: [PATCH 02/11] validate config on required and optional fields #174

---
 tests/input_files/config.yaml | 13 ++++++-----
 workflow/Snakefile            | 41 ++++++++++++++++++++++++++++++-----
 2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/tests/input_files/config.yaml b/tests/input_files/config.yaml
index f7a7410..f3cb261 100644
--- a/tests/input_files/config.yaml
+++ b/tests/input_files/config.yaml
@@ -1,4 +1,5 @@
 ---
+  # Required fields
   samples: "../input_files/samples.tsv"
   rule_config: "../input_files/rule_config.yaml"
   output_dir: "results"
@@ -7,9 +8,11 @@
   salmon_indexes: "results/salmon_indexes"
   star_indexes: "results/star_indexes"
   alfa_indexes: "results/alfa_indexes"
-  report_description: "No description provided by user"
-  report_logo: "../../images/logo.128px.png"
-  report_url: "https://zavolan.biozentrum.unibas.ch/"
-  author_name: "NA"
-  author_email: "NA"
+  # Optional fields
+  optional:
+    report_description: "No description provided by user"
+    report_logo: "../../images/logo.128px.png"
+    report_url: "https://zavolan.biozentrum.unibas.ch/"
+    author_name: "NA"
+    author_email: "NA"
 ...
diff --git a/workflow/Snakefile b/workflow/Snakefile
index 5f2434e..b5e295d 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -17,6 +17,37 @@ samples_table = pd.read_csv(
     sep="\t",
 )
 
+# Validate config with template config
+template_config_path = os.path.join(
+            workflow.current_basedir, 
+            '..',
+            'tests', 
+            'input_files', 
+            'config.yaml')
+try:
+    with open(template_config_path) as _file:
+        template_config = yaml.safe_load(_file)
+    logger.info(f"Loaded template config from {template_config_path}.")
+    # Check if config contains required fields in example config
+    for key in template_config:
+        if key != 'optional':
+            assert key in config
+except FileNotFoundError:
+    logger.error(f"No config file found at {template_config_path}! ")
+    raise
+except AssertionError:
+    logger.error(f"Required config fields from {template_config_path} do not match {config.keys()}")
+    raise
+# Check if optional field available
+if 'optional' not in config:
+    config['optional'] = {}
+# Check optional fields and include in config if not present
+for optkey, value in template_config['optional'].items():
+    if optkey not in config['optional']:
+        config['optional'][optkey] = value
+        logger.info(f"Added optional field: \"{optkey}\" with value: \"{value}\" to config.")
+
+
 # Parse YAML rule config file
 if 'rule_config' in config and config['rule_config']:
     try:
@@ -1544,11 +1575,11 @@ rule prepare_multiqc_config:
             "multiqc_config.yaml")
 
     params:
-        logo_path = config['report_logo'],
-        multiqc_intro_text = config['report_description'],
-        url = config['report_url'],
-        author_name = config['author_name'],
-        author_email = config['author_email'],
+        logo_path = config['optional']['report_logo'],
+        multiqc_intro_text = config['optional']['report_description'],
+        url = config['optional']['report_url'],
+        author_name = config['optional']['author_name'],
+        author_email = config['optional']['author_email'],
         additional_params = parse_rule_config(
             rule_config,
             current_rule=current_rule,
-- 
GitLab


From 1e5e058dc91f1d2dbe1da88e5f5f266fe3eec771 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Tue, 13 Jul 2021 14:31:43 +0200
Subject: [PATCH 03/11] adjust all config files and test cases to new optional
 field.

---
 scripts/prepare_inputs.py                     |  7 +++---
 tests/input_files/config.mutliple_lanes.yml   | 11 +++++-----
 tests/input_files/config.yaml                 |  2 +-
 tests/input_files/config_alfa.yaml            | 22 +++++++++----------
 .../expected_output.md5                       |  2 +-
 workflow/Snakefile                            |  8 +++----
 6 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/scripts/prepare_inputs.py b/scripts/prepare_inputs.py
index 426902a..e47fa3d 100755
--- a/scripts/prepare_inputs.py
+++ b/scripts/prepare_inputs.py
@@ -678,9 +678,10 @@ def main(args):
   salmon_indexes: "{salmon_indexes}"
   star_indexes: "{star_indexes}"
   alfa_indexes: "{alfa_indexes}"
-  report_description: "{args.description}"
-  report_logo: "{args.logo}"
-  report_url: "{args.url}"
+  optional:
+    report_description: "{args.description}"
+    report_logo: "{args.logo}"
+    report_url: "{args.url}"
 ...
 '''
     args.config_file.write(config_file_content)
diff --git a/tests/input_files/config.mutliple_lanes.yml b/tests/input_files/config.mutliple_lanes.yml
index ada2c6b..016692d 100644
--- a/tests/input_files/config.mutliple_lanes.yml
+++ b/tests/input_files/config.mutliple_lanes.yml
@@ -1,15 +1,14 @@
 ---
   samples: "../input_files/samples.multiple_lanes.tsv"
-  rule_config: "../input_files/rule_config.yaml"
   output_dir: "results"
   log_dir: "logs"
   kallisto_indexes: "results/kallisto_indexes"
   salmon_indexes: "results/salmon_indexes"
   star_indexes: "results/star_indexes"
   alfa_indexes: "results/alfa_indexes"
-  report_description: "No description provided by user"
-  report_logo: "../../images/logo.128px.png"
-  report_url: "https://zavolan.biozentrum.unibas.ch/"
-  author_name: "NA"
-  author_email: "NA"
+  optional:
+    rule_config: "../input_files/rule_config.yaml"
+    report_description: "No description provided by user"
+    report_logo: "../../images/logo.128px.png"
+    report_url: "https://zavolan.biozentrum.unibas.ch/"
 ...
diff --git a/tests/input_files/config.yaml b/tests/input_files/config.yaml
index f3cb261..54edf9c 100644
--- a/tests/input_files/config.yaml
+++ b/tests/input_files/config.yaml
@@ -1,7 +1,6 @@
 ---
   # Required fields
   samples: "../input_files/samples.tsv"
-  rule_config: "../input_files/rule_config.yaml"
   output_dir: "results"
   log_dir: "logs"
   kallisto_indexes: "results/kallisto_indexes"
@@ -10,6 +9,7 @@
   alfa_indexes: "results/alfa_indexes"
   # Optional fields
   optional:
+    rule_config: "../input_files/rule_config.yaml"
     report_description: "No description provided by user"
     report_logo: "../../images/logo.128px.png"
     report_url: "https://zavolan.biozentrum.unibas.ch/"
diff --git a/tests/input_files/config_alfa.yaml b/tests/input_files/config_alfa.yaml
index 60c1e0a..06decc6 100644
--- a/tests/input_files/config_alfa.yaml
+++ b/tests/input_files/config_alfa.yaml
@@ -1,14 +1,14 @@
 ---
   samples: "../input_files/samples_alfa.tsv"
-  output_dir: "results/"
-  log_dir: "logs/"
-  kallisto_indexes: "results/kallisto_indexes/"
-  salmon_indexes: "results/salmon_indexes/"
-  star_indexes: "results/star_indexes/"
-  alfa_indexes: "results/alfa_indexes/"
-  report_description: "No description provided by user"
-  report_logo: "../../images/logo.128px.png"
-  report_url: "https://zavolan.biozentrum.unibas.ch/"
-  author_name: "NA"
-  author_email: "NA"
+  output_dir: "results"
+  log_dir: "logs"
+  kallisto_indexes: "results/kallisto_indexes"
+  salmon_indexes: "results/salmon_indexes"
+  star_indexes: "results/star_indexes"
+  alfa_indexes: "results/alfa_indexes"
+  optional:
+    rule_config: "../input_files/rule_config.yaml"
+    report_description: "No description provided by user"
+    report_logo: "../../images/logo.128px.png"
+    report_url: "https://zavolan.biozentrum.unibas.ch/"
 ...
diff --git a/tests/test_scripts_prepare_inputs_table/expected_output.md5 b/tests/test_scripts_prepare_inputs_table/expected_output.md5
index 53afed5..dc555cc 100644
--- a/tests/test_scripts_prepare_inputs_table/expected_output.md5
+++ b/tests/test_scripts_prepare_inputs_table/expected_output.md5
@@ -1,2 +1,2 @@
-40bd0f0fcecdd0d9bc932f63c2811478  config.yaml
+90e90bb60335a2e17cd40cbf058af7b7  config.yaml
 c8dcc5a203e9046806c4090525960151  samples.tsv
diff --git a/workflow/Snakefile b/workflow/Snakefile
index b5e295d..e5d270b 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -49,13 +49,13 @@ for optkey, value in template_config['optional'].items():
 
 
 # Parse YAML rule config file
-if 'rule_config' in config and config['rule_config']:
+if 'rule_config' in config['optional'] and config['optional']['rule_config']:
     try:
-        with open(config['rule_config']) as _file:
+        with open(config['optional']['rule_config']) as _file:
             rule_config = yaml.safe_load(_file)
-        logger.info(f"Loaded rule_config from {config['rule_config']}.")
+        logger.info(f"Loaded rule_config from {config['optional']['rule_config']}.")
     except FileNotFoundError:
-        logger.error(f"No rule config file found at {config['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
+        logger.error(f"No rule config file found at {config['optional']['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
         raise
 else:
     rule_config = {}
-- 
GitLab


From efa866595c1aec6a089a8f1e2efd57e142de3da4 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 09:59:24 +0200
Subject: [PATCH 04/11] Report missing required keys, restructure rule config
 handling.

---
 workflow/Snakefile | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/workflow/Snakefile b/workflow/Snakefile
index e5d270b..346f081 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -28,36 +28,37 @@ try:
     with open(template_config_path) as _file:
         template_config = yaml.safe_load(_file)
     logger.info(f"Loaded template config from {template_config_path}.")
-    # Check if config contains required fields in example config
-    for key in template_config:
-        if key != 'optional':
-            assert key in config
 except FileNotFoundError:
     logger.error(f"No config file found at {template_config_path}! ")
     raise
-except AssertionError:
-    logger.error(f"Required config fields from {template_config_path} do not match {config.keys()}")
-    raise
+# Check if config contains required fields in example config
+missing = [key for key in template_config if key not in config and key != 'optional']
+if missing:
+    err_msg = f"Required keys missing: {missing}"
+    logger.error(err_msg)
+    raise ValueError(err_msg)
 # Check if optional field available
-if 'optional' not in config:
+if 'optional' not in config or config['optional'] != dict:
+    logger.info(f'No "optional" field found or no valid configuration for config.yaml.')
     config['optional'] = {}
 # Check optional fields and include in config if not present
 for optkey, value in template_config['optional'].items():
     if optkey not in config['optional']:
         config['optional'][optkey] = value
-        logger.info(f"Added optional field: \"{optkey}\" with value: \"{value}\" to config.")
+        logger.info(f'Set default value for optional parameter "{optkey}" to : "{value}"')
 
 
 # Parse YAML rule config file
-if 'rule_config' in config['optional'] and config['optional']['rule_config']:
-    try:
-        with open(config['optional']['rule_config']) as _file:
-            rule_config = yaml.safe_load(_file)
-        logger.info(f"Loaded rule_config from {config['optional']['rule_config']}.")
-    except FileNotFoundError:
-        logger.error(f"No rule config file found at {config['optional']['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
-        raise
-else:
+try:
+    with open(config['optional']['rule_config']) as _file:
+        rule_config = yaml.safe_load(_file)
+    logger.info(f"Loaded rule_config from {config['optional']['rule_config']}.")
+except TypeError:
+    logger.error(f'No string supplied at field "rule_config", but: {config["optional"]["rule_config"]}')
+except FileNotFoundError:
+    logger.error(f"No rule config file found at {config['optional']['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
+    raise
+except KeyError:
     rule_config = {}
     logger.warning(f"No rule config specified: using default values for all tools.")
 
-- 
GitLab


From 3baa76e21f951eb7b8e33036bb2c62bbcc2cbe78 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 10:34:53 +0200
Subject: [PATCH 05/11] correct error to create empty optional dict.

---
 workflow/Snakefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/workflow/Snakefile b/workflow/Snakefile
index 346f081..8ffa423 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -38,8 +38,8 @@ if missing:
     logger.error(err_msg)
     raise ValueError(err_msg)
 # Check if optional field available
-if 'optional' not in config or config['optional'] != dict:
-    logger.info(f'No "optional" field found or no valid configuration for config.yaml.')
+if 'optional' not in config or type(config['optional']) not in [OrderedDict, dict]:
+    logger.info(f'No "optional" field found or no valid configuration.')
     config['optional'] = {}
 # Check optional fields and include in config if not present
 for optkey, value in template_config['optional'].items():
-- 
GitLab


From b7dc184aac26bf4f017552d82230a6eec5326f4f Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 11:12:51 +0200
Subject: [PATCH 06/11] separate empty and erroneous optional field.

---
 workflow/Snakefile | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/workflow/Snakefile b/workflow/Snakefile
index 8ffa423..15faefd 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -38,14 +38,17 @@ if missing:
     logger.error(err_msg)
     raise ValueError(err_msg)
 # Check if optional field available
-if 'optional' not in config or type(config['optional']) not in [OrderedDict, dict]:
-    logger.info(f'No "optional" field found or no valid configuration.')
+if 'optional' not in config:
+    logger.info(f'No "optional" section found, adding dictionary "optional" to configuration.')
     config['optional'] = {}
+if type(config['optional']) not in [OrderedDict, dict]:
+    logger.error(f'No valid section "optional" supplied. Got {config["optional"]}, type: {type(config["optional"])} but require dictionary.')
+    raise TypeError
 # Check optional fields and include in config if not present
 for optkey, value in template_config['optional'].items():
     if optkey not in config['optional']:
         config['optional'][optkey] = value
-        logger.info(f'Set default value for optional parameter "{optkey}" to : "{value}"')
+        logger.info(f'No value for optional parameter "{optkey}" found, set to default: "{value}"')
 
 
 # Parse YAML rule config file
-- 
GitLab


From 34622aa1ad5500dec43e71d5daa71ae201d5af64 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 13:46:37 +0200
Subject: [PATCH 07/11] properly raise TypeError and rephrase error message.

---
 workflow/Snakefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/workflow/Snakefile b/workflow/Snakefile
index 15faefd..e55a954 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -57,7 +57,8 @@ try:
         rule_config = yaml.safe_load(_file)
     logger.info(f"Loaded rule_config from {config['optional']['rule_config']}.")
 except TypeError:
-    logger.error(f'No string supplied at field "rule_config", but: {config["optional"]["rule_config"]}')
+    logger.error(f'No string supplied at field "rule_config", but: {type(config["optional"]["rule_config"])} with content: {config["optional"]["rule_config"]}')
+    raise
 except FileNotFoundError:
     logger.error(f"No rule config file found at {config['optional']['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
     raise
-- 
GitLab


From 0486c79f831996f1ee6c60bdc3d6601b48b6effc Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 14:53:43 +0200
Subject: [PATCH 08/11] use json schema and snakemakes validation util.

---
 resources/config_schema.json                | 65 +++++++++++++++++++++
 tests/input_files/config.mutliple_lanes.yml |  9 ++-
 tests/input_files/config.yaml               | 13 ++---
 tests/input_files/config_alfa.yaml          |  9 ++-
 workflow/Snakefile                          | 55 +++++------------
 5 files changed, 92 insertions(+), 59 deletions(-)
 create mode 100644 resources/config_schema.json

diff --git a/resources/config_schema.json b/resources/config_schema.json
new file mode 100644
index 0000000..8db7929
--- /dev/null
+++ b/resources/config_schema.json
@@ -0,0 +1,65 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "title": "Configuration schema",
+    "required": ["samples", "output_dir", "log_dir", "kallisto_indexes", "salmon_indexes", "star_indexes", "alfa_indexes"],
+    "type": "object",
+    "properties": {
+      "samples": {
+        "type": "string",
+        "description": "Path to samples table."
+      },
+      "output_dir": {
+        "type": "string",
+        "description": "Path to output directory."
+      },
+      "log_dir": {
+        "type": "string",
+        "description": "Path to log directory."
+      },
+      "kallisto_indexes": {
+        "type": "string",
+        "description": "Path to kallisto indexes directory."
+      },
+      "salmon_indexes": {
+        "type": "string",
+        "description": "Path to salmon indexes directory."
+      },
+      "star_indexes": {
+        "type": "string",
+        "description": "Path to star indexes directory."
+      },
+      "alfa_indexes": {
+        "type": "string",
+        "description": "Path to alfa indexes directory."
+      },
+      "rule_config": {
+        "type": "string",
+        "description": "Path to rule configuration file."
+      },
+      "report_description": {
+        "type": "string",
+        "description": "Description of the run to appear in the multiqc report.",
+        "default": "No description provided by user."
+      },
+      "report_logo": {
+        "type": "string",
+        "description": "Relative path to image to display as logo in multiqc report.",
+        "default": "../../images/logo.128px.png"
+      },
+      "report_url": {
+        "type": "string",
+        "description": "URL to appear in multiqc report.",
+        "default": "https://zavolan.biozentrum.unibas.ch/"
+      },
+      "author_name": {
+        "type": "string",
+        "description": "Full author name to display in multiqc report.",
+        "default": "NA" 
+      },
+      "author_email": {
+        "type": "string",
+        "description": "Author e-mail address to display in multiqc report.",
+        "default": "NA"
+      }
+    }
+}
diff --git a/tests/input_files/config.mutliple_lanes.yml b/tests/input_files/config.mutliple_lanes.yml
index 016692d..8fb3406 100644
--- a/tests/input_files/config.mutliple_lanes.yml
+++ b/tests/input_files/config.mutliple_lanes.yml
@@ -6,9 +6,8 @@
   salmon_indexes: "results/salmon_indexes"
   star_indexes: "results/star_indexes"
   alfa_indexes: "results/alfa_indexes"
-  optional:
-    rule_config: "../input_files/rule_config.yaml"
-    report_description: "No description provided by user"
-    report_logo: "../../images/logo.128px.png"
-    report_url: "https://zavolan.biozentrum.unibas.ch/"
+  rule_config: "../input_files/rule_config.yaml"
+  report_description: "No description provided by user"
+  report_logo: "../../images/logo.128px.png"
+  report_url: "https://zavolan.biozentrum.unibas.ch/"
 ...
diff --git a/tests/input_files/config.yaml b/tests/input_files/config.yaml
index 54edf9c..1fc480c 100644
--- a/tests/input_files/config.yaml
+++ b/tests/input_files/config.yaml
@@ -8,11 +8,10 @@
   star_indexes: "results/star_indexes"
   alfa_indexes: "results/alfa_indexes"
   # Optional fields
-  optional:
-    rule_config: "../input_files/rule_config.yaml"
-    report_description: "No description provided by user"
-    report_logo: "../../images/logo.128px.png"
-    report_url: "https://zavolan.biozentrum.unibas.ch/"
-    author_name: "NA"
-    author_email: "NA"
+  rule_config: "../input_files/rule_config.yaml"
+  report_description: "No description provided by user"
+  report_logo: "../../images/logo.128px.png"
+  report_url: "https://zavolan.biozentrum.unibas.ch/"
+  author_name: "NA"
+  author_email: "NA"
 ...
diff --git a/tests/input_files/config_alfa.yaml b/tests/input_files/config_alfa.yaml
index 06decc6..5edcd7e 100644
--- a/tests/input_files/config_alfa.yaml
+++ b/tests/input_files/config_alfa.yaml
@@ -6,9 +6,8 @@
   salmon_indexes: "results/salmon_indexes"
   star_indexes: "results/star_indexes"
   alfa_indexes: "results/alfa_indexes"
-  optional:
-    rule_config: "../input_files/rule_config.yaml"
-    report_description: "No description provided by user"
-    report_logo: "../../images/logo.128px.png"
-    report_url: "https://zavolan.biozentrum.unibas.ch/"
+  rule_config: "../input_files/rule_config.yaml"
+  report_description: "No description provided by user"
+  report_logo: "../../images/logo.128px.png"
+  report_url: "https://zavolan.biozentrum.unibas.ch/"
 ...
diff --git a/workflow/Snakefile b/workflow/Snakefile
index e55a954..fc268e4 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -5,6 +5,7 @@ import shutil
 import yaml
 from shlex import quote
 from typing import Tuple
+from snakemake.utils import validate
 
 ## Preparations
 # Get sample table
@@ -17,50 +18,20 @@ samples_table = pd.read_csv(
     sep="\t",
 )
 
-# Validate config with template config
-template_config_path = os.path.join(
-            workflow.current_basedir, 
-            '..',
-            'tests', 
-            'input_files', 
-            'config.yaml')
-try:
-    with open(template_config_path) as _file:
-        template_config = yaml.safe_load(_file)
-    logger.info(f"Loaded template config from {template_config_path}.")
-except FileNotFoundError:
-    logger.error(f"No config file found at {template_config_path}! ")
-    raise
-# Check if config contains required fields in example config
-missing = [key for key in template_config if key not in config and key != 'optional']
-if missing:
-    err_msg = f"Required keys missing: {missing}"
-    logger.error(err_msg)
-    raise ValueError(err_msg)
-# Check if optional field available
-if 'optional' not in config:
-    logger.info(f'No "optional" section found, adding dictionary "optional" to configuration.')
-    config['optional'] = {}
-if type(config['optional']) not in [OrderedDict, dict]:
-    logger.error(f'No valid section "optional" supplied. Got {config["optional"]}, type: {type(config["optional"])} but require dictionary.')
-    raise TypeError
-# Check optional fields and include in config if not present
-for optkey, value in template_config['optional'].items():
-    if optkey not in config['optional']:
-        config['optional'][optkey] = value
-        logger.info(f'No value for optional parameter "{optkey}" found, set to default: "{value}"')
-
+# Validat config
+validate(config, os.path.join("..", "resources", "config_schema.json"))
+logger.info(f'Config file after validation: {config}')
 
 # Parse YAML rule config file
 try:
-    with open(config['optional']['rule_config']) as _file:
+    with open(config['rule_config']) as _file:
         rule_config = yaml.safe_load(_file)
-    logger.info(f"Loaded rule_config from {config['optional']['rule_config']}.")
+    logger.info(f"Loaded rule_config from {config['rule_config']}.")
 except TypeError:
-    logger.error(f'No string supplied at field "rule_config", but: {type(config["optional"]["rule_config"])} with content: {config["optional"]["rule_config"]}')
+    logger.error(f'No string supplied at field "rule_config", but: {type(config["rule_config"])} with content: {config["rule_config"]}')
     raise
 except FileNotFoundError:
-    logger.error(f"No rule config file found at {config['optional']['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
+    logger.error(f"No rule config file found at {config['rule_config']}. Either provide file or remove rule_config parameter from config.yaml! ")
     raise
 except KeyError:
     rule_config = {}
@@ -1580,11 +1551,11 @@ rule prepare_multiqc_config:
             "multiqc_config.yaml")
 
     params:
-        logo_path = config['optional']['report_logo'],
-        multiqc_intro_text = config['optional']['report_description'],
-        url = config['optional']['report_url'],
-        author_name = config['optional']['author_name'],
-        author_email = config['optional']['author_email'],
+        logo_path = config['report_logo'],
+        multiqc_intro_text = config['report_description'],
+        url = config['report_url'],
+        author_name = config['author_name'],
+        author_email = config['author_email'],
         additional_params = parse_rule_config(
             rule_config,
             current_rule=current_rule,
-- 
GitLab


From 4aa9ede05a6148905af6f5ba7f4e372a47754de5 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 14:57:38 +0200
Subject: [PATCH 09/11] cleanup remaining optional keywords

---
 scripts/prepare_inputs.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/scripts/prepare_inputs.py b/scripts/prepare_inputs.py
index e47fa3d..426902a 100755
--- a/scripts/prepare_inputs.py
+++ b/scripts/prepare_inputs.py
@@ -678,10 +678,9 @@ def main(args):
   salmon_indexes: "{salmon_indexes}"
   star_indexes: "{star_indexes}"
   alfa_indexes: "{alfa_indexes}"
-  optional:
-    report_description: "{args.description}"
-    report_logo: "{args.logo}"
-    report_url: "{args.url}"
+  report_description: "{args.description}"
+  report_logo: "{args.logo}"
+  report_url: "{args.url}"
 ...
 '''
     args.config_file.write(config_file_content)
-- 
GitLab


From 39baeaa417f4aa032b848aff248936b575b99818 Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Wed, 14 Jul 2021 15:10:11 +0200
Subject: [PATCH 10/11] update md5sum

---
 tests/test_scripts_prepare_inputs_table/expected_output.md5 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test_scripts_prepare_inputs_table/expected_output.md5 b/tests/test_scripts_prepare_inputs_table/expected_output.md5
index dc555cc..53afed5 100644
--- a/tests/test_scripts_prepare_inputs_table/expected_output.md5
+++ b/tests/test_scripts_prepare_inputs_table/expected_output.md5
@@ -1,2 +1,2 @@
-90e90bb60335a2e17cd40cbf058af7b7  config.yaml
+40bd0f0fcecdd0d9bc932f63c2811478  config.yaml
 c8dcc5a203e9046806c4090525960151  samples.tsv
-- 
GitLab


From b0c6af80e49ac2c88e3c6e410697544ee2b44b0e Mon Sep 17 00:00:00 2001
From: burri0000 <dominik.burri@unibas.ch>
Date: Thu, 15 Jul 2021 14:56:38 +0200
Subject: [PATCH 11/11] do not allow additional properties in config

---
 resources/config_schema.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/config_schema.json b/resources/config_schema.json
index 8db7929..1ad7846 100644
--- a/resources/config_schema.json
+++ b/resources/config_schema.json
@@ -3,6 +3,7 @@
     "title": "Configuration schema",
     "required": ["samples", "output_dir", "log_dir", "kallisto_indexes", "salmon_indexes", "star_indexes", "alfa_indexes"],
     "type": "object",
+    "additionalProperties": false,
     "properties": {
       "samples": {
         "type": "string",
-- 
GitLab