Repository: bihealth/biomedsheets

Issue:
Hyphen not allowed in patientName column - Germline
**Issue**
Hyphens are allowed in SODAR sample sheet (specifically in the patient column), but not by the [biomedsheets](https://github.com/bihealth/biomedsheets) - used while running genomic pipeline.

```
Tue Feb 15 16:55:58 CET 2022
+ snappy-snake --printshellcmds --snappy-pipeline-use-drmaa --snappy-pipeline-drmaa-jobs 500 --restart-times 0 --drmaa-snippet=--partition=medium --rerun-incomplete --
02-15 16:55 root         INFO     Creating directory /data/gpfs-1/work/projects/medgen_genomes/2022-02-11_Aortopathy_WGS/GRCh37/ngs_mapping/slurm_log/681930
02-15 16:55 root         INFO     Executing snakemake '--directory' '/data/...Aortopathy_WGS/GRCh37/ngs_mapping' '--snakefile' '.../snappy-pipeline/snappy_pipeline/workflows/ngs_mapping/Snakefile' '--jobscript' '.../snappy-pipeline/snappy_pipeline/apps/tpls/jobscript.sh' '--rerun-incomplete' '-p' '--use-conda' '--conda-frontend' 'mamba' '--max-jobs-per-second' '10' '--max-status-checks-per-second' '10' '--drmaa' ' --mem={cluster.mem} --time={cluster.time} --cpus-per-task={cluster.ntasks} --output=/data/gpfs-1/work/projects/medgen_genomes/2022-02-11_Aortopathy_WGS/GRCh37/ngs_mapping/slurm_log/681930/slurm-%x-%J.log --partition=medium' '-j' '500'
GermlineTSVSheetException in line 23 of .../snappy-pipeline/snappy_pipeline/workflows/ngs_mapping/Snakefile:
Hyphen not allowed in patientName column
  File ".../snappy-pipeline/snappy_pipeline/workflows/ngs_mapping/Snakefile", line 23, in <module>
  File ".../snappy-pipeline/snappy_pipeline/workflows/ngs_mapping/__init__.py", line 1033, in __init__
  File ".../snappy-pipeline/snappy_pipeline/workflows/abstract/__init__.py", line 504, in __init__
  File ".../snappy-pipeline/snappy_pipeline/workflows/abstract/__init__.py", line 745, in _load_data_set_infos
  File ".../snappy-pipeline/snappy_pipeline/workflows/abstract/__init__.py", line 363, in __init__
  File ".../snappy-pipeline/snappy_pipeline/workflows/abstract/__init__.py", line 386, in _load_sheet
  File ".../snappy-pipeline/snappy_pipeline/workflows/abstract/__init__.py", line 266, in _cached_read_germline_tsv_sheet
  File "miniconda3/lib/python3.8/site-packages/biomedsheets/io_tsv/germline.py", line 186, in read_germline_tsv_sheet
  File "miniconda3/lib/python3.8/site-packages/biomedsheets/io_tsv/base.py", line 359, in read_sheet
  File "miniconda3/lib/python3.8/site-packages/biomedsheets/io_tsv/base.py", line 353, in read_json_data
  File "miniconda3/lib/python3.8/site-packages/biomedsheets/io_tsv/base.py", line 395, in _create_sheet_json
  File "miniconda3/lib/python3.8/site-packages/biomedsheets/io_tsv/germline.py", line 110, in check_tsv_line
02-15 16:56 snakemake.logging ERROR    GermlineTSVSheetException in line 23 of .../snappy-pipeline/snappy_pipeline/workflows/ngs_mapping/Snakefile:
Hyphen not allowed in patientName column
```
biomedsheets              0.11.1                   pypi_0    pypi

**Additional info**
_"[This] restriction is in SNAPPY/biomedsheets only ... Its origin is that I originally wanted to be able to resolve SAMPLE-NORMALTUMORNUMBER-EXTRACTIONNUMBER-LIBRARYNUMBER unambiguously to SAMPLE etc. This functionality is actually used it can be removed."_



Comments:

Patch:
diff --git a/biomedsheets/io_tsv/germline.py b/biomedsheets/io_tsv/germline.py
index 2214d46..9aa02c9 100644
--- a/biomedsheets/io_tsv/germline.py
+++ b/biomedsheets/io_tsv/germline.py
@@ -104,17 +104,7 @@ class GermlineTSVReader(BaseTSVReader):
     optional_body_header_columns = ('seqPlatform', 'bioSample', 'testSample')
 
     def check_tsv_line(self, mapping, lineno):
-        """Cancer sample sheet--specific valiation"""
-        # Check for hyphen in patient or sample name
-        if '-' in mapping['patientName']:
-            raise GermlineTSVSheetException(
-                'Hyphen not allowed in patientName column')  # pragma: no cover
-        if mapping['fatherName'] and '-' in mapping['fatherName']:
-            raise GermlineTSVSheetException(
-                'Hyphen not allowed in fatherName column')  # pragma: no cover
-        if mapping['motherName'] and '-' in mapping['motherName']:
-            raise GermlineTSVSheetException(
-                'Hyphen not allowed in motherName column')  # pragma: no cover
+        """Germline sample sheet--specific validation"""
         # Check "libraryType" field
         if mapping['libraryType'] and (
                 mapping['libraryType'] not in LIBRARY_TYPES):


Test patch:
diff --git a/tests/test_io_tsv_germline.py b/tests/test_io_tsv_germline.py
index 40e48c6..ace0084 100644
--- a/tests/test_io_tsv_germline.py
+++ b/tests/test_io_tsv_germline.py
@@ -45,6 +45,18 @@ def tsv_sheet_germline_no_header():
     return f
 
 
+@pytest.fixture
+def tsv_sheet_germline_no_header_hyphened_identifier():
+    """Germline TSV sheet without header"""
+    return io.StringIO(textwrap.dedent("""
+    patientName\tfatherName\tmotherName\tsex\tisAffected\tlibraryType\tfolderName\thpoTerms
+    12-345\t12-346\t12-347\tM\tY\tWGS\t12-345\tHP:0009946,HP:0009899
+    12-348\t12-346\t12-347\tM\tN\tWGS\t12-348\t.
+    12-346\t.\t.\tM\tN\t.\t.\t.
+    12-347\t.\t.\tF\tN\tWGS\t12-347\t.
+    """.lstrip()))
+
+
 @pytest.fixture
 def tsv_sheet_germline_platform_name():
     """Germline TSV sheet with seqPlatform name"""
@@ -510,6 +522,232 @@ EXPECTED_GERMLINE_SHEET_JSON_NO_HEADER = r"""
     }
 }""".lstrip()
 
+# Expected value for the germline sheet JSON without header and hyphen in identifiers
+EXPECTED_GERMLINE_SHEET_JSON_NO_HEADER_HYPHEN = r"""
+{
+    "identifier": "file://<unknown>",
+    "title": "Germline Sample Sheet",
+    "description": "Sample Sheet constructed from germline compact TSV file",
+    "extraInfoDefs": {
+        "bioEntity": {
+            "ncbiTaxon": {
+                "docs": "Reference to NCBI taxonomy",
+                "key": "taxon",
+                "type": "string",
+                "pattern": "^NCBITaxon_[1-9][0-9]*$"
+            },
+            "fatherPk": {
+                "docs": "Primary key of mother",
+                "key": "fatherPk",
+                "type": "string"
+            },
+            "motherPk": {
+                "docs": "Primary key of mother",
+                "key": "motherPk",
+                "type": "string"
+            },
+            "fatherName": {
+                "docs": "secondary_id of father, used for construction only",
+                "key": "fatherName",
+                "type": "string"
+            },
+            "motherName": {
+                "key": "motherName",
+                "docs": "secondary_id of mother, used for construction only",
+                "type": "string"
+            },
+            "sex": {
+                "docs": "Biological sex of individual",
+                "key": "sex",
+                "type": "enum",
+                "choices": [
+                    "male",
+                    "female",
+                    "unknown"
+                ]
+            },
+            "isAffected": {
+                "docs": "Flag for marking individiual as (un-)affected",
+                "key": "isAffected",
+                "type": "enum",
+                "choices": [
+                    "affected",
+                    "unaffected",
+                    "unknown"
+                ]
+            },
+            "hpoTerms": {
+                "docs": "HPO terms for individual",
+                "key": "hpoTerms",
+                "type": "array",
+                "entry": "string",
+                "pattern": "^HPO:[0-9]+$"
+            }
+        },
+        "bioSample": {},
+        "testSample": {
+            "extractionType": {
+                "docs": "Describes extracted",
+                "key": "extractionType",
+                "type": "enum",
+                "choices": [
+                    "DNA",
+                    "RNA",
+                    "other"
+                ]
+            }
+        },
+        "ngsLibrary": {
+            "seqPlatform": {
+                "docs": "Sequencing platform used",
+                "key": "kitName",
+                "type": "enum",
+                "choices": [
+                    "Illumina",
+                    "PacBio",
+                    "other"
+                ]
+            },
+            "libraryType": {
+                "docs": "Rough classificiation of the library type",
+                "key": "libraryType",
+                "type": "enum",
+                "choices": [
+                    "Panel-seq",
+                    "WES",
+                    "WGS",
+                    "mRNA-seq",
+                    "tRNA-seq",
+                    "other"
+                ]
+            },
+            "folderName": {
+                "docs": "Name of folder with FASTQ files",
+                "key": "folderName",
+                "type": "string"
+            }
+        }
+    },
+    "bioEntities": {
+        "12-345": {
+            "pk": 1,
+            "extraInfo": {
+                "fatherName": "12-346",
+                "motherName": "12-347",
+                "sex": "male",
+                "isAffected": "affected",
+                "hpoTerms": [
+                    "HP:0009946",
+                    "HP:0009899"
+                ],
+                "ncbiTaxon": "NCBITaxon_9606",
+                "fatherPk": 9,
+                "motherPk": 10
+            },
+            "bioSamples": {
+                "N1": {
+                    "pk": 2,
+                    "extraInfo": {},
+                    "testSamples": {
+                        "DNA1": {
+                            "pk": 3,
+                            "extraInfo": {
+                                "extractionType": "DNA"
+                            },
+                            "ngsLibraries": {
+                                "WGS1": {
+                                    "pk": 4,
+                                    "extraInfo": {
+                                        "seqPlatform": "Illumina",
+                                        "folderName": "12-345",
+                                        "libraryType": "WGS"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "12-348": {
+            "pk": 5,
+            "extraInfo": {
+                "fatherName": "12-346",
+                "motherName": "12-347",
+                "sex": "male",
+                "isAffected": "unaffected",
+                "ncbiTaxon": "NCBITaxon_9606",
+                "fatherPk": 9,
+                "motherPk": 10
+            },
+            "bioSamples": {
+                "N1": {
+                    "pk": 6,
+                    "extraInfo": {},
+                    "testSamples": {
+                        "DNA1": {
+                            "pk": 7,
+                            "extraInfo": {
+                                "extractionType": "DNA"
+                            },
+                            "ngsLibraries": {
+                                "WGS1": {
+                                    "pk": 8,
+                                    "extraInfo": {
+                                        "seqPlatform": "Illumina",
+                                        "folderName": "12-348",
+                                        "libraryType": "WGS"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "12-346": {
+            "pk": 9,
+            "extraInfo": {
+                "sex": "male",
+                "isAffected": "unaffected",
+                "ncbiTaxon": "NCBITaxon_9606"
+            },
+            "bioSamples": {}
+        },
+        "12-347": {
+            "pk": 10,
+            "extraInfo": {
+                "sex": "female",
+                "isAffected": "unaffected",
+                "ncbiTaxon": "NCBITaxon_9606"
+            },
+            "bioSamples": {
+                "N1": {
+                    "pk": 11,
+                    "extraInfo": {},
+                    "testSamples": {
+                        "DNA1": {
+                            "pk": 12,
+                            "extraInfo": {
+                                "extractionType": "DNA"
+                            },
+                            "ngsLibraries": {
+                                "WGS1": {
+                                    "pk": 13,
+                                    "extraInfo": {
+                                        "seqPlatform": "Illumina",
+                                        "folderName": "12-347",
+                                        "libraryType": "WGS"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}""".lstrip()
 
 # Expected value when platform name is given
 EXPECTED_GERMLINE_SHEET_JSON_PLATFORM_NAME = r"""
@@ -673,6 +911,13 @@ def test_read_germline_sheet_no_header(tsv_sheet_germline_no_header):
     assert EXPECTED_GERMLINE_SHEET_JSON_NO_HEADER == json.dumps(
         sheet.json_data, indent='    ')
 
+def test_read_germline_sheet_no_header_hyphened_identifiers(
+    tsv_sheet_germline_no_header_hyphened_identifier
+):
+    sheet = io_tsv.read_germline_tsv_sheet(tsv_sheet_germline_no_header_hyphened_identifier)
+    assert EXPECTED_GERMLINE_SHEET_JSON_NO_HEADER_HYPHEN == json.dumps(
+        sheet.json_data, indent='    ')
+
 
 def test_read_germline_sheet_platform_name(tsv_sheet_germline_platform_name):
     sheet = io_tsv.read_germline_tsv_sheet(tsv_sheet_germline_platform_name)