genelastic 0.7.0__py3-none-any.whl → 0.8.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.
@@ -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,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
genelastic/api/server.py CHANGED
@@ -3,6 +3,7 @@ from typing import Any
3
3
 
4
4
  import connexion
5
5
  import yaml
6
+ from connexion import FlaskApp
6
7
 
7
8
  from genelastic.common import ElasticQueryConn
8
9
 
@@ -10,7 +11,7 @@ from genelastic.common import ElasticQueryConn
10
11
  def load_yaml(file_path: Path) -> Any: # noqa: ANN401
11
12
  """Load a YAML file and return its content."""
12
13
  content = None
13
- with Path.open(file_path, encoding="utf-8") as f:
14
+ with file_path.open(encoding="utf-8") as f:
14
15
  try:
15
16
  content = yaml.safe_load(f)
16
17
  except yaml.YAMLError as exc:
@@ -48,33 +49,35 @@ def aggregate_openapi_specs(
48
49
  return main_spec
49
50
 
50
51
 
51
- # Initialiser l'application Connexion
52
- connexion_app = connexion.FlaskApp(__name__)
53
- connexion_app.app.config.from_object("src.genelastic.api.settings.Config")
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")
54
56
 
55
- # Initialiser le client Elasticsearch
56
- es_url = connexion_app.app.config["GENAPI_ES_URL"]
57
- es_cert_fp = connexion_app.app.config["GENAPI_ES_CERT_FP"]
58
- es_api_key = connexion_app.app.config["GENAPI_ES_ENCODED_API_KEY"]
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"]
59
61
 
60
- connexion_app.app.elastic_query_conn = ElasticQueryConn(
61
- es_url, es_cert_fp, api_key=es_api_key
62
- )
62
+ connexion_app.app.elastic_query_conn = ElasticQueryConn(
63
+ es_url, es_cert_fp, api_key=es_api_key
64
+ )
63
65
 
64
- connexion_app.app.logger.debug(
65
- "Successfully connected to Elasticsearch server: %s",
66
- connexion_app.app.elastic_query_conn.client.info(),
67
- )
66
+ connexion_app.app.logger.debug(
67
+ "Successfully connected to Elasticsearch server: %s",
68
+ connexion_app.app.elastic_query_conn.client.info(),
69
+ )
68
70
 
69
- # Chemins des fichiers YAML
70
- main_yaml_file = Path(__file__).parents[0] / "specification.yml"
71
- additional_yaml_dir = Path(__file__).parents[0] / "extends"
71
+ # Chemins des fichiers YAML
72
+ main_yaml_file = Path(__file__).parents[0] / "specification.yml"
73
+ additional_yaml_dir = Path(__file__).parents[0] / "extends"
72
74
 
73
- # Charger et combiner les fichiers YAML
74
- yaml_spec = aggregate_openapi_specs(main_yaml_file, additional_yaml_dir)
75
+ # Charger et combiner les fichiers YAML
76
+ yaml_spec = aggregate_openapi_specs(main_yaml_file, additional_yaml_dir)
75
77
 
76
- # Ajouter la spécification vers OpenAPI
77
- connexion_app.add_api(yaml_spec)
78
+ # Ajouter la spécification vers OpenAPI
79
+ connexion_app.add_api(yaml_spec)
80
+ return connexion_app
78
81
 
79
- if __name__ == "__main__":
80
- connexion_app.run(debug=True)
82
+
83
+ app = create_app()
@@ -3,12 +3,8 @@ from environs import Env
3
3
  env = Env()
4
4
  env.read_env()
5
5
 
6
-
7
- class Config:
8
- """Flask config class."""
9
-
10
- # Charger toutes les variables d'environnement nécessaires
11
- GENAPI_ES_URL = env.url("GENAPI_ES_URL").geturl()
12
- GENAPI_ES_ENCODED_API_KEY = env.str("GENAPI_ES_ENCODED_API_KEY")
13
- GENAPI_ES_INDEX_PREFIX = env.str("GENAPI_ES_INDEX_PREFIX")
14
- GENAPI_ES_CERT_FP = env.str("GENAPI_ES_CERT_FP")
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")
@@ -0,0 +1,350 @@
1
+ ---
2
+ openapi: "3.0.3"
3
+ info:
4
+ description: This is the swagger file for our API
5
+ version: "1.0.1"
6
+ title: Swagger for ReST API
7
+ servers:
8
+ - url: "/api"
9
+
10
+ paths:
11
+ /ping:
12
+ get:
13
+ operationId: genelastic.api.routes.ping
14
+ tags:
15
+ - Tests
16
+ summary: Server status check
17
+ description: Test route to verify that the server is online
18
+ responses:
19
+ 200:
20
+ description: The server is online
21
+ content:
22
+ application/json:
23
+ schema:
24
+ type: object
25
+ properties:
26
+ message:
27
+ type: string
28
+ example: pong
29
+
30
+ /indices:
31
+ get:
32
+ operationId: genelastic.api.routes.list_indices
33
+ tags:
34
+ - Indexes
35
+ summary: Listing the indexes present in Elasticsearch
36
+ description: Listing the indexes present in Elasticsearch
37
+ responses:
38
+ 200:
39
+ description: Success of the request
40
+ content:
41
+ application/json:
42
+ schema:
43
+ type: object
44
+ 400:
45
+ description: The server could not understand the request due to invalid syntax.
46
+ 500:
47
+ description: Internal server error
48
+
49
+ /indices/{index_id}/documents/{document_id}:
50
+ get:
51
+ operationId: genelastic.api.routes.retrieve_document
52
+ parameters:
53
+ - in: path
54
+ name: index_id
55
+ schema:
56
+ type: string
57
+ required: true
58
+ description: The index in which to search for the document
59
+ - in: path
60
+ name: document_id
61
+ schema:
62
+ type: string
63
+ required: true
64
+ description: The ID of the document to retrieve
65
+ tags:
66
+ - Document
67
+ summary: Retrieve a document
68
+ description: Retrieve a specific document from Elasticsearch
69
+ responses:
70
+ 200:
71
+ description: Success in reading the data
72
+ content:
73
+ application/json:
74
+ schema:
75
+ type: object
76
+ 404:
77
+ description: Document not found
78
+ 500:
79
+ description: Internal server error
80
+
81
+ /wet_processes:
82
+ get:
83
+ operationId: genelastic.api.routes.list_wet_processes
84
+ summary: Retrieve a list of wet processes
85
+ tags:
86
+ - Wet processes
87
+ responses:
88
+ 200:
89
+ description: List of wet processes
90
+ content:
91
+ application/json:
92
+ schema:
93
+ type: array
94
+
95
+ /bi_processes:
96
+ get:
97
+ operationId: genelastic.api.routes.list_bi_processes
98
+ summary: Retrieve a list of bi processes
99
+ tags:
100
+ - Bi processes
101
+ responses:
102
+ 200:
103
+ description: List of bi processes
104
+ content:
105
+ application/json:
106
+ schema:
107
+ type: array
108
+
109
+ /analyses:
110
+ get:
111
+ operationId: genelastic.api.routes.list_analyses
112
+ summary: Retrieve a list of analyses
113
+ tags:
114
+ - Analyses
115
+ responses:
116
+ 200:
117
+ description: List of analyses
118
+ content:
119
+ application/json:
120
+ schema:
121
+ type: string
122
+
123
+ /wet_process/{proc_id}:
124
+ get:
125
+ operationId: genelastic.api.routes.list_analyses_wet_processes
126
+ summary: Retrieve a list of analyses of one specific wet process
127
+ tags:
128
+ - Analyses
129
+ parameters:
130
+ - in: path
131
+ name: proc_id
132
+ schema:
133
+ type: string
134
+ required: true
135
+ description: Wet process ID
136
+ responses:
137
+ 200:
138
+ description: List of wet processes
139
+ content:
140
+ application/json:
141
+ schema:
142
+ type: array
143
+ items:
144
+ type: string
145
+
146
+ /bi_process/{proc_id}:
147
+ get:
148
+ operationId: genelastic.api.routes.list_analyses_bi_processes
149
+ summary: Retrieve a list of analyses of one specific bi process
150
+ tags:
151
+ - Analyses
152
+ parameters:
153
+ - in: path
154
+ name: proc_id
155
+ schema:
156
+ type: string
157
+ required: true
158
+ description: Bi process ID
159
+ responses:
160
+ 200:
161
+ description: List of bi processes
162
+ content:
163
+ application/json:
164
+ schema:
165
+ type: array
166
+ items:
167
+ type: string
168
+
169
+ /snvs_documents:
170
+ get:
171
+ operationId: genelastic.api.routes.list_snv_documents
172
+ summary: Retrieve all documents containing an insertion (INS), a deletion (DEL) or a mutation
173
+ at a single position (SNV)
174
+ tags:
175
+ - Documents
176
+ responses:
177
+ 200:
178
+ description: Complete list of documents containing an insertion (INS), a deletion (DEL) or a mutation
179
+ at a single position (SNV)
180
+ content:
181
+ application/json:
182
+ schema:
183
+ type: array
184
+ items:
185
+ type: object
186
+ properties:
187
+ type:
188
+ type: string
189
+ chr:
190
+ type: string
191
+ pos:
192
+ type: integer
193
+ alt:
194
+ type: array
195
+ items:
196
+ type: string
197
+ info:
198
+ type: object
199
+ additionalProperties:
200
+ type: string
201
+ 400:
202
+ description: Invalid request
203
+ 500:
204
+ description: Internal server error
205
+
206
+ /snvs_insertion_documents:
207
+ get:
208
+ operationId: genelastic.api.routes.list_snv_insertion_documents
209
+ summary: Retrieve all documents containing an insertion (INS) at a single position (SNV)
210
+ tags:
211
+ - Documents
212
+ responses:
213
+ 200:
214
+ description: Complete list of documents containing an insertion (INS) at a single position (SNV)
215
+ content:
216
+ application/json:
217
+ schema:
218
+ type: array
219
+ items:
220
+ type: object
221
+ properties:
222
+ type:
223
+ type: string
224
+ chr:
225
+ type: string
226
+ pos:
227
+ type: integer
228
+ alt:
229
+ type: array
230
+ items:
231
+ type: string
232
+ info:
233
+ type: object
234
+ properties:
235
+ SVTYPE:
236
+ type: string
237
+ END:
238
+ type: integer
239
+ SVLEN:
240
+ type: array
241
+ items:
242
+ type: integer
243
+ 400:
244
+ description: Invalid request
245
+ 500:
246
+ description: Internal server error
247
+
248
+ /snvs_deletion_documents:
249
+ get:
250
+ operationId: genelastic.api.routes.list_snv_deletion_documents
251
+ summary: Retrieve all documents containing a deletion (DEL) at a single position (SNV)
252
+ tags:
253
+ - Documents
254
+ responses:
255
+ 200:
256
+ description: Complete list of documents containing a deletion (DEL) at a single position (SNV)
257
+ content:
258
+ application/json:
259
+ schema:
260
+ type: array
261
+ items:
262
+ type: object
263
+ properties:
264
+ type:
265
+ type: string
266
+ chr:
267
+ type: string
268
+ pos:
269
+ type: integer
270
+ alt:
271
+ type: array
272
+ items:
273
+ type: string
274
+ info:
275
+ type: object
276
+ properties:
277
+ SVTYPE:
278
+ type: string
279
+ END:
280
+ type: integer
281
+ SVLEN:
282
+ type: array
283
+ items:
284
+ type: integer
285
+ 400:
286
+ description: Invalid request
287
+ 500:
288
+ description: Internal server error
289
+
290
+ /snvs_mutation_documents:
291
+ get:
292
+ operationId: genelastic.api.routes.list_snv_mutation_documents
293
+ summary: Retrieve all documents containing a mutation at a single position (SNV)
294
+ tags:
295
+ - Documents
296
+ responses:
297
+ 200:
298
+ description: Complete list of documents containing a mutation at a single position (SNV)
299
+ content:
300
+ application/json:
301
+ schema:
302
+ type: array
303
+ items:
304
+ type: object
305
+ properties:
306
+ type:
307
+ type: string
308
+ chr:
309
+ type: string
310
+ pos:
311
+ type: integer
312
+ alt:
313
+ type: array
314
+ items:
315
+ type: string
316
+ info:
317
+ type: object
318
+ properties:
319
+ SVTYPE:
320
+ type: string
321
+ END:
322
+ type: integer
323
+ SVLEN:
324
+ type: array
325
+ items:
326
+ type: integer
327
+ 400:
328
+ description: Invalid request due to incorrect parameters or format
329
+ 500:
330
+ description: Internal server error
331
+
332
+
333
+ /version:
334
+ get:
335
+ operationId: genelastic.api.routes.get_genelastic_version
336
+ tags:
337
+ - Version
338
+ summary: Get the genelastic package version
339
+ description: Return the installed version of the genelastic package
340
+ responses:
341
+ 200:
342
+ description: Success
343
+ content:
344
+ application/json:
345
+ schema:
346
+ type: object
347
+ properties:
348
+ version:
349
+ type: string
350
+ example: "1.0.0"
@@ -1,6 +1,10 @@
1
1
  """Genelastic package for common code between API and import scripts."""
2
2
 
3
- from .cli import add_es_connection_args, add_verbose_control_args
3
+ from .cli import (
4
+ add_es_connection_args,
5
+ add_verbose_control_args,
6
+ parse_server_launch_args,
7
+ )
4
8
  from .elastic import ElasticImportConn, ElasticQueryConn
5
9
  from .exceptions import DBIntegrityError
6
10
  from .types import (
@@ -36,4 +40,5 @@ __all__ = [
36
40
  "WetProcessesData",
37
41
  "add_es_connection_args",
38
42
  "add_verbose_control_args",
43
+ "parse_server_launch_args",
39
44
  ]
genelastic/common/cli.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  import argparse
4
4
 
5
+ BASE_LOG_LEVEL = ["critical", "error", "warning", "info", "debug"]
6
+
5
7
 
6
8
  def add_verbose_control_args(parser: argparse.ArgumentParser) -> None:
7
9
  """Add verbose control arguments to the parser.
@@ -61,3 +63,53 @@ def add_es_connection_args(parser: argparse.ArgumentParser) -> None:
61
63
  dest="es_index_prefix",
62
64
  help="Add the given prefix to each index created during import.",
63
65
  )
66
+
67
+
68
+ def parse_server_launch_args(
69
+ parser_desc: str, default_port: int
70
+ ) -> argparse.Namespace:
71
+ parser = argparse.ArgumentParser(
72
+ description=parser_desc,
73
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
74
+ allow_abbrev=False,
75
+ )
76
+ parser.add_argument(
77
+ "--host",
78
+ type=str,
79
+ default="127.0.0.1",
80
+ )
81
+ parser.add_argument(
82
+ "--port",
83
+ type=int,
84
+ default=default_port,
85
+ )
86
+
87
+ env_subparsers = parser.add_subparsers(dest="env", required=True)
88
+ dev_parser = env_subparsers.add_parser(
89
+ "dev",
90
+ help="Use development environment.",
91
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
92
+ )
93
+ dev_parser.add_argument(
94
+ "--log-level",
95
+ type=str,
96
+ default="info",
97
+ choices=[*BASE_LOG_LEVEL, "trace"],
98
+ )
99
+
100
+ prod_parser = env_subparsers.add_parser(
101
+ "prod",
102
+ help="Use production environment.",
103
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
104
+ )
105
+ prod_parser.add_argument(
106
+ "--log-level", type=str, default="info", choices=BASE_LOG_LEVEL
107
+ )
108
+ prod_parser.add_argument(
109
+ "-w", "--workers", type=int, default=1, help="Number of workers."
110
+ )
111
+
112
+ prod_parser.add_argument("--access-logfile", type=str, default=None)
113
+ prod_parser.add_argument("--log-file", type=str, default=None)
114
+
115
+ return parser.parse_args()
@@ -0,0 +1,51 @@
1
+ import argparse
2
+ import subprocess
3
+ import sys
4
+
5
+ import uvicorn
6
+
7
+
8
+ def start_dev_server(app_module: str, args: argparse.Namespace) -> None:
9
+ """Start the development server using Uvicorn.
10
+ :args app_module: The module containing the Flask server to start.
11
+ :args argparse.Namespace: The parsed arguments.
12
+ """
13
+ uvicorn.run(
14
+ app_module,
15
+ host=args.host,
16
+ port=args.port,
17
+ log_level=args.log_level,
18
+ reload=True,
19
+ )
20
+
21
+
22
+ def start_prod_server(app_module: str, args: argparse.Namespace) -> None:
23
+ """Start the production server using Gunicorn.
24
+ It will spawn one primary process and workers
25
+ :args app_module: The module containing the Flask server to start.
26
+ :args argparse.Namespace: The parsed arguments.
27
+ :raises subprocess.CalledProcessError: If gunicorn exits with a non-zero status code.
28
+ """
29
+ cmd = [
30
+ sys.executable,
31
+ "-m",
32
+ "gunicorn",
33
+ "-k",
34
+ "uvicorn.workers.UvicornWorker",
35
+ "--workers",
36
+ str(args.workers),
37
+ "--log-level",
38
+ args.log_level,
39
+ "-b",
40
+ f"{args.host}:{args.port}",
41
+ "--capture-output",
42
+ app_module,
43
+ ]
44
+
45
+ if args.log_file:
46
+ cmd.extend(["--log-file", args.log_file])
47
+
48
+ if args.access_logfile:
49
+ cmd.extend(["--access-logfile", args.access_logfile])
50
+
51
+ subprocess.run(cmd, check=True) # noqa: S603