variantgrid-api 0.3.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.1
2
+ Name: variantgrid_api
3
+ Version: 0.3.0
4
+ Summary: A Python API client for VariantGrid
5
+ Author-email: Dave Lawrence <davmlaw@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/SACGF/variantgrid_api
29
+ Classifier: Development Status :: 3 - Alpha
30
+ Classifier: Intended Audience :: Developers
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Programming Language :: Python :: 3
33
+ Requires-Python: >=3.8
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: requests
37
+ Requires-Dist: dataclasses-json
38
+
39
+ # variantgrid_api
@@ -0,0 +1 @@
1
+ # variantgrid_api
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "variantgrid_api"
7
+ version = "0.3.0"
8
+ description = "A Python API client for VariantGrid"
9
+ authors = [
10
+ { name = "Dave Lawrence", email = "davmlaw@gmail.com" }
11
+ ]
12
+ readme = "README.md"
13
+ license = {file = "LICENSE"}
14
+ requires-python = ">=3.8"
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ ]
21
+ dependencies = [
22
+ "requests",
23
+ "dataclasses-json"
24
+ ]
25
+
26
+ [project.urls]
27
+ "Homepage" = "https://github.com/SACGF/variantgrid_api"
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["src"]
31
+ exclude = ["examples"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,126 @@
1
+ import json
2
+ import logging
3
+ import os
4
+ from typing import List
5
+
6
+ import requests
7
+
8
+ from variantgrid_api.data_models import EnrichmentKit, SequencingRun, SampleSheet, SampleSheetCombinedVCFFile, \
9
+ SampleSheetLookup, SequencingFile, QCGeneList, QCExecStats, QCGeneCoverage
10
+
11
+
12
+ class VariantGridAPI:
13
+ def __init__(self, server, api_token):
14
+ self.server = server
15
+ self.headers = {"Authorization": f"Token {api_token}"}
16
+
17
+ def _get_url(self, url):
18
+ return os.path.join(self.server, url)
19
+
20
+ def _post(self, path, json_data):
21
+ url = self._get_url(path)
22
+ response = requests.post(url, headers=self.headers, json=json_data)
23
+ try:
24
+ json_response = response.json()
25
+ except Exception as e:
26
+ json_response = f"Couldn't convert JSON: {e}"
27
+ if not response.ok:
28
+ logging.info("url='%s', JSON data:", url)
29
+ logging.info(json.dumps(json_data))
30
+ logging.info("Response: %s", json_response)
31
+ response.raise_for_status()
32
+ return json_response
33
+
34
+ def create_experiment(self, experiment: str):
35
+ json_data = {
36
+ "name": experiment
37
+ }
38
+ return self._post("seqauto/api/v1/experiment/", json_data)
39
+
40
+ def create_enrichment_kit(self, enrichment_kit: EnrichmentKit):
41
+ return self._post("seqauto/api/v1/enrichment_kit/",
42
+ enrichment_kit.to_dict())
43
+
44
+ def create_sequencing_run(self, sequencing_run: SequencingRun):
45
+ return self._post("seqauto/api/v1/sequencing_run/",
46
+ sequencing_run.to_dict())
47
+
48
+ def create_sample_sheet(self, sample_sheet: SampleSheet):
49
+ json_data = sample_sheet.to_dict()
50
+ # We don't want all sequencing_run just the name
51
+ sequencing_run = json_data.pop("sequencing_run")
52
+ json_data["sequencing_run"] = sequencing_run["name"]
53
+ return self._post("seqauto/api/v1/sample_sheet/",
54
+ json_data)
55
+
56
+ def create_sample_sheet_combined_vcf_file(self, sample_sheet_combined_vcf_file: SampleSheetCombinedVCFFile):
57
+ json_data = sample_sheet_combined_vcf_file.to_dict()
58
+ return self._post("seqauto/api/v1/sample_sheet_combined_vcf_file/",
59
+ json_data)
60
+
61
+ def create_sequencing_data(self, sample_sheet_lookup: SampleSheetLookup, sequencing_files: List[SequencingFile]):
62
+ records = []
63
+ for sf in sequencing_files:
64
+ data = sf.to_dict()
65
+ # put into hierarchial JSON DRF expects
66
+ fastq_r1 = data.pop("fastq_r1")
67
+ fastq_r2 = data.pop("fastq_r2")
68
+ data["unaligned_reads"] = {
69
+ "fastq_r1": {"path": fastq_r1},
70
+ "fastq_r2": {"path": fastq_r2}
71
+ }
72
+ records.append(data)
73
+
74
+ json_data = {
75
+ "sample_sheet": sample_sheet_lookup.to_dict(),
76
+ "records": records
77
+ }
78
+ return self._post("seqauto/api/v1/sequencing_files/bulk_create",
79
+ json_data)
80
+
81
+ def create_qc_gene_list(self, qc_gene_list: QCGeneList):
82
+ json_data = qc_gene_list.to_dict()
83
+ return self._post("seqauto/api/v1/qc_gene_list/",
84
+ json_data)
85
+
86
+
87
+ def create_multiple_qc_gene_lists(self, qc_gene_lists: List[QCGeneList]):
88
+ json_data = {
89
+ "records": [
90
+ qcgl.to_dict() for qcgl in qc_gene_lists
91
+ ]
92
+ }
93
+ return self._post("seqauto/api/v1/qc_gene_list/bulk_create",
94
+ json_data)
95
+
96
+ def create_qc_exec_stats(self, qc_exec_stats: QCExecStats):
97
+ json_data = qc_exec_stats.to_dict()
98
+ return self._post("seqauto/api/v1/qc_exec_summary/",
99
+ json_data)
100
+
101
+ def create_multiple_qc_exec_stats(self, qc_exec_stats: List[QCExecStats]):
102
+ json_data = {
103
+ "records": [
104
+ qces.to_dict() for qces in qc_exec_stats
105
+ ]
106
+ }
107
+ return self._post("seqauto/api/v1/qc_exec_summary/bulk_create",
108
+ json_data)
109
+
110
+ def create_multiple_qc_gene_coverage(self, qc_gene_coverage_list: List[QCGeneCoverage]):
111
+ json_data = {
112
+ "records": [
113
+ qcgc.to_dict() for qcgc in qc_gene_coverage_list
114
+ ]
115
+ }
116
+ return self._post("seqauto/api/v1/qc_gene_coverage/bulk_create",
117
+ json_data)
118
+
119
+ def upload_file(self, filename: str):
120
+ url = self._get_url("upload/api/v1/file_upload")
121
+ with open(filename, "rb") as f:
122
+ kwargs = {
123
+ "files": {"file": f},
124
+ "params": {"path": filename}
125
+ }
126
+ return requests.post(url, headers=self.headers, **kwargs)
@@ -0,0 +1,183 @@
1
+ from datetime import date, datetime
2
+ from dataclasses import dataclass, field
3
+ from typing import Optional, List
4
+
5
+ from dataclasses_json import dataclass_json, config
6
+
7
+
8
+ @dataclass_json
9
+ @dataclass
10
+ class EnrichmentKit:
11
+ name: str
12
+ version: int
13
+
14
+
15
+ @dataclass_json
16
+ @dataclass
17
+ class SequencingRun:
18
+ path: str
19
+ name: str
20
+ date: date
21
+ sequencer: str
22
+ experiment: str
23
+ enrichment_kit: EnrichmentKit
24
+
25
+
26
+ @dataclass_json
27
+ @dataclass
28
+ class SequencingSample:
29
+ sample_id: str
30
+ sample_number: int
31
+ lane: int
32
+ barcode: str
33
+ enrichment_kit: EnrichmentKit
34
+ sample_project: Optional[str] = None
35
+ is_control: bool = False
36
+ failed: bool = False
37
+ data: List[dict] = field(default_factory=lambda: [], metadata=config(field_name="sequencingsampledata_set"))
38
+
39
+
40
+ @dataclass_json
41
+ @dataclass
42
+ class SampleSheet:
43
+ path: str
44
+ sequencing_run: SequencingRun
45
+ file_last_modified: datetime
46
+ hash: str
47
+ sequencing_samples: List[SequencingSample] = field(metadata=config(field_name="sequencingsample_set"))
48
+
49
+
50
+ @dataclass_json
51
+ @dataclass
52
+ class SampleSheetLookup:
53
+ """ 'Lookups' are used as arguments to find existing data on server - not enough details to create one,
54
+ but just enough to find one
55
+ """
56
+ sequencing_run: str
57
+ hash: str
58
+
59
+ @staticmethod
60
+ def from_sample_sheet(sample_sheet: SampleSheet) -> 'SampleSheetLookup':
61
+ return SampleSheetLookup(sequencing_run=sample_sheet.sequencing_run.name, hash=sample_sheet.hash)
62
+
63
+
64
+ @dataclass_json
65
+ @dataclass
66
+ class Aligner:
67
+ name: str
68
+ version: str
69
+
70
+
71
+ @dataclass_json
72
+ @dataclass
73
+ class VariantCaller:
74
+ name: str
75
+ version: str
76
+ run_params: Optional[str] = None
77
+
78
+
79
+ @dataclass_json
80
+ @dataclass
81
+ class SampleSheetCombinedVCFFile:
82
+ path: str
83
+ sample_sheet_lookup: SampleSheetLookup = field(metadata=config(field_name="sample_sheet"))
84
+ variant_caller: VariantCaller
85
+
86
+
87
+ @dataclass_json
88
+ @dataclass
89
+ class BamFile:
90
+ path: str
91
+ aligner: Optional[Aligner] = field(default=None, metadata=config(exclude=lambda x: x is None))
92
+
93
+
94
+ @dataclass_json
95
+ @dataclass
96
+ class VCFFile:
97
+ path: str
98
+ variant_caller: Optional[VariantCaller] = field(default=None, metadata=config(exclude=lambda x: x is None))
99
+
100
+
101
+ @dataclass_json
102
+ @dataclass
103
+ class SequencingFile:
104
+ sample_name: str
105
+ fastq_r1: str
106
+ fastq_r2: str
107
+ bam_file: BamFile
108
+ vcf_file: VCFFile
109
+
110
+
111
+ @dataclass_json
112
+ @dataclass
113
+ class SequencingSampleLookup:
114
+ """ Only used as arguments to find existing sequencing sample on server - not enough details to create one """
115
+ sample_sheet_lookup: SampleSheetLookup = field(metadata=config(field_name="sample_sheet"))
116
+ sample_name: str
117
+
118
+
119
+ @dataclass_json
120
+ @dataclass
121
+ class QC:
122
+ """ QC information needs to be matched against a particular BAM/VCF file (as there could be multiple)
123
+ We use this to match gene lists, exec stats and coverage below
124
+ """
125
+ sequencing_sample_lookup: SequencingSampleLookup = field(metadata=config(field_name="sequencing_sample"))
126
+ bam_file: BamFile
127
+ vcf_file: VCFFile
128
+
129
+
130
+ @dataclass_json
131
+ @dataclass
132
+ class QCGeneList:
133
+ path: str
134
+ qc: QC
135
+ gene_list: List[str]
136
+
137
+
138
+ @dataclass_json
139
+ @dataclass
140
+ class QCExecStats:
141
+ path: str
142
+ qc: QC
143
+ created: datetime
144
+ modified: datetime
145
+ hash: str
146
+ is_valid: bool
147
+ deduplicated_reads: int
148
+ indels_dbsnp_percent: float
149
+ mean_coverage_across_genes: float
150
+ mean_coverage_across_kit: float
151
+ median_insert: float
152
+ number_indels: int
153
+ number_snps: int
154
+ percent_10x_goi: float
155
+ percent_20x_goi: float
156
+ percent_20x_kit: float
157
+ percent_error_rate: float
158
+ percent_map_to_diff_chr: float
159
+ percent_read_enrichment: float
160
+ percent_reads: float
161
+ percent_softclip: float
162
+ percent_duplication: float
163
+ reads: int
164
+ sample_id_lod: float
165
+ sex_match: str
166
+ snp_dbsnp_percent: float
167
+ ts_to_tv_ratio: float
168
+ uniformity_of_coverage: float
169
+ percent_100x_goi: Optional[float] = None
170
+ percent_100x_kit: Optional[float] = None
171
+ percent_250x_goi: Optional[float] = None
172
+ percent_250x_kit: Optional[float] = None
173
+ percent_500x_goi: Optional[float] = None
174
+ percent_500x_kit: Optional[float] = None
175
+
176
+
177
+ @dataclass_json
178
+ @dataclass
179
+ class QCGeneCoverage:
180
+ """ We send this up to associate coverage file path with sequencing sample
181
+ Then, later we upload the coverage file - and match via path """
182
+ qc: QC
183
+ path: str
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.1
2
+ Name: variantgrid_api
3
+ Version: 0.3.0
4
+ Summary: A Python API client for VariantGrid
5
+ Author-email: Dave Lawrence <davmlaw@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/SACGF/variantgrid_api
29
+ Classifier: Development Status :: 3 - Alpha
30
+ Classifier: Intended Audience :: Developers
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Programming Language :: Python :: 3
33
+ Requires-Python: >=3.8
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: requests
37
+ Requires-Dist: dataclasses-json
38
+
39
+ # variantgrid_api
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/variantgrid_api/api_client.py
5
+ src/variantgrid_api/data_models.py
6
+ src/variantgrid_api.egg-info/PKG-INFO
7
+ src/variantgrid_api.egg-info/SOURCES.txt
8
+ src/variantgrid_api.egg-info/dependency_links.txt
9
+ src/variantgrid_api.egg-info/requires.txt
10
+ src/variantgrid_api.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ requests
2
+ dataclasses-json
@@ -0,0 +1 @@
1
+ variantgrid_api