eva-sub-cli 0.4.11__tar.gz → 0.4.13__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 (136) hide show
  1. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/PKG-INFO +2 -2
  2. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/_version.py +16 -3
  3. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/eva_schema.json +1 -1
  4. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/spreadsheet2json_conf.yaml +23 -21
  5. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/evidence_type_checker.py +15 -5
  6. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/samples_checker.py +1 -27
  7. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/xlsx2json.py +12 -1
  8. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/file_utils.py +24 -0
  9. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/nextflow/validation.nf +3 -2
  10. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/orchestrator.py +5 -2
  11. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/validators/docker_validator.py +1 -1
  12. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/PKG-INFO +2 -2
  13. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/requires.txt +1 -1
  14. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/requirements.txt +1 -1
  15. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/build_and_test_docker_locally.py +13 -8
  16. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_check_fasta_insdc.py +1 -1
  17. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_docker_validator.py +1 -1
  18. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_evidence_type_checker.py +11 -7
  19. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_orchestrator.py +1 -1
  20. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_submit.py +2 -0
  21. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_xlsx2json.py +6 -5
  22. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.github/workflows/publish.yml +0 -0
  23. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.github/workflows/publish_docs.yml +0 -0
  24. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.github/workflows/publish_packages.yml +0 -0
  25. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.github/workflows/tests.yml +0 -0
  26. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.github/workflows/trigger-eva-sub-cli-integration-tests.yml +0 -0
  27. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/.gitignore +0 -0
  28. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/LICENSE +0 -0
  29. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/README.md +0 -0
  30. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/conda/build.sh +0 -0
  31. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/conda/meta.yaml +0 -0
  32. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docker/Dockerfile +0 -0
  33. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/README.md +0 -0
  34. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/_config.yml +0 -0
  35. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/how_to_submit.md +0 -0
  36. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/input_file_overview.md +0 -0
  37. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/installation.md +0 -0
  38. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/using_nextflow.md +0 -0
  39. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/docs/validation_overview.md +0 -0
  40. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/__init__.py +0 -0
  41. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/auth.py +0 -0
  42. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/date_utils.py +0 -0
  43. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/EVA_Submission_Example.xlsx +0 -0
  44. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
  45. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/eva-biosamples.json +0 -0
  46. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/etc/eva_logo.png +0 -0
  47. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/exceptions/__init__.py +0 -0
  48. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/exceptions/invalid_file_type_exception.py +0 -0
  49. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/exceptions/metadata_template_version_exception.py +0 -0
  50. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/exceptions/submission_not_found_exception.py +0 -0
  51. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/exceptions/submission_status_exception.py +0 -0
  52. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/__init__.py +0 -0
  53. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/check_fasta_insdc.py +0 -0
  54. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/check_metadata_semantics.py +0 -0
  55. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/cli.py +0 -0
  56. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/executables/trim_down.py +0 -0
  57. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/fasta_check.html +0 -0
  58. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/file_validation.html +0 -0
  59. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/metadata_validation.html +0 -0
  60. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/project_details.html +0 -0
  61. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/report.html +0 -0
  62. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/sample_name_check.html +0 -0
  63. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/html/shallow_validation.html +0 -0
  64. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/fasta_check.txt +0 -0
  65. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/file_validation.txt +0 -0
  66. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/metadata_validation.txt +0 -0
  67. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/project_details.txt +0 -0
  68. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/report.txt +0 -0
  69. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/sample_name_check.txt +0 -0
  70. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/jinja_templates/text/shallow_validation.txt +0 -0
  71. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/metadata.py +0 -0
  72. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/report.py +0 -0
  73. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/semantic_metadata.py +0 -0
  74. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/submission_ws.py +0 -0
  75. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/submit.py +0 -0
  76. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/validators/__init__.py +0 -0
  77. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/validators/native_validator.py +0 -0
  78. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/validators/validation_results_parsers.py +0 -0
  79. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli/validators/validator.py +0 -0
  80. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/SOURCES.txt +0 -0
  81. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/dependency_links.txt +0 -0
  82. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/entry_points.txt +0 -0
  83. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/eva_sub_cli.egg-info/top_level.txt +0 -0
  84. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/pyproject.toml +0 -0
  85. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/pytest.ini +0 -0
  86. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/setup.cfg +0 -0
  87. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/setup.py +0 -0
  88. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/ignore_test_nextflow_validation.yml +0 -0
  89. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_Docker_Test.xlsx +0 -0
  90. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_test.json +0 -0
  91. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_test.xlsx +0 -0
  92. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_test_fails.xlsx +0 -0
  93. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_test_version_missing.xlsx +0 -0
  94. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/EVA_Submission_test_with_asm_report.json +0 -0
  95. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/assembly_check/invalid.vcf.assembly_check.log +0 -0
  96. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt +0 -0
  97. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/assembly_reports/input_passed.txt +0 -0
  98. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa +0 -0
  99. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/fasta_files/input_passed.fa +0 -0
  100. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/fasta_files/multi_seq.fa +0 -0
  101. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/metadata_with_filename.json +0 -0
  102. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/sample_checker/example1.vcf.gz +0 -0
  103. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/sample_checker/example2.vcf +0 -0
  104. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/sample_checker/example3.vcf +0 -0
  105. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/sample_checker/metadata.json +0 -0
  106. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_report_metadata_json.html +0 -0
  107. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_report_metadata_json.txt +0 -0
  108. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_report_metadata_xlsx.html +0 -0
  109. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_report_metadata_xlsx.txt +0 -0
  110. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.html +0 -0
  111. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.txt +0 -0
  112. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.assembly_check.log +0 -0
  113. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.text_assembly_report.1680102476700.txt +0 -0
  114. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.valid_assembly_report.1680102476700.txt +0 -0
  115. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/evidence_type_checker.yml +0 -0
  116. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/input_passed.fa_check.yml +0 -0
  117. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/metadata_conversion_errors.yml +0 -0
  118. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/metadata_semantic_check.yml +0 -0
  119. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/metadata_validation.txt +0 -0
  120. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/other_validations/sample_checker.yml +0 -0
  121. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.db +0 -0
  122. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.txt +0 -0
  123. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.vcf_format.log +0 -0
  124. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/vcf_files/example2.vcf.gz +0 -0
  125. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/resources/vcf_files/input_passed.vcf +0 -0
  126. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_auth.py +0 -0
  127. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_cli.py +0 -0
  128. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_file_utils.py +0 -0
  129. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_metadata.py +0 -0
  130. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_report.py +0 -0
  131. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_samples_checker.py +0 -0
  132. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_semantic_metadata.py +0 -0
  133. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_trim_down.py +0 -0
  134. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_utils.py +0 -0
  135. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_validaton_results_parsers.py +0 -0
  136. {eva_sub_cli-0.4.11 → eva_sub_cli-0.4.13}/tests/test_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4.11
3
+ Version: 0.4.13
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.3
22
+ Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.4
23
23
  Requires-Dist: jinja2==3.*,>=3.0.0
24
24
  Requires-Dist: jsonschema==4.*
25
25
  Requires-Dist: openpyxl==3.*
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '0.4.11'
21
- __version_tuple__ = version_tuple = (0, 4, 11)
31
+ __version__ = version = '0.4.13'
32
+ __version_tuple__ = version_tuple = (0, 4, 13)
33
+
34
+ __commit_id__ = commit_id = 'gc6e52eaa9'
@@ -330,7 +330,7 @@
330
330
  "$ref": "eva-biosamples.json"
331
331
  },
332
332
  {
333
- "$ref": "https://www.ebi.ac.uk/biosamples/schema/store/registry/schemas/ERC000011"
333
+ "$ref": "https://www.ebi.ac.uk/biosamples/schema-store/registry/schemas/ERC000011"
334
334
  },
335
335
  {
336
336
  "$ref": "https://www.ebi.ac.uk/biosamples/schemas/certification/plant-miappe.json"
@@ -81,6 +81,8 @@ Sample:
81
81
  required:
82
82
  Analysis Alias: analysisAlias
83
83
  Sample Name in VCF: sampleInVCF
84
+ # Sample property names taken from ERC000011 where present
85
+ # See https://www.ebi.ac.uk/biosamples/schema-store/registry/schemas/ERC000011
84
86
  optional:
85
87
  Sample Accession: bioSampleAccession
86
88
  BioSample Name: bioSampleName
@@ -91,37 +93,37 @@ Sample:
91
93
  Subject: subject
92
94
  Derived From: derivedFrom
93
95
  Taxonomy ID: taxId
94
- Scientific Name: scientificName
96
+ Scientific Name: scientific name
95
97
  Common Name: commonName
96
- mating_type: matingType
98
+ mating_type: mating_type
97
99
  sex: sex
98
100
  population: population
99
- cell_type: cellType
100
- dev_stage: devStage
101
+ cell_type: cell_type
102
+ dev_stage: dev_stage
101
103
  germline: germline
102
- tissue_lib: tissueLib
103
- tissue_type: tissueType
104
- bio_material: BioMaterial
105
- culture_collection: cultureCollection
106
- specimen_voucher: specimenVoucher
107
- collected_by: collectedBy
108
- collection_date: collectionDate
109
- geographic location (country and/or sea): geographicLocationCountrySea
110
- geographic location (region and locality): geographicLocationRegion
104
+ tissue_lib: tissue_lib
105
+ tissue_type: tissue_type
106
+ bio_material: bio_material
107
+ culture_collection: culture_collection
108
+ specimen_voucher: specimen_voucher
109
+ collected_by: collected_by
110
+ collection_date: collection date
111
+ geographic location (country and/or sea): geographic location (country and/or sea)
112
+ geographic location (region and locality): geographic location (region and locality)
111
113
  host: host
112
- identified_by: identifiedBy
113
- isolation_source: isolationSource
114
- lat_lon: latLon
115
- lab_host: LabHost
116
- environmental_sample: environmentalSample
114
+ identified_by: identified_by
115
+ isolation_source: isolation_source
116
+ lat_lon: lat_lon
117
+ lab_host: lab_host
118
+ environmental_sample: environmental_sample
117
119
  cultivar: cultivar
118
120
  ecotype: ecotype
119
121
  isolate: isolate
120
122
  strain: strain
121
- sub_species: subSpecies
123
+ sub_species: sub_species
122
124
  variety: variety
123
- sub_strain: subStrain
124
- cell_line: cellType
125
+ sub_strain: sub_strain
126
+ cell_line: cell_line
125
127
  serotype: serotype
126
128
  serovar: serovar
127
129
  cast:
@@ -3,22 +3,30 @@ import argparse
3
3
  import yaml
4
4
  from ebi_eva_common_pyutils.logger import logging_config
5
5
 
6
- from eva_sub_cli.file_utils import detect_vcf_evidence_type
6
+ from eva_sub_cli.file_utils import detect_vcf_evidence_type, associate_vcf_path_with_analysis
7
7
  from eva_sub_cli.metadata import EvaMetadataJson
8
8
 
9
9
  logger = logging_config.get_logger(__name__)
10
10
 
11
11
 
12
- def check_evidence_type(metadata_json, output_yaml):
12
+ def check_evidence_type(metadata_json, vcf_files, output_yaml):
13
13
  metadata = EvaMetadataJson(metadata_json)
14
+ file_path_per_analysis = associate_vcf_path_with_analysis(metadata, vcf_files)
15
+
14
16
  results_per_analysis_alias = {}
15
17
 
16
- for analysis_alias, vcf_file_set in metadata.files_per_analysis.items():
18
+ all_analysis_alias = set(metadata.files_per_analysis) | set(file_path_per_analysis)
19
+ for analysis_alias in all_analysis_alias:
17
20
  results_per_analysis_alias[analysis_alias] = {
18
21
  'evidence_type': None,
19
22
  'errors': None
20
23
  }
21
- vcf_files = list(vcf_file_set)
24
+ vcf_files = list(file_path_per_analysis.get(analysis_alias, []))
25
+
26
+ if not vcf_files:
27
+ results_per_analysis_alias[analysis_alias]['errors'] = f'No VCF file found for the analysis'
28
+ continue
29
+
22
30
  evidence_types_for_vcf_files = [detect_vcf_evidence_type(vcf_file) for vcf_file in vcf_files]
23
31
 
24
32
  if len(set(evidence_types_for_vcf_files)) == 1 and None not in evidence_types_for_vcf_files:
@@ -43,9 +51,11 @@ def main():
43
51
  arg_parser = argparse.ArgumentParser(description='Check the evidence type in the VCF files for all analysis')
44
52
  arg_parser.add_argument('--metadata_json', required=True, dest='metadata_json',
45
53
  help='EVA metadata json file')
54
+ arg_parser.add_argument('--vcf_files', dest='vcf_files', nargs='+',
55
+ help='Path to the vcf files to compare to the metadata')
46
56
  arg_parser.add_argument('--output_yaml', required=True, dest='output_yaml',
47
57
  help='Path to the location of the results')
48
58
 
49
59
  args = arg_parser.parse_args()
50
60
  logging_config.add_stdout_handler()
51
- check_evidence_type(args.metadata_json, args.output_yaml)
61
+ check_evidence_type(args.metadata_json, args.vcf_files, args.output_yaml)
@@ -5,7 +5,7 @@ from ebi_eva_common_pyutils.logger import logging_config
5
5
 
6
6
  import yaml
7
7
 
8
- from eva_sub_cli.file_utils import open_gzip_if_required, detect_vcf_evidence_type
8
+ from eva_sub_cli.file_utils import open_gzip_if_required, detect_vcf_evidence_type, associate_vcf_path_with_analysis
9
9
  from eva_sub_cli.metadata import EvaMetadataJson
10
10
 
11
11
  logger = logging_config.get_logger(__name__)
@@ -99,32 +99,6 @@ def need_to_check_samples(sample_name_per_file):
99
99
  return True
100
100
 
101
101
 
102
- def associate_vcf_path_with_analysis(metadata, vcf_files):
103
- """
104
- Match the files names associated with analysis provided in the metadata with the file path given on the command
105
- line.
106
- :param vcf_files the list of full path to the vcf files
107
- :param files_per_analysis: dictionary of the analysis and their associated VCF file names
108
- :returns dictionary of analysis and their associated vcf file path
109
- """
110
- result_files_per_analysis = dict()
111
- for analysis in metadata.files_per_analysis:
112
- result_files_per_analysis[analysis] = []
113
- for vcf_file in vcf_files:
114
- analysis_aliases = metadata.get_analysis_for_vcf_file(vcf_file)
115
- if len(analysis_aliases) == 1:
116
- result_files_per_analysis[analysis_aliases[0]].append(vcf_file)
117
- elif len(analysis_aliases) == 0:
118
- logger.error(f'No analysis found for vcf {vcf_file}')
119
- if 'No analysis' not in result_files_per_analysis:
120
- result_files_per_analysis['No analysis'] = []
121
- result_files_per_analysis['No analysis'].append(vcf_file)
122
- else:
123
- logger.error(f'More than one analysis were match to vcf {vcf_file}')
124
-
125
- return result_files_per_analysis
126
-
127
-
128
102
  def write_result_yaml(output_yaml, overall_differences, results_per_analysis_alias):
129
103
  with open(output_yaml, 'w') as open_yaml:
130
104
  yaml.safe_dump(data={
@@ -9,6 +9,8 @@ from ebi_eva_common_pyutils.logger import logging_config
9
9
  from openpyxl.reader.excel import load_workbook
10
10
  from openpyxl.workbook import Workbook
11
11
 
12
+ from eva_sub_cli.orchestrator import get_sub_cli_version, get_sub_cli_github_tags
13
+
12
14
  WORKSHEETS_KEY_NAME = 'worksheets'
13
15
  REQUIRED_HEADERS_KEY_NAME = 'required'
14
16
  OPTIONAL_HEADERS_KEY_NAME = 'optional'
@@ -249,7 +251,8 @@ class XlsxParser:
249
251
  # If the file could not be loaded at all, return without generating JSON.
250
252
  if not self.file_loaded:
251
253
  return
252
- json_data = {}
254
+ # Include which version of the EVA schema we are using
255
+ json_data = {'$schema': self.get_json_schema_link()}
253
256
  for title in self.xlsx_conf[WORKSHEETS_KEY_NAME]:
254
257
  self.active_worksheet = title
255
258
  if title == PROJECT:
@@ -270,6 +273,14 @@ class XlsxParser:
270
273
  with open(output_json_file, 'w') as open_file:
271
274
  json.dump(json_data, open_file, cls=DateTimeEncoder)
272
275
 
276
+ def get_json_schema_link(self):
277
+ sub_cli_version = get_sub_cli_version()
278
+ sub_cli_tags = get_sub_cli_github_tags()
279
+ if sub_cli_version in sub_cli_tags:
280
+ return f'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/refs/tags/v{sub_cli_version}/eva_sub_cli/etc/eva_schema.json'
281
+ else:
282
+ return 'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/main/eva_sub_cli/etc/eva_schema.json'
283
+
273
284
  def translate_header(self, title, header):
274
285
  if header in self.xlsx_conf[title].get(REQUIRED_HEADERS_KEY_NAME, {}):
275
286
  return self.xlsx_conf[title][REQUIRED_HEADERS_KEY_NAME][header]
@@ -35,6 +35,30 @@ def is_vcf_file(file_path):
35
35
  return file_path.endswith('.vcf') or file_path.endswith('.vcf.gz')
36
36
  return False
37
37
 
38
+ def associate_vcf_path_with_analysis(metadata, vcf_files):
39
+ """
40
+ Match the files names associated with analysis provided in the metadata with the given file path
41
+
42
+ :param vcf_files the list of full path to the vcf files
43
+ :param files_per_analysis: dictionary of the analysis and their associated VCF file names
44
+ :returns dictionary of analysis and their associated vcf file path
45
+ """
46
+ result_files_per_analysis = dict()
47
+ for analysis in metadata.files_per_analysis:
48
+ result_files_per_analysis[analysis] = []
49
+ for vcf_file in vcf_files:
50
+ analysis_aliases = metadata.get_analysis_for_vcf_file(vcf_file)
51
+ if len(analysis_aliases) == 1:
52
+ result_files_per_analysis[analysis_aliases[0]].append(vcf_file)
53
+ elif len(analysis_aliases) == 0:
54
+ logger.error(f'No analysis found for vcf {vcf_file}')
55
+ if 'No analysis' not in result_files_per_analysis:
56
+ result_files_per_analysis['No analysis'] = []
57
+ result_files_per_analysis['No analysis'].append(vcf_file)
58
+ else:
59
+ logger.error(f'More than one analysis were match to vcf {vcf_file}')
60
+
61
+ return result_files_per_analysis
38
62
 
39
63
  def detect_vcf_evidence_type(vcf_file):
40
64
  """
@@ -100,7 +100,7 @@ workflow {
100
100
  metadata_json_validation(metadata_json)
101
101
  metadata_semantic_check(metadata_json)
102
102
  sample_name_concordance(metadata_json, vcf_files.collect())
103
- evidence_type_check(metadata_json)
103
+ evidence_type_check(metadata_json, vcf_files.collect())
104
104
  insdc_checker(metadata_json, fasta_to_vcfs)
105
105
  }
106
106
  }
@@ -274,6 +274,7 @@ process evidence_type_check {
274
274
 
275
275
  input:
276
276
  path(metadata_json)
277
+ path(vcf_files)
277
278
 
278
279
  output:
279
280
  path "evidence_type_checker.yml", emit: evidence_type_checker_yml
@@ -281,7 +282,7 @@ process evidence_type_check {
281
282
 
282
283
  script:
283
284
  """
284
- $params.python_scripts.evidence_type_checker --metadata_json $metadata_json --output_yaml evidence_type_checker.yml > evidence_type_checker.log 2>&1
285
+ $params.python_scripts.evidence_type_checker --metadata_json $metadata_json --vcf_files $vcf_files --output_yaml evidence_type_checker.yml > evidence_type_checker.log 2>&1
285
286
  """
286
287
  }
287
288
 
@@ -130,7 +130,10 @@ def get_project_and_vcf_fasta_mapping_from_metadata_json(metadata_json, mapping_
130
130
 
131
131
  def get_sub_cli_version():
132
132
  if version.parse(eva_sub_cli.__version__).is_devrelease:
133
- major, minor, patch = map(int, version.parse(eva_sub_cli.__version__).base_version.split('.'))
133
+ version_values = [int(v) for v in version.parse(eva_sub_cli.__version__).base_version.split('.')]
134
+ major = version_values[0]
135
+ minor = version_values[1] if len(version_values) > 1 else 0
136
+ patch = version_values[2] if len(version_values) > 2 else 0
134
137
  if patch > 0:
135
138
  patch -= 1
136
139
  elif minor > 0:
@@ -160,7 +163,7 @@ def get_metadata_xlsx_template_link():
160
163
  sub_cli_version = get_sub_cli_version()
161
164
  sub_cli_tags = get_sub_cli_github_tags()
162
165
  if sub_cli_version in sub_cli_tags:
163
- return f'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/v{sub_cli_version}/eva-sub-cli/eva_sub_cli/etc/EVA_Submission_template.xlsx'
166
+ return f'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/refs/tags/v{sub_cli_version}/eva_sub_cli/etc/EVA_Submission_template.xlsx'
164
167
  else:
165
168
  return 'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/main/eva_sub_cli/etc/EVA_Submission_template.xlsx'
166
169
 
@@ -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.5'
15
+ default_container_tag = 'v0.0.6'
16
16
  container_validation_dir = '/opt/vcf_validation'
17
17
  container_validation_output_dir = 'vcf_validation_output'
18
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4.11
3
+ Version: 0.4.13
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.3
22
+ Requires-Dist: ebi_eva_common_pyutils==0.*,>=0.7.4
23
23
  Requires-Dist: jinja2==3.*,>=3.0.0
24
24
  Requires-Dist: jsonschema==4.*
25
25
  Requires-Dist: openpyxl==3.*
@@ -1,4 +1,4 @@
1
- ebi_eva_common_pyutils==0.*,>=0.7.3
1
+ ebi_eva_common_pyutils==0.*,>=0.7.4
2
2
  jinja2==3.*,>=3.0.0
3
3
  jsonschema==4.*
4
4
  openpyxl==3.*
@@ -1,4 +1,4 @@
1
- ebi_eva_common_pyutils >= 0.7.3, == 0.*
1
+ ebi_eva_common_pyutils >= 0.7.4, == 0.*
2
2
  jinja2 >= 3.0.0, == 3.*
3
3
  jsonschema == 4.*
4
4
  openpyxl == 3.*
@@ -141,13 +141,14 @@ class TestDockerValidator(TestCase):
141
141
  expected_metadata_val = 'Validation passed successfully.'
142
142
  expected_semantic_val = {'description': 'SAME123 does not exist or is private',
143
143
  'property': '/sample/0/bioSampleAccession'}
144
+ expected_evidence_type_val = {'AA': {'evidence_type': 'genotype', 'errors': None}}
144
145
  expected_metadata_files_json = [
145
146
  {'analysisAlias': 'AA', 'fileName': 'input_passed.vcf', 'fileType': 'vcf',
146
147
  'md5': '96a80c9368cc3c37095c86fbe6044fb2', 'fileSize': 45050}
147
148
  ]
148
149
 
149
150
  self.assert_validation_results(self.validator, expected_sample_checker, expected_metadata_files_json,
150
- expected_metadata_val, expected_semantic_val)
151
+ expected_metadata_val, expected_semantic_val, expected_evidence_type_val)
151
152
 
152
153
  def test_validate_with_xlsx(self):
153
154
  self.xlsx_validator.validate()
@@ -156,13 +157,14 @@ class TestDockerValidator(TestCase):
156
157
  expected_metadata_val = 'Validation passed successfully.'
157
158
  expected_semantic_val = {'description': 'SAME123 does not exist or is private',
158
159
  'property': '/sample/0/bioSampleAccession'}
160
+ expected_evidence_type_val = {'AA': {'evidence_type': 'genotype', 'errors': None}}
159
161
  expected_metadata_files_json = [
160
162
  {'analysisAlias': 'AA', 'fileName': 'input_passed.vcf',
161
163
  'md5': '96a80c9368cc3c37095c86fbe6044fb2', 'fileSize': 45050}
162
164
  ]
163
165
 
164
166
  self.assert_validation_results(self.xlsx_validator, expected_sample_checker, expected_metadata_files_json,
165
- expected_metadata_val, expected_semantic_val)
167
+ expected_metadata_val, expected_semantic_val, expected_evidence_type_val)
166
168
 
167
169
  def get_submission_json_metadata(self):
168
170
  return {
@@ -230,7 +232,7 @@ class TestDockerValidator(TestCase):
230
232
  return docker_cmd
231
233
 
232
234
  def assert_validation_results(self, validator, expected_sample_checker, expected_metadata_files_json,
233
- expected_metadata_val, expected_semantic_val):
235
+ expected_metadata_val, expected_semantic_val, expected_evidence_type_val):
234
236
  vcf_format_dir = os.path.join(validator.output_dir, 'vcf_format')
235
237
  self.assertTrue(os.path.exists(vcf_format_dir))
236
238
 
@@ -260,7 +262,10 @@ class TestDockerValidator(TestCase):
260
262
  self.assertEqual('[info] Percentage of matches: 100%\n', assembly_check_logs[5])
261
263
 
262
264
  # Assert Samples concordance
263
- self.assert_sample_checker(validator._sample_check_yaml, expected_sample_checker)
265
+ self.assert_yaml_file(validator._sample_check_yaml, expected_sample_checker)
266
+
267
+ # assert evidence type check
268
+ self.assert_yaml_file(validator._evidence_type_check_yaml, expected_evidence_type_val)
264
269
 
265
270
  with open(validator.metadata_json_post_validation) as open_file:
266
271
  json_data = json.load(open_file)
@@ -278,10 +283,10 @@ class TestDockerValidator(TestCase):
278
283
  semantic_output = yaml.safe_load(open_yaml)
279
284
  assert semantic_output[0] == expected_semantic_val
280
285
 
281
- def assert_sample_checker(self, sample_checker_file, expected_checker):
282
- self.assertTrue(os.path.isfile(sample_checker_file))
283
- with open(sample_checker_file) as open_yaml:
284
- self.assert_same_dict_and_unordered_list(yaml.safe_load(open_yaml), expected_checker)
286
+ def assert_yaml_file(self, yaml_file, expected_data):
287
+ self.assertTrue(os.path.isfile(yaml_file))
288
+ with open(yaml_file) as open_yaml:
289
+ self.assert_same_dict_and_unordered_list(yaml.safe_load(open_yaml), expected_data)
285
290
 
286
291
  def assert_same_dict_and_unordered_list(self, o1, o2):
287
292
  if isinstance(o1, dict) and isinstance(o2, dict):
@@ -132,5 +132,5 @@ class TestFastaChecker(TestCase):
132
132
  @pytest.mark.integration
133
133
  def test_get_containing_assemblies(self):
134
134
  results = get_containing_assemblies('6ac8f815bf8e845bb3031b73f812c012')
135
- assert len(results) == 14
135
+ assert len(results) == 15
136
136
  assert 'GCA_000001405.29' in results
@@ -158,7 +158,7 @@ class TestDockerValidator(TestCase):
158
158
  {'analysisAlias': 'AA', 'fileName': 'input_passed.vcf', 'fileType': 'vcf',
159
159
  'md5': '96a80c9368cc3c37095c86fbe6044fb2', 'fileSize': 45050}
160
160
  ]
161
- expected_metadata_val = 'must match pattern "^PRJ(EB|NA)\\d+$"'
161
+ expected_metadata_val = 'must match pattern "^PRJ(E|D|N)[A-Z][0-9]+$"'
162
162
  expected_semantic_val = {'description': 'SAME123 does not exist or is private',
163
163
  'property': '/sample/0/bioSampleAccession'}
164
164
 
@@ -21,7 +21,12 @@ class TestEvidenceTypeChecker(TestCase):
21
21
  metadata_json = os.path.join(working_dir, 'metadata.json')
22
22
  # Change to working_dir so filenames in metadata.json are resolvable
23
23
  os.chdir(working_dir)
24
- self.run_and_assert_evidence_type_check(metadata_json)
24
+ vcf_files = [
25
+ os.path.join(working_dir, file_name)
26
+ for file_name in ['example1.vcf.gz', 'example2.vcf', 'example3.vcf']
27
+ ]
28
+
29
+ self.run_and_assert_evidence_type_check(metadata_json, vcf_files)
25
30
 
26
31
  def test_evidence_check_absolute_paths(self):
27
32
  working_dir = os.path.join(self.resource_dir, 'sample_checker')
@@ -39,18 +44,17 @@ class TestEvidenceTypeChecker(TestCase):
39
44
  updated_metadata = os.path.join(working_dir, 'updated_metadata.json')
40
45
  metadata.write(updated_metadata)
41
46
 
42
- self.run_and_assert_evidence_type_check(updated_metadata)
47
+ self.run_and_assert_evidence_type_check(updated_metadata, vcf_files)
43
48
 
44
49
  if os.path.exists(updated_metadata):
45
50
  os.remove(updated_metadata)
46
51
 
47
- def run_and_assert_evidence_type_check(self, metadata_json):
48
- check_evidence_type(metadata_json, self.output_yaml)
49
- failing_vcf = os.path.join(self.resource_dir,'sample_checker','example1.vcf.gz.tbi')
52
+ def run_and_assert_evidence_type_check(self, metadata_json, vcf_files):
53
+ check_evidence_type(metadata_json, vcf_files, self.output_yaml)
50
54
  expected_results = {
51
55
  'VD1': {
52
- 'errors': f'VCF file evidence type could not be determined: {failing_vcf}',
53
- 'evidence_type': None
56
+ 'evidence_type': 'genotype',
57
+ 'errors': None
54
58
  },
55
59
  'VD2': {
56
60
  'evidence_type': 'genotype',
@@ -306,7 +306,7 @@ class TestOrchestrator(unittest.TestCase):
306
306
  patch('eva_sub_cli.orchestrator.get_sub_cli_github_tags') as sub_cli_tags:
307
307
  sub_cli_version.return_value = '1.1.6'
308
308
  sub_cli_tags.return_value = ['1.1.6']
309
- assert get_metadata_xlsx_template_link() == 'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/v1.1.6/eva-sub-cli/eva_sub_cli/etc/EVA_Submission_template.xlsx'
309
+ assert get_metadata_xlsx_template_link() == 'https://raw.githubusercontent.com/EBIvariation/eva-sub-cli/refs/tags/v1.1.6/eva_sub_cli/etc/EVA_Submission_template.xlsx'
310
310
 
311
311
  sub_cli_version.return_value = '1.1.5'
312
312
  sub_cli_tags.return_value = ['1.1.6']
@@ -79,8 +79,10 @@ class TestSubmit(unittest.TestCase):
79
79
  assert is_submission_dir_writable(self.test_sub_dir)
80
80
  assert not os.path.exists(self.config_file)
81
81
  sub_config = WritableConfig(self.config_file, version='version1.0')
82
+ sub_config.set('metadata_json', value=os.path.join(self.resource_dir, 'EVA_Submission_test.json'))
82
83
  sub_config.set(READY_FOR_SUBMISSION_TO_EVA, value=True)
83
84
  sub_config.write()
85
+ self.submitter = StudySubmitter(submission_dir=self.test_sub_dir, submission_config=sub_config)
84
86
 
85
87
  test_submission_ws_client = SubmissionWSClient()
86
88
 
@@ -55,7 +55,8 @@ class TestXlsReader(TestCase):
55
55
  with open(output_json) as open_file:
56
56
  json_data = json.load(open_file)
57
57
  # assert json file is created with expected data
58
- assert sorted(json_data.keys()) == ['analysis', 'files', 'project', 'sample', 'submitterDetails']
58
+ assert sorted(json_data.keys()) == ['$schema', 'analysis', 'files', 'project', 'sample', 'submitterDetails']
59
+ json_data.pop('$schema', None)
59
60
  self.assertEqual(self.get_expected_json(), json_data)
60
61
 
61
62
  # assert json schema
@@ -94,7 +95,7 @@ class TestXlsReader(TestCase):
94
95
  assert os.path.exists(output_json)
95
96
  with open(output_json) as open_file:
96
97
  json_data = json.load(open_file)
97
- assert sorted(json_data.keys()) == ['analysis', 'files', 'project', 'sample', 'submitterDetails']
98
+ assert sorted(json_data.keys()) == ['$schema', 'analysis', 'files', 'project', 'sample', 'submitterDetails']
98
99
  # required field taxId is missing
99
100
  assert 'taxId' not in json_data['project']
100
101
  # novel sample is missing scientific name in characteristics and sample name
@@ -220,19 +221,19 @@ class TestXlsReader(TestCase):
220
221
  "taxId": [
221
222
  {"text": "9447"}
222
223
  ],
223
- "scientificName": [
224
+ "scientific name": [
224
225
  {"text": "Lemur catta"}
225
226
  ],
226
227
  "sex": [
227
228
  {"text": "Female"}
228
229
  ],
229
- "tissueType": [
230
+ "tissue_type": [
230
231
  {"text": "skin"}
231
232
  ],
232
233
  "species": [
233
234
  {"text": "Lemur catta"}
234
235
  ],
235
- 'collectionDate': [
236
+ 'collection date': [
236
237
  {'text': '2021-03-12'}
237
238
  ]
238
239
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes