eva-sub-cli 0.4.6__tar.gz → 0.4.7__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 (113) hide show
  1. {eva_sub_cli-0.4.6/eva_sub_cli.egg-info → eva_sub_cli-0.4.7}/PKG-INFO +4 -2
  2. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/_version.py +2 -2
  3. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/eva_schema.json +7 -5
  4. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/trim_down.py +21 -11
  5. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/file_utils.py +3 -3
  6. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/nextflow/validation.nf +1 -0
  7. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/semantic_metadata.py +42 -5
  8. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/validators/docker_validator.py +15 -11
  9. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/validators/validator.py +5 -2
  10. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7/eva_sub_cli.egg-info}/PKG-INFO +4 -2
  11. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli.egg-info/SOURCES.txt +4 -0
  12. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli.egg-info/requires.txt +3 -1
  13. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/requirements.txt +3 -1
  14. eva_sub_cli-0.4.7/tests/build_and_test_docker_locally.py +293 -0
  15. eva_sub_cli-0.4.7/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
  16. eva_sub_cli-0.4.7/tests/resources/fasta_files/multi_seq.fa +8 -0
  17. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/other_validations/metadata_validation.txt +2 -0
  18. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_cli.py +5 -0
  19. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_semantic_metadata.py +41 -17
  20. eva_sub_cli-0.4.7/tests/test_trim_down.py +108 -0
  21. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_validator.py +11 -2
  22. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_xlsx2json.py +27 -0
  23. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/.github/workflows/publish.yml +0 -0
  24. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/.github/workflows/publish_packages.yml +0 -0
  25. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/.github/workflows/tests.yml +0 -0
  26. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/.gitignore +0 -0
  27. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/LICENSE +0 -0
  28. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/README.md +0 -0
  29. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/conda/build.sh +0 -0
  30. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/conda/meta.yaml +0 -0
  31. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/docker/Dockerfile +0 -0
  32. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/docs/Getting_Started_with_eva_sub_cli.md +0 -0
  33. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/__init__.py +0 -0
  34. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/auth.py +0 -0
  35. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/date_utils.py +0 -0
  36. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/EVA_Submission_Example.xlsx +0 -0
  37. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
  38. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/eva-biosamples.json +0 -0
  39. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/eva_logo.png +0 -0
  40. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/etc/spreadsheet2json_conf.yaml +0 -0
  41. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/exceptions/__init__.py +0 -0
  42. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/exceptions/invalid_file_type_exception.py +0 -0
  43. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/exceptions/metadata_template_version_exception.py +0 -0
  44. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/exceptions/submission_not_found_exception.py +0 -0
  45. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/exceptions/submission_status_exception.py +0 -0
  46. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/__init__.py +0 -0
  47. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/check_fasta_insdc.py +0 -0
  48. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/check_metadata_semantics.py +0 -0
  49. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/cli.py +0 -0
  50. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/samples_checker.py +0 -0
  51. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/executables/xlsx2json.py +0 -0
  52. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/fasta_check.html +0 -0
  53. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/file_validation.html +0 -0
  54. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/html_report.html +0 -0
  55. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/metadata_validation.html +0 -0
  56. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/project_details.html +0 -0
  57. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/sample_name_check.html +0 -0
  58. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/jinja_templates/shallow_validation.html +0 -0
  59. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/metadata_utils.py +0 -0
  60. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/orchestrator.py +0 -0
  61. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/report.py +0 -0
  62. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/submission_ws.py +0 -0
  63. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/submit.py +0 -0
  64. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/validators/__init__.py +0 -0
  65. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/validators/native_validator.py +0 -0
  66. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli/validators/validation_results_parsers.py +0 -0
  67. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli.egg-info/dependency_links.txt +0 -0
  68. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli.egg-info/entry_points.txt +0 -0
  69. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/eva_sub_cli.egg-info/top_level.txt +0 -0
  70. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/pyproject.toml +0 -0
  71. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/pytest.ini +0 -0
  72. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/setup.cfg +0 -0
  73. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/setup.py +0 -0
  74. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/ignore_test_nextflow_validation.yml +0 -0
  75. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/EVA_Submission_test.json +0 -0
  76. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/EVA_Submission_test.xlsx +0 -0
  77. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/EVA_Submission_test_fails.xlsx +0 -0
  78. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
  79. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/EVA_Submission_test_with_asm_report.json +0 -0
  80. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/assembly_check/invalid.vcf.assembly_check.log +0 -0
  81. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt +0 -0
  82. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/assembly_reports/input_passed.txt +0 -0
  83. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa +0 -0
  84. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/fasta_files/input_passed.fa +0 -0
  85. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/sample_checker/example1.vcf.gz +0 -0
  86. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/sample_checker/example2.vcf +0 -0
  87. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/sample_checker/example3.vcf +0 -0
  88. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/sample_checker/metadata.json +0 -0
  89. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/expected_report_metadata_json.html +0 -0
  90. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/expected_report_metadata_xlsx.html +0 -0
  91. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.html +0 -0
  92. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.assembly_check.log +0 -0
  93. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.text_assembly_report.1680102476700.txt +0 -0
  94. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.valid_assembly_report.1680102476700.txt +0 -0
  95. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/other_validations/input_passed.fa_check.yml +0 -0
  96. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/other_validations/metadata_conversion_errors.yml +0 -0
  97. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/other_validations/metadata_semantic_check.yml +0 -0
  98. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/other_validations/sample_checker.yml +0 -0
  99. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.db +0 -0
  100. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.txt +0 -0
  101. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.vcf_format.log +0 -0
  102. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/vcf_files/example2.vcf.gz +0 -0
  103. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/resources/vcf_files/input_passed.vcf +0 -0
  104. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_auth.py +0 -0
  105. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_check_fasta_insdc.py +0 -0
  106. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_docker_validator.py +0 -0
  107. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_file_utils.py +0 -0
  108. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_orchestrator.py +0 -0
  109. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_report.py +0 -0
  110. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_samples_checker.py +0 -0
  111. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_submit.py +0 -0
  112. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_utils.py +0 -0
  113. {eva_sub_cli-0.4.6 → eva_sub_cli-0.4.7}/tests/test_validaton_results_parsers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4.6
3
+ Version: 0.4.7
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,12 +19,14 @@ 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.6.11
22
+ Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.1
23
23
  Requires-Dist: jinja2==3.*,>=3.0.0
24
24
  Requires-Dist: jsonschema==4.*
25
25
  Requires-Dist: openpyxl==3.*
26
26
  Requires-Dist: pyyaml==6.*
27
27
  Requires-Dist: requests==2.*
28
+ Requires-Dist: packaging==24.*
29
+ Requires-Dist: setuptools-scm
28
30
  Dynamic: license-file
29
31
 
30
32
  # eva-sub-cli
@@ -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.6'
21
- __version_tuple__ = version_tuple = (0, 4, 6)
20
+ __version__ = version = '0.4.7'
21
+ __version_tuple__ = version_tuple = (0, 4, 7)
@@ -75,11 +75,13 @@
75
75
  "properties": {
76
76
  "title": {
77
77
  "type": "string",
78
- "description": "Title of the project"
78
+ "description": "Title of the project",
79
+ "maxLength": 500
79
80
  },
80
81
  "description": {
81
82
  "type": "string",
82
- "description": "Description of the project"
83
+ "description": "Description of the project",
84
+ "maxLength": 5000
83
85
  },
84
86
  "centre": {
85
87
  "type": "string",
@@ -166,11 +168,11 @@
166
168
  "type": "string",
167
169
  "description": "Reference against which the analysis was performed. ENA or NCBI accession (starting with GCA) accepted."
168
170
  },
169
- "referenceFasta": {
171
+ "referenceFasta": {
170
172
  "type": "string",
171
173
  "description": "The path to the reference in fasta format that was used to create the VCF. (This is a local path)"
172
174
  },
173
- "assemblyReport": {
175
+ "assemblyReport": {
174
176
  "type": "string",
175
177
  "description": "The path to the assembly report associated with the assembly as found in NCBI assemblies. (This is a local path and only applicable for GCAs)"
176
178
  },
@@ -319,7 +321,7 @@
319
321
  "$ref": "eva-biosamples.json"
320
322
  },
321
323
  {
322
- "$ref": "https://www.ebi.ac.uk/biosamples/schema/store/registry/schemas/ERC000011"
324
+ "$ref": "https://www.ebi.ac.uk/biosamples/schema/store/registry/schemas/ERC000011"
323
325
  },
324
326
  {
325
327
  "$ref": "https://www.ebi.ac.uk/biosamples/schemas/certification/plant-miappe.json"
@@ -1,6 +1,7 @@
1
1
  import argparse
2
2
  import os
3
3
 
4
+ import sys
4
5
  import yaml
5
6
  from ebi_eva_common_pyutils.logger import logging_config
6
7
  from eva_sub_cli.file_utils import open_gzip_if_required, fasta_iter
@@ -8,15 +9,16 @@ from eva_sub_cli.file_utils import open_gzip_if_required, fasta_iter
8
9
  logger = logging_config.get_logger(__name__)
9
10
 
10
11
 
11
- max_nb_lines = 10000
12
+ MAX_NB_LINES = 10000
12
13
 
13
14
 
14
- def trim_down_vcf(vcf_file, output_vcf):
15
+ def trim_down_vcf(vcf_file, output_vcf, max_nb_lines=MAX_NB_LINES):
15
16
  """
16
17
  Produce a smaller vcf files containing a maximum of 10000 records
17
18
  """
18
- with open_gzip_if_required(vcf_file) as vcf_in, open(output_vcf, 'w') as vcf_out:
19
+ with open_gzip_if_required(vcf_file) as vcf_in, open_gzip_if_required(output_vcf, 'w') as vcf_out:
19
20
  line_count = 0
21
+ trimmed_down = False
20
22
  ref_seq_names = set()
21
23
  for line in vcf_in:
22
24
  if line.startswith('#') or line_count < max_nb_lines:
@@ -25,10 +27,12 @@ def trim_down_vcf(vcf_file, output_vcf):
25
27
  line_count += 1
26
28
  ref_seq_names.add(line.split('\t')[0])
27
29
  else:
30
+ trimmed_down = True
28
31
  break
29
32
  if line_count != max_nb_lines:
30
33
  logger.warning(f'Only {line_count} found in the source VCF {vcf_file} ')
31
- return line_count, ref_seq_names
34
+
35
+ return line_count, trimmed_down, ref_seq_names
32
36
 
33
37
 
34
38
  def trim_down_fasta(fasta_file, output_fasta, ref_seq_names):
@@ -46,10 +50,9 @@ def trim_down_fasta(fasta_file, output_fasta, ref_seq_names):
46
50
  print(sequence[i:i+80], file=fasta_out)
47
51
  return found_sequences
48
52
 
49
-
50
- def main():
53
+ def parse_args(cmd_line_args):
51
54
  arg_parser = argparse.ArgumentParser(
52
- description=f'Take a VCF file and only keep {max_nb_lines} lines and remove unused fasta sequence from the '
55
+ description=f'Take a VCF file and only keep {MAX_NB_LINES} lines and remove unused fasta sequence from the '
53
56
  f'associated reference genome')
54
57
  arg_parser.add_argument('--vcf_file', dest='vcf_file', required=True,
55
58
  help='Path to the vcf file to be trimmed down')
@@ -63,16 +66,23 @@ def main():
63
66
  help='Path to the yaml file containing the trim down metrics')
64
67
 
65
68
  args = arg_parser.parse_args()
69
+ return args
70
+
71
+ def main():
72
+ args = parse_args(sys.argv[1:])
73
+
66
74
  logging_config.add_stdout_handler()
67
75
 
68
- line_count, ref_sequence = trim_down_vcf(args.vcf_file, args.output_vcf_file)
76
+ line_count, trimmed_down, ref_sequence = trim_down_vcf(args.vcf_file, args.output_vcf_file)
69
77
  sequence_found = trim_down_fasta(args.fasta_file, args.output_fasta_file, ref_sequence)
70
- trim_down_metrics = {'trim_down_vcf_record': line_count, 'number_sequence_found': sequence_found,
71
- 'trim_down_required': line_count == max_nb_lines}
78
+ trim_down_metrics = {'trim_down_vcf_record': line_count, 'number_sequence_found': len(sequence_found),
79
+ 'trim_down_required': trimmed_down}
72
80
  if len(sequence_found) != len(ref_sequence):
73
81
  logger.warning(f'Not all sequences were found in the fasta file. Cancelling trimming down of fasta file')
82
+ if os.path.exists(args.output_fasta_file):
83
+ os.remove(args.output_fasta_file)
74
84
  os.link(args.fasta_file, args.output_fasta_file)
75
85
  trim_down_metrics.pop('number_sequence_found')
76
- with open(args.output_yaml_file) as open_file:
86
+ with open(args.output_yaml_file, 'w') as open_file:
77
87
  yaml.safe_dump(trim_down_metrics, open_file)
78
88
 
@@ -46,12 +46,12 @@ def backup_file_or_directory(file_name, max_backups=None):
46
46
  os.rename(file_name, file_name + '.1')
47
47
 
48
48
 
49
- def open_gzip_if_required(input_file):
49
+ def open_gzip_if_required(input_file, mode='r'):
50
50
  """Open a file in read mode using gzip if the file extension says .gz"""
51
51
  if input_file.endswith('.gz'):
52
- return gzip.open(input_file, 'rt')
52
+ return gzip.open(input_file, mode + 't')
53
53
  else:
54
- return open(input_file, 'r')
54
+ return open(input_file, mode)
55
55
 
56
56
 
57
57
  def fasta_iter(input_fasta):
@@ -116,6 +116,7 @@ process trim_down_vcf {
116
116
  path "${vcf.getBaseName()}_trim_down.log", emit: trim_down_log
117
117
  path "${vcf.getBaseName()}_trim_down.yml", emit: trim_down_metric
118
118
 
119
+ script:
119
120
  """
120
121
  mkdir output
121
122
  $params.python_scripts.trim_down --vcf_file $vcf --output_vcf_file output/$vcf --fasta_file $fasta --output_fasta_file output/$fasta --output_yaml_file ${vcf.getBaseName()}_trim_down.yml > ${vcf.getBaseName()}_trim_down.log
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  from collections import Counter
3
3
  from copy import deepcopy
4
+ from datetime import datetime
4
5
 
5
6
  import yaml
6
7
 
@@ -26,6 +27,8 @@ SCI_NAME_KEYS = ['species', 'Species', 'organism', 'Organism']
26
27
  ANALYSIS_ALIAS_KEY = 'analysisAlias'
27
28
  ANALYSIS_RUNS_KEY = 'runAccessions'
28
29
 
30
+ # Samples created before this date are not required to have collection date or geographic location
31
+ threshold_2023 = datetime(2023,1,1)
29
32
 
30
33
  def cast_list(l, type_to_cast=str):
31
34
  for e in l:
@@ -147,8 +150,12 @@ class SemanticMetadataChecker(AppLogger):
147
150
  """
148
151
  self.errors.append({'property': property, 'description': description})
149
152
 
150
- def _get_biosample(self, sample_accession):
151
- return self.communicator.follows_link('samples', join_url=sample_accession)
153
+ def _get_biosample(self, sample_accession, include_curation=False):
154
+ if include_curation:
155
+ append_to_url = sample_accession
156
+ else:
157
+ append_to_url = sample_accession + '?curationdomain='
158
+ return self.communicator.follows_link('samples', join_url=append_to_url)
152
159
 
153
160
  def check_existing_biosamples(self):
154
161
  """Check that existing BioSamples are accessible and contain the required attributes."""
@@ -184,15 +191,45 @@ class SemanticMetadataChecker(AppLogger):
184
191
  # Successful response returns the sample object, error response has a list of error objects.
185
192
  if isinstance(response, list):
186
193
  for error_dict in response:
194
+ error_property = ''
195
+ # Retrieve the property the error applied to in the datapath
196
+ if 'dataPath' in error_dict:
197
+ if error_dict['dataPath'].startswith('/characteristics/'):
198
+ error_property = error_dict['dataPath'].split('/')[2]
199
+ else:
200
+ error_property = error_dict['dataPath']
201
+ # Define the error
202
+ error_list = []
187
203
  if accession:
188
- self.add_error(json_path, f'Existing sample {accession} {error_dict["errors"][0]}')
189
- else:
190
- self.add_error(json_path, error_dict["errors"][0])
204
+ error_list.append(f'Error validating existing sample {accession}:')
205
+ if error_property and error_property not in error_dict['errors'][0]:
206
+ error_list.append(error_property)
207
+ error_list.append(error_dict['errors'][0])
208
+ error = ' '.join(error_list)
209
+ if self._should_bypass_error(sample_data, error):
210
+ self.debug(f'bypass error {error} from {json_path}')
211
+ continue
212
+ self.add_error(json_path, error)
213
+
191
214
  finally:
192
215
  self.communicator.acceptable_code = pre_acceptable_code
193
216
 
217
+ def _should_bypass_error(self, sample_data, error):
218
+ try:
219
+ created_dated = datetime.strptime(sample_data['create'],'%Y-%m-%dT%H:%M:%S.%fZ')
220
+ if created_dated < threshold_2023 and (
221
+ 'collection date' in error or
222
+ 'geographic location (country and/or sea)' in error
223
+ ):
224
+ return True
225
+ except Exception:
226
+ pass
227
+ return False
228
+
194
229
  def _local_validate_existing_biosample(self, sample_data, json_path, accession):
195
230
  """Check if the existing sample has the expected fields present"""
231
+ if self._should_bypass_error(sample_data, 'collection date'):
232
+ return
196
233
  found_collection_date = False
197
234
  for key in ['collection_date', 'collection date']:
198
235
  if key in sample_data['characteristics'] and check_date(sample_data['characteristics'][key][0]['text']):
@@ -11,8 +11,8 @@ from eva_sub_cli.validators.validator import Validator
11
11
 
12
12
  logger = logging_config.get_logger(__name__)
13
13
 
14
- container_image = 'ebivariation/eva-sub-cli'
15
- container_tag = 'v0.0.3'
14
+ default_container_image = 'ebivariation/eva-sub-cli'
15
+ default_container_tag = 'v0.0.3'
16
16
  container_validation_dir = '/opt/vcf_validation'
17
17
  container_validation_output_dir = 'vcf_validation_output'
18
18
 
@@ -20,13 +20,16 @@ container_validation_output_dir = 'vcf_validation_output'
20
20
  class DockerValidator(Validator):
21
21
 
22
22
  def __init__(self, mapping_file, submission_dir, project_title, metadata_json=None,
23
- metadata_xlsx=None, shallow_validation=False, docker_path='docker', submission_config=None):
23
+ metadata_xlsx=None, shallow_validation=False, docker_path='docker', submission_config=None,
24
+ container_image=None, container_tag=None, container_name=None):
24
25
  super().__init__(mapping_file, submission_dir, project_title,
25
26
  metadata_json=metadata_json, metadata_xlsx=metadata_xlsx,
26
27
  shallow_validation=shallow_validation, submission_config=submission_config)
27
28
  self.docker_path = docker_path
28
29
  submission_basename = re.sub('[^a-zA-Z0-9]', '', os.path.basename(submission_dir))
29
- self.container_name = f'{container_image.split("/")[1]}.{container_tag}.{submission_basename}'
30
+ self.container_image = container_image or default_container_image
31
+ self.container_tag = container_tag or default_container_tag
32
+ self.container_name = container_name or f'{self.container_image.split("/")[1]}.{self.container_tag}.{submission_basename}'
30
33
 
31
34
  def _validate(self):
32
35
  self.run_docker_validator()
@@ -130,11 +133,11 @@ class DockerValidator(Validator):
130
133
  f"{self.docker_path} images",
131
134
  return_process_output=True
132
135
  )
133
- if container_images_cmd_ouptut is not None and re.search(container_image + r'\s+' + container_tag, container_images_cmd_ouptut):
134
- logger.debug(f"Container ({container_image}) image is available locally")
136
+ if container_images_cmd_ouptut is not None and re.search(self.container_image + r'\s+' + self.container_tag, container_images_cmd_ouptut):
137
+ logger.debug(f"Container ({self.container_image}) image is available locally")
135
138
  return True
136
139
  else:
137
- logger.debug(f"Container ({container_image}) image is not available locally")
140
+ logger.debug(f"Container ({self.container_image}) image is not available locally")
138
141
  return False
139
142
 
140
143
  def run_container_if_required(self):
@@ -149,7 +152,7 @@ class DockerValidator(Validator):
149
152
  try:
150
153
  self._run_quiet_command(
151
154
  "Running container",
152
- f"{self.docker_path} run -it --rm -d --name {self.container_name} {container_image}:{container_tag}"
155
+ f"{self.docker_path} run -it --rm -d --name {self.container_name} {self.container_image}:{self.container_tag}"
153
156
  )
154
157
  # Wait to give some time to container to get up and running
155
158
  time.sleep(5)
@@ -169,12 +172,13 @@ class DockerValidator(Validator):
169
172
  @retry(RuntimeError, tries=3, delay=5, backoff=1, jitter=2, logger=logger)
170
173
  def download_container_image_if_needed(self):
171
174
  if not self.verify_image_available_locally():
172
- logger.debug(f"Pulling container ({container_image}) image")
175
+ logger.debug(f"Pulling container ({self.container_image}) image")
173
176
  try:
174
- self._run_quiet_command("pull container image", f"{self.docker_path} pull {container_image}:{container_tag}")
177
+ self._run_quiet_command("pull container image",
178
+ f"{self.docker_path} pull {self.container_image}:{self.container_tag}")
175
179
  except subprocess.CalledProcessError as ex:
176
180
  logger.error(ex)
177
- raise RuntimeError(f"Cannot pull container ({container_image}) image")
181
+ raise RuntimeError(f"Cannot pull container ({self.container_image}) image")
178
182
  # Give the pull command some time to complete
179
183
  time.sleep(5)
180
184
 
@@ -371,15 +371,18 @@ class Validator(AppLogger):
371
371
  sheet = convert_metadata_sheet(sheet_json, xls2json_conf)
372
372
  row = convert_metadata_row(sheet, row_json, xls2json_conf)
373
373
  column = convert_metadata_attribute(sheet, attribute_json, xls2json_conf)
374
+
374
375
  if row_json is None and attribute_json is None and sheet is not None:
375
376
  new_description = f'Sheet "{sheet}" is missing'
376
377
  elif row_json is None:
377
- if 'have required' not in error['description']:
378
+ missing_property_error = f" have required property '{sheet_json}'"
379
+ if not error['description'].endswith(missing_property_error):
378
380
  new_description = error['description']
379
381
  else:
380
382
  new_description = f'Column "{column}" is not populated'
381
383
  elif attribute_json and column:
382
- if 'have required' not in error['description']:
384
+ missing_property_error = f" have required property '{attribute_json}'"
385
+ if not error['description'].endswith(missing_property_error):
383
386
  new_description = error['description']
384
387
  else:
385
388
  new_description = f'Column "{column}" is not populated'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4.6
3
+ Version: 0.4.7
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,12 +19,14 @@ 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.6.11
22
+ Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.1
23
23
  Requires-Dist: jinja2==3.*,>=3.0.0
24
24
  Requires-Dist: jsonschema==4.*
25
25
  Requires-Dist: openpyxl==3.*
26
26
  Requires-Dist: pyyaml==6.*
27
27
  Requires-Dist: requests==2.*
28
+ Requires-Dist: packaging==24.*
29
+ Requires-Dist: setuptools-scm
28
30
  Dynamic: license-file
29
31
 
30
32
  # eva-sub-cli
@@ -61,6 +61,7 @@ eva_sub_cli/validators/docker_validator.py
61
61
  eva_sub_cli/validators/native_validator.py
62
62
  eva_sub_cli/validators/validation_results_parsers.py
63
63
  eva_sub_cli/validators/validator.py
64
+ tests/build_and_test_docker_locally.py
64
65
  tests/ignore_test_nextflow_validation.yml
65
66
  tests/test_auth.py
66
67
  tests/test_check_fasta_insdc.py
@@ -72,10 +73,12 @@ tests/test_report.py
72
73
  tests/test_samples_checker.py
73
74
  tests/test_semantic_metadata.py
74
75
  tests/test_submit.py
76
+ tests/test_trim_down.py
75
77
  tests/test_utils.py
76
78
  tests/test_validaton_results_parsers.py
77
79
  tests/test_validator.py
78
80
  tests/test_xlsx2json.py
81
+ tests/resources/EVA_Submission_Docker_Test.xlsx
79
82
  tests/resources/EVA_Submission_test.json
80
83
  tests/resources/EVA_Submission_test.xlsx
81
84
  tests/resources/EVA_Submission_test_fails.xlsx
@@ -86,6 +89,7 @@ tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt
86
89
  tests/resources/assembly_reports/input_passed.txt
87
90
  tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa
88
91
  tests/resources/fasta_files/input_passed.fa
92
+ tests/resources/fasta_files/multi_seq.fa
89
93
  tests/resources/sample_checker/example1.vcf.gz
90
94
  tests/resources/sample_checker/example2.vcf
91
95
  tests/resources/sample_checker/example3.vcf
@@ -1,6 +1,8 @@
1
- ebi_eva_common_pyutils==0.*,>0.6.11
1
+ ebi_eva_common_pyutils==0.*,>=0.7.1
2
2
  jinja2==3.*,>=3.0.0
3
3
  jsonschema==4.*
4
4
  openpyxl==3.*
5
5
  pyyaml==6.*
6
6
  requests==2.*
7
+ packaging==24.*
8
+ setuptools-scm
@@ -1,6 +1,8 @@
1
- ebi_eva_common_pyutils > 0.6.11, == 0.*
1
+ ebi_eva_common_pyutils >= 0.7.1, == 0.*
2
2
  jinja2 >= 3.0.0, ==3.*
3
3
  jsonschema == 4.*
4
4
  openpyxl == 3.*
5
5
  pyyaml == 6.*
6
6
  requests == 2.*
7
+ packaging ==24.*
8
+ setuptools-scm