Skip to content

Commit 1fb46ce

Browse files
authored
Type hinting (#214)
* refactor: add type hint flask module
1 parent e2ff4bf commit 1fb46ce

File tree

7 files changed

+45
-32
lines changed

7 files changed

+45
-32
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ py_ms.egg-info/*
1616
.eggs/*
1717
pylintReport.txt
1818
.scannerwork/
19+
.mypy_cache
1920

2021
# Deploy
2122
build/

pyms/flask/app/create_app.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def reload_conf(self):
205205
self.crypt.config.reload()
206206
self.create_app()
207207

208-
def create_app(self):
208+
def create_app(self) -> Flask:
209209
"""Initialize the Flask app, register blueprints and initialize
210210
all libraries like Swagger, database,
211211
the trace system...
@@ -234,13 +234,13 @@ def create_app(self):
234234

235235
return self.application
236236

237-
def add_error_handlers(self):
237+
def add_error_handlers(self) -> None:
238238
"""Subclasses will override this method in order to add specific error handlers. This should be done with
239239
calls to add_error_handler method.
240240
"""
241241
pass
242242

243-
def add_error_handler(self, code_or_exception, handler):
243+
def add_error_handler(self, code_or_exception, handler) -> None:
244244
"""Add custom handler for an error code or exception in the connexion app.
245245
246246
:param code_or_exception: HTTP error code or exception

pyms/flask/app/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class SingletonMeta(type):
1010
_instances: Dict[type, type] = {}
1111
_singleton = True
1212

13-
def __call__(cls, *args, **kwargs):
13+
def __call__(cls, *args, **kwargs) -> type:
1414
if cls not in cls._instances or not cls._singleton:
1515
cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)
1616
else:
@@ -32,7 +32,7 @@ def __init__(self, app):
3232
self.app = app
3333

3434
@staticmethod
35-
def _extract_prefix(environ):
35+
def _extract_prefix(environ: dict) -> str:
3636
"""
3737
Get Path from environment from:
3838
- Traefik with HTTP_X_SCRIPT_NAME https://docs.traefik.io/v2.0/middlewares/headers/

pyms/flask/services/metrics.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import time
22
import logging
3+
34
from typing import Text
45

5-
from flask import Blueprint, Response, request
6+
from flask import Blueprint, Response, request, Flask
67
from prometheus_client import multiprocess, Counter, Histogram, generate_latest, CollectorRegistry, REGISTRY
78
from pyms.flask.services.driver import DriverService
89

@@ -27,10 +28,10 @@ class FlaskMetricsWrapper():
2728
def __init__(self, app_name):
2829
self.app_name = app_name
2930

30-
def before_request(self): # pylint: disable=R0201
31+
def before_request(self) -> None: # pylint: disable=R0201
3132
request.start_time = time.time()
3233

33-
def after_request(self, response):
34+
def after_request(self, response: Response) -> Response:
3435
if hasattr(request.url_rule, "rule"):
3536
path = request.url_rule.rule
3637
else:
@@ -54,7 +55,7 @@ def __init__(self, *args, **kwargs):
5455
self.init_registry()
5556
self.serve_metrics()
5657

57-
def init_registry(self):
58+
def init_registry(self) -> None:
5859
try:
5960
multiprocess_registry = CollectorRegistry()
6061
multiprocess.MultiProcessCollector(multiprocess_registry)
@@ -63,7 +64,7 @@ def init_registry(self):
6364
self.registry = REGISTRY
6465

6566
@staticmethod
66-
def monitor(app_name, app):
67+
def monitor(app_name: str, app: Flask) -> None:
6768
metric = FlaskMetricsWrapper(app_name)
6869
app.before_request(metric.before_request)
6970
app.after_request(metric.after_request)
@@ -78,7 +79,7 @@ def metrics(): # pylint: disable=unused-variable
7879
)
7980

8081
@staticmethod
81-
def add_logger_handler(logger, service_name):
82+
def add_logger_handler(logger: logging.Logger, service_name: str) -> logging.Logger:
8283
logger.addHandler(MetricsLogHandler(service_name))
8384
return logger
8485

@@ -90,5 +91,5 @@ def __init__(self, app_name):
9091
super().__init__()
9192
self.app_name = app_name
9293

93-
def emit(self, record):
94+
def emit(self, record) -> None:
9495
LOGGER_TOTAL_MESSAGES.labels(self.app_name, record.levelname).inc()

pyms/flask/services/requests.py

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Encapsulate common rest operations between business services propagating trace headers if configured.
22
"""
33
import logging
4+
from typing import Any
45

56
import requests
67
from flask import request
7-
from requests.adapters import HTTPAdapter
8+
from requests.adapters import HTTPAdapter, Response
89
from urllib3.util.retry import Retry
910

1011
from pyms.constants import LOGGER_NAME
@@ -18,8 +19,8 @@
1819
DEFAULT_STATUS_RETRIES = (500, 502, 504)
1920

2021

21-
def retry(f):
22-
def wrapper(*args, **kwargs):
22+
def retry(f) -> Any:
23+
def wrapper(*args, **kwargs) -> Any:
2324
response = False
2425
i = 0
2526
response_ok = False
@@ -53,7 +54,7 @@ class Service(DriverService):
5354
}
5455
tracer = None
5556

56-
def requests(self, session: requests.Session):
57+
def requests(self, session: requests.Session) -> requests.Session:
5758
"""
5859
A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
5960
second try without a delay). urllib3 will sleep for: {backoff factor} * (2 ^ ({number of total retries} - 1))
@@ -113,7 +114,7 @@ def _get_headers(self, headers: dict, propagate_headers: bool = False) -> dict:
113114
return headers
114115

115116
@staticmethod
116-
def _build_url(url, path_params=None):
117+
def _build_url(url, path_params: dict = None) -> str:
117118
"""Compose full url replacing placeholders with path_params values.
118119
119120
:param url: base url
@@ -124,7 +125,7 @@ def _build_url(url, path_params=None):
124125

125126
return url.format_map(path_params)
126127

127-
def parse_response(self, response):
128+
def parse_response(self, response: Response) -> dict:
128129
"""Parses response's json object. Checks configuration in order to parse a concrete node or the whole response.
129130
130131
:param response: request's response that contains a valid json
@@ -142,7 +143,8 @@ def parse_response(self, response):
142143
return {}
143144

144145
@retry
145-
def get(self, url, path_params=None, params=None, headers=None, propagate_headers=False, **kwargs):
146+
def get(self, url: str, path_params: dict = None, params: dict = None, headers: dict = None,
147+
propagate_headers: bool = False, **kwargs) -> Response:
146148
"""Sends a GET request.
147149
148150
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -167,7 +169,8 @@ def get(self, url, path_params=None, params=None, headers=None, propagate_header
167169

168170
return response
169171

170-
def get_for_object(self, url, path_params=None, params=None, headers=None, **kwargs):
172+
def get_for_object(self, url: str, path_params: dict = None, params: dict = None, headers: dict = None,
173+
**kwargs) -> dict:
171174
"""Sends a GET request and returns the json representation found in response's content data node.
172175
173176
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -184,7 +187,8 @@ def get_for_object(self, url, path_params=None, params=None, headers=None, **kwa
184187
return self.parse_response(response)
185188

186189
@retry
187-
def post(self, url, path_params=None, data=None, json=None, headers=None, **kwargs):
190+
def post(self, url: str, path_params: dict = None, data: dict = None, json: dict = None, headers: dict = None,
191+
**kwargs) -> Response:
188192
"""Sends a POST request.
189193
190194
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -210,7 +214,8 @@ def post(self, url, path_params=None, data=None, json=None, headers=None, **kwar
210214

211215
return response
212216

213-
def post_for_object(self, url, path_params=None, data=None, json=None, headers=None, **kwargs):
217+
def post_for_object(self, url: str, path_params: dict = None, data: dict = None, json: dict = None,
218+
headers: dict = None, **kwargs) -> dict:
214219
"""Sends a POST request and returns the json representation found in response's content data node.
215220
216221
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -228,7 +233,7 @@ def post_for_object(self, url, path_params=None, data=None, json=None, headers=N
228233
return self.parse_response(response)
229234

230235
@retry
231-
def put(self, url, path_params=None, data=None, headers=None, **kwargs):
236+
def put(self, url: str, path_params: dict = None, data: dict = None, headers: dict = None, **kwargs) -> Response:
232237
"""Sends a PUT request.
233238
234239
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -254,7 +259,8 @@ def put(self, url, path_params=None, data=None, headers=None, **kwargs):
254259

255260
return response
256261

257-
def put_for_object(self, url, path_params=None, data=None, headers=None, **kwargs):
262+
def put_for_object(self, url: str, path_params: dict = None, data: dict = None, headers: dict = None,
263+
**kwargs) -> dict:
258264
"""Sends a PUT request and returns the json representation found in response's content data node.
259265
260266
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -272,7 +278,7 @@ def put_for_object(self, url, path_params=None, data=None, headers=None, **kwarg
272278
return self.parse_response(response)
273279

274280
@retry
275-
def patch(self, url, path_params=None, data=None, headers=None, **kwargs):
281+
def patch(self, url: str, path_params: dict = None, data: dict = None, headers: dict = None, **kwargs) -> Response:
276282
"""Sends a PATCH request.
277283
278284
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -298,7 +304,8 @@ def patch(self, url, path_params=None, data=None, headers=None, **kwargs):
298304

299305
return response
300306

301-
def patch_for_object(self, url, path_params=None, data=None, headers=None, **kwargs):
307+
def patch_for_object(self, url: str, path_params: dict = None, data: dict = None, headers: dict = None,
308+
**kwargs) -> dict:
302309
"""Sends a PATCH request and returns the json representation found in response's content data node.
303310
304311
:param url: URL for the new :class:`Request` object. Could contain path parameters
@@ -316,7 +323,7 @@ def patch_for_object(self, url, path_params=None, data=None, headers=None, **kwa
316323
return self.parse_response(response)
317324

318325
@retry
319-
def delete(self, url, path_params=None, headers=None, **kwargs):
326+
def delete(self, url: str, path_params: dict = None, headers: dict = None, **kwargs) -> Response:
320327
"""Sends a DELETE request.
321328
322329
:param url: URL for the new :class:`Request` object. Could contain path parameters

pyms/flask/services/swagger.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from pathlib import Path
33
from typing import Dict, Any
44

5+
from flask import Flask
6+
57
import connexion
68
from connexion.resolver import RestyResolver
79

@@ -33,7 +35,7 @@ def get_bundled_specs(main_file: Path) -> Dict[str, Any]:
3335
return parser.specification
3436

3537

36-
def merge_swagger_file(main_file: str):
38+
def merge_swagger_file(main_file: str) -> None:
3739
"""
3840
Generate swagger into a single file
3941
:param main_file: Swagger file path
@@ -71,14 +73,14 @@ class Service(DriverService):
7173
}
7274

7375
@staticmethod
74-
def _get_application_root(config):
76+
def _get_application_root(config) -> str:
7577
try:
7678
application_root = config.APPLICATION_ROOT
7779
except AttrDoesNotExistException:
7880
application_root = "/"
7981
return application_root
8082

81-
def init_app(self, config, path):
83+
def init_app(self, config, path: Path) -> Flask:
8284
"""
8385
Initialize Connexion App. See more info in [Connexion Github](https://github.com/zalando/connexion)
8486
:param config: The Flask configuration defined in the config.yaml:

pyms/flask/services/tracer.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
from typing import Union
3+
24

35
try:
46
import opentracing
@@ -28,7 +30,7 @@
2830
DEFAULT_CLIENT = JAEGER_CLIENT
2931

3032

31-
def inject_span_in_headers(headers):
33+
def inject_span_in_headers(headers: dict) -> dict:
3234
if has_request_context():
3335
# FLASK https://github.com/opentracing-contrib/python-flask
3436
tracer = current_app.tracer if getattr(current_app, "tracer") else None
@@ -56,7 +58,7 @@ class Service(DriverService):
5658
"client": DEFAULT_CLIENT,
5759
}
5860

59-
def get_client(self):
61+
def get_client(self) -> Union[bool, type]:
6062
opentracing_tracer = False
6163
if self.config.client == JAEGER_CLIENT:
6264
opentracing_tracer = self.init_jaeger_tracer()

0 commit comments

Comments
 (0)