eva-sub-cli 0.4.7__tar.gz → 0.4.8__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.
- eva_sub_cli-0.4.8/.github/workflows/trigger-eva-sub-cli-integration-tests.yml +16 -0
- {eva_sub_cli-0.4.7/eva_sub_cli.egg-info → eva_sub_cli-0.4.8}/PKG-INFO +1 -1
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/__init__.py +1 -1
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/_version.py +2 -2
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/etc/EVA_Submission_Example.xlsx +0 -0
- eva_sub_cli-0.4.8/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/etc/eva_schema.json +3 -2
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/check_fasta_insdc.py +18 -25
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/samples_checker.py +13 -19
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/xlsx2json.py +3 -3
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/file_utils.py +5 -0
- eva_sub_cli-0.4.8/eva_sub_cli/metadata.py +95 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/orchestrator.py +53 -52
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/validators/docker_validator.py +1 -1
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/validators/native_validator.py +4 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/validators/validator.py +39 -43
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8/eva_sub_cli.egg-info}/PKG-INFO +1 -1
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli.egg-info/SOURCES.txt +4 -1
- eva_sub_cli-0.4.8/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
- eva_sub_cli-0.4.8/tests/resources/EVA_Submission_test.xlsx +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/EVA_Submission_test_fails.xlsx +0 -0
- eva_sub_cli-0.4.8/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
- eva_sub_cli-0.4.8/tests/resources/metadata_with_filename.json +19 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_check_fasta_insdc.py +35 -3
- eva_sub_cli-0.4.8/tests/test_metadata.py +69 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_orchestrator.py +27 -6
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_samples_checker.py +29 -2
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_validator.py +35 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_xlsx2json.py +14 -0
- eva_sub_cli-0.4.7/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
- eva_sub_cli-0.4.7/eva_sub_cli/metadata_utils.py +0 -46
- eva_sub_cli-0.4.7/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
- eva_sub_cli-0.4.7/tests/resources/EVA_Submission_test.xlsx +0 -0
- eva_sub_cli-0.4.7/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/.github/workflows/publish.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/.github/workflows/publish_packages.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/.github/workflows/tests.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/.gitignore +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/LICENSE +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/README.md +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/conda/build.sh +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/conda/meta.yaml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/docker/Dockerfile +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/docs/Getting_Started_with_eva_sub_cli.md +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/auth.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/date_utils.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/etc/eva-biosamples.json +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/etc/eva_logo.png +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/etc/spreadsheet2json_conf.yaml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/exceptions/__init__.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/exceptions/invalid_file_type_exception.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/exceptions/metadata_template_version_exception.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/exceptions/submission_not_found_exception.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/exceptions/submission_status_exception.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/__init__.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/check_metadata_semantics.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/cli.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/executables/trim_down.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/fasta_check.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/file_validation.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/html_report.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/metadata_validation.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/project_details.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/sample_name_check.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/jinja_templates/shallow_validation.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/nextflow/validation.nf +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/report.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/semantic_metadata.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/submission_ws.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/submit.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/validators/__init__.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli/validators/validation_results_parsers.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli.egg-info/dependency_links.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli.egg-info/entry_points.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli.egg-info/requires.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/eva_sub_cli.egg-info/top_level.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/pyproject.toml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/pytest.ini +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/requirements.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/setup.cfg +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/setup.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/build_and_test_docker_locally.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/ignore_test_nextflow_validation.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/EVA_Submission_test.json +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/EVA_Submission_test_with_asm_report.json +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/assembly_check/invalid.vcf.assembly_check.log +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/assembly_reports/input_passed.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/fasta_files/input_passed.fa +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/fasta_files/multi_seq.fa +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/sample_checker/example1.vcf.gz +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/sample_checker/example2.vcf +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/sample_checker/example3.vcf +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/sample_checker/metadata.json +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/expected_report_metadata_json.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/expected_report_metadata_xlsx.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.html +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.assembly_check.log +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.text_assembly_report.1680102476700.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.valid_assembly_report.1680102476700.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/other_validations/input_passed.fa_check.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/other_validations/metadata_conversion_errors.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/other_validations/metadata_semantic_check.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/other_validations/metadata_validation.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/other_validations/sample_checker.yml +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.db +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.txt +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.vcf_format.log +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/vcf_files/example2.vcf.gz +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/resources/vcf_files/input_passed.vcf +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_auth.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_cli.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_docker_validator.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_file_utils.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_report.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_semantic_metadata.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_submit.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_trim_down.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/tests/test_utils.py +0 -0
- {eva_sub_cli-0.4.7 → eva_sub_cli-0.4.8}/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
|
|
@@ -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
|
-
|
|
9
|
+
MINIMUM_METADATA_XLSX_TEMPLATE_VERSION = '2.0.0'
|
|
10
10
|
|
|
11
11
|
SUB_CLI_CONFIG_FILE = ".eva_sub_cli_config.yml"
|
|
12
12
|
|
|
Binary file
|
|
Binary file
|
|
@@ -310,9 +310,10 @@
|
|
|
310
310
|
"type": "string",
|
|
311
311
|
"description": "Sample Name used in the VCF file"
|
|
312
312
|
},
|
|
313
|
-
"
|
|
313
|
+
"bioSampleAccession": {
|
|
314
314
|
"type": "string",
|
|
315
|
-
"
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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.
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
127
|
-
file_path_per_analysis = associate_vcf_path_with_analysis(
|
|
128
|
-
overall_differences, results_per_analysis_alias = compare_all_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
|
-
|
|
112
|
-
|
|
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
|
"""
|
|
@@ -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)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
import csv
|
|
3
|
-
import json
|
|
4
3
|
import os
|
|
5
4
|
import re
|
|
6
5
|
from collections import defaultdict
|
|
@@ -14,13 +13,15 @@ from requests import HTTPError
|
|
|
14
13
|
from retry import retry
|
|
15
14
|
|
|
16
15
|
import eva_sub_cli
|
|
17
|
-
from eva_sub_cli import
|
|
16
|
+
from eva_sub_cli import MINIMUM_METADATA_XLSX_TEMPLATE_VERSION
|
|
18
17
|
from eva_sub_cli import SUB_CLI_CONFIG_FILE, __version__
|
|
19
18
|
from eva_sub_cli.exceptions.invalid_file_type_exception import InvalidFileTypeError
|
|
20
19
|
from eva_sub_cli.exceptions.metadata_template_version_exception import MetadataTemplateVersionException, \
|
|
21
20
|
MetadataTemplateVersionNotFoundException
|
|
22
21
|
from eva_sub_cli.exceptions.submission_not_found_exception import SubmissionNotFoundException
|
|
23
22
|
from eva_sub_cli.exceptions.submission_status_exception import SubmissionStatusException
|
|
23
|
+
from eva_sub_cli.file_utils import is_vcf_file
|
|
24
|
+
from eva_sub_cli.metadata import EvaMetadataJson
|
|
24
25
|
from eva_sub_cli.submission_ws import SubmissionWSClient
|
|
25
26
|
from eva_sub_cli.submit import StudySubmitter, SUB_CLI_CONFIG_KEY_SUBMISSION_ID, \
|
|
26
27
|
SUB_CLI_CONFIG_KEY_SUBMISSION_UPLOAD_URL
|
|
@@ -76,6 +77,8 @@ def get_project_title_and_create_vcf_files_mapping(submission_dir, vcf_files, re
|
|
|
76
77
|
elif metadata_xlsx:
|
|
77
78
|
project_title, vcf_files_mapping = get_project_and_vcf_fasta_mapping_from_metadata_xlsx(metadata_xlsx, True)
|
|
78
79
|
|
|
80
|
+
# Filter out non-vcf files
|
|
81
|
+
vcf_files_mapping = [(vcf, fasta, report) for vcf, fasta, report in vcf_files_mapping if is_vcf_file(vcf)]
|
|
79
82
|
validate_vcf_mapping(vcf_files_mapping)
|
|
80
83
|
for mapping in vcf_files_mapping:
|
|
81
84
|
writer.writerow(mapping)
|
|
@@ -103,27 +106,24 @@ def validate_vcf_mapping(vcf_mapping):
|
|
|
103
106
|
|
|
104
107
|
|
|
105
108
|
def get_project_and_vcf_fasta_mapping_from_metadata_json(metadata_json, mapping_req=False):
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
analysis_alias_dict =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
vcf_fasta_report_mapping.append([os.path.abspath(file_dict['fileName']),
|
|
125
|
-
os.path.abspath(reference_fasta),
|
|
126
|
-
os.path.abspath(assembly_report) if assembly_report else ''])
|
|
109
|
+
metadata = EvaMetadataJson(metadata_json)
|
|
110
|
+
|
|
111
|
+
project_title = metadata.project.get('title')
|
|
112
|
+
|
|
113
|
+
vcf_fasta_report_mapping = []
|
|
114
|
+
if mapping_req:
|
|
115
|
+
analysis_alias_dict = defaultdict(dict)
|
|
116
|
+
for analysis in metadata.analyses:
|
|
117
|
+
analysis_alias_dict[analysis['analysisAlias']]['referenceFasta'] = analysis['referenceFasta']
|
|
118
|
+
analysis_alias_dict[analysis['analysisAlias']]['assemblyReport'] = analysis['assemblyReport'] \
|
|
119
|
+
if 'assemblyReport' in analysis else ''
|
|
120
|
+
|
|
121
|
+
for file_dict in metadata.resolved_files:
|
|
122
|
+
reference_fasta = analysis_alias_dict[file_dict['analysisAlias']]['referenceFasta']
|
|
123
|
+
assembly_report = analysis_alias_dict[file_dict['analysisAlias']]['assemblyReport']
|
|
124
|
+
vcf_fasta_report_mapping.append([os.path.abspath(file_dict['fileName']),
|
|
125
|
+
os.path.abspath(reference_fasta),
|
|
126
|
+
os.path.abspath(assembly_report) if assembly_report else ''])
|
|
127
127
|
|
|
128
128
|
return project_title, vcf_fasta_report_mapping
|
|
129
129
|
|
|
@@ -225,35 +225,36 @@ def get_project_and_vcf_fasta_mapping_from_metadata_xlsx(metadata_xlsx, mapping_
|
|
|
225
225
|
|
|
226
226
|
def check_validation_required(tasks, sub_config, username=None, password=None):
|
|
227
227
|
# Validation is mandatory so if submit is requested then VALIDATE must have run before or be requested as well
|
|
228
|
-
if SUBMIT in tasks:
|
|
229
|
-
if not sub_config.get(READY_FOR_SUBMISSION_TO_EVA, False):
|
|
230
|
-
return True
|
|
231
|
-
# If we are working with an existing submission check its status to see if it was submitted and failed before.
|
|
232
|
-
submission_id = sub_config.get(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, None)
|
|
233
|
-
if submission_id:
|
|
234
|
-
try:
|
|
235
|
-
submission_status = SubmissionWSClient(username, password).get_submission_status(submission_id)
|
|
236
|
-
if submission_status == 'FAILED':
|
|
237
|
-
# Reset the submission_id which will force the creation of a new one
|
|
238
|
-
sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, value=None)
|
|
239
|
-
sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_UPLOAD_URL, value=None)
|
|
240
|
-
return True
|
|
241
|
-
else:
|
|
242
|
-
return False
|
|
243
|
-
except requests.HTTPError as ex:
|
|
244
|
-
if ex.response.status_code == 404:
|
|
245
|
-
logger.error(
|
|
246
|
-
f'Submission with id {submission_id} could not be found: '
|
|
247
|
-
f'status code: {ex.response.status_code} response: {ex.response.text}')
|
|
248
|
-
raise SubmissionNotFoundException(f'Submission with id {submission_id} could not be found')
|
|
249
|
-
else:
|
|
250
|
-
logger.error(f'Error occurred while getting status of the submission with Id {submission_id}: '
|
|
251
|
-
f'status code: {ex.response.status_code} response: {ex.response.text}')
|
|
252
|
-
raise SubmissionStatusException(f'Error occurred while getting status of the submission '
|
|
253
|
-
f'with Id {submission_id}')
|
|
254
|
-
|
|
255
|
-
logger.debug(f'submission id not found in config. This might be the first time user is submitting')
|
|
228
|
+
if SUBMIT not in tasks:
|
|
256
229
|
return False
|
|
230
|
+
if not sub_config.get(READY_FOR_SUBMISSION_TO_EVA, False):
|
|
231
|
+
return True
|
|
232
|
+
# If we are working with an existing submission check its status to see if it was submitted and failed before.
|
|
233
|
+
submission_id = sub_config.get(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, None)
|
|
234
|
+
if submission_id:
|
|
235
|
+
try:
|
|
236
|
+
submission_status = SubmissionWSClient(username, password).get_submission_status(submission_id)
|
|
237
|
+
if submission_status == 'FAILED':
|
|
238
|
+
# Reset the submission_id which will force the creation of a new one
|
|
239
|
+
sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, value=None)
|
|
240
|
+
sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_UPLOAD_URL, value=None)
|
|
241
|
+
return True
|
|
242
|
+
else:
|
|
243
|
+
return False
|
|
244
|
+
except requests.HTTPError as ex:
|
|
245
|
+
if ex.response.status_code == 404:
|
|
246
|
+
logger.error(
|
|
247
|
+
f'Submission with id {submission_id} could not be found: '
|
|
248
|
+
f'status code: {ex.response.status_code} response: {ex.response.text}')
|
|
249
|
+
raise SubmissionNotFoundException(f'Submission with id {submission_id} could not be found')
|
|
250
|
+
else:
|
|
251
|
+
logger.error(f'Error occurred while getting status of the submission with Id {submission_id}: '
|
|
252
|
+
f'status code: {ex.response.status_code} response: {ex.response.text}')
|
|
253
|
+
raise SubmissionStatusException(f'Error occurred while getting status of the submission '
|
|
254
|
+
f'with Id {submission_id}')
|
|
255
|
+
|
|
256
|
+
logger.debug(f'submission id not found in config. This might be the first time user is submitting')
|
|
257
|
+
return False
|
|
257
258
|
|
|
258
259
|
|
|
259
260
|
def orchestrate_process(submission_dir, vcf_files, reference_fasta, metadata_json, metadata_xlsx,
|
|
@@ -272,7 +273,7 @@ def orchestrate_process(submission_dir, vcf_files, reference_fasta, metadata_jso
|
|
|
272
273
|
if metadata_xlsx:
|
|
273
274
|
metadata_xlsx = os.path.abspath(metadata_xlsx)
|
|
274
275
|
# check metadata xlsx version is not lower than the required min metadata template version
|
|
275
|
-
verify_metadata_xlsx_version(metadata_xlsx,
|
|
276
|
+
verify_metadata_xlsx_version(metadata_xlsx, MINIMUM_METADATA_XLSX_TEMPLATE_VERSION)
|
|
276
277
|
|
|
277
278
|
# Get the provided Project Title and VCF files mapping (VCF, Fasta and Report)
|
|
278
279
|
project_title, vcf_files_mapping = get_project_title_and_create_vcf_files_mapping(
|
|
@@ -12,7 +12,7 @@ from eva_sub_cli.validators.validator import Validator
|
|
|
12
12
|
logger = logging_config.get_logger(__name__)
|
|
13
13
|
|
|
14
14
|
default_container_image = 'ebivariation/eva-sub-cli'
|
|
15
|
-
default_container_tag = 'v0.0.
|
|
15
|
+
default_container_tag = 'v0.0.4.dev0'
|
|
16
16
|
container_validation_dir = '/opt/vcf_validation'
|
|
17
17
|
container_validation_output_dir = 'vcf_validation_output'
|
|
18
18
|
|
|
@@ -22,6 +22,10 @@ class NativeValidator(Validator):
|
|
|
22
22
|
self.assembly_checker_path = assembly_checker_path
|
|
23
23
|
self.biovalidator_path = biovalidator_path
|
|
24
24
|
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _validation_file_path_for(file_path):
|
|
27
|
+
return file_path
|
|
28
|
+
|
|
25
29
|
def _validate(self):
|
|
26
30
|
self.run_validator()
|
|
27
31
|
|
|
@@ -12,6 +12,7 @@ from ebi_eva_common_pyutils.config import WritableConfig
|
|
|
12
12
|
|
|
13
13
|
from eva_sub_cli import ETC_DIR, SUB_CLI_CONFIG_FILE, __version__
|
|
14
14
|
from eva_sub_cli.file_utils import backup_file_or_directory, resolve_single_file_path
|
|
15
|
+
from eva_sub_cli.metadata import EvaMetadataJson
|
|
15
16
|
from eva_sub_cli.report import generate_html_report
|
|
16
17
|
from ebi_eva_common_pyutils.logger import logging_config, AppLogger
|
|
17
18
|
|
|
@@ -119,7 +120,7 @@ class Validator(AppLogger):
|
|
|
119
120
|
|
|
120
121
|
@staticmethod
|
|
121
122
|
def _validation_file_path_for(file_path):
|
|
122
|
-
|
|
123
|
+
raise NotImplementedError
|
|
123
124
|
|
|
124
125
|
def verify_files_present(self):
|
|
125
126
|
# verify mapping file exists
|
|
@@ -431,29 +432,25 @@ class Validator(AppLogger):
|
|
|
431
432
|
f"Cannot locate file_info.txt at {os.path.join(self.output_dir, 'other_validations', 'file_info.txt')}"
|
|
432
433
|
)
|
|
433
434
|
if self.metadata_json_post_validation:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
self.error('Error while loading or parsing metadata json: ' + str(e))
|
|
454
|
-
if json_data:
|
|
455
|
-
with open(self.metadata_json_post_validation, 'w') as open_file:
|
|
456
|
-
json.dump(json_data, open_file)
|
|
435
|
+
metadata = EvaMetadataJson(self.metadata_json_post_validation)
|
|
436
|
+
try:
|
|
437
|
+
file_rows = []
|
|
438
|
+
if metadata.files:
|
|
439
|
+
for file_dict in metadata.files:
|
|
440
|
+
file_path = self._validation_file_path_for(file_dict.get('fileName'))
|
|
441
|
+
file_dict['md5'] = file_path_2_md5.get(file_path) or \
|
|
442
|
+
file_name_2_md5.get(file_dict.get('fileName')) or ''
|
|
443
|
+
file_dict['fileSize'] = file_path_2_file_size.get(file_path) or \
|
|
444
|
+
file_name_2_file_size.get(file_dict.get('fileName')) or ''
|
|
445
|
+
file_rows.append(file_dict)
|
|
446
|
+
else:
|
|
447
|
+
self.error('No file found in metadata and multiple analysis alias exist: '
|
|
448
|
+
'cannot infer the relationship between files and analysis alias')
|
|
449
|
+
metadata.set_files(file_rows)
|
|
450
|
+
except Exception as e:
|
|
451
|
+
# Skip adding the md5
|
|
452
|
+
self.error('Error while loading or parsing metadata json: ' + str(e))
|
|
453
|
+
metadata.write(self.metadata_json_post_validation)
|
|
457
454
|
else:
|
|
458
455
|
self.error(f'Cannot locate the metadata in JSON format in {os.path.join(self.output_dir, "metadata.json")}')
|
|
459
456
|
|
|
@@ -479,27 +476,26 @@ class Validator(AppLogger):
|
|
|
479
476
|
vcf_fasta_analysis_mapping.append({'vcf_file': row['vcf'], 'fasta_file': row['fasta']})
|
|
480
477
|
|
|
481
478
|
if self.metadata_json_post_validation:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
except Exception as e:
|
|
500
|
-
self.error('Error building Validation Report : Error getting info from metadata file' + str(e))
|
|
479
|
+
metadata = EvaMetadataJson(self.metadata_json_post_validation)
|
|
480
|
+
try:
|
|
481
|
+
vcf_analysis_dict = {}
|
|
482
|
+
for file in metadata.resolved_files:
|
|
483
|
+
if file.get('fileName', []) and file.get('analysisAlias', []):
|
|
484
|
+
vcf_analysis_dict[file.get('fileName')] = file.get('analysisAlias')
|
|
485
|
+
|
|
486
|
+
for vcf_fasta_mapping in vcf_fasta_analysis_mapping:
|
|
487
|
+
vcf_file = vcf_fasta_mapping.get('vcf_file')
|
|
488
|
+
if vcf_file in vcf_analysis_dict:
|
|
489
|
+
vcf_fasta_mapping.update({'analysis': vcf_analysis_dict.get(vcf_file)})
|
|
490
|
+
else:
|
|
491
|
+
vcf_fasta_mapping.update({'analysis': 'Could not be linked'})
|
|
492
|
+
|
|
493
|
+
return vcf_fasta_analysis_mapping
|
|
494
|
+
except Exception as e:
|
|
495
|
+
self.error('Error building Validation Report : Error getting info from metadata file' + str(e))
|
|
501
496
|
else:
|
|
502
497
|
self.error('Error building validation report : Metadata file not present')
|
|
498
|
+
return []
|
|
503
499
|
|
|
504
500
|
def create_reports(self):
|
|
505
501
|
report_html = generate_html_report(self.results, self.validation_date, self.submission_dir,
|