variantgrid-api 0.3.0__tar.gz → 1.0.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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: variantgrid_api
3
- Version: 0.3.0
3
+ Version: 1.0.0
4
4
  Summary: A Python API client for VariantGrid
5
5
  Author-email: Dave Lawrence <davmlaw@gmail.com>
6
6
  License: MIT License
@@ -35,5 +35,11 @@ Description-Content-Type: text/markdown
35
35
  License-File: LICENSE
36
36
  Requires-Dist: requests
37
37
  Requires-Dist: dataclasses-json
38
+ Requires-Dist: samshee
39
+ Dynamic: license-file
38
40
 
39
41
  # variantgrid_api
42
+
43
+ Python API client for [VariantGrid](https://github.com/SACGF/variantgrid) Open source Variant database and analysis platform
44
+
45
+ See [changelog](https://github.com/SACGF/variantgrid_api/blob/main/CHANGELOG.md)
@@ -0,0 +1,5 @@
1
+ # variantgrid_api
2
+
3
+ Python API client for [VariantGrid](https://github.com/SACGF/variantgrid) Open source Variant database and analysis platform
4
+
5
+ See [changelog](https://github.com/SACGF/variantgrid_api/blob/main/CHANGELOG.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "variantgrid_api"
7
- version = "0.3.0"
7
+ version = "1.0.0"
8
8
  description = "A Python API client for VariantGrid"
9
9
  authors = [
10
10
  { name = "Dave Lawrence", email = "davmlaw@gmail.com" }
@@ -20,7 +20,8 @@ classifiers = [
20
20
  ]
21
21
  dependencies = [
22
22
  "requests",
23
- "dataclasses-json"
23
+ "dataclasses-json",
24
+ "samshee"
24
25
  ]
25
26
 
26
27
  [project.urls]
@@ -1,13 +1,21 @@
1
+ import datetime
1
2
  import json
2
3
  import logging
3
4
  import os
4
- from typing import List
5
+ from typing import List, Optional
5
6
 
6
7
  import requests
7
8
 
8
9
  from variantgrid_api.data_models import EnrichmentKit, SequencingRun, SampleSheet, SampleSheetCombinedVCFFile, \
9
10
  SampleSheetLookup, SequencingFile, QCGeneList, QCExecStats, QCGeneCoverage
10
11
 
12
+ class DateTimeEncoder(json.JSONEncoder):
13
+ def default(self,o):
14
+ if isinstance(o,(datetime.date, datetime.datetime)):
15
+ return o.isoformat()
16
+ return super().default(o)
17
+
18
+
11
19
 
12
20
  class VariantGridAPI:
13
21
  def __init__(self, server, api_token):
@@ -19,15 +27,23 @@ class VariantGridAPI:
19
27
 
20
28
  def _post(self, path, json_data):
21
29
  url = self._get_url(path)
22
- response = requests.post(url, headers=self.headers, json=json_data)
30
+ json_string = json.dumps(json_data, cls=DateTimeEncoder)
31
+ response = requests.post(url,
32
+ headers={**self.headers, "Content-Type": "application/json"},
33
+ data=json_string)
34
+
35
+ extra_error_message = f"{url=}, {json_string=}"
36
+ return self._handle_json_response(response, extra_error_message)
37
+
38
+ def _handle_json_response(self, response, extra_error_message: Optional[str] = None):
23
39
  try:
24
40
  json_response = response.json()
25
41
  except Exception as e:
26
42
  json_response = f"Couldn't convert JSON: {e}"
27
43
  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)
44
+ if extra_error_message:
45
+ logging.error(extra_error_message)
46
+ logging.error("Response: %s", json_response)
31
47
  response.raise_for_status()
32
48
  return json_response
33
49
 
@@ -123,4 +139,38 @@ class VariantGridAPI:
123
139
  "files": {"file": f},
124
140
  "params": {"path": filename}
125
141
  }
126
- return requests.post(url, headers=self.headers, **kwargs)
142
+ response = requests.post(url, headers=self.headers, **kwargs)
143
+ extra_error_message = f"{filename=}"
144
+ return self._handle_json_response(response, extra_error_message)
145
+
146
+ ###############
147
+ ## Get methods
148
+
149
+ def _get(self, path, params=None):
150
+ url = self._get_url(path)
151
+ response = requests.get(url,
152
+ params,
153
+ headers=self.headers)
154
+
155
+ extra_error_message = f"{url=}, {params=}"
156
+ return self._handle_json_response(response, extra_error_message)
157
+
158
+ def sequencing_run_has_vcf(self, sequencing_run: SequencingRun, path: Optional[str] = None):
159
+ """ Returns whether the SequencingRun has a VCF associated with it. If path is set, VCF must match that path
160
+ otherwise - any VCF present will retur True """
161
+ return self.sequencing_run_name_has_vcf(sequencing_run.name, path)
162
+
163
+ def sequencing_run_name_has_vcf(self, sequencing_run_name: str, path: Optional[str] = None):
164
+ """ Returns whether the SequencingRun has a VCF associated with it. If path is set, VCF must match that path
165
+ otherwise - any VCF present will retur True """
166
+ data = self._get(f"seqauto/api/v1/sequencing_run/{sequencing_run_name}/")
167
+ found_vcf = False
168
+ for vcf in data["vcf_set"]:
169
+ if path is None or path in vcf["path"]:
170
+ found_vcf = True
171
+ break
172
+ return found_vcf
173
+
174
+
175
+
176
+
@@ -1,3 +1,4 @@
1
+ import re
1
2
  from datetime import date, datetime
2
3
  from dataclasses import dataclass, field
3
4
  from typing import Optional, List
@@ -22,15 +23,25 @@ class SequencingRun:
22
23
  experiment: str
23
24
  enrichment_kit: EnrichmentKit
24
25
 
26
+ @staticmethod
27
+ def get_date_from_name(name) -> Optional[datetime.date]:
28
+ date = None
29
+ if m := re.match(r".*_?([12]\d{5})_", name):
30
+ date_str = m.group(1)
31
+ dt = datetime.strptime(date_str, "%y%m%d")
32
+ date = dt.date()
33
+ return date
34
+
35
+
25
36
 
26
37
  @dataclass_json
27
38
  @dataclass
28
39
  class SequencingSample:
29
40
  sample_id: str
30
- sample_number: int
31
- lane: int
41
+ sample_number: int # Sample sheet row (to keep in order)
32
42
  barcode: str
33
43
  enrichment_kit: EnrichmentKit
44
+ lane: Optional[int] = None
34
45
  sample_project: Optional[str] = None
35
46
  is_control: bool = False
36
47
  failed: bool = False
@@ -42,7 +53,7 @@ class SequencingSample:
42
53
  class SampleSheet:
43
54
  path: str
44
55
  sequencing_run: SequencingRun
45
- file_last_modified: datetime
56
+ file_last_modified: float
46
57
  hash: str
47
58
  sequencing_samples: List[SequencingSample] = field(metadata=config(field_name="sequencingsample_set"))
48
59
 
@@ -144,34 +155,34 @@ class QCExecStats:
144
155
  modified: datetime
145
156
  hash: str
146
157
  is_valid: bool
147
- deduplicated_reads: int
148
- indels_dbsnp_percent: float
149
158
  mean_coverage_across_genes: float
150
159
  mean_coverage_across_kit: float
151
160
  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
161
  percent_read_enrichment: float
160
- percent_reads: float
161
- percent_softclip: float
162
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
163
  uniformity_of_coverage: float
164
+ deduplicated_reads: Optional[int] = None
165
+ indels_dbsnp_percent: Optional[float] = None
166
+ number_indels: Optional[int] = None
167
+ number_snps: Optional[int] = None
168
+ percent_10x_goi: Optional[float] = None
169
+ percent_20x_goi: Optional[float] = None
170
+ percent_20x_kit: Optional[float] = None
169
171
  percent_100x_goi: Optional[float] = None
170
172
  percent_100x_kit: Optional[float] = None
171
173
  percent_250x_goi: Optional[float] = None
172
174
  percent_250x_kit: Optional[float] = None
173
175
  percent_500x_goi: Optional[float] = None
174
176
  percent_500x_kit: Optional[float] = None
177
+ percent_error_rate: Optional[float] = None
178
+ percent_map_to_diff_chr: Optional[float] = None
179
+ percent_reads: Optional[float] = None
180
+ percent_softclip: Optional[float] = None
181
+ reads: Optional[int] = None
182
+ sample_id_lod: Optional[float] = None
183
+ sex_match: Optional[str] = None
184
+ snp_dbsnp_percent: Optional[float] = None
185
+ ts_to_tv_ratio: Optional[float] = None
175
186
 
176
187
 
177
188
  @dataclass_json
@@ -180,4 +191,4 @@ class QCGeneCoverage:
180
191
  """ We send this up to associate coverage file path with sequencing sample
181
192
  Then, later we upload the coverage file - and match via path """
182
193
  qc: QC
183
- path: str
194
+ path: str
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: variantgrid_api
3
- Version: 0.3.0
3
+ Version: 1.0.0
4
4
  Summary: A Python API client for VariantGrid
5
5
  Author-email: Dave Lawrence <davmlaw@gmail.com>
6
6
  License: MIT License
@@ -35,5 +35,11 @@ Description-Content-Type: text/markdown
35
35
  License-File: LICENSE
36
36
  Requires-Dist: requests
37
37
  Requires-Dist: dataclasses-json
38
+ Requires-Dist: samshee
39
+ Dynamic: license-file
38
40
 
39
41
  # variantgrid_api
42
+
43
+ Python API client for [VariantGrid](https://github.com/SACGF/variantgrid) Open source Variant database and analysis platform
44
+
45
+ See [changelog](https://github.com/SACGF/variantgrid_api/blob/main/CHANGELOG.md)
@@ -1,2 +1,3 @@
1
1
  requests
2
2
  dataclasses-json
3
+ samshee
@@ -1 +0,0 @@
1
- # variantgrid_api
File without changes