genelastic 0.7.0__py3-none-any.whl → 0.9.0__py3-none-any.whl
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.
- genelastic/api/.env +4 -0
- genelastic/api/cli_start_api.py +18 -0
- genelastic/api/errors.py +52 -0
- genelastic/api/extends/example.py +0 -6
- genelastic/api/extends/example.yml +0 -0
- genelastic/api/routes.py +313 -181
- genelastic/api/server.py +34 -26
- genelastic/api/settings.py +5 -9
- genelastic/api/specification.yml +512 -0
- genelastic/common/__init__.py +0 -39
- genelastic/common/cli.py +100 -0
- genelastic/common/elastic.py +374 -46
- genelastic/common/exceptions.py +34 -2
- genelastic/common/server.py +59 -0
- genelastic/common/types.py +1 -14
- genelastic/import_data/__init__.py +0 -27
- genelastic/import_data/checker.py +99 -0
- genelastic/import_data/checker_observer.py +13 -0
- genelastic/import_data/cli/__init__.py +0 -0
- genelastic/import_data/cli/cli_check.py +136 -0
- genelastic/import_data/cli/gen_data.py +143 -0
- genelastic/import_data/cli/import_data.py +346 -0
- genelastic/import_data/cli/info.py +247 -0
- genelastic/import_data/{cli_integrity.py → cli/integrity.py} +29 -7
- genelastic/import_data/cli/validate.py +146 -0
- genelastic/import_data/collect.py +185 -0
- genelastic/import_data/constants.py +136 -11
- genelastic/import_data/import_bundle.py +102 -59
- genelastic/import_data/import_bundle_factory.py +70 -149
- genelastic/import_data/importers/__init__.py +0 -0
- genelastic/import_data/importers/importer_base.py +131 -0
- genelastic/import_data/importers/importer_factory.py +85 -0
- genelastic/import_data/importers/importer_types.py +223 -0
- genelastic/import_data/logger.py +2 -1
- genelastic/import_data/models/__init__.py +0 -0
- genelastic/import_data/models/analyses.py +178 -0
- genelastic/import_data/models/analysis.py +144 -0
- genelastic/import_data/models/data_file.py +110 -0
- genelastic/import_data/models/process.py +45 -0
- genelastic/import_data/models/processes.py +84 -0
- genelastic/import_data/models/tags.py +170 -0
- genelastic/import_data/models/unique_list.py +109 -0
- genelastic/import_data/models/validate.py +26 -0
- genelastic/import_data/patterns.py +90 -0
- genelastic/import_data/random_bundle.py +79 -54
- genelastic/import_data/resolve.py +157 -0
- genelastic/ui/.env +1 -0
- genelastic/ui/cli_start_ui.py +20 -0
- genelastic/ui/routes.py +333 -0
- genelastic/ui/server.py +9 -82
- genelastic/ui/settings.py +2 -6
- genelastic/ui/static/cea-cnrgh.ico +0 -0
- genelastic/ui/static/cea.ico +0 -0
- genelastic/ui/static/layout.ico +0 -0
- genelastic/ui/static/novaseq6000.png +0 -0
- genelastic/ui/static/style.css +430 -0
- genelastic/ui/static/ui.js +458 -0
- genelastic/ui/templates/analyses.html +98 -0
- genelastic/ui/templates/analysis_detail.html +44 -0
- genelastic/ui/templates/bi_process_detail.html +129 -0
- genelastic/ui/templates/bi_processes.html +116 -0
- genelastic/ui/templates/explorer.html +356 -0
- genelastic/ui/templates/home.html +207 -0
- genelastic/ui/templates/layout.html +153 -0
- genelastic/ui/templates/version.html +21 -0
- genelastic/ui/templates/wet_process_detail.html +131 -0
- genelastic/ui/templates/wet_processes.html +116 -0
- genelastic-0.9.0.dist-info/METADATA +686 -0
- genelastic-0.9.0.dist-info/RECORD +76 -0
- genelastic-0.9.0.dist-info/WHEEL +4 -0
- genelastic-0.9.0.dist-info/entry_points.txt +10 -0
- genelastic-0.9.0.dist-info/licenses/LICENSE +519 -0
- genelastic/import_data/analyses.py +0 -69
- genelastic/import_data/analysis.py +0 -205
- genelastic/import_data/bi_process.py +0 -27
- genelastic/import_data/bi_processes.py +0 -49
- genelastic/import_data/cli_gen_data.py +0 -116
- genelastic/import_data/cli_import.py +0 -379
- genelastic/import_data/cli_info.py +0 -256
- genelastic/import_data/cli_validate.py +0 -54
- genelastic/import_data/data_file.py +0 -87
- genelastic/import_data/filename_pattern.py +0 -57
- genelastic/import_data/tags.py +0 -123
- genelastic/import_data/wet_process.py +0 -28
- genelastic/import_data/wet_processes.py +0 -53
- genelastic-0.7.0.dist-info/METADATA +0 -105
- genelastic-0.7.0.dist-info/RECORD +0 -40
- genelastic-0.7.0.dist-info/WHEEL +0 -5
- genelastic-0.7.0.dist-info/entry_points.txt +0 -6
- genelastic-0.7.0.dist-info/top_level.txt +0 -1
genelastic/api/.env
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
GENAPI_ES_URL="https://192.168.73.11:9200"
|
|
2
|
+
GENAPI_ES_CERT_FP="CB:8F:94:61:DB:57:65:38:9E:A2:1E:C4:75:AA:3E:9B:03:5C:2A:04:74:06:96:3E:B5:CE:81:7C:64:3C:D4:C5"
|
|
3
|
+
GENAPI_ES_ENCODED_API_KEY="YlNSWjY1Z0JoN1BKQ1BHTW95OGI6VExoTUxPc1VaRVFJazRnMWdwdGtNdw=="
|
|
4
|
+
GENAPI_ES_INDEX_PREFIX="genelastic"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from genelastic.common.cli import parse_server_launch_args
|
|
2
|
+
from genelastic.common.server import start_dev_server, start_prod_server
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def main() -> None:
|
|
6
|
+
app_module = "genelastic.api.server:app"
|
|
7
|
+
args = parse_server_launch_args("Start API server.", 8000)
|
|
8
|
+
if args.env == "dev":
|
|
9
|
+
start_dev_server(app_module, args, reload_includes=["*.yml"])
|
|
10
|
+
elif args.env == "prod":
|
|
11
|
+
start_prod_server(app_module, args)
|
|
12
|
+
else:
|
|
13
|
+
msg = f"Environment '{args.env}' is not implemented."
|
|
14
|
+
raise NotImplementedError(msg)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
main()
|
genelastic/api/errors.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import elasticsearch
|
|
2
|
+
from flask import Flask, Response, jsonify
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def register_error_handlers(app: Flask) -> None:
|
|
6
|
+
"""Register handlers for elasticsearch ApiError and TransportError
|
|
7
|
+
exceptions.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
@app.errorhandler(elasticsearch.ApiError)
|
|
11
|
+
def handle_api_error(e: elasticsearch.ApiError) -> tuple[Response, int]:
|
|
12
|
+
# See https://elasticsearch-py.readthedocs.io/en/latest/exceptions.html#api-errors
|
|
13
|
+
app.logger.error("Elasticsearch ApiError: %s", e, exc_info=True)
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
jsonify(
|
|
17
|
+
{
|
|
18
|
+
"error": {
|
|
19
|
+
"message": str(e),
|
|
20
|
+
"type": e.__class__.__name__,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
),
|
|
24
|
+
e.status_code,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@app.errorhandler(elasticsearch.TransportError)
|
|
28
|
+
def handle_transport_error(
|
|
29
|
+
e: elasticsearch.TransportError,
|
|
30
|
+
) -> tuple[Response, int]:
|
|
31
|
+
# See https://elasticsearch-py.readthedocs.io/en/latest/exceptions.html#transport-and-connection-errors
|
|
32
|
+
app.logger.error("Elasticsearch TransportError: %s", e, exc_info=True)
|
|
33
|
+
|
|
34
|
+
status_code = 502
|
|
35
|
+
if (
|
|
36
|
+
e.errors
|
|
37
|
+
and hasattr(e.errors[0], "status")
|
|
38
|
+
and e.errors[0].status is not None
|
|
39
|
+
):
|
|
40
|
+
status_code = e.errors[0].status
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
jsonify(
|
|
44
|
+
{
|
|
45
|
+
"error": {
|
|
46
|
+
"message": str(e),
|
|
47
|
+
"type": e.__class__.__name__,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
status_code,
|
|
52
|
+
)
|
|
File without changes
|
genelastic/api/routes.py
CHANGED
|
@@ -1,221 +1,353 @@
|
|
|
1
|
-
|
|
2
|
-
from
|
|
3
|
-
from typing import Any
|
|
1
|
+
import typing
|
|
2
|
+
from importlib.metadata import version as get_version
|
|
4
3
|
|
|
5
4
|
from flask import Response, current_app, jsonify
|
|
6
5
|
|
|
6
|
+
if typing.TYPE_CHECKING:
|
|
7
|
+
from genelastic.common.elastic import ElasticQueryConn
|
|
7
8
|
|
|
8
|
-
def ping() -> Response:
|
|
9
|
-
"""Test route to verify that the server is online."""
|
|
10
|
-
return jsonify({"message": "pong"})
|
|
11
9
|
|
|
10
|
+
def indexes() -> tuple[Response, int]:
|
|
11
|
+
"""List all Elasticsearch indexes."""
|
|
12
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
13
|
+
return jsonify({"result": es_query_conn.get_indices()}), 200
|
|
12
14
|
|
|
13
|
-
def list_indices() -> Response:
|
|
14
|
-
"""Route to list Elasticsearch indexes."""
|
|
15
|
-
return current_app.elastic_query_conn.get_indices() # type: ignore[attr-defined, no-any-return]
|
|
16
15
|
|
|
16
|
+
def retrieve_document_by_index_and_id(
|
|
17
|
+
index_id: str, document_id: str
|
|
18
|
+
) -> tuple[Response, int]:
|
|
19
|
+
"""Retrieve a document by its index name and ID."""
|
|
20
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
21
|
+
result = es_query_conn.get_document_by_id(index_id, document_id)
|
|
22
|
+
return jsonify({"result": result}), 200
|
|
17
23
|
|
|
18
|
-
def retrieve_document(index_id: str, document_id: str) -> Response:
|
|
19
|
-
"""Route to retrieve a document by its ID."""
|
|
20
|
-
document = current_app.elastic_query_conn.get_document_by_id( # type: ignore[attr-defined]
|
|
21
|
-
index_id, document_id
|
|
22
|
-
)
|
|
23
|
-
return jsonify(document)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def list_wet_processes() -> Response:
|
|
27
|
-
"""Route to list wet processes."""
|
|
28
|
-
wet_processes_index = (
|
|
29
|
-
f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-wet_processes"
|
|
30
|
-
)
|
|
31
|
-
result = current_app.elastic_query_conn.get_field_values( # type: ignore[attr-defined]
|
|
32
|
-
wet_processes_index, "proc_id"
|
|
33
|
-
)
|
|
34
|
-
return jsonify(list(result))
|
|
35
24
|
|
|
25
|
+
def wet_processes() -> tuple[Response, int]:
|
|
26
|
+
"""List wet processes."""
|
|
27
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-bi_processes"
|
|
29
|
+
result = es_query_conn.get_field_values(
|
|
30
|
+
es_query_conn.wet_processes_index,
|
|
31
|
+
"proc_id",
|
|
41
32
|
)
|
|
42
|
-
result
|
|
43
|
-
bi_processes_index, "proc_id"
|
|
44
|
-
)
|
|
45
|
-
return jsonify(list(result))
|
|
33
|
+
return jsonify({"result": list(result)}), 200
|
|
46
34
|
|
|
47
35
|
|
|
48
|
-
def
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
result =
|
|
52
|
-
|
|
36
|
+
def get_wet_process(proc_id: str) -> tuple[Response, int]:
|
|
37
|
+
"""Retrieve details of a specific wet process by its ID."""
|
|
38
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
39
|
+
result = es_query_conn.get_process(
|
|
40
|
+
es_query_conn.wet_processes_index, proc_id
|
|
53
41
|
)
|
|
54
|
-
filenames = [Path(path).name for path in result]
|
|
55
|
-
return jsonify(filenames)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def list_analyses_wet_processes(proc_id: str) -> Response:
|
|
59
|
-
"""Route to list analyses one of specific wet process"""
|
|
60
|
-
analyses_index = f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-analyses"
|
|
61
|
-
|
|
62
|
-
search_query = {
|
|
63
|
-
"query": {
|
|
64
|
-
"term": {
|
|
65
|
-
"metadata.wet_process.keyword": proc_id,
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
|
|
70
|
-
index=analyses_index, body=search_query
|
|
71
|
-
)
|
|
72
|
-
result = [hit["_source"]["path"] for hit in response["hits"]["hits"]]
|
|
73
|
-
|
|
74
|
-
return jsonify(result)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def list_analyses_bi_processes(proc_id: str) -> Response:
|
|
78
|
-
"""Route to list analyses one of specific bi process"""
|
|
79
|
-
analyses_index = f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-analyses"
|
|
80
|
-
|
|
81
|
-
search_query = {
|
|
82
|
-
"query": {
|
|
83
|
-
"term": {
|
|
84
|
-
"metadata.bi_process.keyword": proc_id,
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
|
|
89
|
-
index=analyses_index, body=search_query
|
|
90
|
-
)
|
|
91
|
-
result = [hit["_source"]["path"] for hit in response["hits"]["hits"]]
|
|
92
|
-
|
|
93
|
-
return jsonify(result)
|
|
94
|
-
|
|
95
42
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"snv_docs": {
|
|
104
|
-
"composite": {
|
|
105
|
-
"sources": [
|
|
106
|
-
{"alt_value": {"terms": {"field": "alt.keyword"}}}
|
|
107
|
-
],
|
|
108
|
-
"size": 1000,
|
|
43
|
+
if not result:
|
|
44
|
+
return jsonify(
|
|
45
|
+
{
|
|
46
|
+
"error": {
|
|
47
|
+
"message": f"Wet process with proc_id "
|
|
48
|
+
f"'{proc_id}' not found.",
|
|
49
|
+
"type": "NotFoundError",
|
|
109
50
|
}
|
|
110
51
|
}
|
|
111
|
-
|
|
112
|
-
"query": {"term": {"alt.keyword": target_value}},
|
|
113
|
-
"size": 0,
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
all_documents = []
|
|
117
|
-
buckets = current_app.elastic_query_conn.run_composite_aggregation( # type: ignore[attr-defined]
|
|
118
|
-
index_pattern, search_query
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
for bucket in buckets:
|
|
122
|
-
alt_value = bucket["key"]["alt_value"]
|
|
123
|
-
|
|
124
|
-
search_query_docs = {
|
|
125
|
-
"query": {"term": {"alt.keyword": alt_value}},
|
|
126
|
-
"size": 1000,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
|
|
130
|
-
index=index_pattern, body=search_query_docs
|
|
131
|
-
)
|
|
52
|
+
), 404
|
|
132
53
|
|
|
133
|
-
|
|
54
|
+
return jsonify({"result": result}), 200
|
|
134
55
|
|
|
135
|
-
return jsonify(all_documents)
|
|
136
56
|
|
|
57
|
+
def list_analyses_by_wet_process(proc_id: str) -> tuple[Response, int]:
|
|
58
|
+
"""List analyses that contain the specified wet process."""
|
|
59
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
60
|
+
result = es_query_conn.list_analyses_by_process("wet_process", proc_id)
|
|
61
|
+
return jsonify({"result": result}), 200
|
|
137
62
|
|
|
138
|
-
def build_snv_search_query(
|
|
139
|
-
target_alt: str, target_svtype: str
|
|
140
|
-
) -> dict[str, Any]:
|
|
141
|
-
"""Helper function to build the search query for SNV documents with specified alt and SVTYPE."""
|
|
142
|
-
return {
|
|
143
|
-
"query": {
|
|
144
|
-
"bool": {
|
|
145
|
-
"must": [
|
|
146
|
-
{"term": {"alt.keyword": target_alt}},
|
|
147
|
-
{"term": {"info.SVTYPE.keyword": target_svtype}},
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
"size": 1000,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def build_snv_mutation_search_query(
|
|
156
|
-
target_svtypes: list[str],
|
|
157
|
-
) -> dict[str, Any]:
|
|
158
|
-
"""Helper function to build the search query for SNV mutations with specified SVTYPE values."""
|
|
159
|
-
return {
|
|
160
|
-
"query": {
|
|
161
|
-
"bool": {
|
|
162
|
-
"must": [
|
|
163
|
-
{"term": {"alt.keyword": "SNV"}},
|
|
164
|
-
{"terms": {"info.SVTYPE.keyword": target_svtypes}},
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
"size": 1000,
|
|
169
|
-
}
|
|
170
63
|
|
|
64
|
+
def bi_processes() -> tuple[Response, int]:
|
|
65
|
+
"""List bioinformatics processes."""
|
|
66
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
67
|
+
result = es_query_conn.get_field_values(
|
|
68
|
+
es_query_conn.bi_processes_index, "proc_id"
|
|
69
|
+
)
|
|
70
|
+
return jsonify({"result": list(result)}), 200
|
|
171
71
|
|
|
172
|
-
def list_snv_insertion_documents() -> Response:
|
|
173
|
-
"""Route to list all documents containing an insertion (INS) at a single position (SNV)."""
|
|
174
|
-
index_pattern = "genelastic-file-*"
|
|
175
|
-
search_query = build_snv_search_query(target_alt="SNV", target_svtype="INS")
|
|
176
72
|
|
|
177
|
-
|
|
178
|
-
|
|
73
|
+
def get_bi_process(proc_id: str) -> tuple[Response, int]:
|
|
74
|
+
"""Retrieve details of a specific bioinformatics process by its ID."""
|
|
75
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
76
|
+
result = es_query_conn.get_process(
|
|
77
|
+
es_query_conn.bi_processes_index, proc_id
|
|
179
78
|
)
|
|
180
79
|
|
|
181
|
-
|
|
80
|
+
if not result:
|
|
81
|
+
return jsonify(
|
|
82
|
+
{
|
|
83
|
+
"error": {
|
|
84
|
+
"message": f"Bioinformatics process with proc_id "
|
|
85
|
+
f"'{proc_id}' not found.",
|
|
86
|
+
"type": "NotFoundError",
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
), 404
|
|
182
90
|
|
|
183
|
-
return jsonify(
|
|
91
|
+
return jsonify({"result": result}), 200
|
|
184
92
|
|
|
185
93
|
|
|
186
|
-
def
|
|
187
|
-
"""
|
|
188
|
-
|
|
189
|
-
|
|
94
|
+
def list_analyses_by_bi_process(proc_id: str) -> tuple[Response, int]:
|
|
95
|
+
"""List analyses that contain the specified bioinformatics process"""
|
|
96
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
97
|
+
result = es_query_conn.list_analyses_by_process("bi_process", proc_id)
|
|
98
|
+
return jsonify({"result": result}), 200
|
|
190
99
|
|
|
191
|
-
response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
|
|
192
|
-
index=index_pattern, body=search_query
|
|
193
|
-
)
|
|
194
100
|
|
|
195
|
-
|
|
101
|
+
def list_analyses_by_bi_process_esql(
|
|
102
|
+
proc_id: str,
|
|
103
|
+
) -> tuple[Response, int]:
|
|
104
|
+
"""List analyses that contain the specified bioinformatics process using
|
|
105
|
+
an ES|QL query.
|
|
106
|
+
"""
|
|
107
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
108
|
+
result = es_query_conn.list_analyses_by_process_esql("bi_process", proc_id)
|
|
109
|
+
return jsonify({"result": result}), 200
|
|
196
110
|
|
|
197
|
-
return jsonify(all_documents)
|
|
198
111
|
|
|
112
|
+
def list_analyses_by_bi_process_sql(
|
|
113
|
+
proc_id: str,
|
|
114
|
+
) -> tuple[Response, int]:
|
|
115
|
+
"""List analyses that contain the specified bioinformatics process using
|
|
116
|
+
an SQL query.
|
|
117
|
+
"""
|
|
118
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
119
|
+
result = es_query_conn.list_analyses_by_process_sql("bi_process", proc_id)
|
|
120
|
+
return jsonify({"result": result}), 200
|
|
199
121
|
|
|
200
|
-
def list_snv_mutation_documents() -> Response:
|
|
201
|
-
"""Route to list all documents containing a mutation at a single position (SNV)."""
|
|
202
|
-
index_pattern = "genelastic-file-*"
|
|
203
|
-
target_svtypes = ["INS", "DEL"]
|
|
204
122
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
123
|
+
def analyses() -> tuple[Response, int]:
|
|
124
|
+
"""List analyses."""
|
|
125
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
208
126
|
|
|
209
|
-
|
|
210
|
-
|
|
127
|
+
result = es_query_conn.get_field_values(
|
|
128
|
+
es_query_conn.analyses_index, "analysis_id"
|
|
211
129
|
)
|
|
130
|
+
return jsonify({"result": list(result)}), 200
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# TODO(?): All the following functions are commented because it is currently
|
|
134
|
+
# unclear what they do and if they are still needed.
|
|
135
|
+
|
|
136
|
+
# def list_snv_documents() -> Response:
|
|
137
|
+
# """Route to list all documents containing a mutation at a single position (SNV)."""
|
|
138
|
+
# es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
139
|
+
# index_pattern = "genelastic-file-*"
|
|
140
|
+
# target_value = "SNV"
|
|
141
|
+
#
|
|
142
|
+
# search_query = {
|
|
143
|
+
# "aggs": {
|
|
144
|
+
# "snv_docs": {
|
|
145
|
+
# "composite": {
|
|
146
|
+
# "sources": [
|
|
147
|
+
# {"alt_value": {"terms": {"field": "alt.keyword"}}}
|
|
148
|
+
# ],
|
|
149
|
+
# "size": 1000,
|
|
150
|
+
# }
|
|
151
|
+
# }
|
|
152
|
+
# },
|
|
153
|
+
# "query": {"term": {"alt.keyword": target_value}},
|
|
154
|
+
# "size": 0,
|
|
155
|
+
# }
|
|
156
|
+
#
|
|
157
|
+
# all_documents = []
|
|
158
|
+
# buckets = es_query_conn.run_composite_aggregation(
|
|
159
|
+
# index_pattern, search_query
|
|
160
|
+
# )
|
|
161
|
+
#
|
|
162
|
+
# for bucket in buckets:
|
|
163
|
+
# alt_value = bucket["key"]["alt_value"]
|
|
164
|
+
#
|
|
165
|
+
# search_query_docs = {
|
|
166
|
+
# "query": {"term": {"alt.keyword": alt_value}},
|
|
167
|
+
# "size": 1000,
|
|
168
|
+
# }
|
|
169
|
+
#
|
|
170
|
+
# response = es_query_conn.client.search(
|
|
171
|
+
# index=index_pattern, body=search_query_docs
|
|
172
|
+
# )
|
|
173
|
+
#
|
|
174
|
+
# all_documents.extend(response["hits"]["hits"])
|
|
175
|
+
#
|
|
176
|
+
# return jsonify(all_documents)
|
|
177
|
+
#
|
|
178
|
+
#
|
|
179
|
+
# def build_snv_search_query(
|
|
180
|
+
# target_alt: str, target_svtype: str
|
|
181
|
+
# ) -> dict[str, Any]:
|
|
182
|
+
# """Helper function to build the search query for SNV documents with specified alt and SVTYPE."""
|
|
183
|
+
# return {
|
|
184
|
+
# "query": {
|
|
185
|
+
# "bool": {
|
|
186
|
+
# "must": [
|
|
187
|
+
# {"term": {"alt.keyword": target_alt}},
|
|
188
|
+
# {"term": {"info.SVTYPE.keyword": target_svtype}},
|
|
189
|
+
# ]
|
|
190
|
+
# }
|
|
191
|
+
# },
|
|
192
|
+
# "size": 1000,
|
|
193
|
+
# }
|
|
194
|
+
#
|
|
195
|
+
#
|
|
196
|
+
# def build_snv_mutation_search_query(
|
|
197
|
+
# target_svtypes: list[str],
|
|
198
|
+
# ) -> dict[str, Any]:
|
|
199
|
+
# """Helper function to build the search query for SNV mutations with specified SVTYPE values."""
|
|
200
|
+
# return {
|
|
201
|
+
# "query": {
|
|
202
|
+
# "bool": {
|
|
203
|
+
# "must": [
|
|
204
|
+
# {"term": {"alt.keyword": "SNV"}},
|
|
205
|
+
# {"terms": {"info.SVTYPE.keyword": target_svtypes}},
|
|
206
|
+
# ]
|
|
207
|
+
# }
|
|
208
|
+
# },
|
|
209
|
+
# "size": 1000,
|
|
210
|
+
# }
|
|
211
|
+
#
|
|
212
|
+
#
|
|
213
|
+
# def list_snv_insertion_documents() -> Response:
|
|
214
|
+
# """Route to list all documents containing an insertion (INS) at a single position (SNV)."""
|
|
215
|
+
# es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
216
|
+
#
|
|
217
|
+
# index_pattern = "genelastic-file-*"
|
|
218
|
+
# search_query = build_snv_search_query(target_alt="SNV", target_svtype="INS")
|
|
219
|
+
#
|
|
220
|
+
# response = es_query_conn.client.search(
|
|
221
|
+
# index=index_pattern, body=search_query
|
|
222
|
+
# )
|
|
223
|
+
#
|
|
224
|
+
# all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
|
|
225
|
+
#
|
|
226
|
+
# return jsonify(all_documents)
|
|
227
|
+
#
|
|
228
|
+
#
|
|
229
|
+
# def list_snv_deletion_documents() -> Response:
|
|
230
|
+
# """Route to list all documents containing a deletion (DEL) at a single position (SNV)."""
|
|
231
|
+
# es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
232
|
+
# index_pattern = "genelastic-file-*"
|
|
233
|
+
# search_query = build_snv_search_query(target_alt="SNV", target_svtype="DEL")
|
|
234
|
+
#
|
|
235
|
+
# response = es_query_conn.client.search(
|
|
236
|
+
# index=index_pattern, body=search_query
|
|
237
|
+
# )
|
|
238
|
+
#
|
|
239
|
+
# all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
|
|
240
|
+
#
|
|
241
|
+
# return jsonify(all_documents)
|
|
242
|
+
#
|
|
243
|
+
#
|
|
244
|
+
# def list_snv_mutation_documents() -> Response:
|
|
245
|
+
# """Route to list all documents containing a mutation at a single position (SNV)."""
|
|
246
|
+
# es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
247
|
+
# index_pattern = "genelastic-file-*"
|
|
248
|
+
# target_svtypes = ["INS", "DEL"]
|
|
249
|
+
#
|
|
250
|
+
# search_query = build_snv_mutation_search_query(
|
|
251
|
+
# target_svtypes=target_svtypes
|
|
252
|
+
# )
|
|
253
|
+
#
|
|
254
|
+
# response = es_query_conn.client.search(
|
|
255
|
+
# index=index_pattern, body=search_query
|
|
256
|
+
# )
|
|
257
|
+
#
|
|
258
|
+
# all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
|
|
259
|
+
#
|
|
260
|
+
# return jsonify(all_documents)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def version() -> tuple[Response, int]:
|
|
264
|
+
"""Obtain genelastic package version used by the server."""
|
|
265
|
+
top_level_package = __package__.split(".")[0]
|
|
266
|
+
return jsonify({"result": {"version": get_version(top_level_package)}}), 200
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def key_value_analyses_index() -> tuple[Response, int]:
|
|
270
|
+
"""Route to return all key-values in an index."""
|
|
271
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
272
|
+
result = es_query_conn.get_all_documents_kv(es_query_conn.analyses_index)
|
|
273
|
+
return jsonify({"result": result}), 200
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def count_key_value_analyses_index() -> tuple[Response, int]:
|
|
277
|
+
"""Route to return the key-value counts for fields in an index."""
|
|
278
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
279
|
+
fields = [
|
|
280
|
+
"metadata.barcode",
|
|
281
|
+
"metadata.reference_genome",
|
|
282
|
+
"metadata.sample_name",
|
|
283
|
+
"metadata.source",
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
result: dict[str, dict[str, int]] = {}
|
|
287
|
+
for field in fields:
|
|
288
|
+
result[field] = es_query_conn.get_all_documents_kv_count(
|
|
289
|
+
es_query_conn.analyses_index, field
|
|
290
|
+
)
|
|
212
291
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
292
|
+
return jsonify({"result": result}), 200
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def count_wet_process_fields() -> tuple[Response, int]:
|
|
296
|
+
"""Return key-value counts for each field in wet_process documents."""
|
|
297
|
+
# BUG: this does not work for numeric values.
|
|
298
|
+
# error_rate_expected, fragmentation, reads_size will always return an
|
|
299
|
+
# empty dict.
|
|
300
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
301
|
+
wet_fields = [
|
|
302
|
+
"metadata.amplification",
|
|
303
|
+
"metadata.error_rate_expected",
|
|
304
|
+
"metadata.flowcell_type",
|
|
305
|
+
"metadata.fragmentation",
|
|
306
|
+
"metadata.generic_kit",
|
|
307
|
+
"metadata.input_type",
|
|
308
|
+
"metadata.library_kit",
|
|
309
|
+
"metadata.manufacturer",
|
|
310
|
+
"metadata.reads_size",
|
|
311
|
+
"metadata.sequencer",
|
|
312
|
+
"metadata.sequencing_kit",
|
|
313
|
+
"metadata.sequencing_type",
|
|
314
|
+
"proc_id",
|
|
315
|
+
"type",
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
result: dict[str, dict[str, int]] = {}
|
|
319
|
+
for field in wet_fields:
|
|
320
|
+
result[field] = es_query_conn.get_all_documents_kv_count(
|
|
321
|
+
es_query_conn.wet_processes_index, field
|
|
322
|
+
)
|
|
216
323
|
|
|
324
|
+
return jsonify({"result": result}), 200
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def count_bi_process_fields() -> tuple[Response, int]:
|
|
328
|
+
"""Return key-value counts for each field in bi_process documents, including steps."""
|
|
329
|
+
es_query_conn: ElasticQueryConn = current_app.elastic_query_conn # type: ignore[attr-defined]
|
|
330
|
+
# Champs de niveau racine
|
|
331
|
+
bi_fields = [
|
|
332
|
+
"metadata.name",
|
|
333
|
+
"metadata.pipeline_version",
|
|
334
|
+
"metadata.sequencing_type",
|
|
335
|
+
"proc_id",
|
|
336
|
+
"type",
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
# Champs des steps (dans la liste steps[])
|
|
340
|
+
step_fields = [
|
|
341
|
+
"metadata.steps.name",
|
|
342
|
+
"metadata.steps.cmd",
|
|
343
|
+
"metadata.steps.version",
|
|
344
|
+
"metadata.steps.output", # optionnel
|
|
345
|
+
]
|
|
346
|
+
|
|
347
|
+
result: dict[str, dict[str, int]] = {}
|
|
348
|
+
for field in bi_fields + step_fields:
|
|
349
|
+
result[field] = es_query_conn.get_all_documents_kv_count(
|
|
350
|
+
es_query_conn.bi_processes_index, field
|
|
351
|
+
)
|
|
217
352
|
|
|
218
|
-
|
|
219
|
-
"""Retourne la version du package genelastic."""
|
|
220
|
-
top_level_package = __package__.split(".")[0]
|
|
221
|
-
return jsonify({"version": version(top_level_package)})
|
|
353
|
+
return jsonify({"result": result}), 200
|