Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask_restx/utils.py: 35%
37 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
1import re
3from collections import OrderedDict
4from copy import deepcopy
6from ._http import HTTPStatus
9FIRST_CAP_RE = re.compile("(.)([A-Z][a-z]+)")
10ALL_CAP_RE = re.compile("([a-z0-9])([A-Z])")
13__all__ = (
14 "merge",
15 "camel_to_dash",
16 "default_id",
17 "not_none",
18 "not_none_sorted",
19 "unpack",
20)
23def merge(first, second):
24 """
25 Recursively merges two dictionaries.
27 Second dictionary values will take precedence over those from the first one.
28 Nested dictionaries are merged too.
30 :param dict first: The first dictionary
31 :param dict second: The second dictionary
32 :return: the resulting merged dictionary
33 :rtype: dict
34 """
35 if not isinstance(second, dict):
36 return second
37 result = deepcopy(first)
38 for key, value in second.items():
39 if key in result and isinstance(result[key], dict):
40 result[key] = merge(result[key], value)
41 else:
42 result[key] = deepcopy(value)
43 return result
46def camel_to_dash(value):
47 """
48 Transform a CamelCase string into a low_dashed one
50 :param str value: a CamelCase string to transform
51 :return: the low_dashed string
52 :rtype: str
53 """
54 first_cap = FIRST_CAP_RE.sub(r"\1_\2", value)
55 return ALL_CAP_RE.sub(r"\1_\2", first_cap).lower()
58def default_id(resource, method):
59 """Default operation ID generator"""
60 return "{0}_{1}".format(method, camel_to_dash(resource))
63def not_none(data):
64 """
65 Remove all keys where value is None
67 :param dict data: A dictionary with potentially some values set to None
68 :return: The same dictionary without the keys with values to ``None``
69 :rtype: dict
70 """
71 return dict((k, v) for k, v in data.items() if v is not None)
74def not_none_sorted(data):
75 """
76 Remove all keys where value is None
78 :param OrderedDict data: A dictionary with potentially some values set to None
79 :return: The same dictionary without the keys with values to ``None``
80 :rtype: OrderedDict
81 """
82 return OrderedDict((k, v) for k, v in sorted(data.items()) if v is not None)
85def unpack(response, default_code=HTTPStatus.OK):
86 """
87 Unpack a Flask standard response.
89 Flask response can be:
90 - a single value
91 - a 2-tuple ``(value, code)``
92 - a 3-tuple ``(value, code, headers)``
94 .. warning::
96 When using this function, you must ensure that the tuple is not the response data.
97 To do so, prefer returning list instead of tuple for listings.
99 :param response: A Flask style response
100 :param int default_code: The HTTP code to use as default if none is provided
101 :return: a 3-tuple ``(data, code, headers)``
102 :rtype: tuple
103 :raise ValueError: if the response does not have one of the expected format
104 """
105 if not isinstance(response, tuple):
106 # data only
107 return response, default_code, {}
108 elif len(response) == 1:
109 # data only as tuple
110 return response[0], default_code, {}
111 elif len(response) == 2:
112 # data and code
113 data, code = response
114 return data, code, {}
115 elif len(response) == 3:
116 # data, code and headers
117 data, code, headers = response
118 return data, code or default_code, headers
119 else:
120 raise ValueError("Too many response values")