variantgrid-api 0.1.5__tar.gz → 0.2.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.
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/PKG-INFO +2 -2
- variantgrid_api-0.2.0/README.md +108 -0
- variantgrid_api-0.2.0/bin/vg_api +127 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/setup.py +4 -2
- variantgrid_api-0.2.0/variantgrid_api/__init__.py +2 -0
- variantgrid_api-0.2.0/variantgrid_api/api.py +166 -0
- variantgrid_api-0.2.0/variantgrid_api/shariant_classification.py +18 -0
- variantgrid_api-0.2.0/variantgrid_api/shariant_classification_modify.py +15 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/PKG-INFO +2 -2
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/SOURCES.txt +3 -0
- variantgrid_api-0.2.0/variantgrid_api.egg-info/requires.txt +4 -0
- variantgrid_api-0.1.5/bin/vg_api +0 -108
- variantgrid_api-0.1.5/variantgrid_api/__init__.py +0 -2
- variantgrid_api-0.1.5/variantgrid_api/api.py +0 -130
- variantgrid_api-0.1.5/variantgrid_api.egg-info/requires.txt +0 -2
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/setup.cfg +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/add_classification.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/annotation.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/classifications.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/gene_list.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/variant_classification_vcf.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/vcf_utils.py +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/dependency_links.txt +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/not-zip-safe +0 -0
- {variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 1.0
|
|
2
2
|
Name: variantgrid_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: API to connect to VariantGrid
|
|
5
|
-
Home-page: https://
|
|
5
|
+
Home-page: https://github.com/SACGF/vg_api
|
|
6
6
|
Author: David Lawrence
|
|
7
7
|
Author-email: davmlaw@gmail.com
|
|
8
8
|
License: MIT License
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# VariantGrid API
|
|
2
|
+
|
|
3
|
+
Command line tool and Python library to connect to the [Shariant](https://shariant.org.au) variant database.
|
|
4
|
+
|
|
5
|
+
### Installing
|
|
6
|
+
|
|
7
|
+
Install the [Pip Package](https://pypi.python.org/pypi/variantgrid_api). On Linux this is via:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
sudo pip install variantgrid_api
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
or if you have downloaded the source code and wish to install from the local copy, run from this directory
|
|
14
|
+
```
|
|
15
|
+
sudo pip install -e .
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Command line Example
|
|
19
|
+
|
|
20
|
+
Retrieve a list of classified variants
|
|
21
|
+
```
|
|
22
|
+
vg_api classifications --user XXX --password YYYY --all
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Configuration Files
|
|
26
|
+
|
|
27
|
+
Create ~/.vg_api to store command line parameters so you don't have to pass them each time, eg:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
user = XXX
|
|
31
|
+
password = YYY
|
|
32
|
+
```
|
|
33
|
+
### Classifications (reading)
|
|
34
|
+
|
|
35
|
+
Retrieve the complete set of keys that can be used in variant evidence
|
|
36
|
+
```
|
|
37
|
+
vg_api classifications --keys
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Retrieve a list of classified variants
|
|
41
|
+
```
|
|
42
|
+
vg_api classifications --all
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Retrieve a specific classified variant
|
|
46
|
+
```
|
|
47
|
+
vg_api classifications --id 5
|
|
48
|
+
```
|
|
49
|
+
Retrieve a specific version
|
|
50
|
+
```
|
|
51
|
+
vg_api classifications --id 5 --version 1
|
|
52
|
+
```
|
|
53
|
+
Retrieve using a lab id, where the lab id is B5886D3C-3E86-4F56-A550-1417D8AB1563
|
|
54
|
+
```
|
|
55
|
+
vg_api classifications --id L_B5886D3C-3E86-4F56-A550-1417D8AB1563
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Classifications (uploading)
|
|
59
|
+
|
|
60
|
+
Inserting or replacing a record with a lab id of B5886D3C-3E86-4F56-A550-1417D8AB1563
|
|
61
|
+
```
|
|
62
|
+
vg_api classification_upload --id L_B5886D3C-3E86-4F56-A550-1417D8AB1563 < record_data.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
where the contents of record_data would look like
|
|
66
|
+
```
|
|
67
|
+
{
|
|
68
|
+
"condition": "OMIM:3242",
|
|
69
|
+
"BA1": "NM",
|
|
70
|
+
"age": 7,
|
|
71
|
+
etc
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Updating a few fields
|
|
77
|
+
```
|
|
78
|
+
vg_api classification_upload --method PATCH --id L_B5886D3C-3E86-4F56-A550-1417D8AB1563 < delta.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Python
|
|
82
|
+
|
|
83
|
+
You can make your own API calls via Python:
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
from variantgrid_api import VariantGridAPI
|
|
88
|
+
|
|
89
|
+
In [1]: api = VariantGridAPI(login, password)
|
|
90
|
+
|
|
91
|
+
In [2]: api.shariant_classification('4')
|
|
92
|
+
Out[2]:
|
|
93
|
+
{
|
|
94
|
+
"id": 3,
|
|
95
|
+
"data": {
|
|
96
|
+
"x": {
|
|
97
|
+
"value": "y"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"versions": 1,
|
|
101
|
+
"version": "latest",
|
|
102
|
+
....
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
from __future__ import print_function
|
|
4
|
+
|
|
5
|
+
from configargparse import Action, ArgParser
|
|
6
|
+
from requests.exceptions import ConnectionError
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from variantgrid_api.add_classification import add_classification_handle_args
|
|
10
|
+
from variantgrid_api.annotation import annotation_handle_args
|
|
11
|
+
from variantgrid_api.classifications import classifications_handle_args
|
|
12
|
+
from variantgrid_api.shariant_classification import shariant_classifications_handle_args
|
|
13
|
+
from variantgrid_api.shariant_classification_modify import shariant_classifications_modify_handle_args
|
|
14
|
+
from variantgrid_api.gene_list import gene_list_handle_args
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ClassificationAction(Action):
|
|
18
|
+
VALID_CLASSIFICATIONS = range(1, 6)
|
|
19
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
20
|
+
if values not in self.VALID_CLASSIFICATIONS:
|
|
21
|
+
valid_classifications_str = ','.join(map(str, self.VALID_CLASSIFICATIONS))
|
|
22
|
+
raise ValueError("classification must be one of %s" % valid_classifications_str)
|
|
23
|
+
setattr(namespace, self.dest, values)
|
|
24
|
+
|
|
25
|
+
def add_authentication(parser, required):
|
|
26
|
+
parser.add("--user", required=required, env_var='VG_USER')
|
|
27
|
+
parser.add("--password", required=required, env_var='VG_PASSWORD')
|
|
28
|
+
parser.add("--basic_auth", action='store_true', env_var='VG_BASIC_AUTH', help='(Only needed for non shariant server) Set to true to just use username and password, otherwise oauth will be attempted')
|
|
29
|
+
parser.add("--oauth_url", default='https://shariant.org.au/auth/realms/agha/protocol/openid-connect/token', env_var='VG_OAUTH', help='(Only needed for non shariant server) Address of where to get the token for oauth')
|
|
30
|
+
parser.add("--client_id", default='shariant-client-tools', env_var="VG_CLIENT_ID", help='(Only needed for non shariant server) OAuth Client ID to request token against')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_args():
|
|
34
|
+
# CLASSIFICATION_HELP = 'HGNC classifications: 1 - Benign, 2 - Likely benign, 3 - VUS, 4 - Likely Pathogenic, 5 - Pathogenic'
|
|
35
|
+
|
|
36
|
+
parser = ArgParser(default_config_files=['~/.vg_api'])
|
|
37
|
+
parser.add('-c', '--config', is_config_file=True, help='config file path')
|
|
38
|
+
|
|
39
|
+
# Global settings
|
|
40
|
+
|
|
41
|
+
parser.add("--host", default='https://shariant.org.au', env_var='VG_HOST', help='Server Address (default=https://shariant.org.au)')
|
|
42
|
+
parser.add("--verbose", action='store_true', env_var='VG_VERBOSE', help='Print debugging information')
|
|
43
|
+
|
|
44
|
+
subparsers = parser.add_subparsers(help='sub-command help', dest='command')
|
|
45
|
+
|
|
46
|
+
# Add Classification
|
|
47
|
+
# add_classification_parser = subparsers.add_parser('add_classification', help='Add new classification for a variant')
|
|
48
|
+
# add_authentication(add_classification_parser, required=True)
|
|
49
|
+
# variant_group = add_classification_parser.add_mutually_exclusive_group(required=True)
|
|
50
|
+
# variant_group.add_argument('--variant', help='hg19 coordinate eg "1:169519049 T>C"')
|
|
51
|
+
# variant_group.add_argument('--dbsnp', help='dbSNP rsId eg "rs6025"')
|
|
52
|
+
# variant_group.add_argument('--hgvs', help='HGVS string eg "F5 (NM_000130) p.Gln534Arg/c.1601A>G"')
|
|
53
|
+
# add_classification_parser.add_argument('--classification', type=int, action=ClassificationAction, help=CLASSIFICATION_HELP)
|
|
54
|
+
# add_classification_parser.add_argument('--public', action='store_true', default=False, help="Classification is public (default=False)")
|
|
55
|
+
|
|
56
|
+
classification_upload_parser = subparsers.add_parser('classification_upload', help="Create/Update a classification in Shariant")
|
|
57
|
+
add_authentication(classification_upload_parser, required=True)
|
|
58
|
+
classification_upload_parser.add_argument("--method", default="POST", help="POST or PATCH")
|
|
59
|
+
classification_upload_parser.add_argument("--id", help="Id of the record, for new record provide own id prefixed by L_ or omit")
|
|
60
|
+
|
|
61
|
+
# Classifications
|
|
62
|
+
# classifications_parser = subparsers.add_parser('classifications', help='Get classification from VariantGrid')
|
|
63
|
+
# add_authentication(classifications_parser, required=False)
|
|
64
|
+
# classifications_parser.add_argument("--classification", type=int, action=ClassificationAction)
|
|
65
|
+
# group = classifications_parser.add_mutually_exclusive_group(required=True)
|
|
66
|
+
# group.add_argument("--all", action='store_true')
|
|
67
|
+
# group.add_argument("--dbsnp")
|
|
68
|
+
# group.add_argument("--gene")
|
|
69
|
+
# group.add_argument("--locus")
|
|
70
|
+
# group.add_argument("--variant")
|
|
71
|
+
|
|
72
|
+
# Classifications
|
|
73
|
+
classifications_parser = subparsers.add_parser('classifications', help="Retrieve classifications from Shariant")
|
|
74
|
+
add_authentication(classifications_parser, required=True)
|
|
75
|
+
classifications_parser.add_argument("--version", default=None, help="Version of the record")
|
|
76
|
+
group = classifications_parser.add_mutually_exclusive_group(required=True)
|
|
77
|
+
group.add_argument("--all", action='store_true')
|
|
78
|
+
group.add_argument("--keys", action='store_true')
|
|
79
|
+
group.add_argument("--id")
|
|
80
|
+
|
|
81
|
+
group = classifications_parser.add
|
|
82
|
+
|
|
83
|
+
# Annotation
|
|
84
|
+
annotation_parser = subparsers.add_parser('annotation', help='Get VariantGrid Annotations')
|
|
85
|
+
|
|
86
|
+
group = annotation_parser.add_mutually_exclusive_group(required=True)
|
|
87
|
+
group.add_argument("--gene-id")
|
|
88
|
+
group.add_argument("--gene")
|
|
89
|
+
group.add_argument("--variant")
|
|
90
|
+
# TODO: Annotation Versions??
|
|
91
|
+
|
|
92
|
+
# Gene List
|
|
93
|
+
gene_list_parser = subparsers.add_parser('gene_list', help='Get Gene List')
|
|
94
|
+
add_authentication(gene_list_parser, required=False)
|
|
95
|
+
gene_list_parser.add_argument("--category", default='Uploaded', help="One of 'Diagnostic', 'Uploaded'")
|
|
96
|
+
group = gene_list_parser.add_mutually_exclusive_group(required=True)
|
|
97
|
+
group.add_argument("--pk")
|
|
98
|
+
group.add_argument("--name")
|
|
99
|
+
|
|
100
|
+
return parser.parse_args()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main(args):
|
|
104
|
+
SUBCOMMAND_HANDLERS = {
|
|
105
|
+
"annotation" : annotation_handle_args,
|
|
106
|
+
"add_classification" : add_classification_handle_args,
|
|
107
|
+
"classifications": shariant_classifications_handle_args,
|
|
108
|
+
"classification_upload": shariant_classifications_modify_handle_args,
|
|
109
|
+
# "classifications" : classifications_handle_args,
|
|
110
|
+
"gene_list" : gene_list_handle_args,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
handler = SUBCOMMAND_HANDLERS[args.command or '<no command given>']
|
|
114
|
+
try:
|
|
115
|
+
return handler(args)
|
|
116
|
+
except ConnectionError as nce:
|
|
117
|
+
if args.verbose:
|
|
118
|
+
msg = str(nce)
|
|
119
|
+
else:
|
|
120
|
+
msg = "Could not connect to server."
|
|
121
|
+
print(msg, file=sys.stderr)
|
|
122
|
+
return 1
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
args = get_args()
|
|
127
|
+
main(args)
|
|
@@ -5,14 +5,16 @@ from variantgrid_api import __version__
|
|
|
5
5
|
setup(name='variantgrid_api',
|
|
6
6
|
version=__version__,
|
|
7
7
|
description='API to connect to VariantGrid',
|
|
8
|
-
url='https://
|
|
8
|
+
url='https://github.com/SACGF/vg_api',
|
|
9
9
|
author='David Lawrence',
|
|
10
10
|
author_email='davmlaw@gmail.com',
|
|
11
11
|
license='MIT License',
|
|
12
12
|
packages=['variantgrid_api'],
|
|
13
13
|
install_requires=[
|
|
14
|
-
'requests',
|
|
15
14
|
'configargparse',
|
|
15
|
+
'oauthlib',
|
|
16
|
+
'requests',
|
|
17
|
+
'requests_oauthlib',
|
|
16
18
|
],
|
|
17
19
|
scripts=['bin/vg_api',],
|
|
18
20
|
zip_safe=False)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import requests
|
|
5
|
+
from requests_oauthlib.oauth2_auth import OAuth2
|
|
6
|
+
from requests_oauthlib.oauth2_session import OAuth2Session
|
|
7
|
+
from oauthlib.oauth2 import LegacyApplicationClient
|
|
8
|
+
|
|
9
|
+
class VariantGridAPI(object):
|
|
10
|
+
def __init__(self,
|
|
11
|
+
user = None,
|
|
12
|
+
password = None,
|
|
13
|
+
host = 'https://shariant.org.au',
|
|
14
|
+
basic_auth = False,
|
|
15
|
+
oauth_url = 'https://shariant.org.au/auth/realms/agha/protocol/openid-connect/token',
|
|
16
|
+
client_id = 'shariant-client-tools',
|
|
17
|
+
verbose=False):
|
|
18
|
+
|
|
19
|
+
if user and password and basic_auth:
|
|
20
|
+
self.auth = (user, password)
|
|
21
|
+
elif user and password and oauth_url and client_id:
|
|
22
|
+
oauth = OAuth2Session(client=LegacyApplicationClient(client_id=client_id))
|
|
23
|
+
if verbose:
|
|
24
|
+
print(user)
|
|
25
|
+
print(password)
|
|
26
|
+
print(client_id)
|
|
27
|
+
print(oauth_url)
|
|
28
|
+
token = oauth.fetch_token(token_url=oauth_url, username=user, password=password, client_id=client_id)
|
|
29
|
+
self.auth = OAuth2(client_id = client_id, token = token)
|
|
30
|
+
else:
|
|
31
|
+
self.auth = None
|
|
32
|
+
self.host = host
|
|
33
|
+
self.verbose = verbose
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def from_args(args):
|
|
37
|
+
return VariantGridAPI(user = args.user,
|
|
38
|
+
password = args.password,
|
|
39
|
+
host = args.host,
|
|
40
|
+
basic_auth = args.basic_auth,
|
|
41
|
+
oauth_url = args.oauth_url,
|
|
42
|
+
client_id = args.client_id,
|
|
43
|
+
verbose = args.verbose)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def url(self):
|
|
48
|
+
u = "%s" % self.host
|
|
49
|
+
return u
|
|
50
|
+
|
|
51
|
+
def get(self, path, extension = '.json'):
|
|
52
|
+
# extension defaults to .json for variantgrid methods that expect it
|
|
53
|
+
# maybe should add .json to the end of shariant methods for consistancy?
|
|
54
|
+
url_path = os.path.join(self.url, path) + extension
|
|
55
|
+
r = requests.get(url_path, auth=self.auth)
|
|
56
|
+
r.raise_for_status()
|
|
57
|
+
try:
|
|
58
|
+
return json.loads(r.text)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
logging.error("Couldn't decode: %s" % r.text)
|
|
61
|
+
logging.error(e)
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
def _send(self, path, method, data):
|
|
65
|
+
url_path = os.path.join(self.url, path)
|
|
66
|
+
r = None
|
|
67
|
+
if data is not None:
|
|
68
|
+
data = json.loads(data)
|
|
69
|
+
|
|
70
|
+
if method == 'POST':
|
|
71
|
+
r = requests.post(url_path, auth=self.auth, data=data)
|
|
72
|
+
elif method == 'PUT':
|
|
73
|
+
r = requests.put(url_path, auth=self.auth, data=data)
|
|
74
|
+
elif method == 'PATCH':
|
|
75
|
+
r = requests.patch(url_path, auth=self.auth, data=data)
|
|
76
|
+
elif method == 'DELETE':
|
|
77
|
+
r = requests.put(url_path, auth=self.auth, data=data)
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError('Unsupported method ' + str(method))
|
|
80
|
+
|
|
81
|
+
r.raise_for_status()
|
|
82
|
+
try:
|
|
83
|
+
return json.loads(r.text)
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logging.error("Couldn't decode: %s" % r.text)
|
|
86
|
+
logging.error(e)
|
|
87
|
+
raise e
|
|
88
|
+
|
|
89
|
+
def put(self, path, data):
|
|
90
|
+
return self._send(path, 'PUT', data)
|
|
91
|
+
|
|
92
|
+
def patch(self, path, data):
|
|
93
|
+
return self._send(path, 'PATCH', data)
|
|
94
|
+
|
|
95
|
+
def post(self, path, data):
|
|
96
|
+
return self._send(path, 'POST', data)
|
|
97
|
+
|
|
98
|
+
def delete(self, path, data):
|
|
99
|
+
return self._send(path, 'PUT', data)
|
|
100
|
+
|
|
101
|
+
# shariant stuff below
|
|
102
|
+
|
|
103
|
+
def shariant_classification_all(self):
|
|
104
|
+
'''
|
|
105
|
+
Retrieves a list of shariant classifications the user has access to, will just provide ids
|
|
106
|
+
'''
|
|
107
|
+
return self.get('variantclassification/api/shariant/classification', extension = '')
|
|
108
|
+
|
|
109
|
+
def shariant_classification(self, record_id, version = None):
|
|
110
|
+
'''
|
|
111
|
+
Retrieves a shariant classification
|
|
112
|
+
@param record_id either number that match internal id or previously posted lab id prefixed with 'L_'
|
|
113
|
+
@param version optional, load the classification at this version (or latest if None)
|
|
114
|
+
'''
|
|
115
|
+
if version is None:
|
|
116
|
+
return self.get('variantclassification/api/shariant/classification/' + str(record_id), extension = '')
|
|
117
|
+
else:
|
|
118
|
+
return self.get('variantclassification/api/shariant/classification/' + str(record_id) + '?version=' + str(version), extension = '')
|
|
119
|
+
|
|
120
|
+
def shariant_classification_modify(self, record_id = None, method = 'POST', change = {}):
|
|
121
|
+
'''
|
|
122
|
+
Lets you update or create a shariant classification.
|
|
123
|
+
If POST, record_id can be left blank or to use an internal code prefix any string with 'L_'
|
|
124
|
+
If PATCH or PUT record_id can be it's internal id number or a previously used lab id prefixed with 'L_'
|
|
125
|
+
'''
|
|
126
|
+
#FIXME escape record_id in case it has a slash in it
|
|
127
|
+
return self._send('variantclassification/api/shariant/classification/' + str(record_id) + '?overwrite=true', method, change)
|
|
128
|
+
|
|
129
|
+
def shariant_keys(self):
|
|
130
|
+
'''
|
|
131
|
+
Returns all the currently registered key values for classification evidence and meta data about them.
|
|
132
|
+
'''
|
|
133
|
+
return self.get('variantclassification/api/shariant/keys', extension = '')
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# variant grid stuff below
|
|
137
|
+
|
|
138
|
+
def loci_variants(self, variant_string):
|
|
139
|
+
''' returns a list of variant objects for this loci '''
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
def gene_annotation(self, ensembl_gene__id, version=None):
|
|
143
|
+
return self.get('annotation/api/gene_id/%(ensembl_gene__id)s' % {'ensembl_gene__id' : ensembl_gene__id})
|
|
144
|
+
|
|
145
|
+
def gene_annotations(self, gene_symbol, version=None):
|
|
146
|
+
''' This may return multiple annotations for multiple genes '''
|
|
147
|
+
return self.get('annotation/api/gene/%(gene_symbol)s' % {'gene_symbol' : gene_symbol})
|
|
148
|
+
|
|
149
|
+
def variant_annotation(self, variant_string, version=None):
|
|
150
|
+
''' variant_string can be ID, rsId, HGVS '''
|
|
151
|
+
return self.get('annotation/api/variant/%(variant_string)s' % {'variant_string' : variant_string})
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def get_gene_list_genes(self, pk=None, category=None, name=None, version=None):
|
|
155
|
+
''' Use either PK or both (category, name) '''
|
|
156
|
+
too_many = pk and any([category, name])
|
|
157
|
+
too_few = pk is None and not all([category, name])
|
|
158
|
+
if too_many or too_few:
|
|
159
|
+
msg = "You need to supply either 'pk' OR both ('category' AND 'name') arguments"
|
|
160
|
+
raise ValueError(msg)
|
|
161
|
+
|
|
162
|
+
if pk:
|
|
163
|
+
gene_list = self.get('snpdb/gene_list/%s' % pk)
|
|
164
|
+
else:
|
|
165
|
+
gene_list = self.get('snpdb/named_gene_list/%s/%s' % (category, name))
|
|
166
|
+
return gene_list["genelistgene_set"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from variantgrid_api.api import VariantGridAPI
|
|
5
|
+
|
|
6
|
+
def get_classifications(args):
|
|
7
|
+
api = VariantGridAPI.from_args(args)
|
|
8
|
+
|
|
9
|
+
if args.keys:
|
|
10
|
+
return api.shariant_keys()
|
|
11
|
+
elif args.id:
|
|
12
|
+
return api.shariant_classification(args.id, args.version)
|
|
13
|
+
if args.all:
|
|
14
|
+
return api.shariant_classification_all()
|
|
15
|
+
|
|
16
|
+
def shariant_classifications_handle_args(args):
|
|
17
|
+
classifications = get_classifications(args)
|
|
18
|
+
print(json.dumps(classifications))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from variantgrid_api.api import VariantGridAPI
|
|
6
|
+
|
|
7
|
+
def modify_classifications(args):
|
|
8
|
+
api = VariantGridAPI.from_args(args)
|
|
9
|
+
upload = sys.stdin.read() or {}
|
|
10
|
+
return api.shariant_classification_modify(args.id, args.method, upload)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def shariant_classifications_modify_handle_args(args):
|
|
14
|
+
classifications = modify_classifications(args)
|
|
15
|
+
print(json.dumps(classifications))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 1.0
|
|
2
2
|
Name: variantgrid-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: API to connect to VariantGrid
|
|
5
|
-
Home-page: https://
|
|
5
|
+
Home-page: https://github.com/SACGF/vg_api
|
|
6
6
|
Author: David Lawrence
|
|
7
7
|
Author-email: davmlaw@gmail.com
|
|
8
8
|
License: MIT License
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
README.md
|
|
1
2
|
setup.py
|
|
2
3
|
bin/vg_api
|
|
3
4
|
variantgrid_api/__init__.py
|
|
@@ -6,6 +7,8 @@ variantgrid_api/annotation.py
|
|
|
6
7
|
variantgrid_api/api.py
|
|
7
8
|
variantgrid_api/classifications.py
|
|
8
9
|
variantgrid_api/gene_list.py
|
|
10
|
+
variantgrid_api/shariant_classification.py
|
|
11
|
+
variantgrid_api/shariant_classification_modify.py
|
|
9
12
|
variantgrid_api/variant_classification_vcf.py
|
|
10
13
|
variantgrid_api/vcf_utils.py
|
|
11
14
|
variantgrid_api.egg-info/PKG-INFO
|
variantgrid_api-0.1.5/bin/vg_api
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
|
|
3
|
-
from __future__ import print_function
|
|
4
|
-
|
|
5
|
-
from configargparse import Action, ArgParser
|
|
6
|
-
from requests.exceptions import ConnectionError
|
|
7
|
-
import sys
|
|
8
|
-
|
|
9
|
-
from variantgrid_api.add_classification import add_classification_handle_args
|
|
10
|
-
from variantgrid_api.annotation import annotation_handle_args
|
|
11
|
-
from variantgrid_api.classifications import classifications_handle_args
|
|
12
|
-
from variantgrid_api.gene_list import gene_list_handle_args
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ClassificationAction(Action):
|
|
16
|
-
VALID_CLASSIFICATIONS = range(1, 6)
|
|
17
|
-
def __call__(self, parser, namespace, values, option_string=None):
|
|
18
|
-
if values not in self.VALID_CLASSIFICATIONS:
|
|
19
|
-
valid_classifications_str = ','.join(map(str, self.VALID_CLASSIFICATIONS))
|
|
20
|
-
raise ValueError("classification must be one of %s" % valid_classifications_str)
|
|
21
|
-
setattr(namespace, self.dest, values)
|
|
22
|
-
|
|
23
|
-
def add_authentication(parser, required):
|
|
24
|
-
parser.add("--login", required=required, env_var='VG_LOGIN')
|
|
25
|
-
parser.add("--password", required=required, env_var='VG_PASSWORD')
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def get_args():
|
|
29
|
-
CLASSIFICATION_HELP = 'HGNC classifications: 1 - Benign, 2 - Likely benign, 3 - VUS, 4 - Likely Pathogenic, 5 - Pathogenic'
|
|
30
|
-
|
|
31
|
-
parser = ArgParser(default_config_files=['~/.vg_api'])
|
|
32
|
-
parser.add('-c', '--config', is_config_file=True, help='config file path')
|
|
33
|
-
|
|
34
|
-
# Global settings
|
|
35
|
-
parser.add("--host", default='https://variantgrid.com', env_var='VG_HOST', help='Server Address (default=https://variantgrid.com)')
|
|
36
|
-
parser.add("--port", type=int, env_var='VG_PORT', help='Server port')
|
|
37
|
-
parser.add("--verbose", default=False, action='store_true', env_var='VG_VERBOSE', help='Print debugging information')
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
subparsers = parser.add_subparsers(help='sub-command help', dest='command')
|
|
41
|
-
|
|
42
|
-
# Add Classification
|
|
43
|
-
add_classification_parser = subparsers.add_parser('add_classification', help='Add new classification for a variant')
|
|
44
|
-
add_authentication(add_classification_parser, required=True)
|
|
45
|
-
variant_group = add_classification_parser.add_mutually_exclusive_group(required=True)
|
|
46
|
-
variant_group.add_argument('--variant', help='hg19 coordinate eg "1:169519049 T>C"')
|
|
47
|
-
variant_group.add_argument('--dbsnp', help='dbSNP rsId eg "rs6025"')
|
|
48
|
-
variant_group.add_argument('--hgvs', help='HGVS string eg "F5 (NM_000130) p.Gln534Arg/c.1601A>G"')
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
add_classification_parser.add_argument('--classification', type=int, action=ClassificationAction, help=CLASSIFICATION_HELP)
|
|
52
|
-
add_classification_parser.add_argument('--public', action='store_true', default=False, help="Classification is public (default=False)")
|
|
53
|
-
|
|
54
|
-
# Classifications
|
|
55
|
-
classifications_parser = subparsers.add_parser('classifications', help='Get classification from VariantGrid')
|
|
56
|
-
add_authentication(classifications_parser, required=False)
|
|
57
|
-
classifications_parser.add_argument("--classification", type=int, action=ClassificationAction)
|
|
58
|
-
|
|
59
|
-
group = classifications_parser.add_mutually_exclusive_group(required=True)
|
|
60
|
-
group.add_argument("--all", action='store_true')
|
|
61
|
-
group.add_argument("--dbsnp")
|
|
62
|
-
group.add_argument("--gene")
|
|
63
|
-
group.add_argument("--locus")
|
|
64
|
-
group.add_argument("--variant")
|
|
65
|
-
|
|
66
|
-
# Annotation
|
|
67
|
-
annotation_parser = subparsers.add_parser('annotation', help='Get VariantGrid Annotations')
|
|
68
|
-
|
|
69
|
-
group = annotation_parser.add_mutually_exclusive_group(required=True)
|
|
70
|
-
group.add_argument("--gene-id")
|
|
71
|
-
group.add_argument("--gene")
|
|
72
|
-
group.add_argument("--variant")
|
|
73
|
-
# TODO: Annotation Versions??
|
|
74
|
-
|
|
75
|
-
# Gene List
|
|
76
|
-
gene_list_parser = subparsers.add_parser('gene_list', help='Get Gene List')
|
|
77
|
-
add_authentication(gene_list_parser, required=False)
|
|
78
|
-
gene_list_parser.add_argument("--category", default='Uploaded', help="One of 'Diagnostic', 'Uploaded'")
|
|
79
|
-
group = gene_list_parser.add_mutually_exclusive_group(required=True)
|
|
80
|
-
group.add_argument("--pk")
|
|
81
|
-
group.add_argument("--name")
|
|
82
|
-
|
|
83
|
-
return parser.parse_args()
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def main(args):
|
|
87
|
-
SUBCOMMAND_HANDLERS = {
|
|
88
|
-
"annotation" : annotation_handle_args,
|
|
89
|
-
"add_classification" : add_classification_handle_args,
|
|
90
|
-
"classifications" : classifications_handle_args,
|
|
91
|
-
"gene_list" : gene_list_handle_args,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
handler = SUBCOMMAND_HANDLERS[args.command]
|
|
95
|
-
try:
|
|
96
|
-
return handler(args)
|
|
97
|
-
except ConnectionError as nce:
|
|
98
|
-
if args.verbose:
|
|
99
|
-
msg = str(nce)
|
|
100
|
-
else:
|
|
101
|
-
msg = "Could not connect to server."
|
|
102
|
-
print(msg, file=sys.stderr)
|
|
103
|
-
return 1
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if __name__ == "__main__":
|
|
107
|
-
args = get_args()
|
|
108
|
-
main(args)
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
import requests
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class VariantGridAPI(object):
|
|
8
|
-
def __init__(self, login=None, password=None, host='https://variantgrid.com', port=None):
|
|
9
|
-
if login and password:
|
|
10
|
-
self.auth = (login, password)
|
|
11
|
-
else:
|
|
12
|
-
self.auth = None
|
|
13
|
-
self.host = host
|
|
14
|
-
self.port = port
|
|
15
|
-
|
|
16
|
-
@staticmethod
|
|
17
|
-
def from_args(args):
|
|
18
|
-
return VariantGridAPI(args.login,
|
|
19
|
-
args.password,
|
|
20
|
-
host=args.host,
|
|
21
|
-
port=args.port)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def url(self):
|
|
26
|
-
u = "%s" % self.host
|
|
27
|
-
if self.port:
|
|
28
|
-
u += ":%d" % self.port
|
|
29
|
-
return u
|
|
30
|
-
|
|
31
|
-
def get(self, path):
|
|
32
|
-
url_path = os.path.join(self.url, path) + ".json"
|
|
33
|
-
r = requests.get(url_path, auth=self.auth)
|
|
34
|
-
r.raise_for_status()
|
|
35
|
-
try:
|
|
36
|
-
return json.loads(r.text)
|
|
37
|
-
except Exception as e:
|
|
38
|
-
logging.error("Couldn't decode: %s" % r.text)
|
|
39
|
-
logging.error(e)
|
|
40
|
-
return None
|
|
41
|
-
|
|
42
|
-
def loci_variants(self, variant_string):
|
|
43
|
-
''' returns a list of variant objects for this loci '''
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
|
-
def gene_annotation(self, ensembl_gene__id, version=None):
|
|
47
|
-
return self.get('annotation/api/gene_id/%(ensembl_gene__id)s' % {'ensembl_gene__id' : ensembl_gene__id})
|
|
48
|
-
|
|
49
|
-
def gene_annotations(self, gene_symbol, version=None):
|
|
50
|
-
''' This may return multiple annotations for multiple genes '''
|
|
51
|
-
return self.get('annotation/api/gene/%(gene_symbol)s' % {'gene_symbol' : gene_symbol})
|
|
52
|
-
|
|
53
|
-
def variant_annotation(self, variant_string, version=None):
|
|
54
|
-
''' variant_string can be ID, rsId, HGVS '''
|
|
55
|
-
return self.get('annotation/api/variant/%(variant_string)s' % {'variant_string' : variant_string})
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def get_gene_list_genes(self, pk=None, category=None, name=None, version=None):
|
|
59
|
-
''' Use either PK or both (category, name) '''
|
|
60
|
-
too_many = pk and any([category, name])
|
|
61
|
-
too_few = pk is None and not all([category, name])
|
|
62
|
-
if too_many or too_few:
|
|
63
|
-
msg = "You need to supply either 'pk' OR both ('category' AND 'name') arguments"
|
|
64
|
-
raise ValueError(msg)
|
|
65
|
-
|
|
66
|
-
if pk:
|
|
67
|
-
gene_list = self.get('snpdb/gene_list/%s' % pk)
|
|
68
|
-
else:
|
|
69
|
-
gene_list = self.get('snpdb/named_gene_list/%s/%s' % (category, name))
|
|
70
|
-
return gene_list["genelistgene_set"]
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _get_classification_json(self, url, classification=None):
|
|
74
|
-
''' so we can modify to stream JSON '''
|
|
75
|
-
|
|
76
|
-
if classification:
|
|
77
|
-
url = os.path.join(url, "classification", str(classification))
|
|
78
|
-
return self.get(url)
|
|
79
|
-
|
|
80
|
-
def variant_classifications_all(self, classification=None):
|
|
81
|
-
return self._get_classification_json('variantclassification/api/classifications/all', classification)
|
|
82
|
-
|
|
83
|
-
def variant_classifications_for_gene(self, gene_symbol, classification=None):
|
|
84
|
-
url = 'variantclassification/api/classifications/gene/%(gene_symbol)s' % {'gene_symbol' : gene_symbol}
|
|
85
|
-
return self._get_classification_json(url, classification)
|
|
86
|
-
|
|
87
|
-
def variant_classifications_for_dbsnp(self, dbsnp, classification=None):
|
|
88
|
-
url = 'variantclassification/api/classifications/dbsnp/%(dbsnp)s' % {'dbsnp' : dbsnp}
|
|
89
|
-
return self._get_classification_json(url, classification)
|
|
90
|
-
|
|
91
|
-
def variant_classifications_for_locus(self, locus_string, classification=None):
|
|
92
|
-
url = 'variantclassification/api/classifications/locus/%(locus_string)s' % {'locus_string' : locus_string}
|
|
93
|
-
return self._get_classification_json(url, classification)
|
|
94
|
-
|
|
95
|
-
def variant_classifications_for_variant(self, variant_string, classification=None):
|
|
96
|
-
url = 'variantclassification/classifications/api/variant/%(variant_string)s' % {'variant_string' : variant_string}
|
|
97
|
-
return self._get_classification_json(url, classification)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def _add_classification_json(self, path, classification, dbsnp=None, variant=None, public=False):
|
|
101
|
-
url_path = os.path.join(self.url, path) + ".json"
|
|
102
|
-
data = {"classification" : classification,
|
|
103
|
-
"public" : public}
|
|
104
|
-
if dbsnp:
|
|
105
|
-
data["dbsnp_string"] = dbsnp
|
|
106
|
-
elif variant:
|
|
107
|
-
data["variant_string"] = variant
|
|
108
|
-
else:
|
|
109
|
-
msg = "Need to specify either 'dbsnp' or 'variant'"
|
|
110
|
-
raise ValueError(msg)
|
|
111
|
-
|
|
112
|
-
r = requests.post(url_path, auth=self.auth, json=data)
|
|
113
|
-
r.raise_for_status()
|
|
114
|
-
return json.loads(r.text)
|
|
115
|
-
|
|
116
|
-
def add_classifications_for_dbsnp(self, dbsnp, classification, public):
|
|
117
|
-
url = 'variantclassification/api/add_classification'
|
|
118
|
-
return self._add_classification_json(url, classification, dbsnp=dbsnp, public=public)
|
|
119
|
-
|
|
120
|
-
def add_classifications_for_variant(self, variant_string, classification, public):
|
|
121
|
-
url = 'variantclassification/api/add_classification'
|
|
122
|
-
return self._add_classification_json(url, classification, variant=variant_string, public=public)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def create_variant_classification(self, variant_string, classification):
|
|
127
|
-
# Check whether the variant string is correct - get back
|
|
128
|
-
# Send up classification
|
|
129
|
-
# Get back ID and return it
|
|
130
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api/variant_classification_vcf.py
RENAMED
|
File without changes
|
|
File without changes
|
{variantgrid_api-0.1.5 → variantgrid_api-0.2.0}/variantgrid_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|