eva-sub-cli 0.4__tar.gz → 0.4.4__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 (110) hide show
  1. {eva_sub_cli-0.4/eva_sub_cli.egg-info → eva_sub_cli-0.4.4}/PKG-INFO +33 -38
  2. eva_sub_cli-0.4.4/README.md +134 -0
  3. eva_sub_cli-0.4.4/conda/build.sh +20 -0
  4. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/conda/meta.yaml +17 -11
  5. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/docker/Dockerfile +1 -1
  6. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/_version.py +9 -4
  7. eva_sub_cli-0.4.4/eva_sub_cli/exceptions/invalid_file_type_exception.py +4 -0
  8. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/cli.py +20 -5
  9. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/file_utils.py +45 -0
  10. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/html_report.html +4 -0
  11. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/nextflow/validation.nf +1 -2
  12. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/orchestrator.py +42 -8
  13. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/semantic_metadata.py +13 -0
  14. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/submit.py +13 -0
  15. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/validators/docker_validator.py +41 -43
  16. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/validators/validation_results_parsers.py +10 -3
  17. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/validators/validator.py +49 -22
  18. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4/eva_sub_cli.egg-info}/PKG-INFO +33 -38
  19. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli.egg-info/SOURCES.txt +1 -0
  20. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli.egg-info/requires.txt +1 -1
  21. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/requirements.txt +1 -1
  22. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_cli.py +19 -4
  23. eva_sub_cli-0.4.4/tests/test_docker_validator.py +207 -0
  24. eva_sub_cli-0.4.4/tests/test_file_utils.py +82 -0
  25. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_orchestrator.py +34 -21
  26. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_report.py +6 -1
  27. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_semantic_metadata.py +20 -0
  28. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_submit.py +26 -2
  29. eva_sub_cli-0.4.4/tests/test_validaton_results_parsers.py +44 -0
  30. eva_sub_cli-0.4/README.md +0 -140
  31. eva_sub_cli-0.4/conda/build.sh +0 -48
  32. eva_sub_cli-0.4/tests/test_docker_validator.py +0 -151
  33. eva_sub_cli-0.4/tests/test_file_utils.py +0 -46
  34. eva_sub_cli-0.4/tests/test_validaton_results_parsers.py +0 -32
  35. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/.github/workflows/publish_packages.yml +0 -0
  36. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/.github/workflows/tests.yml +0 -0
  37. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/.gitignore +0 -0
  38. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/Getting_Started_with_eva_sub_cli.md +0 -0
  39. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/LICENSE +0 -0
  40. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/__init__.py +0 -0
  41. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/auth.py +0 -0
  42. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/date_utils.py +0 -0
  43. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/etc/EVA_Submission_template.xlsx +0 -0
  44. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/etc/eva-biosamples.json +0 -0
  45. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/etc/eva_logo.png +0 -0
  46. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/etc/eva_schema.json +0 -0
  47. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/etc/spreadsheet2json_conf.yaml +0 -0
  48. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/exceptions/__init__.py +0 -0
  49. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/exceptions/submission_not_found_exception.py +0 -0
  50. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/exceptions/submission_status_exception.py +0 -0
  51. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/__init__.py +0 -0
  52. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/check_fasta_insdc.py +0 -0
  53. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/check_metadata_semantics.py +0 -0
  54. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/samples_checker.py +0 -0
  55. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/trim_down.py +0 -0
  56. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/executables/xlsx2json.py +1 -1
  57. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/fasta_check.html +0 -0
  58. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/file_validation.html +0 -0
  59. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/metadata_validation.html +0 -0
  60. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/project_details.html +0 -0
  61. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/sample_name_check.html +0 -0
  62. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/jinja_templates/shallow_validation.html +0 -0
  63. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/metadata_utils.py +0 -0
  64. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/report.py +0 -0
  65. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/submission_ws.py +0 -0
  66. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/validators/__init__.py +0 -0
  67. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli/validators/native_validator.py +0 -0
  68. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli.egg-info/dependency_links.txt +0 -0
  69. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli.egg-info/entry_points.txt +0 -0
  70. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/eva_sub_cli.egg-info/top_level.txt +0 -0
  71. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/pyproject.toml +0 -0
  72. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/pytest.ini +0 -0
  73. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/setup.cfg +0 -0
  74. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/setup.py +0 -0
  75. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/ignore_test_nextflow_validation.yml +0 -0
  76. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/EVA_Submission_test.json +0 -0
  77. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/EVA_Submission_test.xlsx +0 -0
  78. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/EVA_Submission_test_fails.xlsx +0 -0
  79. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/EVA_Submission_test_with_asm_report.json +0 -0
  80. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/assembly_check/invalid.vcf.assembly_check.log +0 -0
  81. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/assembly_check/invalid.vcf.text_assembly_report.txt +0 -0
  82. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/assembly_reports/input_passed.txt +0 -0
  83. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/fasta_files/Saccharomyces_cerevisiae_I.fa +0 -0
  84. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/fasta_files/input_passed.fa +0 -0
  85. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/sample_checker/example1.vcf.gz +0 -0
  86. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/sample_checker/example2.vcf +0 -0
  87. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/sample_checker/example3.vcf +0 -0
  88. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/sample_checker/metadata.json +0 -0
  89. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/expected_report_metadata_json.html +0 -0
  90. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/expected_report_metadata_xlsx.html +0 -0
  91. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/expected_shallow_metadata_xlsx_report.html +0 -0
  92. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.assembly_check.log +0 -0
  93. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.text_assembly_report.1680102476700.txt +0 -0
  94. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/assembly_check/input_passed.vcf.valid_assembly_report.1680102476700.txt +0 -0
  95. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/other_validations/input_passed.fa_check.yml +0 -0
  96. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/other_validations/metadata_conversion_errors.yml +0 -0
  97. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/other_validations/metadata_semantic_check.yml +0 -0
  98. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/other_validations/metadata_validation.txt +0 -0
  99. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/other_validations/sample_checker.yml +0 -0
  100. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.db +0 -0
  101. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.errors.1680102476854.txt +0 -0
  102. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/validation_reports/validation_output/vcf_format/input_passed.vcf.vcf_format.log +0 -0
  103. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/vcf_files/example2.vcf.gz +0 -0
  104. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/resources/vcf_files/input_passed.vcf +0 -0
  105. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_auth.py +0 -0
  106. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_check_fasta_insdc.py +0 -0
  107. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_samples_checker.py +0 -0
  108. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_utils.py +0 -0
  109. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_validator.py +0 -0
  110. {eva_sub_cli-0.4 → eva_sub_cli-0.4.4}/tests/test_xlsx2json.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: eva_sub_cli
3
- Version: 0.4
3
+ Version: 0.4.4
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,13 +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.6.10
22
+ Requires-Dist: ebi_eva_common_pyutils==0.6.11
23
23
  Requires-Dist: jinja2
24
24
  Requires-Dist: jsonschema
25
25
  Requires-Dist: openpyxl
26
26
  Requires-Dist: pyyaml
27
27
  Requires-Dist: requests
28
28
  Requires-Dist: retry
29
+ Dynamic: license-file
29
30
 
30
31
  # eva-sub-cli
31
32
  The eva-sub-cli tool is a command line interface tool for data validation and upload. The tool transforms the submission process at EVA by enabling users to take control of data validation process. Previously handled by our helpdesk team, validation can now be performed directly by users, streamlining and improving the overall submission workflow at the EVA.
@@ -53,21 +54,9 @@ eva-sub-cli.py --help
53
54
 
54
55
  Docker provides an easy way to run eva-sub-cli without installing dependencies separately.
55
56
  This method requires just Python 3.8+ and [Docker](https://docs.docker.com/engine/install/) to be installed.
56
- Once it is set up, you can either clone the git repository, or download the newest tagged release from [here](https://github.com/EBIvariation/eva-sub-cli/tags):
57
+ Then you can install the most recent version from [PyPI](https://pypi.org/project/eva-sub-cli/) in a virtual environment:
57
58
  ```bash
58
- git clone https://github.com/EBIvariation/eva-sub-cli.git
59
-
60
- # OR (replace "v0.2" with the newest version)
61
-
62
- wget -O eva-sub-cli.zip https://github.com/EBIvariation/eva-sub-cli/archive/refs/tags/v0.2.zip
63
- unzip eva-sub-cli.zip && mv eva-sub-cli-* eva-sub-cli
64
- ```
65
-
66
- Then install the library and its dependencies as follows (e.g. in a virtual environment):
67
- ```bash
68
- cd eva-sub-cli
69
- # Activate your virtual environment
70
- python -m pip install .
59
+ pip install eva-sub-cli
71
60
  ```
72
61
 
73
62
  To verify that the cli tool is installed correctly, run the following command, and you should see the help message displayed :
@@ -83,41 +72,47 @@ This installation method requires the following :
83
72
  * [biovalidator](https://github.com/elixir-europe/biovalidator) 2.1.0+
84
73
  * [vcf-validator](https://github.com/EBIvariation/vcf-validator) 0.9.7+
85
74
 
86
- Install each of these and ensure they are included in your PATH. Then, either clone the repository using Git or install the latest release as previously described.
75
+ Install each of these and ensure they are included in your PATH. Then install the latest release as previously described.
87
76
 
88
77
  ## Getting started with the eva-sub-cli tool
89
78
 
90
-
91
79
  The ["Getting Started" guide](Getting_Started_with_eva_sub_cli.md) serves as an introduction for users of the eva-sub-cli tool. It includes instructions on how to prepare your data and metadata, ensuring that users are equipped with the necessary information to successfully submit variant data. This guide is essential for new users, offering practical advice and tips for a smooth onboarding experience with the eva-sub-cli tool.
92
80
 
93
- ## eva-sub-cli tool: Options and parameters guide
81
+ ## Options and parameters guide
82
+
83
+ The eva-sub-cli tool provides several options and parameters that you can use to tailor its functionality to your needs.
84
+ You can view all the available parameters with the command `eva-sub-cli.py -h` and view detailed explanations for the
85
+ input file requirements in the ["Getting Started" guide](Getting_Started_with_eva_sub_cli.md).
86
+ Below is an overview of the key parameters.
87
+
88
+ ### Submission directory
94
89
 
95
- The eva-sub-cli tool provides several options/parameters that you can use to tailor its functionality to your needs. Understanding these parameters is crucial for configuring the tool correctly. Below is an overview of the key parameters and options:
90
+ This is the directory where all processing will take place, and where configuration and reports will be saved.
91
+ Crucially, the eva-sub-cli tool requires that there be **only one submission per directory** and that the submission directory not be reused.
92
+ Running multiple submissions from a single directory can result in data loss during validation and submission.
96
93
 
97
- | OPTIONS/PARAMETERS | DESCRIPTION |
98
- |----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
99
- | --version | Shows version number of the program and exit |
100
- | --metadata_xlsx | Excel spreadsheet that describe the project, analysis, samples and files |
101
- | --metadata_json | Json file that describe the project, analysis, samples and files |
102
- | --vcf_files | One or several vcf files to validate.This allows you to provide multiple VCF files to validate and a single associated reference genome file. The VCF files and the associated reference genome file must use the same chromosome naming convention |
103
- | --reference_fasta | The fasta file containing the reference genome from which the variants were derived |
104
- | --submission_dir | Path to the directory where all processing will be done and submission data is/will be stored |
105
- | --tasks {validate,submit} | Selecting VALIDATE will run the validation regardless of the outcome of previous runs. Selecting SUBMIT will run validate only if the validation was not performed successfully before and then run the submission |
106
- | --executor {docker,native} | Select an execution type for running validation (default native) |
107
- | --shallow | Set the validation to be performed on the first 10000 records of the VCF. Only applies if the number of record exceed 10000 |
108
- | --username | Username used for connecting to the ENA webin account |
109
- | --password | Password used for connecting to the ENA webin account |
94
+ ### Metadata file
110
95
 
96
+ Metadata can be provided in one of two files.
111
97
 
112
98
  #### The metadata spreadsheet
113
99
 
114
- The metadata template can be found within the etc folder at `eva_sub_cli/etc/EVA_Submission_template.xlsx`
115
- It should be populated following the instruction provided within the template
100
+ The metadata template can be found within the [etc folder](eva_sub_cli/etc/EVA_Submission_template.xlsx). It should be populated following the instructions provided within the template.
101
+ This is passed using the option `--metadata_xlsx`.
116
102
 
117
103
  #### The metadata JSON
118
104
 
119
105
  The metadata can also be provided via a JSON file, which should conform to the schema located [here](eva_sub_cli/etc/eva_schema.json).
106
+ This is passed using the option `--metadata_json`.
107
+
108
+ ### VCF files and Reference FASTA
109
+
110
+ These can be provided either in the metadata file directly, or on the command line using the `--vcf_files` and `--reference_fata` options.
111
+ Note that if you are using more than one reference FASTA, you **cannot** use the command line options; you must specify which VCF files use which FASTA files in the metadata.
120
112
 
113
+ VCF files can be either uncompressed or compressed using bgzip.
114
+ Other types of compression are not allowed and will result in errors during validation.
115
+ FASTA files must be uncompressed.
121
116
 
122
117
  ## Execution
123
118
 
@@ -141,7 +136,7 @@ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submis
141
136
 
142
137
  ### Validate and submit your dataset
143
138
 
144
- To validate and submit run the following command
139
+ To validate and submit, run the following command:
145
140
 
146
141
  ```shell
147
142
  eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx \
@@ -160,7 +155,7 @@ or
160
155
  ```shell
161
156
  eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submission_dir --tasks SUBMIT
162
157
  ```
163
- Will only submit the data and not validate.
158
+ This will only submit the data and not validate.
164
159
 
165
160
  ### Shallow validation
166
161
 
@@ -0,0 +1,134 @@
1
+ # eva-sub-cli
2
+ The eva-sub-cli tool is a command line interface tool for data validation and upload. The tool transforms the submission process at EVA by enabling users to take control of data validation process. Previously handled by our helpdesk team, validation can now be performed directly by users, streamlining and improving the overall submission workflow at the EVA.
3
+
4
+
5
+ ## Installation
6
+
7
+ There are currently three ways to install and run the tool :
8
+ - Using conda
9
+ - From source using Docker
10
+ - From source natively (i.e. installing dependencies yourself)
11
+
12
+ ### 1. Conda
13
+
14
+ The most straightforward way to install eva-sub-cli and its dependencies is through conda.
15
+ For instance, the following commands install eva-sub-cli in a new environment called `eva`, activate the environment, and print
16
+ the help message:
17
+ ```bash
18
+ conda create -n eva -c conda-forge -c bioconda eva-sub-cli
19
+ conda activate eva
20
+ eva-sub-cli.py --help
21
+ ````
22
+
23
+ ### 2. From source using Docker
24
+
25
+ Docker provides an easy way to run eva-sub-cli without installing dependencies separately.
26
+ This method requires just Python 3.8+ and [Docker](https://docs.docker.com/engine/install/) to be installed.
27
+ Then you can install the most recent version from [PyPI](https://pypi.org/project/eva-sub-cli/) in a virtual environment:
28
+ ```bash
29
+ pip install eva-sub-cli
30
+ ```
31
+
32
+ To verify that the cli tool is installed correctly, run the following command, and you should see the help message displayed :
33
+ ```bash
34
+ eva-sub-cli.py -h
35
+ ```
36
+
37
+ ### 3. From source natively
38
+
39
+ This installation method requires the following :
40
+ * Python 3.8+
41
+ * [Nextflow](https://www.nextflow.io/docs/latest/getstarted.html) 21.10+
42
+ * [biovalidator](https://github.com/elixir-europe/biovalidator) 2.1.0+
43
+ * [vcf-validator](https://github.com/EBIvariation/vcf-validator) 0.9.7+
44
+
45
+ Install each of these and ensure they are included in your PATH. Then install the latest release as previously described.
46
+
47
+ ## Getting started with the eva-sub-cli tool
48
+
49
+ The ["Getting Started" guide](Getting_Started_with_eva_sub_cli.md) serves as an introduction for users of the eva-sub-cli tool. It includes instructions on how to prepare your data and metadata, ensuring that users are equipped with the necessary information to successfully submit variant data. This guide is essential for new users, offering practical advice and tips for a smooth onboarding experience with the eva-sub-cli tool.
50
+
51
+ ## Options and parameters guide
52
+
53
+ The eva-sub-cli tool provides several options and parameters that you can use to tailor its functionality to your needs.
54
+ You can view all the available parameters with the command `eva-sub-cli.py -h` and view detailed explanations for the
55
+ input file requirements in the ["Getting Started" guide](Getting_Started_with_eva_sub_cli.md).
56
+ Below is an overview of the key parameters.
57
+
58
+ ### Submission directory
59
+
60
+ This is the directory where all processing will take place, and where configuration and reports will be saved.
61
+ Crucially, the eva-sub-cli tool requires that there be **only one submission per directory** and that the submission directory not be reused.
62
+ Running multiple submissions from a single directory can result in data loss during validation and submission.
63
+
64
+ ### Metadata file
65
+
66
+ Metadata can be provided in one of two files.
67
+
68
+ #### The metadata spreadsheet
69
+
70
+ The metadata template can be found within the [etc folder](eva_sub_cli/etc/EVA_Submission_template.xlsx). It should be populated following the instructions provided within the template.
71
+ This is passed using the option `--metadata_xlsx`.
72
+
73
+ #### The metadata JSON
74
+
75
+ The metadata can also be provided via a JSON file, which should conform to the schema located [here](eva_sub_cli/etc/eva_schema.json).
76
+ This is passed using the option `--metadata_json`.
77
+
78
+ ### VCF files and Reference FASTA
79
+
80
+ These can be provided either in the metadata file directly, or on the command line using the `--vcf_files` and `--reference_fata` options.
81
+ Note that if you are using more than one reference FASTA, you **cannot** use the command line options; you must specify which VCF files use which FASTA files in the metadata.
82
+
83
+ VCF files can be either uncompressed or compressed using bgzip.
84
+ Other types of compression are not allowed and will result in errors during validation.
85
+ FASTA files must be uncompressed.
86
+
87
+ ## Execution
88
+
89
+ ### Validate only
90
+
91
+ To validate and not submit, run the following command:
92
+
93
+ ```shell
94
+ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submission_dir --tasks VALIDATE
95
+ ```
96
+
97
+ **Note for Docker users:**
98
+
99
+ Make sure that Docker is running in the background, e.g. by opening Docker Desktop.
100
+ For each of the below commands, add the command line option `--executor docker`, which will
101
+ fetch and manage the docker container for you.
102
+
103
+ ```shell
104
+ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submission_dir --tasks VALIDATE --executor docker
105
+ ```
106
+
107
+ ### Validate and submit your dataset
108
+
109
+ To validate and submit, run the following command:
110
+
111
+ ```shell
112
+ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx \
113
+ --vcf_files vcf_file1.vcf vcf_file2.vcf --reference_fasta assembly.fa --submission_dir submission_dir
114
+ ```
115
+
116
+
117
+ ### Submit only
118
+
119
+ All submissions must have been validated. You cannot run the submission without validation. Once validated, execute the following command:
120
+
121
+ ```shell
122
+ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submission_dir
123
+ ```
124
+ or
125
+ ```shell
126
+ eva-sub-cli.py --metadata_xlsx metadata_spreadsheet.xlsx --submission_dir submission_dir --tasks SUBMIT
127
+ ```
128
+ This will only submit the data and not validate.
129
+
130
+ ### Shallow validation
131
+
132
+ If you are working with large VCF files and find that validation takes a very long time, you can add the
133
+ argument `--shallow` to the command, which will validate only the first 10,000 lines in each VCF. Note that running
134
+ shallow validation will **not** be sufficient for actual submission.
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+
3
+ BIOVALIDATOR_VERSION=2.2.1
4
+
5
+ EVA_SUB_CLI="${PREFIX}/share/${PKG_NAME}-${PKG_VERSION}"
6
+ mkdir -p ${EVA_SUB_CLI}
7
+
8
+ # Install eva-sub-cli
9
+ $PYTHON -m pip install .
10
+ echo "Done with eva-sub-cli"
11
+
12
+ cd ${EVA_SUB_CLI}
13
+
14
+ # Install biovalidator from source
15
+ curl -Lo biovalidator.zip https://github.com/elixir-europe/biovalidator/archive/refs/tags/v${BIOVALIDATOR_VERSION}.zip \
16
+ && unzip -q biovalidator.zip && rm biovalidator.zip \
17
+ && cd biovalidator-${BIOVALIDATOR_VERSION} \
18
+ && npm install && npm install -g \
19
+ && cd ..
20
+ echo "Done with biovalidator"
@@ -1,37 +1,42 @@
1
1
  {% set name = "eva-sub-cli" %}
2
- {% set version = "0.2" %}
2
+ {% set version = "0.4" %}
3
3
 
4
4
  package:
5
5
  name: {{ name }}
6
6
  version: {{ version }}
7
7
 
8
8
  source:
9
- path: ../
10
- # For submission to bioconda recipes, replace 'path' with the following (filling in the appropriate sha256):
11
- # url: https://github.com/EBIvariation/eva-sub-cli/archive/v{{version}}.tar.gz
12
- # sha256:
9
+ url: https://github.com/EBIvariation/eva-sub-cli/archive/v{{version}}.tar.gz
10
+ sha256: be4d4109d9879ad94ccc01a3bd534ff6077775f126977dfb3f2d6fd9cfb251ba
13
11
 
14
12
  build:
15
13
  number: 0
16
14
  noarch: generic
17
- preserve_egg_dir: True
18
- # For submission to bioconda recipes, replace 'preserve_egg_dir' with the following:
19
- # run_exports:
20
- # - {{ pin_subpackage(name, max_pin="x.x") }}
15
+ script_env:
16
+ - SETUPTOOLS_SCM_PRETEND_VERSION={{ version }}
17
+ run_exports:
18
+ - {{ pin_subpackage(name, max_pin="x.x") }}
21
19
 
22
20
  requirements:
23
21
  host:
24
22
  - nextflow >=21.10.0
25
23
  - python >=3.8
26
24
  - nodejs >=10.19.1
25
+ - vcf-validator >=0.10.0
26
+ - ebi-eva-common-pyutils >=0.6.1
27
27
  - pyyaml
28
28
  - jinja2
29
29
  - openpyxl
30
30
  - requests
31
31
  - jsonschema
32
+ - unzip
33
+ - setuptools-scm
32
34
  run:
33
35
  - nextflow >=21.10.0
34
36
  - python >=3.8
37
+ - nodejs >=10.19.1
38
+ - vcf-validator >=0.9.7
39
+ - ebi-eva-common-pyutils >=0.6.1
35
40
  - pyyaml
36
41
  - jinja2
37
42
  - openpyxl
@@ -43,7 +48,6 @@ test:
43
48
  - eva_sub_cli
44
49
  commands:
45
50
  - biovalidator --help
46
- - vcf_validator --help
47
51
  - eva-sub-cli.py --help
48
52
 
49
53
  about:
@@ -54,4 +58,6 @@ about:
54
58
 
55
59
  extra:
56
60
  recipe-maintainers:
57
- - apriltuesday
61
+ - apriltuesday
62
+ - tcezard
63
+ - ebi-variation
@@ -1,6 +1,6 @@
1
1
  FROM python:3.10
2
2
 
3
- ENV vcf_validator_version=0.9.7
3
+ ENV vcf_validator_version=0.10.0
4
4
  ENV NXF_VER=22.10.6
5
5
 
6
6
  WORKDIR /opt
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '0.4'
16
- __version_tuple__ = version_tuple = (0, 4)
20
+ __version__ = version = '0.4.4'
21
+ __version_tuple__ = version_tuple = (0, 4, 4)
@@ -0,0 +1,4 @@
1
+ class InvalidFileTypeError(Exception):
2
+ def __init__(self, message):
3
+ self.message = message
4
+ super().__init__(self.message)
@@ -15,7 +15,7 @@ from ebi_eva_common_pyutils.logger import logging_config
15
15
 
16
16
  from eva_sub_cli import orchestrator
17
17
  from eva_sub_cli.orchestrator import VALIDATE, SUBMIT, DOCKER, NATIVE
18
- from eva_sub_cli.file_utils import is_submission_dir_writable
18
+ from eva_sub_cli.file_utils import is_submission_dir_writable, DirLockError, DirLock
19
19
 
20
20
 
21
21
  def validate_command_line_arguments(args, argparser):
@@ -68,7 +68,7 @@ def parse_args(cmd_line_args):
68
68
  'to submit to the EVA')
69
69
  credential_group.add_argument("--username", help="Username for your ENA Webin account")
70
70
  credential_group.add_argument("--password", help="Password for your ENA Webin account")
71
- argparser.add_argument('--shallow', action='store_true', default=False,
71
+ argparser.add_argument('--shallow', action='store_true', default=False, dest='shallow_validation',
72
72
  help='Set the validation to be performed on the first 10000 records of the VCF. '
73
73
  'Only applies if the number of records exceed 10000')
74
74
  argparser.add_argument('--debug', action='store_true', default=False,
@@ -79,6 +79,7 @@ def parse_args(cmd_line_args):
79
79
 
80
80
 
81
81
  def main():
82
+ exit_status = 0
82
83
  args = parse_args(sys.argv[1:])
83
84
 
84
85
  args.submission_dir = os.path.abspath(args.submission_dir)
@@ -87,14 +88,28 @@ def main():
87
88
  logging_config.add_stdout_handler(logging.DEBUG)
88
89
  else:
89
90
  logging_config.add_stdout_handler(logging.INFO)
90
- logging_config.add_file_handler(os.path.join(args.submission_dir, 'eva_submission.log'), logging.DEBUG)
91
91
 
92
92
  try:
93
- # Pass on all the arguments
94
- orchestrator.orchestrate_process(**args.__dict__)
93
+ # lock the submission directory
94
+
95
+ with DirLock(os.path.join(args.submission_dir)) as lock:
96
+ # Create the log file
97
+ logging_config.add_file_handler(os.path.join(args.submission_dir, 'eva_submission.log'), logging.DEBUG)
98
+ # Pass on all the arguments to the orchestrator
99
+ orchestrator.orchestrate_process(**args.__dict__)
100
+ except DirLockError:
101
+ print(f'Could not acquire the lock file for {args.submission_dir} because another process is using this '
102
+ f'directory or a previous process did not terminate correctly. '
103
+ f'If the problem persists, remove the lock file manually.')
104
+ exit_status = 65
95
105
  except FileNotFoundError as fne:
96
106
  print(fne)
107
+ exit_status = 66
97
108
  except SubmissionNotFoundException as snfe:
98
109
  print(f'{snfe}. Please contact EVA Helpdesk')
110
+ exit_status = 67
99
111
  except SubmissionStatusException as sse:
100
112
  print(f'{sse}. Please try again later. If the problem persists, please contact EVA Helpdesk')
113
+ exit_status = 68
114
+ return exit_status
115
+
@@ -2,6 +2,7 @@ import glob
2
2
  import gzip
3
3
  import os
4
4
  import shutil
5
+ import time
5
6
  from itertools import groupby
6
7
 
7
8
 
@@ -70,3 +71,47 @@ def fasta_iter(input_fasta):
70
71
  # join all sequence lines to one.
71
72
  seq = "".join(s.strip() for s in faiter.__next__())
72
73
  yield (headerStr, seq)
74
+
75
+
76
+ class DirLockError(Exception):
77
+ pass
78
+
79
+
80
+ class DirLock(object):
81
+
82
+ _SPIN_PERIOD_SECONDS = 0.05
83
+
84
+ def __init__(self, dirname, timeout=3):
85
+ """Prepare a file lock to protect access to dirname. timeout is the
86
+ period (in seconds) after an acquisition attempt is aborted.
87
+ The directory must exist, otherwise aquire() will timeout.
88
+ """
89
+ self._lockfilename = os.path.join(dirname, ".lock")
90
+ self._timeout = timeout
91
+
92
+ def acquire(self):
93
+ start_time = time.time()
94
+ while True:
95
+ try:
96
+ # O_EXCL: fail if file exists or create it (atomically)
97
+ os.close(os.open(self._lockfilename,
98
+ os.O_CREAT | os.O_EXCL | os.O_RDWR))
99
+ break
100
+ except OSError:
101
+ if (time.time() - start_time) > self._timeout:
102
+ raise DirLockError(f"could not create {self._lockfilename} after {self._timeout} seconds")
103
+ else:
104
+ time.sleep(self._SPIN_PERIOD_SECONDS)
105
+
106
+ def release(self):
107
+ try:
108
+ os.remove(self._lockfilename)
109
+ except OSError:
110
+ pass
111
+
112
+ def __enter__(self):
113
+ self.acquire()
114
+ return self
115
+
116
+ def __exit__(self, type_, value, traceback):
117
+ self.release()
@@ -73,8 +73,10 @@
73
73
  Also checks whether the variants' reference alleles match against the reference assembly.
74
74
  </div>
75
75
  {% for file_name in vcf_files %}
76
+ {% if file_name!= "pass"%}
76
77
  <h3>{{ file_name }}</h3>
77
78
  {{ file_validation_report(validation_results, file_name) }}
79
+ {% endif %}
78
80
  {% endfor %}
79
81
  </section>
80
82
 
@@ -93,8 +95,10 @@
93
95
  Also checks if the reference assembly accession in the metadata matches the one determined from the FASTA file.
94
96
  </div>
95
97
  {% for file_name in fasta_files %}
98
+ {% if file_name!= "pass"%}
96
99
  <h3>{{ file_name }}</h3>
97
100
  {{ fasta_check_report(validation_results, file_name) }}
101
+ {% endif %}
98
102
  {% endfor %}
99
103
  </section>
100
104
 
@@ -137,7 +137,6 @@ process check_vcf_valid {
137
137
  tuple path(vcf), path(fasta), path(report)
138
138
 
139
139
  output:
140
- path "vcf_format/*.errors.*.db", emit: vcf_validation_db
141
140
  path "vcf_format/*.errors.*.txt", emit: vcf_validation_txt
142
141
  path "vcf_format/*.vcf_format.log", emit: vcf_validation_log
143
142
 
@@ -145,7 +144,7 @@ process check_vcf_valid {
145
144
  trap 'if [[ \$? == 1 ]]; then exit 0; fi' EXIT
146
145
 
147
146
  mkdir -p vcf_format
148
- $params.executable.vcf_validator -i $vcf -r database,text -o vcf_format --require-evidence > vcf_format/${vcf}.vcf_format.log 2>&1
147
+ $params.executable.vcf_validator -i $vcf -r text -o vcf_format --require-evidence > vcf_format/${vcf}.vcf_format.log 2>&1
149
148
  """
150
149
  }
151
150
 
@@ -10,10 +10,12 @@ from ebi_eva_common_pyutils.logger import logging_config
10
10
  from openpyxl.reader.excel import load_workbook
11
11
 
12
12
  from eva_sub_cli import SUB_CLI_CONFIG_FILE, __version__
13
+ from eva_sub_cli.exceptions.invalid_file_type_exception import InvalidFileTypeError
13
14
  from eva_sub_cli.exceptions.submission_not_found_exception import SubmissionNotFoundException
14
15
  from eva_sub_cli.exceptions.submission_status_exception import SubmissionStatusException
15
16
  from eva_sub_cli.submission_ws import SubmissionWSClient
16
- from eva_sub_cli.submit import StudySubmitter, SUB_CLI_CONFIG_KEY_SUBMISSION_ID
17
+ from eva_sub_cli.submit import StudySubmitter, SUB_CLI_CONFIG_KEY_SUBMISSION_ID, \
18
+ SUB_CLI_CONFIG_KEY_SUBMISSION_UPLOAD_URL
17
19
  from eva_sub_cli.validators.docker_validator import DockerValidator
18
20
  from eva_sub_cli.validators.native_validator import NativeValidator
19
21
  from eva_sub_cli.validators.validator import READY_FOR_SUBMISSION_TO_EVA
@@ -35,7 +37,19 @@ def get_vcf_files(mapping_file):
35
37
  return vcf_files
36
38
 
37
39
 
38
- def get_project_title_and_create_vcf_files_mapping(submission_dir, vcf_files, reference_fasta, metadata_json, metadata_xlsx):
40
+ def get_project_title_and_create_vcf_files_mapping(submission_dir, vcf_files, reference_fasta,
41
+ metadata_json, metadata_xlsx):
42
+ """
43
+ Get project title and mapping between VCF files and reference FASTA files, from three sources: command line
44
+ arguments, metadata JSON file, or metadata XLSX file.
45
+
46
+ :param submission_dir: Directory where mapping file will be saved
47
+ :param vcf_files: VCF files from command line, if present
48
+ :param reference_fasta: Reference FASTA from command line, if present
49
+ :param metadata_json: Metadata JSON from command line, if present
50
+ :param metadata_xlsx: Metadata XLSX from command line, if present
51
+ :return: Project title and path to the mapping file
52
+ """
39
53
  mapping_file = os.path.join(submission_dir, 'vcf_mapping_file.csv')
40
54
  with open(mapping_file, 'w') as open_file:
41
55
  writer = csv.writer(open_file, delimiter=',')
@@ -44,7 +58,7 @@ def get_project_title_and_create_vcf_files_mapping(submission_dir, vcf_files, re
44
58
  vcf_files_mapping = []
45
59
  if vcf_files and reference_fasta:
46
60
  for vcf_file in vcf_files:
47
- vcf_files_mapping.append([os.path.abspath(vcf_file), os.path.abspath(reference_fasta)])
61
+ vcf_files_mapping.append([os.path.abspath(vcf_file), os.path.abspath(reference_fasta), ''])
48
62
  if metadata_json:
49
63
  project_title, _ = get_project_and_vcf_fasta_mapping_from_metadata_json(metadata_json, False)
50
64
  elif metadata_xlsx:
@@ -54,12 +68,32 @@ def get_project_title_and_create_vcf_files_mapping(submission_dir, vcf_files, re
54
68
  elif metadata_xlsx:
55
69
  project_title, vcf_files_mapping = get_project_and_vcf_fasta_mapping_from_metadata_xlsx(metadata_xlsx, True)
56
70
 
71
+ validate_vcf_mapping(vcf_files_mapping)
57
72
  for mapping in vcf_files_mapping:
58
73
  writer.writerow(mapping)
59
74
 
60
75
  return project_title, mapping_file
61
76
 
62
77
 
78
+ def validate_vcf_mapping(vcf_mapping):
79
+ """
80
+ Validate that VCF files and FASTA files in the mapping are present and FASTA files are not compressed.
81
+
82
+ :param vcf_mapping: iterable of triples (VCF file path, reference FASTA path, optional assembly report path)
83
+ :return:
84
+ """
85
+ for vcf_file, fasta_file, report_file in vcf_mapping:
86
+ if not (vcf_file and os.path.isfile(vcf_file)):
87
+ raise FileNotFoundError(f'The variant file {vcf_file} does not exist, please check the file path.')
88
+ if not (fasta_file and os.path.isfile(fasta_file)):
89
+ raise FileNotFoundError(f'The reference fasta {fasta_file} does not exist, please check the file path.')
90
+ if fasta_file.lower().endswith('gz'):
91
+ raise InvalidFileTypeError(f'The reference fasta {fasta_file} is compressed, please uncompress the file.')
92
+ if report_file and not os.path.isfile(report_file):
93
+ raise FileNotFoundError(f'The assembly report file {report_file} does not exist, please check the file '
94
+ f'path.')
95
+
96
+
63
97
  def get_project_and_vcf_fasta_mapping_from_metadata_json(metadata_json, mapping_req=False):
64
98
  with open(metadata_json) as file:
65
99
  json_metadata = json.load(file)
@@ -117,10 +151,6 @@ def get_project_and_vcf_fasta_mapping_from_metadata_xlsx(metadata_xlsx, mapping_
117
151
  file_name = os.path.abspath(row[files_headers['File Name']])
118
152
  analysis_alias = row[files_headers['Analysis Alias']]
119
153
  reference_fasta = os.path.abspath(analysis_alias_dict[analysis_alias])
120
- if not (file_name and os.path.isfile(file_name)):
121
- raise FileNotFoundError(f'The variant file {file_name} provided in spreadsheet {metadata_xlsx} does not exist')
122
- if not (reference_fasta and os.path.isfile(reference_fasta)):
123
- raise FileNotFoundError(f'The reference fasta {reference_fasta} in spreadsheet {metadata_xlsx} does not exist')
124
154
  vcf_fasta_report_mapping.append([os.path.abspath(file_name), os.path.abspath(reference_fasta), ''])
125
155
 
126
156
  return project_title, vcf_fasta_report_mapping
@@ -131,11 +161,15 @@ def check_validation_required(tasks, sub_config, username=None, password=None):
131
161
  if SUBMIT in tasks:
132
162
  if not sub_config.get(READY_FOR_SUBMISSION_TO_EVA, False):
133
163
  return True
164
+ # If we are working with an existing submission check its status to see if it was submitted and failed before.
134
165
  submission_id = sub_config.get(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, None)
135
166
  if submission_id:
136
167
  try:
137
168
  submission_status = SubmissionWSClient(username, password).get_submission_status(submission_id)
138
169
  if submission_status == 'FAILED':
170
+ # Reset the submission_id which will force the creation of a new one
171
+ sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_ID, value=None)
172
+ sub_config.set(SUB_CLI_CONFIG_KEY_SUBMISSION_UPLOAD_URL, value=None)
139
173
  return True
140
174
  else:
141
175
  return False
@@ -151,7 +185,7 @@ def check_validation_required(tasks, sub_config, username=None, password=None):
151
185
  raise SubmissionStatusException(f'Error occurred while getting status of the submission '
152
186
  f'with Id {submission_id}')
153
187
 
154
- logger.info(f'submission id not found in config. This might be the first time user is submitting')
188
+ logger.debug(f'submission id not found in config. This might be the first time user is submitting')
155
189
  return False
156
190
 
157
191