NGPIris 4.2.0__tar.gz → 5.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.

Potentially problematic release.


This version of NGPIris might be problematic. Click here for more details.

Files changed (91) hide show
  1. ngpiris-5.0.0/NGPIris/__init__.py +2 -0
  2. ngpiris-5.0.0/NGPIris/cli/__init__.py +230 -0
  3. ngpiris-5.0.0/NGPIris/hci/__init__.py +1 -0
  4. ngpiris-5.0.0/NGPIris/hci/exceptions.py +3 -0
  5. ngpiris-5.0.0/NGPIris/hci/hci.py +132 -0
  6. ngpiris-5.0.0/NGPIris/hci/helpers.py +98 -0
  7. ngpiris-5.0.0/NGPIris/hcp/__init__.py +1 -0
  8. ngpiris-5.0.0/NGPIris/hcp/exceptions.py +8 -0
  9. ngpiris-5.0.0/NGPIris/hcp/hcp.py +540 -0
  10. ngpiris-5.0.0/NGPIris/hcp/helpers.py +39 -0
  11. ngpiris-5.0.0/NGPIris/hcp/statistics.py +25 -0
  12. ngpiris-5.0.0/NGPIris/parse_credentials/__init__.py +3 -0
  13. ngpiris-5.0.0/NGPIris/parse_credentials/parse_credentials.py +58 -0
  14. ngpiris-5.0.0/NGPIris/utils/__init__.py +1 -0
  15. ngpiris-5.0.0/NGPIris/utils/utils.py +9 -0
  16. ngpiris-5.0.0/NGPIris.egg-info/PKG-INFO +288 -0
  17. ngpiris-5.0.0/NGPIris.egg-info/SOURCES.txt +52 -0
  18. ngpiris-5.0.0/NGPIris.egg-info/entry_points.txt +3 -0
  19. ngpiris-5.0.0/NGPIris.egg-info/requires.txt +7 -0
  20. {NGPIris-4.2.0 → ngpiris-5.0.0}/NGPIris.egg-info/top_level.txt +0 -1
  21. ngpiris-5.0.0/PKG-INFO +288 -0
  22. ngpiris-5.0.0/README.md +274 -0
  23. ngpiris-5.0.0/docs/IRIS_5_changelog.md +43 -0
  24. ngpiris-5.0.0/docs/Makefile +20 -0
  25. ngpiris-5.0.0/docs/NGPIris.cli.rst +10 -0
  26. ngpiris-5.0.0/docs/NGPIris.hci.rst +37 -0
  27. ngpiris-5.0.0/docs/NGPIris.hcp.rst +45 -0
  28. ngpiris-5.0.0/docs/NGPIris.parse_credentials.rst +21 -0
  29. ngpiris-5.0.0/docs/NGPIris.rst +22 -0
  30. ngpiris-5.0.0/docs/NGPIris.utils.rst +21 -0
  31. ngpiris-5.0.0/docs/Tutorial.md +326 -0
  32. ngpiris-5.0.0/docs/conf.py +45 -0
  33. ngpiris-5.0.0/docs/index.rst +21 -0
  34. ngpiris-5.0.0/docs/make.bat +35 -0
  35. ngpiris-5.0.0/docs/modules.rst +7 -0
  36. ngpiris-5.0.0/pyproject.toml +36 -0
  37. ngpiris-5.0.0/setup.cfg +4 -0
  38. ngpiris-5.0.0/tests/data/80MB_test_file +0 -0
  39. ngpiris-5.0.0/tests/data/a folder of data/80MB_test_file_0 +0 -0
  40. ngpiris-5.0.0/tests/data/a folder of data/80MB_test_file_1 +0 -0
  41. ngpiris-5.0.0/tests/data/complete_creds_0.json +14 -0
  42. ngpiris-5.0.0/tests/data/complete_creds_1.json +14 -0
  43. ngpiris-5.0.0/tests/data/complete_creds_2.json +14 -0
  44. ngpiris-5.0.0/tests/data/incomplete_creds_0.json +14 -0
  45. ngpiris-5.0.0/tests/data/incomplete_creds_1.json +14 -0
  46. ngpiris-5.0.0/tests/data/incomplete_creds_2.json +14 -0
  47. ngpiris-5.0.0/tests/data/incomplete_creds_3.json +14 -0
  48. ngpiris-5.0.0/tests/data/incomplete_creds_4.json +14 -0
  49. ngpiris-5.0.0/tests/test_hci.py +68 -0
  50. ngpiris-5.0.0/tests/test_hcp.py +212 -0
  51. ngpiris-5.0.0/tests/test_parse_credentials.py +38 -0
  52. NGPIris-4.2.0/NGPIris/__init__.py +0 -22
  53. NGPIris-4.2.0/NGPIris/cli/__init__.py +0 -0
  54. NGPIris-4.2.0/NGPIris/cli/base.py +0 -61
  55. NGPIris-4.2.0/NGPIris/cli/functions.py +0 -141
  56. NGPIris-4.2.0/NGPIris/cli/utils.py +0 -62
  57. NGPIris-4.2.0/NGPIris/hci/__init__.py +0 -1
  58. NGPIris-4.2.0/NGPIris/hci/hci.py +0 -85
  59. NGPIris-4.2.0/NGPIris/hci/template_query.json +0 -16
  60. NGPIris-4.2.0/NGPIris/hcp/__init__.py +0 -1
  61. NGPIris-4.2.0/NGPIris/hcp/config.py +0 -20
  62. NGPIris-4.2.0/NGPIris/hcp/errors.py +0 -26
  63. NGPIris-4.2.0/NGPIris/hcp/hcp.py +0 -293
  64. NGPIris-4.2.0/NGPIris/hcp/helpers.py +0 -39
  65. NGPIris-4.2.0/NGPIris/hcp/interactive.py +0 -124
  66. NGPIris-4.2.0/NGPIris/preproc/__init__.py +0 -0
  67. NGPIris-4.2.0/NGPIris/preproc/preproc.py +0 -147
  68. NGPIris-4.2.0/NGPIris.egg-info/PKG-INFO +0 -137
  69. NGPIris-4.2.0/NGPIris.egg-info/SOURCES.txt +0 -40
  70. NGPIris-4.2.0/NGPIris.egg-info/entry_points.txt +0 -2
  71. NGPIris-4.2.0/NGPIris.egg-info/not-zip-safe +0 -1
  72. NGPIris-4.2.0/NGPIris.egg-info/requires.txt +0 -3
  73. NGPIris-4.2.0/PKG-INFO +0 -137
  74. NGPIris-4.2.0/README.md +0 -122
  75. NGPIris-4.2.0/config.ini +0 -5
  76. NGPIris-4.2.0/docs/package.md +0 -77
  77. NGPIris-4.2.0/pyproject.toml +0 -10
  78. NGPIris-4.2.0/reference/covidMetadataAllowedValues.csv +0 -32
  79. NGPIris-4.2.0/reference/covidMetadataTemplate.csv +0 -3
  80. NGPIris-4.2.0/requirements.txt +0 -3
  81. NGPIris-4.2.0/setup.cfg +0 -20
  82. NGPIris-4.2.0/setup.py +0 -23
  83. NGPIris-4.2.0/tests/__init__.py +0 -0
  84. NGPIris-4.2.0/tests/data/test.json +0 -7
  85. NGPIris-4.2.0/tests/data/test_reads_R1.fasterq +0 -0
  86. NGPIris-4.2.0/tests/data/test_reads_R1.fastq.gz +0 -0
  87. NGPIris-4.2.0/tests/test_cmds.py +0 -106
  88. NGPIris-4.2.0/tests/test_hcp.py +0 -58
  89. {NGPIris-4.2.0 → ngpiris-5.0.0}/LICENSE +0 -0
  90. {NGPIris-4.2.0 → ngpiris-5.0.0}/MANIFEST.in +0 -0
  91. {NGPIris-4.2.0 → ngpiris-5.0.0}/NGPIris.egg-info/dependency_links.txt +0 -0
@@ -0,0 +1,2 @@
1
+ from NGPIris.hci import HCIHandler
2
+ from NGPIris.hcp import HCPHandler
@@ -0,0 +1,230 @@
1
+
2
+ import click
3
+ from click.core import Context
4
+ from json import dumps, dump
5
+ from pathlib import Path
6
+
7
+ from NGPIris.hcp import HCPHandler
8
+
9
+ def get_HCPHandler(context : Context)-> HCPHandler:
10
+ return context.obj["hcph"]
11
+
12
+ def format_list(list_of_things : list) -> str:
13
+ list_of_buckets = list(map(lambda s : s + "\n", list_of_things))
14
+ return "".join(list_of_buckets).strip("\n")
15
+
16
+ @click.group()
17
+ @click.argument("credentials")
18
+ @click.version_option(package_name = "NGPIris")
19
+ @click.pass_context
20
+ def cli(context : Context, credentials : str):
21
+ """
22
+ NGP Intelligence and Repository Interface Software, IRIS.
23
+
24
+ CREDENTIALS refers to the path to the JSON credentials file.
25
+ """
26
+ context.ensure_object(dict)
27
+ context.obj["hcph"] = HCPHandler(credentials)
28
+
29
+ @cli.command()
30
+ @click.argument("bucket")
31
+ @click.argument("file-or-folder")
32
+ @click.pass_context
33
+ def upload(context : Context, bucket : str, file_or_folder : str):
34
+ """
35
+ Upload files to an HCP bucket/namespace.
36
+
37
+ BUCKET is the name of the upload destination bucket.
38
+
39
+ FILE-OR-FOLDER is the path to the file or folder of files to be uploaded.
40
+ """
41
+ hcph : HCPHandler = get_HCPHandler(context)
42
+ hcph.mount_bucket(bucket)
43
+ if Path(file_or_folder).is_dir():
44
+ hcph.upload_folder(file_or_folder)
45
+ else:
46
+ hcph.upload_file(file_or_folder)
47
+
48
+ @cli.command()
49
+ @click.argument("bucket")
50
+ @click.argument("object_path")
51
+ @click.argument("local_path")
52
+ @click.option(
53
+ "-f",
54
+ "--force",
55
+ help = "Overwrite existing file with the same name",
56
+ is_flag = True
57
+ )
58
+ @click.pass_context
59
+ def download(context : Context, bucket : str, object_path : str, local_path : str, force : bool):
60
+ """
61
+ Download a file from an HCP bucket/namespace.
62
+
63
+ BUCKET is the name of the upload destination bucket.
64
+
65
+ OBJECT_PATH is the path to the object to be downloaded.
66
+
67
+ LOCAL_PATH is the folder where the downloaded object is to be stored locally.
68
+ """
69
+ if not Path(local_path).exists():
70
+ Path(local_path).mkdir()
71
+ downloaded_object_path = Path(local_path) / Path(object_path).name
72
+ if downloaded_object_path.exists() and not force:
73
+ exit("Object already exists. If you wish to overwrite the existing file, use the -f, --force option")
74
+ hcph : HCPHandler = get_HCPHandler(context)
75
+ hcph.mount_bucket(bucket)
76
+ hcph.download_file(object_path, downloaded_object_path.as_posix())
77
+
78
+ @cli.command()
79
+ @click.argument("bucket")
80
+ @click.argument("object")
81
+ @click.pass_context
82
+ def delete_object(context : Context, bucket : str, object : str):
83
+ """
84
+ Delete an object from an HCP bucket/namespace.
85
+
86
+ BUCKET is the name of the bucket where the object to be deleted exist.
87
+
88
+ OBJECT is the name of the object to be deleted.
89
+ """
90
+ hcph : HCPHandler = get_HCPHandler(context)
91
+ hcph.mount_bucket(bucket)
92
+ hcph.delete_object(object)
93
+
94
+ @cli.command()
95
+ @click.argument("bucket")
96
+ @click.argument("folder")
97
+ @click.pass_context
98
+ def delete_folder(context : Context, bucket : str, folder : str):
99
+ """
100
+ Delete a folder from an HCP bucket/namespace.
101
+
102
+ BUCKET is the name of the bucket where the folder to be deleted exist.
103
+
104
+ FOLDER is the name of the folder to be deleted.
105
+ """
106
+ hcph : HCPHandler = get_HCPHandler(context)
107
+ hcph.mount_bucket(bucket)
108
+ hcph.delete_folder(folder)
109
+
110
+ @cli.command()
111
+ @click.pass_context
112
+ def list_buckets(context : Context):
113
+ """
114
+ List the available buckets/namespaces on the HCP.
115
+ """
116
+ hcph : HCPHandler = get_HCPHandler(context)
117
+ click.echo(format_list(hcph.list_buckets()))
118
+
119
+ @cli.command()
120
+ @click.argument("bucket")
121
+ @click.option(
122
+ "-no",
123
+ "--name-only",
124
+ help = "Output only the name of the objects instead of all the associated metadata",
125
+ default = False
126
+ )
127
+ @click.pass_context
128
+ def list_objects(context : Context, bucket : str, name_only : bool):
129
+ """
130
+ List the objects in a certain bucket/namespace on the HCP.
131
+
132
+ BUCKET is the name of the bucket in which to list its objects.
133
+ """
134
+ hcph : HCPHandler = get_HCPHandler(context)
135
+ hcph.mount_bucket(bucket)
136
+ objects_list = hcph.list_objects(name_only)
137
+ if name_only:
138
+ click.echo(format_list(objects_list))
139
+ else:
140
+ out = []
141
+ for d in objects_list:
142
+ out.append(dumps(d, indent = 4, default = str) + "\n")
143
+ click.echo("".join(out))
144
+
145
+ @cli.command()
146
+ @click.argument("bucket")
147
+ @click.argument("search_string")
148
+ @click.option(
149
+ "-cs",
150
+ "--case_sensitive",
151
+ help = "Use case sensitivity? Default value is False",
152
+ default = False
153
+ )
154
+ @click.pass_context
155
+ def simple_search(context : Context, bucket : str, search_string : str, case_sensitive : bool):
156
+ """
157
+ Make simple search using substrings in a bucket/namespace on the HCP.
158
+
159
+ BUCKET is the name of the bucket in which to make the search.
160
+
161
+ SEARCH_STRING is any string that is to be used for the search.
162
+ """
163
+ hcph : HCPHandler = get_HCPHandler(context)
164
+ hcph.mount_bucket(bucket)
165
+ list_of_results = hcph.search_objects_in_bucket(search_string, case_sensitive)
166
+ click.echo("Search results:")
167
+ for result in list_of_results:
168
+ click.echo("- " + result)
169
+
170
+ @cli.command()
171
+ @click.argument("bucket")
172
+ @click.pass_context
173
+ def test_connection(context : Context, bucket : str):
174
+ """
175
+ Test the connection to a bucket/namespace.
176
+
177
+ BUCKET is the name of the bucket for which a connection test should be made.
178
+ """
179
+ hcph : HCPHandler = get_HCPHandler(context)
180
+ click.echo(hcph.test_connection(bucket))
181
+
182
+ @click.command()
183
+ @click.option(
184
+ "--path",
185
+ help = "Path for where to put the new credentials file.",
186
+ default = ""
187
+ )
188
+ @click.option(
189
+ "--name",
190
+ help = "Custom name for the credentials file. Will filter out everything after a \".\" character, if any exist.",
191
+ default = "credentials"
192
+ )
193
+ def iris_generate_credentials_file(path : str, name : str):
194
+ """
195
+ Generate blank credentials file for the HCI and HCP.
196
+
197
+ WARNING: This file will store sensitive information (such as passwords) in plaintext.
198
+ """
199
+ credentials_dict = {
200
+ "hcp" : {
201
+ "endpoint" : "",
202
+ "aws_access_key_id" : "",
203
+ "aws_secret_access_key" : ""
204
+ },
205
+ "hci" : {
206
+ "username" : "",
207
+ "password" : "",
208
+ "address" : "",
209
+ "auth_port" : "",
210
+ "api_port" : ""
211
+ }
212
+ }
213
+
214
+ name = name.split(".")[0] + ".json"
215
+
216
+ if not path[-1] == "/":
217
+ path += "/"
218
+
219
+ if path == ".":
220
+ file_path = name
221
+ else:
222
+ file_path = path + name
223
+
224
+ if not Path(path).is_dir():
225
+ Path(path).mkdir()
226
+
227
+ with open(file_path, "w") as f:
228
+ dump(credentials_dict, f, indent = 4)
229
+
230
+
@@ -0,0 +1 @@
1
+ from NGPIris.hci.hci import HCIHandler
@@ -0,0 +1,3 @@
1
+ class VPNConnectionError(Exception):
2
+ pass
3
+
@@ -0,0 +1,132 @@
1
+
2
+ from NGPIris.parse_credentials import CredentialsHandler
3
+ from NGPIris.hci.helpers import (
4
+ get_index_response,
5
+ get_query_response
6
+ )
7
+ from NGPIris.hci.exceptions import *
8
+
9
+ from requests import (
10
+ Response,
11
+ post
12
+ )
13
+ from urllib3 import disable_warnings
14
+ from json import load
15
+
16
+ class HCIHandler:
17
+ def __init__(self, credentials_path : str, use_ssl : bool = False) -> None:
18
+ """
19
+ Class for handling HCI requests.
20
+
21
+ :param credentials_path: Path to the JSON credentials file
22
+ :type credentials_path: str
23
+
24
+ :param use_ssl: Boolean choice between using SSL, defaults to False
25
+ :type use_ssl: bool, optional
26
+ """
27
+ credentials_handler = CredentialsHandler(credentials_path)
28
+ self.hci = credentials_handler.hci
29
+ self.username = self.hci["username"]
30
+ self.password = self.hci["password"]
31
+ self.address = self.hci["address"]
32
+ self.auth_port = self.hci["auth_port"]
33
+ self.api_port = self.hci["api_port"]
34
+ self.token = ""
35
+
36
+ self.use_ssl = use_ssl
37
+
38
+ if not self.use_ssl:
39
+ disable_warnings()
40
+
41
+ def request_token(self) -> None:
42
+ """
43
+ Request a token from the HCI, which is stored in the HCIHandler object.
44
+ The token is used for every operation that needs to send a request to
45
+ HCI.
46
+
47
+ :raises VPNConnectionError: If there was a problem when requesting a token, a runtime error will be raised
48
+ """
49
+ url = "https://" + self.address + ":" + self.auth_port + "/auth/oauth/"
50
+ data = {
51
+ "grant_type": "password",
52
+ "username": self.username,
53
+ "password": self.password,
54
+ "scope": "*",
55
+ "client_secret": "hci-client",
56
+ "client_id": "hci-client",
57
+ "realm": "LOCAL"
58
+ }
59
+ try:
60
+ response : Response = post(url, data = data, verify = self.use_ssl)
61
+ except: # pragma: no cover
62
+ error_msg : str = "The token request made at " + url + " failed. Please check your connection and that you have your VPN enabled"
63
+ raise VPNConnectionError(error_msg) from None
64
+
65
+ token : str = response.json()["access_token"]
66
+ self.token = token
67
+
68
+ def list_index_names(self) -> list[str]:
69
+ """
70
+ Retrieve a list of all index names.
71
+
72
+ :return: A list of index names
73
+ :rtype: list[str]
74
+ """
75
+ response : Response = get_index_response(self.address, self.api_port, self.token, self.use_ssl)
76
+ return [entry["name"]for entry in response.json()]
77
+
78
+ def look_up_index(self, index_name : str) -> dict:
79
+ """
80
+ Look up index information in the form of a dictionary by submitting
81
+ the index name. Will return an empty dictionary if no index was found.
82
+
83
+ :param index_name: The index name
84
+ :type index_name: str
85
+
86
+ :return: A dictionary containing information about an index
87
+ :rtype: dict
88
+ """
89
+ response : Response = get_index_response(self.address, self.api_port, self.token, self.use_ssl)
90
+
91
+ for entry in response.json():
92
+ if entry["name"] == index_name:
93
+ return dict(entry)
94
+
95
+ return {}
96
+
97
+ def raw_query(self, query_dict : dict[str, str]) -> dict:
98
+ """
99
+ Make query to an HCI index, with a dictionary
100
+
101
+ :param query_dict: Dictionary consisting of the query
102
+ :type query_dict: dict[str, str]
103
+
104
+ :return: Dictionary containing the raw query
105
+ :rtype: dict
106
+ """
107
+ return dict(get_query_response(
108
+ query_dict,
109
+ self.address,
110
+ self.api_port,
111
+ self.token,
112
+ self.use_ssl
113
+ ).json())
114
+
115
+ def raw_query_from_JSON(self, query_path : str) -> dict:
116
+ """
117
+ Make query to an HCI index, with prewritten query in a JSON file
118
+
119
+ :param query_path: Path to the JSON file
120
+ :type query_path: str
121
+
122
+ :return: Dictionary containing the raw query
123
+ :rtype: dict
124
+ """
125
+ with open(query_path, "r") as inp:
126
+ return dict(get_query_response(
127
+ dict(load(inp)),
128
+ self.address,
129
+ self.api_port,
130
+ self.token,
131
+ self.use_ssl
132
+ ).json())
@@ -0,0 +1,98 @@
1
+
2
+ from json import (
3
+ dumps
4
+ )
5
+ from requests import (
6
+ Response,
7
+ get,
8
+ post
9
+ )
10
+
11
+ def get_index_response(address : str, api_port : str, token : str, use_ssl : bool) -> Response:
12
+ """
13
+ Retrieve the index response given the address, API port and token.
14
+
15
+ :param address: The address where request is to be made
16
+ :type address: str
17
+
18
+ :param api_port: The API port at the given address
19
+ :type api_port: str
20
+
21
+ :param token: The HCI token
22
+ :type token: str
23
+
24
+ :param use_ssl: Boolean choice of using SSL
25
+ :type use_ssl: bool
26
+
27
+ :return: A response containing information about the index
28
+ :rtype: requests.Response
29
+ """
30
+ url : str = "https://" + address + ":" + api_port + "/api/search/indexes/"
31
+ headers : dict[str, str] = {
32
+ "Accept": "application/json",
33
+ "Authorization": "Bearer " + token
34
+ }
35
+
36
+ response : Response = get(
37
+ url,
38
+ headers = headers,
39
+ verify = use_ssl
40
+ )
41
+
42
+ response.raise_for_status()
43
+
44
+ return response
45
+
46
+ def get_query_response(
47
+ query_dict : dict[str, str],
48
+ address : str,
49
+ api_port : str,
50
+ token : str,
51
+ use_ssl : bool,
52
+ path_extension : str = ""
53
+ ) -> Response:
54
+ """
55
+ Retrieve the query response given the address, API port and token.
56
+
57
+ :param query_dict: The query dictionary
58
+ :type query_dict: dict[str, str]
59
+
60
+ :param address: The address where request is to be made
61
+ :type address: str
62
+
63
+ :param api_port: The API port at the given address
64
+ :type api_port: str
65
+
66
+ :param token: The HCI token
67
+ :type token: str
68
+
69
+ :param use_ssl: Boolean choice of using SSL
70
+ :type use_ssl: bool
71
+
72
+ :param path_extension: possibly extend the request URL. Used for example when making SQL requests. Defaults to ""
73
+ :type path_extension: str, optional
74
+
75
+ :return: A response containing information about the query
76
+ :rtype: requests.Response
77
+ """
78
+ if not "indexName" in query_dict.keys():
79
+ raise RuntimeError("Field indexName is missing in the query dictionary")
80
+
81
+ url : str = "https://" + address + ":" + api_port + "/api/search/query/" + path_extension
82
+ query : dict[str, str] = query_dict
83
+ headers : dict[str, str] = {
84
+ "Content-Type": "application/json",
85
+ "Accept": "application/json",
86
+ "Authorization": "Bearer " + token
87
+ }
88
+ response : Response = post(
89
+ url,
90
+ dumps(query),
91
+ headers = headers,
92
+ verify = use_ssl
93
+ )
94
+
95
+ response.raise_for_status()
96
+
97
+ return response
98
+
@@ -0,0 +1 @@
1
+ from NGPIris.hcp.hcp import HCPHandler
@@ -0,0 +1,8 @@
1
+ class VPNConnectionError(Exception):
2
+ pass
3
+
4
+ class BucketNotFound(Exception):
5
+ pass
6
+
7
+ class NoBucketMounted(Exception):
8
+ pass