eva-sub-cli 0.4.7__tar.gz → 0.4.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. eva_sub_cli-0.4.9/.github/workflows/trigger-eva-sub-cli-integration-tests.yml +16 -0
  2. {eva_sub_cli-0.4.7/eva_sub_cli.egg-info → eva_sub_cli-0.4.9}/PKG-INFO +2 -2
  3. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/__init__.py +1 -1
  4. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/_version.py +2 -2
  5. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/etc/EVA_Submission_Example.xlsx +0 -0
  6. eva_sub_cli-0.4.9/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
  7. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/etc/eva_schema.json +3 -2
  8. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/check_fasta_insdc.py +18 -25
  9. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/samples_checker.py +13 -19
  10. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/xlsx2json.py +3 -3
  11. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/file_utils.py +5 -0
  12. eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates/html_report.html → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html/report.html +3 -3
  13. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/fasta_check.txt +46 -0
  14. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/file_validation.txt +58 -0
  15. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/metadata_validation.txt +33 -0
  16. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/project_details.txt +21 -0
  17. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/report.txt +59 -0
  18. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/sample_name_check.txt +24 -0
  19. eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/text/shallow_validation.txt +16 -0
  20. eva_sub_cli-0.4.9/eva_sub_cli/metadata.py +95 -0
  21. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/orchestrator.py +53 -52
  22. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/report.py +13 -4
  23. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/validators/docker_validator.py +1 -1
  24. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/validators/native_validator.py +4 -0
  25. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/validators/validator.py +53 -49
  26. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9/eva_sub_cli.egg-info}/PKG-INFO +2 -2
  27. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli.egg-info/SOURCES.txt +21 -8
  28. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli.egg-info/requires.txt +1 -1
  29. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/requirements.txt +1 -1
  30. eva_sub_cli-0.4.9/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
  31. eva_sub_cli-0.4.9/tests/resources/EVA_Submission_test.xlsx +0 -0
  32. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/EVA_Submission_test_fails.xlsx +0 -0
  33. eva_sub_cli-0.4.9/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
  34. eva_sub_cli-0.4.9/tests/resources/metadata_with_filename.json +19 -0
  35. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/expected_report_metadata_json.html +1 -1
  36. eva_sub_cli-0.4.9/tests/resources/validation_reports/expected_report_metadata_json.txt +132 -0
  37. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/expected_report_metadata_xlsx.html +1 -1
  38. eva_sub_cli-0.4.9/tests/resources/validation_reports/expected_report_metadata_xlsx.txt +126 -0
  39. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.html +1 -1
  40. eva_sub_cli-0.4.9/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.txt +135 -0
  41. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_check_fasta_insdc.py +35 -3
  42. eva_sub_cli-0.4.9/tests/test_metadata.py +69 -0
  43. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_orchestrator.py +27 -6
  44. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_report.py +96 -30
  45. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_samples_checker.py +29 -2
  46. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_validator.py +40 -3
  47. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_xlsx2json.py +14 -0
  48. eva_sub_cli-0.4.7/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
  49. eva_sub_cli-0.4.7/eva_sub_cli/metadata_utils.py +0 -46
  50. eva_sub_cli-0.4.7/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
  51. eva_sub_cli-0.4.7/tests/resources/EVA_Submission_test.xlsx +0 -0
  52. eva_sub_cli-0.4.7/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
  53. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/.github/workflows/publish.yml +0 -0
  54. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/.github/workflows/publish_packages.yml +0 -0
  55. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/.github/workflows/tests.yml +0 -0
  56. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/.gitignore +0 -0
  57. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/LICENSE +0 -0
  58. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/README.md +0 -0
  59. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/conda/build.sh +0 -0
  60. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/conda/meta.yaml +0 -0
  61. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/docker/Dockerfile +0 -0
  62. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/docs/Getting_Started_with_eva_sub_cli.md +0 -0
  63. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/auth.py +0 -0
  64. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/date_utils.py +0 -0
  65. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/etc/eva-biosamples.json +0 -0
  66. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/etc/eva_logo.png +0 -0
  67. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/etc/spreadsheet2json_conf.yaml +0 -0
  68. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/exceptions/__init__.py +0 -0
  69. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/exceptions/invalid_file_type_exception.py +0 -0
  70. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/exceptions/metadata_template_version_exception.py +0 -0
  71. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/exceptions/submission_not_found_exception.py +0 -0
  72. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/exceptions/submission_status_exception.py +0 -0
  73. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/__init__.py +0 -0
  74. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/check_metadata_semantics.py +0 -0
  75. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/cli.py +0 -0
  76. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/executables/trim_down.py +0 -0
  77. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/fasta_check.html +0 -0
  78. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/file_validation.html +0 -0
  79. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/metadata_validation.html +0 -0
  80. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/project_details.html +0 -0
  81. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/sample_name_check.html +0 -0
  82. {eva_sub_cli-0.4.7/eva_sub_cli/jinja_templates → eva_sub_cli-0.4.9/eva_sub_cli/jinja_templates/html}/shallow_validation.html +0 -0
  83. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/nextflow/validation.nf +0 -0
  84. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/semantic_metadata.py +0 -0
  85. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/submission_ws.py +0 -0
  86. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/submit.py +0 -0
  87. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/validators/__init__.py +0 -0
  88. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli/validators/validation_results_parsers.py +0 -0
  89. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli.egg-info/dependency_links.txt +0 -0
  90. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli.egg-info/entry_points.txt +0 -0
  91. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/eva_sub_cli.egg-info/top_level.txt +0 -0
  92. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/pyproject.toml +0 -0
  93. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/pytest.ini +0 -0
  94. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/setup.cfg +0 -0
  95. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/setup.py +0 -0
  96. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/build_and_test_docker_locally.py +0 -0
  97. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/ignore_test_nextflow_validation.yml +0 -0
  98. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/EVA_Submission_test.json +0 -0
  99. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/EVA_Submission_test_with_asm_report.json +0 -0
  100. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/assembly_check/invalid.vcf.assembly_check.log +0 -0
  101. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt +0 -0
  102. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/assembly_reports/input_passed.txt +0 -0
  103. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa +0 -0
  104. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/fasta_files/input_passed.fa +0 -0
  105. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/fasta_files/multi_seq.fa +0 -0
  106. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/sample_checker/example1.vcf.gz +0 -0
  107. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/sample_checker/example2.vcf +0 -0
  108. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/sample_checker/example3.vcf +0 -0
  109. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/sample_checker/metadata.json +0 -0
  110. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.assembly_check.log +0 -0
  111. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.text_assembly_report.1680102476700.txt +0 -0
  112. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.valid_assembly_report.1680102476700.txt +0 -0
  113. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/other_validations/input_passed.fa_check.yml +0 -0
  114. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/other_validations/metadata_conversion_errors.yml +0 -0
  115. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/other_validations/metadata_semantic_check.yml +0 -0
  116. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/other_validations/metadata_validation.txt +0 -0
  117. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/other_validations/sample_checker.yml +0 -0
  118. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.db +0 -0
  119. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.txt +0 -0
  120. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.vcf_format.log +0 -0
  121. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/vcf_files/example2.vcf.gz +0 -0
  122. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/resources/vcf_files/input_passed.vcf +0 -0
  123. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_auth.py +0 -0
  124. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_cli.py +0 -0
  125. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_docker_validator.py +0 -0
  126. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_file_utils.py +0 -0
  127. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_semantic_metadata.py +0 -0
  128. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_submit.py +0 -0
  129. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_trim_down.py +0 -0
  130. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_utils.py +0 -0
  131. {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.9}/tests/test_validaton_results_parsers.py +0 -0
@@ -0,0 +1,16 @@
1
+ name: Trigger Eva Sub Cli Integration Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main, test-trigger-integration-tests]
6
+
7
+ jobs:
8
+ trigger-integration-tests:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Trigger eva sub cli integration tests
12
+ uses: peter-evans/repository-dispatch@v2
13
+ with:
14
+ token: ${{ secrets.TRIGGER_INTEGRATION_TESTS }}
15
+ repository: EBIvariation/eva-integration-tests
16
+ event-type: trigger-eva-sub-cli-tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4.7
3
+ Version: 0.4.9
4
4
  Summary: EBI EVA - validation and submission command line tool
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Environment :: Console
@@ -19,7 +19,7 @@ Classifier: License :: OSI Approved :: Apache Software License
19
19
  Requires-Python: >=3.6
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
- Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.1
22
+ Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.3
23
23
  Requires-Dist: jinja2==3.*,>=3.0.0
24
24
  Requires-Dist: jsonschema==4.*
25
25
  Requires-Dist: openpyxl==3.*
@@ -6,7 +6,7 @@ PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__))
6
6
  NEXTFLOW_DIR = os.path.join(PACKAGE_DIR, 'nextflow')
7
7
  ETC_DIR = os.path.join(PACKAGE_DIR, 'etc')
8
8
  LSRI_CLIENT_ID = "aa0fcc42-096a-4f9d-b871-aceb1a97d174"
9
- DEFAULT_METADATA_XLSX_TEMPLATE_VERSION = '1.1.6'
9
+ MINIMUM_METADATA_XLSX_TEMPLATE_VERSION = '2.0.0'
10
10
 
11
11
  SUB_CLI_CONFIG_FILE = ".eva_sub_cli_config.yml"
12
12
 
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.4.7'
21
- __version_tuple__ = version_tuple = (0, 4, 7)
20
+ __version__ = version = '0.4.9'
21
+ __version_tuple__ = version_tuple = (0, 4, 9)
@@ -310,9 +310,10 @@
310
310
  "type": "string",
311
311
  "description": "Sample Name used in the VCF file"
312
312
  },
313
- "sampleAccession": {
313
+ "bioSampleAccession": {
314
314
  "type": "string",
315
- "description": "Accession of the sample (BioSamples, ENA or EGA)"
315
+ "pattern": "^SAM(E|D|N)[A-Z]?[0-9]+$",
316
+ "description": "BioSample accession of pre-existing sample. Only use for preregistered samples"
316
317
  },
317
318
  "bioSampleObject": {
318
319
  "type": "object",
@@ -1,8 +1,5 @@
1
1
  import argparse
2
- import gzip
3
2
  import hashlib
4
- import json
5
- from itertools import groupby
6
3
 
7
4
  import requests
8
5
  import yaml
@@ -11,8 +8,7 @@ from requests import HTTPError
11
8
  from retry import retry
12
9
 
13
10
  from eva_sub_cli.file_utils import fasta_iter
14
- from eva_sub_cli.metadata_utils import get_files_per_analysis, get_analysis_for_vcf_file, \
15
- get_reference_assembly_for_analysis
11
+ from eva_sub_cli.metadata import EvaMetadataJson
16
12
 
17
13
  REFGET_SERVER = 'https://www.ebi.ac.uk/ena/cram'
18
14
  CONTIG_ALIAS_SERVER = 'https://www.ebi.ac.uk/eva/webservices/contig-alias/v1/chromosomes/md5checksum'
@@ -52,7 +48,7 @@ def _get_containing_assemblies_paged(url):
52
48
  results.add(contigEntity['assembly']['insdcAccession'])
53
49
  if '_links' in response_data and 'next' in response_data['_links']:
54
50
  # Add results from next page if needed
55
- results |= _get_containing_assemblies_paged(response_data['_links']['next'])
51
+ results = results.union(_get_containing_assemblies_paged(response_data['_links']['next']['href']))
56
52
  return results
57
53
  return set()
58
54
 
@@ -94,7 +90,7 @@ def assess_fasta(input_fasta, analyses, assembly_in_metadata):
94
90
  possible_assemblies = containing_assemblies
95
91
  else:
96
92
  possible_assemblies &= containing_assemblies
97
- except (ConnectionError, HTTPError) as e:
93
+ except Exception as e:
98
94
  # Server errors from either ENA refget or EVA contig alias will halt the check prematurely.
99
95
  # Report the error but do not return from the method, so that incomplete results can be reported
100
96
  # (i.e. any sequences found to be INSDC and any compatible assemblies so far)
@@ -121,23 +117,21 @@ def get_analyses_and_reference_genome_from_metadata(vcf_files_for_fasta, json_fi
121
117
  single assembly accession
122
118
  :param json_file: JSON file of the metadata
123
119
  """
124
- with open(json_file) as open_json:
125
- metadata = json.load(open_json)
126
- files_per_analysis = get_files_per_analysis(metadata)
127
- # Get all analyses associated with all vcf files that are linked with a single fasta file
128
- all_analyses = set()
129
- for vcf_file in vcf_files_for_fasta:
130
- analysis_aliases = get_analysis_for_vcf_file(vcf_file, files_per_analysis)
131
- if len(analysis_aliases) != 1:
132
- logger.error(f'Could not determine analysis associated with VCF file: {vcf_file}')
133
- else:
134
- all_analyses.add(analysis_aliases[0])
135
- # Get (single) assembly associated with these analyses
136
- assemblies = [get_reference_assembly_for_analysis(metadata, analysis) for analysis in all_analyses]
137
- if len(assemblies) != 1:
138
- logger.error(f'Could not determine assembly accession to check against fasta file, out of: {assemblies}')
139
- return all_analyses, None
140
- return all_analyses, assemblies[0]
120
+ metadata = EvaMetadataJson(json_file)
121
+ # Get all analyses associated with all vcf files that are linked with a single fasta file
122
+ all_analyses = set()
123
+ for vcf_file in vcf_files_for_fasta:
124
+ analysis_aliases = metadata.get_analysis_for_vcf_file(vcf_file)
125
+ if len(analysis_aliases) != 1:
126
+ logger.error(f'Could not determine analysis associated with VCF file: {vcf_file}')
127
+ else:
128
+ all_analyses.add(analysis_aliases[0])
129
+ # Get (single) assembly associated with these analyses
130
+ assemblies = [metadata.get_reference_assembly_for_analysis(analysis) for analysis in all_analyses]
131
+ if len(assemblies) != 1:
132
+ logger.error(f'Could not determine assembly accession to check against fasta file, out of: {assemblies}')
133
+ return all_analyses, None
134
+ return all_analyses, assemblies[0]
141
135
 
142
136
 
143
137
  def main():
@@ -156,4 +150,3 @@ def main():
156
150
  analyses, metadata_insdc = get_analyses_and_reference_genome_from_metadata(args.vcf_files, args.metadata_json)
157
151
  results = assess_fasta(args.input_fasta, analyses, metadata_insdc)
158
152
  write_result_yaml(args.output_yaml, results)
159
-
@@ -1,6 +1,4 @@
1
1
  import argparse
2
- import gzip
3
- import json
4
2
  import os
5
3
 
6
4
  from ebi_eva_common_pyutils.logger import logging_config
@@ -8,7 +6,7 @@ from ebi_eva_common_pyutils.logger import logging_config
8
6
  import yaml
9
7
 
10
8
  from eva_sub_cli.file_utils import open_gzip_if_required
11
- from eva_sub_cli.metadata_utils import get_samples_per_analysis, get_files_per_analysis, get_analysis_for_vcf_file
9
+ from eva_sub_cli.metadata import EvaMetadataJson
12
10
 
13
11
  logger = logging_config.get_logger(__name__)
14
12
 
@@ -24,8 +22,10 @@ def get_samples_from_vcf(vcf_file):
24
22
  if len(sp_line) > 9:
25
23
  return sp_line[9:]
26
24
  else:
27
- logger.warning(f"No Sample names found in file {vcf_file}")
25
+ logger.warning(f"No sample names found in file {vcf_file}")
28
26
  return []
27
+ logger.warning(f"No sample names found in file {vcf_file}")
28
+ return []
29
29
 
30
30
 
31
31
  def compare_names_in_files_and_samples(sample_name_in_analysis, sample_name_per_file):
@@ -54,12 +54,12 @@ def compare_names_in_files_and_samples(sample_name_in_analysis, sample_name_per_
54
54
  more_metadata_submitted_files)
55
55
 
56
56
 
57
- def compare_all_analysis(samples_per_analysis, files_per_analysis):
57
+ def compare_all_analysis(metadata, files_per_analysis):
58
58
  overall_differences = False
59
59
  results_per_analysis_alias = {}
60
- all_analysis_alias = set(samples_per_analysis) | set(files_per_analysis)
60
+ all_analysis_alias = set(metadata.samples_per_analysis) | set(files_per_analysis)
61
61
  for analysis_alias in all_analysis_alias:
62
- sample_name_in_analysis = samples_per_analysis.get(analysis_alias, [])
62
+ sample_name_in_analysis = metadata.samples_per_analysis.get(analysis_alias, [])
63
63
  sample_name_per_file = {
64
64
  file_path: get_samples_from_vcf(file_path)
65
65
  for file_path in files_per_analysis.get(analysis_alias, [])
@@ -78,13 +78,7 @@ def compare_all_analysis(samples_per_analysis, files_per_analysis):
78
78
  return overall_differences, results_per_analysis_alias
79
79
 
80
80
 
81
- def read_metadata_json(json_file):
82
- with open(json_file) as open_json:
83
- metadata = json.load(open_json)
84
- return get_samples_per_analysis(metadata), get_files_per_analysis(metadata)
85
-
86
-
87
- def associate_vcf_path_with_analysis(vcf_files, files_per_analysis):
81
+ def associate_vcf_path_with_analysis(metadata, vcf_files):
88
82
  """
89
83
  Match the files names associated with analysis provided in the metadata with the file path given on the command
90
84
  line.
@@ -93,10 +87,10 @@ def associate_vcf_path_with_analysis(vcf_files, files_per_analysis):
93
87
  :returns dictionary of analysis and their associated vcf file path
94
88
  """
95
89
  result_files_per_analysis = dict()
96
- for analysis in files_per_analysis:
90
+ for analysis in metadata.files_per_analysis:
97
91
  result_files_per_analysis[analysis] = []
98
92
  for vcf_file in vcf_files:
99
- analysis_aliases = get_analysis_for_vcf_file(vcf_file, files_per_analysis)
93
+ analysis_aliases = metadata.get_analysis_for_vcf_file(vcf_file)
100
94
  if len(analysis_aliases) == 1:
101
95
  result_files_per_analysis[analysis_aliases[0]].append(vcf_file)
102
96
  elif len(analysis_aliases) == 0:
@@ -123,9 +117,9 @@ def check_sample_name_concordance(metadata_json, vcf_files, output_yaml):
123
117
  Take the metadata following EVA standard and formatted in JSON then compare the sample names in it to the ones
124
118
  found in the VCF files
125
119
  """
126
- samples_per_analysis, files_per_analysis = read_metadata_json(metadata_json)
127
- file_path_per_analysis = associate_vcf_path_with_analysis(vcf_files, files_per_analysis)
128
- overall_differences, results_per_analysis_alias = compare_all_analysis(samples_per_analysis, file_path_per_analysis)
120
+ metadata = EvaMetadataJson(metadata_json)
121
+ file_path_per_analysis = associate_vcf_path_with_analysis(metadata, vcf_files)
122
+ overall_differences, results_per_analysis_alias = compare_all_analysis(metadata, file_path_per_analysis)
129
123
  write_result_yaml(output_yaml, overall_differences, results_per_analysis_alias)
130
124
 
131
125
 
@@ -105,11 +105,11 @@ class XlsxParser:
105
105
  if type_name == 'string':
106
106
  return str(value)
107
107
  if type_name == 'boolean':
108
- return str(value).lower() in ['true', '1', 't', 'y', 'yes']
108
+ return str(value).lower() in ['true', '1', "'1'", 't', 'y', 'yes']
109
109
  if type_name == 'list':
110
110
  # split and remove empty values
111
- return [XlsxParser.trim_value(v)
112
- for v in value.split(',') if v]
111
+ split_values = [XlsxParser.trim_value(v) for v in value.split(',') if v]
112
+ return [v for v in split_values if v]
113
113
  if type_name == 'date':
114
114
  return XlsxParser.serialize(value)
115
115
  return value
@@ -23,6 +23,11 @@ def is_submission_dir_writable(submission_dir):
23
23
  return False
24
24
  return True
25
25
 
26
+ def is_vcf_file(file_path):
27
+ if file_path:
28
+ file_path = file_path.strip().lower()
29
+ return file_path.endswith('.vcf') or file_path.endswith('.vcf.gz')
30
+ return False
26
31
 
27
32
  def backup_file_or_directory(file_name, max_backups=None):
28
33
  """
@@ -69,11 +69,11 @@
69
69
  <section>
70
70
  <h2>VCF validation results</h2>
71
71
  <div class="description">
72
- Checks whether each file is compliant with the <a href="http://samtools.github.io/hts-specs/VCFv4.3.pdf" target=”_blank”>VCF specification</a>.
72
+ Checks whether each file is compliant with the <a href="http://samtools.github.io/hts-specs/VCFv4.4.pdf" target=”_blank”>VCF specification</a>.
73
73
  Also checks whether the variants' reference alleles match against the reference assembly.
74
74
  </div>
75
75
  {% for file_name in vcf_files %}
76
- {% if file_name!= "pass"%}
76
+ {% if file_name != "pass"%}
77
77
  <h3>{{ file_name }}</h3>
78
78
  {{ file_validation_report(validation_results, file_name) }}
79
79
  {% endif %}
@@ -95,7 +95,7 @@
95
95
  Also checks if the reference assembly accession in the metadata matches the one determined from the FASTA file.
96
96
  </div>
97
97
  {% for file_name in fasta_files %}
98
- {% if file_name!= "pass"%}
98
+ {% if file_name != "pass"%}
99
99
  <h3>{{ file_name }}</h3>
100
100
  {{ fasta_check_report(validation_results, file_name) }}
101
101
  {% endif %}
@@ -0,0 +1,46 @@
1
+ {% macro fasta_check_report(validation_results, file_name) -%}
2
+
3
+ {% set results_for_fasta = validation_results['fasta_check'][file_name] %}
4
+
5
+ {% if results_for_fasta.get('connection_error') %}
6
+ Warning: The following results may be incomplete due to problems with external services.
7
+ Please try again later for complete results.
8
+ Error message: {{ results_for_fasta.get('connection_error') }}
9
+ {% endif %}
10
+
11
+ {% if results_for_fasta.get('all_insdc') %}
12
+ {{ "\u2714" }} All sequences are INSDC accessioned.
13
+ {% else %}
14
+ {{ "\u274C" }} Some sequences are not INSDC accessioned
15
+ First 10 sequences not in INSDC. Full report: {{ results_for_fasta.get('report_path', '') }}
16
+ {% set sequence_info_list = results_for_fasta.get('sequences', [])|rejectattr("insdc")|list %}
17
+ {% for sequence_info in sequence_info_list[:10] %}
18
+ Sequence name: {{ sequence_info.get('sequence_name') }}
19
+ Refget md5: {{ sequence_info.get('sequence_md5') }}
20
+ ---
21
+ {% endfor %}
22
+ {% endif %}
23
+
24
+ {% if 'possible_assemblies' in results_for_fasta %}
25
+ {% if 'metadata_assembly_compatible' in results_for_fasta %}
26
+ {% set analysis_text = results_for_fasta.get('associated_analyses')|join(", ") %}
27
+ {% if results_for_fasta.get('metadata_assembly_compatible') %}
28
+ {% set icon = "\u2714" %}
29
+ {% set text = analysis_text + ": Assembly accession in metadata is compatible" %}
30
+ {% else %}
31
+ {% set icon = "\u274C" %}
32
+ {% set text = analysis_text + ": Assembly accession in metadata is not compatible" %}
33
+ {% endif %}
34
+ {% else %}
35
+ {% set icon = "\u274C" %}
36
+ {% set text = "No assembly accession found in metadata" %}
37
+ {% endif %}
38
+ {{ icon }} {{ text }}
39
+ {% if 'metadata_assembly_compatible' not in results_for_fasta or not results_for_fasta['metadata_assembly_compatible'] %}
40
+ Full report: {{ results_for_fasta.get('report_path', '') }}
41
+ Assembly accession found in metadata: {{ results_for_fasta.get('assembly_in_metadata', 'Not found') }}
42
+ Assembly accession(s) compatible with FASTA: {{ results_for_fasta.get('possible_assemblies')|join(", ") }}
43
+ {% endif %}
44
+ {% endif %}
45
+
46
+ {%- endmacro %}
@@ -0,0 +1,58 @@
1
+
2
+ {% macro file_validation_report(validation_results, file_name) -%}
3
+ {% for check_type, check_per_file in validation_results.items() %}
4
+ {% set result = check_per_file.get(file_name, {}) %}
5
+ {% if check_type == "assembly_check" %}
6
+ {{ assembly_check(result) }}
7
+ {% elif check_type == "vcf_check" %}
8
+ {{ vcf_check(result) }}
9
+ {% endif %}
10
+ {% endfor %}
11
+ {%- endmacro %}
12
+
13
+ {% macro vcf_check(vcf_check_result) %}
14
+ {% set critical_count = vcf_check_result.get("critical_count", 0) %}
15
+ {% set error_count = vcf_check_result.get("error_count", 0) %}
16
+ {% if critical_count > 0 or error_count > 0 %}
17
+ {% set icon = "\u274C" %}
18
+ {% else %}
19
+ {% set icon = "\u2714" %}
20
+ {% endif %}
21
+ {{ icon }} VCF check: {{ critical_count }} critical errors, {{ error_count }} non-critical errors
22
+
23
+ {% set critical_list = vcf_check_result.get("critical_list") %}
24
+ {% set error_list = vcf_check_result.get("error_list") %}
25
+ {% if critical_list or error_list%}
26
+ First 10 errors per category are below. Full report: {{ vcf_check_result.get('report_path', '') }}
27
+ {% for error in critical_list[:10] %}
28
+ Critical error: {{ error }}
29
+ {% endfor %}
30
+ {% for error in error_list[:10] %}
31
+ Non-critical error: {{ error }}
32
+ {% endfor %}
33
+ {% endif %}
34
+ {%- endmacro %}
35
+
36
+ {% macro assembly_check(assembly_check_result) %}
37
+ {% set nb_match = assembly_check_result.get("match", 0) %}
38
+ {% set nb_total = assembly_check_result.get("total", 0) %}
39
+ {% set match_percentage = nb_match / nb_total * 100 if nb_total else 0 %}
40
+ {% if assembly_check_result.get("nb_mismatch", 0) > 0 or nb_total == 0 %}
41
+ {% set icon = "\u274C" %}
42
+ {% else %}
43
+ {% set icon = "\u2714" %}
44
+ {% endif %}
45
+ {{ icon }} Assembly check: {{ nb_match }}/{{ nb_total }} ({{ match_percentage|round(2) }}%)
46
+
47
+ {% set mismatch_list = assembly_check_result.get("mismatch_list") %}
48
+ {% set error_list = assembly_check_result.get("error_list") %}
49
+ {% if mismatch_list or error_list %}
50
+ First 10 errors per category are below. Full report: {{ assembly_check_result.get('report_path', '') }}
51
+ {% for error in error_list[:10] %}
52
+ Parsing error: {{ error }}
53
+ {% endfor %}
54
+ {% for error in mismatch_list[:10] %}
55
+ Mismatch error: {{ error }}
56
+ {% endfor %}
57
+ {% endif %}
58
+ {%- endmacro %}
@@ -0,0 +1,33 @@
1
+
2
+ {% macro metadata_validation_report(validation_results) -%}
3
+
4
+ {% set results = validation_results.get('metadata_check', {}) %}
5
+ {% set spreadsheet_errors = results.get('spreadsheet_errors', []) %}
6
+ {% set json_errors = results.get('json_errors', []) %}
7
+ {% set has_errors = spreadsheet_errors or json_errors %}
8
+ {% if has_errors %}
9
+ {% set icon = "\u274C" %}
10
+ {% else %}
11
+ {% set icon = "\u2714" %}
12
+ {% endif %}
13
+ {{ icon }} Metadata validation check
14
+
15
+ {% if spreadsheet_errors %}
16
+ Full report: {{ results.get('spreadsheet_report_path', '') }}
17
+ {% for error in spreadsheet_errors %}
18
+ Sheet: {{ error.get('sheet') }} | Row: {{ error.get('row') }} | Column: {{ error.get('column') }}
19
+ Error: {{ error.get('description') }}
20
+ ---
21
+ {% endfor %}
22
+ {% endif %}
23
+
24
+ {% if json_errors %}
25
+ Full report: {{ results.get('json_report_path', '') }}
26
+ {% for error in json_errors %}
27
+ JSON Property: {{ error.get('property') }}
28
+ Error: {{ error.get('description') }}
29
+ ---
30
+ {% endfor %}
31
+ {% endif %}
32
+
33
+ {%- endmacro %}
@@ -0,0 +1,21 @@
1
+ {% macro project_details_report(project_title, validation_date, submission_dir, vcf_fasta_analysis_mapping) -%}
2
+
3
+ {% if project_title %}
4
+ Project Title: {{ project_title }}
5
+ {% else %}
6
+ Project Title: Not Found
7
+ {% endif %}
8
+ Validation Date: {{ validation_date }}
9
+ Submission Directory: {{ submission_dir }}
10
+
11
+ {% if vcf_fasta_analysis_mapping %}
12
+ Files mapping:
13
+ {% for mapping in vcf_fasta_analysis_mapping %}
14
+ ---
15
+ VCF File: {{ mapping.vcf_file }}
16
+ Fasta File: {{ mapping.fasta_file }}
17
+ Analysis: {{ mapping.analysis }}
18
+ {% endfor %}
19
+ {% endif %}
20
+
21
+ {%- endmacro %}
@@ -0,0 +1,59 @@
1
+ {% from 'project_details.txt' import project_details_report %}
2
+ {% from 'file_validation.txt' import file_validation_report %}
3
+ {% from 'sample_name_check.txt' import sample_name_check_report %}
4
+ {% from 'fasta_check.txt' import fasta_check_report %}
5
+ {% from 'metadata_validation.txt' import metadata_validation_report %}
6
+ {% from 'shallow_validation.txt' import optional_shallow_validation_report %}
7
+
8
+ VALIDATION REPORT
9
+ eva-sub-cli v{{cli_version}}
10
+
11
+ {{ optional_shallow_validation_report(validation_results) }}
12
+
13
+ -
14
+
15
+ PROJECT SUMMARY
16
+ General details about the project
17
+
18
+ {{ project_details_report(project_title, validation_date, submission_dir, vcf_fasta_analysis_mapping) }}
19
+
20
+ -
21
+
22
+ METADATA VALIDATION RESULTS
23
+ Ensures that required fields are present and values are formatted correctly.
24
+ For requirements, please refer to the EVA website (https://www.ebi.ac.uk/eva/?Submit-Data).
25
+
26
+ {{ metadata_validation_report(validation_results) }}
27
+
28
+ -
29
+
30
+ VCF VALIDATION RESULTS
31
+ Checks whether each file is compliant with the VCF specification (http://samtools.github.io/hts-specs/VCFv4.4.pdf).
32
+ Also checks whether the variants' reference alleles match against the reference assembly.
33
+
34
+ {% for file_name in vcf_files %}
35
+ {% if file_name != "pass"%}
36
+ {{ file_name }}
37
+ {{ file_validation_report(validation_results, file_name) }}
38
+ {% endif %}
39
+ {% endfor %}
40
+
41
+ -
42
+
43
+ SAMPLE NAME CONCORDANCE CHECK
44
+ Checks whether information in the metadata is concordant with that contained in the VCF files, in particular sample names.
45
+
46
+ {{ sample_name_check_report(validation_results)}}
47
+
48
+ -
49
+
50
+ REFERENCE GENOME INSDC CHECK
51
+ Checks that the reference sequences in the FASTA file used to call the variants are accessioned in INSDC.
52
+ Also checks if the reference assembly accession in the metadata matches the one determined from the FASTA file.
53
+
54
+ {% for file_name in fasta_files %}
55
+ {% if file_name != "pass"%}
56
+ {{ file_name }}
57
+ {{ fasta_check_report(validation_results, file_name) }}
58
+ {% endif %}
59
+ {% endfor %}
@@ -0,0 +1,24 @@
1
+
2
+ {% macro sample_name_check_report(validation_results) -%}
3
+ {% set results = validation_results.get('sample_check', {}) %}
4
+ {% macro format_error(error) %}
5
+ {{ error | replace(' ', '•') }}
6
+ {% endmacro %}
7
+
8
+ {% for analysis, results_for_analysis in results.get('results_per_analysis', {}).items() %}
9
+ {% if results_for_analysis.get('difference') %}
10
+ {% set icon = "\u274C" %}
11
+ {% set text = "Sample names in metadata do not match with those in VCF files" %}
12
+ {% else %}
13
+ {% set icon = "\u2714" %}
14
+ {% set text = "Sample names in metadata match with those in VCF files" %}
15
+ {% endif %}
16
+ {{ icon }} {{ analysis }}: {{ text }}
17
+
18
+ {% if results_for_analysis.get('difference') %}
19
+ First 10 errors per category are below. Full report: {{ results.get('report_path', '') }}
20
+ Samples described in the metadata but not in the VCF files: {{ results_for_analysis.get('more_metadata_submitted_files')[:10]|join(", ") }}
21
+ Samples in the VCF files but not described in the metadata: {{ results_for_analysis.get('more_submitted_files_metadata')[:10]|join(", ") }}
22
+ {% endif %}
23
+ {% endfor %}
24
+ {%- endmacro %}
@@ -0,0 +1,16 @@
1
+ {% macro optional_shallow_validation_report(validation_results) -%}
2
+
3
+ {% set results = validation_results.get('shallow_validation', {}) %}
4
+ {% if results.get('required') %}
5
+
6
+ {{ "\u274C" }} You requested to run the shallow validation, please run full validation before submitting the data
7
+ {% for vcf_file in results.get('metrics') %}
8
+ ---
9
+ VCF File: {{ vcf_file }}
10
+ Variant lines validated in VCF: {{ results.get('metrics').get(vcf_file).get('trim_down_vcf_record') }}
11
+ Entries used in Fasta: {{ results.get('metrics').get(vcf_file).get('number_sequence_found') }}
12
+ {% endfor %}
13
+
14
+ {% endif %}
15
+
16
+ {%- endmacro %}
@@ -0,0 +1,95 @@
1
+ import json
2
+ import os
3
+ from collections import defaultdict
4
+ from copy import deepcopy
5
+ from functools import cached_property
6
+
7
+ from ebi_eva_common_pyutils.logger import AppLogger
8
+
9
+
10
+ class EvaMetadataJson(AppLogger):
11
+
12
+ def __init__(self, path_to_json):
13
+ with open(path_to_json) as open_json:
14
+ self.content = json.load(open_json)
15
+
16
+ @property
17
+ def project(self):
18
+ return self.content.get('project', {})
19
+
20
+ @property
21
+ def submitter_details(self):
22
+ return self.content.get('submitterDetails', {})
23
+
24
+ @property
25
+ def analyses(self):
26
+ return self.content.get('analysis', [])
27
+
28
+ @property
29
+ def samples(self):
30
+ return self.content.get('sample', [])
31
+
32
+ @property
33
+ def files(self):
34
+ return self.content.get('files', [])
35
+
36
+ @cached_property
37
+ def resolved_files(self):
38
+ """Returns list of files with fileName resolved to an absolute path."""
39
+ mod_files = deepcopy(self.content.get('files', []))
40
+ for file_info in mod_files:
41
+ if 'fileName' in file_info:
42
+ file_info['fileName'] = os.path.abspath(file_info['fileName'])
43
+ return mod_files
44
+
45
+ def set_files(self, file_list):
46
+ assert isinstance(file_list, list)
47
+ self.content['files'] = file_list
48
+ # invalidate the cached property
49
+ if self.resolved_files:
50
+ del self.resolved_files
51
+
52
+ @cached_property
53
+ def samples_per_analysis(self):
54
+ """Returns mapping of analysis alias to sample names, based on metadata."""
55
+ samples_per_analysis = defaultdict(list)
56
+ for sample_info in self.samples:
57
+ for analysis_alias in sample_info.get('analysisAlias', []):
58
+ samples_per_analysis[analysis_alias].append(sample_info.get('sampleInVCF'))
59
+ return {
60
+ analysis_alias: set(samples)
61
+ for analysis_alias, samples in samples_per_analysis.items()
62
+ }
63
+
64
+ @cached_property
65
+ def files_per_analysis(self):
66
+ """Returns mapping of analysis alias to filenames, based on metadata."""
67
+ files_per_analysis = defaultdict(list)
68
+ for file_info in self.resolved_files:
69
+ files_per_analysis[file_info.get('analysisAlias')].append(file_info.get('fileName'))
70
+ return {
71
+ analysis_alias: set(filepaths)
72
+ for analysis_alias, filepaths in files_per_analysis.items()
73
+ }
74
+
75
+ def get_reference_assembly_for_analysis(self, analysis_alias):
76
+ """Returns the reference assembly for this analysis (does not validate format)."""
77
+ for analysis in self.analyses:
78
+ if analysis.get('analysisAlias') == analysis_alias:
79
+ return analysis.get('referenceGenome')
80
+ return None
81
+
82
+ def get_analysis_for_vcf_file(self, vcf_file):
83
+ """Returns list of analysis aliases associated with the vcf file path."""
84
+ if not os.path.exists(vcf_file):
85
+ raise FileNotFoundError(f'{vcf_file} cannot be resolved')
86
+ analysis_aliases = [analysis_alias for analysis_alias in self.files_per_analysis
87
+ if vcf_file in self.files_per_analysis[analysis_alias]
88
+ or os.path.basename(vcf_file) in [
89
+ os.path.basename(p) for p in self.files_per_analysis[analysis_alias]
90
+ ]]
91
+ return analysis_aliases
92
+
93
+ def write(self, output_path):
94
+ with open(output_path, 'w') as open_file:
95
+ json.dump(self.content, open_file)