genelastic 0.6.1__tar.gz → 0.8.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.
Files changed (83) hide show
  1. genelastic-0.8.0/MANIFEST.in +2 -0
  2. genelastic-0.8.0/PKG-INFO +109 -0
  3. genelastic-0.8.0/README.md +60 -0
  4. genelastic-0.8.0/pyproject.toml +126 -0
  5. genelastic-0.8.0/src/genelastic/api/cli_start_api.py +18 -0
  6. genelastic-0.8.0/src/genelastic/api/extends/example.py +6 -0
  7. genelastic-0.8.0/src/genelastic/api/extends/example.yml +20 -0
  8. genelastic-0.8.0/src/genelastic/api/routes.py +221 -0
  9. genelastic-0.8.0/src/genelastic/api/server.py +83 -0
  10. genelastic-0.8.0/src/genelastic/api/settings.py +10 -0
  11. genelastic-0.8.0/src/genelastic/api/specification.yml +350 -0
  12. genelastic-0.8.0/src/genelastic/common/__init__.py +44 -0
  13. genelastic-0.8.0/src/genelastic/common/cli.py +115 -0
  14. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/common/elastic.py +80 -49
  15. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/common/exceptions.py +0 -2
  16. genelastic-0.8.0/src/genelastic/common/server.py +51 -0
  17. genelastic-0.8.0/src/genelastic/common/types.py +25 -0
  18. genelastic-0.8.0/src/genelastic/import_data/__init__.py +27 -0
  19. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/analyses.py +17 -20
  20. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/analysis.py +69 -65
  21. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/bi_process.py +7 -5
  22. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/bi_processes.py +8 -8
  23. genelastic-0.8.0/src/genelastic/import_data/cli_gen_data.py +143 -0
  24. genelastic-0.8.0/src/genelastic/import_data/cli_import.py +379 -0
  25. genelastic-0.6.1/src/genelastic/import_data/info.py → genelastic-0.8.0/src/genelastic/import_data/cli_info.py +104 -75
  26. genelastic-0.8.0/src/genelastic/import_data/cli_integrity.py +384 -0
  27. genelastic-0.8.0/src/genelastic/import_data/cli_validate.py +54 -0
  28. genelastic-0.8.0/src/genelastic/import_data/constants.py +24 -0
  29. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/data_file.py +23 -20
  30. genelastic-0.8.0/src/genelastic/import_data/filename_pattern.py +57 -0
  31. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/import_bundle.py +56 -47
  32. genelastic-0.8.0/src/genelastic/import_data/import_bundle_factory.py +298 -0
  33. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/logger.py +22 -18
  34. genelastic-0.8.0/src/genelastic/import_data/random_bundle.py +425 -0
  35. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/tags.py +46 -26
  36. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/wet_process.py +8 -4
  37. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/import_data/wet_processes.py +13 -8
  38. genelastic-0.8.0/src/genelastic/ui/__init__.py +0 -0
  39. genelastic-0.8.0/src/genelastic/ui/cli_start_ui.py +18 -0
  40. genelastic-0.8.0/src/genelastic/ui/routes.py +86 -0
  41. genelastic-0.8.0/src/genelastic/ui/server.py +14 -0
  42. genelastic-0.8.0/src/genelastic/ui/settings.py +7 -0
  43. genelastic-0.8.0/src/genelastic/ui/templates/analyses.html +11 -0
  44. genelastic-0.8.0/src/genelastic/ui/templates/bi_processes.html +11 -0
  45. genelastic-0.8.0/src/genelastic/ui/templates/home.html +4 -0
  46. genelastic-0.8.0/src/genelastic/ui/templates/layout.html +34 -0
  47. genelastic-0.8.0/src/genelastic/ui/templates/version.html +9 -0
  48. genelastic-0.8.0/src/genelastic/ui/templates/wet_processes.html +11 -0
  49. genelastic-0.8.0/src/genelastic.egg-info/PKG-INFO +109 -0
  50. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic.egg-info/SOURCES.txt +24 -6
  51. genelastic-0.8.0/src/genelastic.egg-info/entry_points.txt +8 -0
  52. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic.egg-info/requires.txt +15 -3
  53. genelastic-0.8.0/tests/test_010_analyses.py +14 -0
  54. genelastic-0.8.0/tests/test_100_import_bundle_format.py +701 -0
  55. genelastic-0.8.0/tests/test_200_cli_gen_data.py +236 -0
  56. genelastic-0.6.1/PKG-INFO +0 -41
  57. genelastic-0.6.1/README.md +0 -3
  58. genelastic-0.6.1/pyproject.toml +0 -60
  59. genelastic-0.6.1/src/genelastic/api/extends/example.py +0 -7
  60. genelastic-0.6.1/src/genelastic/api/routes.py +0 -84
  61. genelastic-0.6.1/src/genelastic/api/server.py +0 -72
  62. genelastic-0.6.1/src/genelastic/api/settings.py +0 -13
  63. genelastic-0.6.1/src/genelastic/common/__init__.py +0 -12
  64. genelastic-0.6.1/src/genelastic/common/cli.py +0 -35
  65. genelastic-0.6.1/src/genelastic/common/types.py +0 -20
  66. genelastic-0.6.1/src/genelastic/import_data/__init__.py +0 -9
  67. genelastic-0.6.1/src/genelastic/import_data/constants.py +0 -45
  68. genelastic-0.6.1/src/genelastic/import_data/filename_pattern.py +0 -63
  69. genelastic-0.6.1/src/genelastic/import_data/gen_data.py +0 -194
  70. genelastic-0.6.1/src/genelastic/import_data/import_bundle_factory.py +0 -290
  71. genelastic-0.6.1/src/genelastic/import_data/import_data.py +0 -292
  72. genelastic-0.6.1/src/genelastic/import_data/integrity.py +0 -290
  73. genelastic-0.6.1/src/genelastic/import_data/validate_data.py +0 -43
  74. genelastic-0.6.1/src/genelastic.egg-info/PKG-INFO +0 -41
  75. genelastic-0.6.1/src/genelastic.egg-info/entry_points.txt +0 -6
  76. genelastic-0.6.1/tests/test_010_analyses.py +0 -16
  77. genelastic-0.6.1/tests/test_100_import_bundle_format.py +0 -598
  78. {genelastic-0.6.1 → genelastic-0.8.0}/setup.cfg +0 -0
  79. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/__init__.py +0 -0
  80. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/api/__init__.py +0 -0
  81. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic/api/extends/__init__.py +0 -0
  82. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic.egg-info/dependency_links.txt +0 -0
  83. {genelastic-0.6.1 → genelastic-0.8.0}/src/genelastic.egg-info/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ recursive-include src *.yml
2
+ recursive-include src *.html
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.2
2
+ Name: genelastic
3
+ Version: 0.8.0
4
+ Summary: Generate and store genetic data into an Elasticsearch database.
5
+ Author: CNRGH
6
+ Author-email: Pierrick ROGER <pierrick.roger@cnrgh.fr>, Maxime BLANCHON <maxime.blanchon@cnrgh.fr>
7
+ License: CeCILL
8
+ Keywords: CNRGH,genelastic,generation,storage,elasticsearch,database
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: elasticsearch
16
+ Requires-Dist: PyVCF3
17
+ Requires-Dist: schema
18
+ Requires-Dist: PyYAML
19
+ Requires-Dist: biophony<1.4,>=1.3.0
20
+ Requires-Dist: colorlog
21
+ Provides-Extra: tests
22
+ Requires-Dist: pytest; extra == "tests"
23
+ Requires-Dist: mypy; extra == "tests"
24
+ Requires-Dist: coverage; extra == "tests"
25
+ Requires-Dist: yamllint; extra == "tests"
26
+ Requires-Dist: types-PyYAML; extra == "tests"
27
+ Requires-Dist: ruff<0.9,>=0.8.1; extra == "tests"
28
+ Requires-Dist: pre-commit<4.1,>=4.0.1; extra == "tests"
29
+ Requires-Dist: types-requests; extra == "tests"
30
+ Requires-Dist: ansible-core>=2.17.0; extra == "tests"
31
+ Requires-Dist: ansible-lint<25,>=24.12.2; extra == "tests"
32
+ Provides-Extra: docs
33
+ Requires-Dist: sphinx; extra == "docs"
34
+ Requires-Dist: sphinx-autoapi; extra == "docs"
35
+ Requires-Dist: furo; extra == "docs"
36
+ Provides-Extra: api
37
+ Requires-Dist: flask; extra == "api"
38
+ Requires-Dist: elasticsearch; extra == "api"
39
+ Requires-Dist: environs; extra == "api"
40
+ Requires-Dist: connexion[flask,swagger-ui,uvicorn]; extra == "api"
41
+ Requires-Dist: gunicorn; extra == "api"
42
+ Provides-Extra: ui
43
+ Requires-Dist: flask; extra == "ui"
44
+ Requires-Dist: requests; extra == "ui"
45
+ Requires-Dist: environs; extra == "ui"
46
+ Requires-Dist: uvicorn; extra == "ui"
47
+ Requires-Dist: asgiref; extra == "ui"
48
+ Requires-Dist: gunicorn; extra == "ui"
49
+
50
+ # genelastic
51
+
52
+ Storing of genetics data into an Elasticsearch database.
53
+
54
+ ## Prerequisites
55
+
56
+ - `python` >= 3.11
57
+ - `make`
58
+
59
+ ## Installation
60
+
61
+ To install dependencies, run the following command:
62
+
63
+ ```bash
64
+ python -m venv .venv
65
+ source .venv/bin/activate
66
+ make install.deps
67
+ ```
68
+
69
+ ## Configuration
70
+
71
+ To start the **API server**, the following environment variables should be defined:
72
+
73
+ - `GENAPI_ES_URL`: URL of the Elasticsearch server,
74
+ - `GENAPI_ES_ENCODED_API_KEY`: Encoded API key,
75
+ - `GENAPI_ES_INDEX_PREFIX`: Prefix to identify indices of interest,
76
+ - `GENAPI_ES_CERT_FP`: Certificate fingerprint of the Elasticsearch server.
77
+
78
+ Then, run the following command:
79
+
80
+ ```bash
81
+ make start-api
82
+ ```
83
+
84
+ To start the **UI server**, the following environment variables should be defined:
85
+
86
+ - `GENUI_API_URL`: URL of the API server.
87
+
88
+ Then, run the following command:
89
+
90
+ ```bash
91
+ make start-ui
92
+ ```
93
+
94
+ ## Developers
95
+
96
+ This project uses [pre-commit](https://pre-commit.com/) to manage Git hooks scripts. To install project hooks, run:
97
+
98
+ ```bash
99
+ pre-commit install
100
+ ```
101
+
102
+ After that, each commit will succeed only if all hooks (defined in `.pre-commit-config.yaml`) pass.
103
+
104
+ If necessary (though not recommended),
105
+ you can skip these hooks by using the `--no-verify` / `-n` option when committing:
106
+
107
+ ```bash
108
+ git commit -m "My commit message" --no-verify # This commit will not run installed hooks.
109
+ ```
@@ -0,0 +1,60 @@
1
+ # genelastic
2
+
3
+ Storing of genetics data into an Elasticsearch database.
4
+
5
+ ## Prerequisites
6
+
7
+ - `python` >= 3.11
8
+ - `make`
9
+
10
+ ## Installation
11
+
12
+ To install dependencies, run the following command:
13
+
14
+ ```bash
15
+ python -m venv .venv
16
+ source .venv/bin/activate
17
+ make install.deps
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ To start the **API server**, the following environment variables should be defined:
23
+
24
+ - `GENAPI_ES_URL`: URL of the Elasticsearch server,
25
+ - `GENAPI_ES_ENCODED_API_KEY`: Encoded API key,
26
+ - `GENAPI_ES_INDEX_PREFIX`: Prefix to identify indices of interest,
27
+ - `GENAPI_ES_CERT_FP`: Certificate fingerprint of the Elasticsearch server.
28
+
29
+ Then, run the following command:
30
+
31
+ ```bash
32
+ make start-api
33
+ ```
34
+
35
+ To start the **UI server**, the following environment variables should be defined:
36
+
37
+ - `GENUI_API_URL`: URL of the API server.
38
+
39
+ Then, run the following command:
40
+
41
+ ```bash
42
+ make start-ui
43
+ ```
44
+
45
+ ## Developers
46
+
47
+ This project uses [pre-commit](https://pre-commit.com/) to manage Git hooks scripts. To install project hooks, run:
48
+
49
+ ```bash
50
+ pre-commit install
51
+ ```
52
+
53
+ After that, each commit will succeed only if all hooks (defined in `.pre-commit-config.yaml`) pass.
54
+
55
+ If necessary (though not recommended),
56
+ you can skip these hooks by using the `--no-verify` / `-n` option when committing:
57
+
58
+ ```bash
59
+ git commit -m "My commit message" --no-verify # This commit will not run installed hooks.
60
+ ```
@@ -0,0 +1,126 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 70.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "genelastic"
7
+ version = "0.8.0"
8
+ dependencies = [
9
+ "elasticsearch",
10
+ "PyVCF3",
11
+ "schema",
12
+ "PyYAML",
13
+ "biophony >= 1.3.0, < 1.4",
14
+ "colorlog",
15
+ ]
16
+ requires-python = ">= 3.11"
17
+ authors = [
18
+ { name = "CNRGH" },
19
+ { name = "Pierrick ROGER", email = "pierrick.roger@cnrgh.fr" },
20
+ { name = "Maxime BLANCHON", email = "maxime.blanchon@cnrgh.fr" }]
21
+ description = "Generate and store genetic data into an Elasticsearch database."
22
+ readme = "README.md"
23
+ license = { text = "CeCILL" }
24
+ keywords = ["CNRGH", "genelastic", "generation", "storage", "elasticsearch", "database"]
25
+ classifiers = [
26
+ "Development Status :: 3 - Alpha",
27
+ "Intended Audience :: Science/Research",
28
+ "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)",
29
+ "Programming Language :: Python :: 3.11"
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ tests = [
34
+ "pytest",
35
+ "mypy",
36
+ "coverage",
37
+ "yamllint",
38
+ "types-PyYAML",
39
+ "ruff >= 0.8.1, < 0.9",
40
+ "pre-commit >= 4.0.1, < 4.1",
41
+ "types-requests",
42
+ "ansible-core >= 2.17.0",
43
+ "ansible-lint >= 24.12.2, < 25"
44
+ ]
45
+ docs = [
46
+ "sphinx",
47
+ "sphinx-autoapi",
48
+ "furo"
49
+ ]
50
+
51
+ api = [
52
+ "flask",
53
+ "elasticsearch",
54
+ "environs",
55
+ "connexion[flask,swagger-ui,uvicorn]",
56
+ "gunicorn"
57
+ ]
58
+
59
+ ui = [
60
+ "flask",
61
+ "requests",
62
+ "environs",
63
+ "uvicorn",
64
+ "asgiref",
65
+ "gunicorn"
66
+ ]
67
+
68
+ [project.scripts]
69
+ gnl-data = "genelastic.import_data.cli_gen_data:main"
70
+ gnl-import = "genelastic.import_data.cli_import:main"
71
+ gnl-info = "genelastic.import_data.cli_info:main"
72
+ gnl-integrity = "genelastic.import_data.cli_integrity:main"
73
+ gnl-start-api = "genelastic.api.cli_start_api:main"
74
+ gnl-start-ui = "genelastic.ui.cli_start_ui:main"
75
+ gnl-validate = "genelastic.import_data.cli_validate:main"
76
+
77
+ [tool.setuptools]
78
+ include-package-data = true
79
+
80
+ [tool.setuptools.packages.find]
81
+ where = ["src"]
82
+
83
+ [tool.ruff]
84
+ line-length = 80
85
+ target-version = "py311"
86
+
87
+ [tool.ruff.lint]
88
+ ignore = [
89
+ "E501",
90
+ "D100",
91
+ "D103",
92
+ "D104",
93
+ "D105",
94
+ "D107",
95
+ "D205",
96
+ "D415",
97
+ "TRY400",
98
+ "S311", # Disable rule 'Standard pseudo-random generators are not suitable for cryptographic purposes'.
99
+ # Bellow are rules disabled as they conflict with 'ruff format'.
100
+ # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
101
+ "W191",
102
+ "E111",
103
+ "E114",
104
+ "E117",
105
+ "D206",
106
+ "D300",
107
+ "Q000",
108
+ "Q001",
109
+ "Q002",
110
+ "Q003",
111
+ "COM812",
112
+ "COM819",
113
+ "ISC001",
114
+ "ISC002",
115
+ ]
116
+ select = ["ALL"]
117
+
118
+ [tool.ruff.lint.per-file-ignores]
119
+ "tests/*" = [
120
+ "S101", # Disable "Use of assert detected" rule.
121
+ "PLR2004", # Disable "Magic value used in comparison" rule.
122
+ "SLF001" # Disable "Private member accessed" rule.
123
+ ]
124
+
125
+ [tool.ruff.lint.pydocstyle]
126
+ convention = "google"
@@ -0,0 +1,18 @@
1
+ from genelastic.common 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)
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()
@@ -0,0 +1,6 @@
1
+ from flask import Response, jsonify
2
+
3
+
4
+ def ping_2() -> Response:
5
+ """Test route to verify that the server is online."""
6
+ return jsonify({"message": "pong_2"})
@@ -0,0 +1,20 @@
1
+ ---
2
+ paths:
3
+ /ping_2:
4
+ get:
5
+ operationId: genelastic.api.extends.example.ping_2
6
+ tags:
7
+ - Tests
8
+ summary: Vérification du statut du serveur
9
+ description: Route de test pour vérifier que le serveur est en ligne
10
+ responses:
11
+ 200:
12
+ description: Le serveur est en ligne
13
+ content:
14
+ application/json:
15
+ schema:
16
+ type: object
17
+ properties:
18
+ message:
19
+ type: string
20
+ example: pong_2
@@ -0,0 +1,221 @@
1
+ from importlib.metadata import version
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ from flask import Response, current_app, jsonify
6
+
7
+
8
+ def ping() -> Response:
9
+ """Test route to verify that the server is online."""
10
+ return jsonify({"message": "pong"})
11
+
12
+
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
+
17
+
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
+
36
+
37
+ def list_bi_processes() -> Response:
38
+ """Route to list bi processes."""
39
+ bi_processes_index = (
40
+ f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-bi_processes"
41
+ )
42
+ result = current_app.elastic_query_conn.get_field_values( # type: ignore[attr-defined]
43
+ bi_processes_index, "proc_id"
44
+ )
45
+ return jsonify(list(result))
46
+
47
+
48
+ def list_analyses() -> Response:
49
+ """Route to list analyses."""
50
+ analyses_index = f"{current_app.config['GENAPI_ES_INDEX_PREFIX']}-analyses"
51
+ result = current_app.elastic_query_conn.get_field_values( # type: ignore[attr-defined]
52
+ analyses_index, "path"
53
+ )
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
+
96
+ def list_snv_documents() -> Response:
97
+ """Route to list all documents containing a mutation at a single position (SNV)."""
98
+ index_pattern = "genelastic-file-*"
99
+ target_value = "SNV"
100
+
101
+ search_query = {
102
+ "aggs": {
103
+ "snv_docs": {
104
+ "composite": {
105
+ "sources": [
106
+ {"alt_value": {"terms": {"field": "alt.keyword"}}}
107
+ ],
108
+ "size": 1000,
109
+ }
110
+ }
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
+ )
132
+
133
+ all_documents.extend(response["hits"]["hits"])
134
+
135
+ return jsonify(all_documents)
136
+
137
+
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
+
171
+
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
+
177
+ response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
178
+ index=index_pattern, body=search_query
179
+ )
180
+
181
+ all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
182
+
183
+ return jsonify(all_documents)
184
+
185
+
186
+ def list_snv_deletion_documents() -> Response:
187
+ """Route to list all documents containing a deletion (DEL) at a single position (SNV)."""
188
+ index_pattern = "genelastic-file-*"
189
+ search_query = build_snv_search_query(target_alt="SNV", target_svtype="DEL")
190
+
191
+ response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
192
+ index=index_pattern, body=search_query
193
+ )
194
+
195
+ all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
196
+
197
+ return jsonify(all_documents)
198
+
199
+
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
+
205
+ search_query = build_snv_mutation_search_query(
206
+ target_svtypes=target_svtypes
207
+ )
208
+
209
+ response = current_app.elastic_query_conn.client.search( # type: ignore[attr-defined]
210
+ index=index_pattern, body=search_query
211
+ )
212
+
213
+ all_documents = [hit["_source"] for hit in response["hits"]["hits"]]
214
+
215
+ return jsonify(all_documents)
216
+
217
+
218
+ def get_genelastic_version() -> Response:
219
+ """Retourne la version du package genelastic."""
220
+ top_level_package = __package__.split(".")[0]
221
+ return jsonify({"version": version(top_level_package)})
@@ -0,0 +1,83 @@
1
+ from pathlib import Path
2
+ from typing import Any
3
+
4
+ import connexion
5
+ import yaml
6
+ from connexion import FlaskApp
7
+
8
+ from genelastic.common import ElasticQueryConn
9
+
10
+
11
+ def load_yaml(file_path: Path) -> Any: # noqa: ANN401
12
+ """Load a YAML file and return its content."""
13
+ content = None
14
+ with file_path.open(encoding="utf-8") as f:
15
+ try:
16
+ content = yaml.safe_load(f)
17
+ except yaml.YAMLError as exc:
18
+ raise SystemExit(exc) from exc
19
+ return content
20
+
21
+
22
+ def aggregate_openapi_specs(
23
+ main_spec_file: Path, additional_spec_path: Path
24
+ ) -> Any: # noqa: ANN401
25
+ """Aggregate OpenAPI specifications from a main file and a directory
26
+ of additional specifications.
27
+ """
28
+ main_spec = load_yaml(main_spec_file)
29
+ try:
30
+ entries = additional_spec_path.iterdir()
31
+ except OSError as exc:
32
+ raise SystemExit(exc) from exc
33
+
34
+ if "paths" not in main_spec:
35
+ main_spec["paths"] = []
36
+
37
+ for entry in entries:
38
+ if not entry.is_file():
39
+ continue
40
+
41
+ if entry.suffix not in [".yml", ".yaml"]:
42
+ continue
43
+
44
+ content = load_yaml(entry)
45
+
46
+ if "paths" in content:
47
+ main_spec["paths"].update(content["paths"])
48
+
49
+ return main_spec
50
+
51
+
52
+ def create_app() -> FlaskApp:
53
+ # Initialiser l'application Connexion
54
+ connexion_app = connexion.FlaskApp(__name__)
55
+ connexion_app.app.config.from_object("genelastic.api.settings")
56
+
57
+ # Initialiser le client Elasticsearch
58
+ es_url = connexion_app.app.config["GENAPI_ES_URL"]
59
+ es_cert_fp = connexion_app.app.config["GENAPI_ES_CERT_FP"]
60
+ es_api_key = connexion_app.app.config["GENAPI_ES_ENCODED_API_KEY"]
61
+
62
+ connexion_app.app.elastic_query_conn = ElasticQueryConn(
63
+ es_url, es_cert_fp, api_key=es_api_key
64
+ )
65
+
66
+ connexion_app.app.logger.debug(
67
+ "Successfully connected to Elasticsearch server: %s",
68
+ connexion_app.app.elastic_query_conn.client.info(),
69
+ )
70
+
71
+ # Chemins des fichiers YAML
72
+ main_yaml_file = Path(__file__).parents[0] / "specification.yml"
73
+ additional_yaml_dir = Path(__file__).parents[0] / "extends"
74
+
75
+ # Charger et combiner les fichiers YAML
76
+ yaml_spec = aggregate_openapi_specs(main_yaml_file, additional_yaml_dir)
77
+
78
+ # Ajouter la spécification vers OpenAPI
79
+ connexion_app.add_api(yaml_spec)
80
+ return connexion_app
81
+
82
+
83
+ app = create_app()
@@ -0,0 +1,10 @@
1
+ from environs import Env
2
+
3
+ env = Env()
4
+ env.read_env()
5
+
6
+ # Load required environment variables.
7
+ GENAPI_ES_URL = env.url("GENAPI_ES_URL").geturl()
8
+ GENAPI_ES_ENCODED_API_KEY = env.str("GENAPI_ES_ENCODED_API_KEY")
9
+ GENAPI_ES_INDEX_PREFIX = env.str("GENAPI_ES_INDEX_PREFIX")
10
+ GENAPI_ES_CERT_FP = env.str("GENAPI_ES_CERT_FP")