MambuPy 2.1.0__tar.gz → 2.1.1__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.
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/__init__.py +1 -1
- {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/api/connector/rest.py +81 -23
- {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/mambuconfig.py +9 -0
- {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/mambuutil.py +2 -2
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuclient.py +1 -1
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburestutils.py +0 -3
- {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/rest/mambustruct.py +1 -1
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/PKG-INFO +5 -4
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/requires.txt +1 -1
- {mambupy-2.1.0 → mambupy-2.1.1}/PKG-INFO +5 -4
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/__init__.py +1 -1
- {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/api/connector/rest.py +81 -23
- {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/mambuconfig.py +9 -0
- {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/mambuutil.py +2 -2
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuclient.py +1 -1
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburestutils.py +0 -3
- {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/rest/mambustruct.py +1 -1
- {mambupy-2.1.0 → mambupy-2.1.1}/pyproject.toml +8 -3
- {mambupy-2.1.0 → mambupy-2.1.1}/LICENSE +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/classes.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/connector/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/connector/mambuconnector.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/entities.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/interfaces.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambubranch.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambucentre.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuclient.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambucustomfield.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambugroup.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuloan.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuproduct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mamburole.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambustruct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambutask.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambutransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuuser.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/vos.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/mambugeturl.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_activities.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_addresses.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_branches.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_centres.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_clients.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_customfields.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_dummies.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_groups.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_loans.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_mambu.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_orm.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_tasks.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_users.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuactivity.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambubranch.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambucentre.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambugroup.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuloan.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuproduct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburepayment.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburoles.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusaving.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusavingfundingrepayment.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusavingtransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutask.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutransactionchannel.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuuser.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/utils/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/utils/userdeactivate.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/SOURCES.txt +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/dependency_links.txt +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/top_level.txt +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/README.md +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/classes.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/connector/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/connector/mambuconnector.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/entities.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/interfaces.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambubranch.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambucentre.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuclient.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambucustomfield.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambugroup.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuloan.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuproduct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mamburole.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambustruct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambutask.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambutransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuuser.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/vos.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/mambugeturl.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_activities.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_addresses.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_branches.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_centres.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_clients.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_customfields.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_dummies.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_groups.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_loans.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_mambu.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_orm.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_tasks.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_users.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuactivity.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambubranch.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambucentre.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambugroup.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuloan.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuproduct.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburepayment.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburoles.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusaving.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusavingfundingrepayment.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusavingtransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutask.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutransaction.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutransactionchannel.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuuser.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/utils/__init__.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/utils/userdeactivate.py +0 -0
- {mambupy-2.1.0 → mambupy-2.1.1}/setup.cfg +0 -0
|
@@ -36,12 +36,82 @@ from MambuPy.mambuutil import (
|
|
|
36
36
|
apiurl,
|
|
37
37
|
apiuser,
|
|
38
38
|
setup_logging,
|
|
39
|
+
activate_request_session_objects,
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
logger = setup_logging(__name__)
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _configure_retry_strategy(session, retries=5):
|
|
47
|
+
"""Configure retry strategy for a session.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
session (requests.Session): The session to configure
|
|
51
|
+
retries (int, optional): Number of retries. Defaults to 5.
|
|
52
|
+
"""
|
|
53
|
+
retry_strategy = Retry(
|
|
54
|
+
total=retries,
|
|
55
|
+
status_forcelist=[429, 500, 502, 503, 504],
|
|
56
|
+
backoff_factor=1,
|
|
57
|
+
allowed_methods=[
|
|
58
|
+
"HEAD",
|
|
59
|
+
"GET",
|
|
60
|
+
"OPTIONS",
|
|
61
|
+
"POST",
|
|
62
|
+
"PUT",
|
|
63
|
+
"DELETE",
|
|
64
|
+
"TRACE",
|
|
65
|
+
"PATCH",
|
|
66
|
+
],
|
|
67
|
+
)
|
|
68
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
69
|
+
session.mount("https://", adapter)
|
|
70
|
+
session.mount("http://", adapter)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SessionSingleton:
|
|
74
|
+
"""Singleton class to manage HTTP sessions for MambuPy.
|
|
75
|
+
|
|
76
|
+
This class ensures that only one requests.Session object is created and reused
|
|
77
|
+
across all requests to the Mambu API. This helps improve performance by reusing
|
|
78
|
+
TCP connections.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
>>> session = SessionSingleton()
|
|
82
|
+
>>> session.get_session() # Returns a requests.Session object
|
|
83
|
+
>>> session2 = SessionSingleton()
|
|
84
|
+
>>> session2.get_session() # Returns the same requests.Session object
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
__instance = None
|
|
88
|
+
__session = None
|
|
89
|
+
_RETRIES = 5
|
|
90
|
+
|
|
91
|
+
def __new__(cls):
|
|
92
|
+
"""Create a new instance of SessionSingleton if one doesn't exist.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
SessionSingleton: The singleton instance.
|
|
96
|
+
"""
|
|
97
|
+
if cls.__instance is None:
|
|
98
|
+
cls.__instance = super(SessionSingleton, cls).__new__(cls)
|
|
99
|
+
return cls.__instance
|
|
100
|
+
|
|
101
|
+
def get_session(self):
|
|
102
|
+
"""Get the requests.Session object.
|
|
103
|
+
|
|
104
|
+
If no session exists, create a new one. Otherwise, return the existing one.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
requests.Session: The session object to use for HTTP requests.
|
|
108
|
+
"""
|
|
109
|
+
if self.__session is None:
|
|
110
|
+
self.__session = requests.Session()
|
|
111
|
+
_configure_retry_strategy(self.__session, self._RETRIES)
|
|
112
|
+
return self.__session
|
|
113
|
+
|
|
114
|
+
|
|
45
115
|
class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWriter):
|
|
46
116
|
"""A connector for Mambu REST API"""
|
|
47
117
|
|
|
@@ -55,6 +125,9 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
|
|
|
55
125
|
}
|
|
56
126
|
self.__set_authorization_header(user, pwd)
|
|
57
127
|
self.__set_url(url)
|
|
128
|
+
self._session = None
|
|
129
|
+
if activate_request_session_objects.lower() == "true":
|
|
130
|
+
self._session = SessionSingleton().get_session()
|
|
58
131
|
|
|
59
132
|
def __set_authorization_header(self, user, pwd):
|
|
60
133
|
self._headers["Authorization"] = "Basic {}".format(
|
|
@@ -108,26 +181,6 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
|
|
|
108
181
|
params = self.__request_params(params)
|
|
109
182
|
data = self.__request_data(data)
|
|
110
183
|
|
|
111
|
-
retry_strategy = Retry(
|
|
112
|
-
total=self._RETRIES,
|
|
113
|
-
status_forcelist=[429, 500, 502, 503, 504],
|
|
114
|
-
backoff_factor=1,
|
|
115
|
-
allowed_methods=[
|
|
116
|
-
"HEAD",
|
|
117
|
-
"GET",
|
|
118
|
-
"OPTIONS",
|
|
119
|
-
"POST",
|
|
120
|
-
"PUT",
|
|
121
|
-
"DELETE",
|
|
122
|
-
"TRACE",
|
|
123
|
-
"PATCH",
|
|
124
|
-
],
|
|
125
|
-
)
|
|
126
|
-
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
127
|
-
http = requests.Session()
|
|
128
|
-
http.mount("https://", adapter)
|
|
129
|
-
http.mount("http://", adapter)
|
|
130
|
-
|
|
131
184
|
resp = ""
|
|
132
185
|
try:
|
|
133
186
|
logger.debug(
|
|
@@ -139,10 +192,15 @@ url %s, params %s, data %s, headers %s",
|
|
|
139
192
|
data,
|
|
140
193
|
[(k, v) for k, v in headers.items() if k != "Authorization"],
|
|
141
194
|
)
|
|
142
|
-
|
|
195
|
+
if self._session:
|
|
196
|
+
resp = self._session.request(method, url, params=params, data=data, headers=headers)
|
|
197
|
+
else:
|
|
198
|
+
http = requests.Session()
|
|
199
|
+
_configure_retry_strategy(http, self._RETRIES)
|
|
200
|
+
resp = http.request(method, url, params=params, data=data, headers=headers)
|
|
143
201
|
resp.raise_for_status()
|
|
144
202
|
except requests.exceptions.HTTPError as httperr:
|
|
145
|
-
logger.
|
|
203
|
+
logger.warning(
|
|
146
204
|
"%s on %s request: params %s, data %s, headers %s",
|
|
147
205
|
str(httperr),
|
|
148
206
|
method,
|
|
@@ -151,7 +209,7 @@ url %s, params %s, data %s, headers %s",
|
|
|
151
209
|
[(k, v) for k, v in headers.items() if k != "Authorization"],
|
|
152
210
|
)
|
|
153
211
|
if hasattr(resp, "content"): # pragma: no cover
|
|
154
|
-
logger.
|
|
212
|
+
logger.warning("HTTPError, resp content: %s", resp.content)
|
|
155
213
|
try:
|
|
156
214
|
content = json.loads(resp.content.decode())
|
|
157
215
|
except ValueError:
|
|
@@ -24,6 +24,7 @@ RC files must have the following format:
|
|
|
24
24
|
apiuser=API_user
|
|
25
25
|
apipwd=API_password
|
|
26
26
|
apipagination=API_pagination_limit
|
|
27
|
+
activate_request_session_objects=API_persistent_session
|
|
27
28
|
[DB]
|
|
28
29
|
dbname=Database_name
|
|
29
30
|
dbuser=Database_user
|
|
@@ -75,6 +76,10 @@ user on your Mambu instance
|
|
|
75
76
|
|
|
76
77
|
The db* configs refer to Database configurations which hold a backup of
|
|
77
78
|
your Mambu Database on some server.
|
|
79
|
+
|
|
80
|
+
The activate_request_session_objects config enables or disables HTTP persistent sessions
|
|
81
|
+
for API requests. When enabled, it will reuse the same TCP connection for
|
|
82
|
+
multiple requests, improving performance. Default is False.
|
|
78
83
|
"""
|
|
79
84
|
|
|
80
85
|
default_configs = {
|
|
@@ -83,6 +88,7 @@ default_configs = {
|
|
|
83
88
|
"apiuser": "mambu_api_user",
|
|
84
89
|
"apipwd": "mambu_api_password",
|
|
85
90
|
"apipagination": "50",
|
|
91
|
+
"activate_request_session_objects": "False",
|
|
86
92
|
# Mambu DB configurations
|
|
87
93
|
"dbname": "mambu_db",
|
|
88
94
|
"dbuser": "mambu_db_user",
|
|
@@ -123,6 +129,7 @@ argparser.add_argument("--mambupy_apiurl")
|
|
|
123
129
|
argparser.add_argument("--mambupy_apiuser")
|
|
124
130
|
argparser.add_argument("--mambupy_apipwd")
|
|
125
131
|
argparser.add_argument("--mambupy_apipagination")
|
|
132
|
+
argparser.add_argument("--mambupy_activate_request_session_objects")
|
|
126
133
|
argparser.add_argument("--mambupy_dbname")
|
|
127
134
|
argparser.add_argument("--mambupy_dbuser")
|
|
128
135
|
argparser.add_argument("--mambupy_dbpwd")
|
|
@@ -184,6 +191,8 @@ apipwd = get_conf(config, "API", "apipwd")
|
|
|
184
191
|
"""Password to access Mambu API"""
|
|
185
192
|
apipagination = get_conf(config, "API", "apipagination")
|
|
186
193
|
"""Pagination default limit for requests to Mambu API"""
|
|
194
|
+
activate_request_session_objects = get_conf(config, "API", "activate_request_session_objects")
|
|
195
|
+
"""Whether to use persistent HTTP sessions for API requests"""
|
|
187
196
|
dbname = get_conf(config, "DB", "dbname")
|
|
188
197
|
"""Name of the DB with a backup of Mambu's DB"""
|
|
189
198
|
dbuser = get_conf(config, "DB", "dbuser")
|
|
@@ -28,7 +28,7 @@ from codecs import open as copen
|
|
|
28
28
|
|
|
29
29
|
import yaml
|
|
30
30
|
|
|
31
|
-
from .mambuconfig import apipagination, apipwd, apiurl, apiuser, loggingconf
|
|
31
|
+
from .mambuconfig import apipagination, apipwd, apiurl, apiuser, loggingconf, activate_request_session_objects
|
|
32
32
|
from .mambugeturl import getmambuurl
|
|
33
33
|
|
|
34
34
|
try:
|
|
@@ -258,7 +258,7 @@ def strip_consecutive_repeated_char(s, ch):
|
|
|
258
258
|
|
|
259
259
|
if sys.version_info >= (3, 0):
|
|
260
260
|
# python3
|
|
261
|
-
from
|
|
261
|
+
from urllib import parse as urlparse
|
|
262
262
|
else: # pragma: no cover
|
|
263
263
|
# python2
|
|
264
264
|
import urlparse
|
|
@@ -13,7 +13,7 @@ Uses mambugeturl.getclienturl as default urlfunc
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
unicode = str
|
|
17
17
|
|
|
18
18
|
from ..mambugeturl import getclientcustominformationurl, getclienturl
|
|
19
19
|
from ..mambuutil import strip_consecutive_repeated_char as scrc
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from future.utils import implements_iterator
|
|
2
|
-
|
|
3
1
|
from ..mambuutil import MambuError
|
|
4
2
|
|
|
5
3
|
|
|
@@ -30,7 +28,6 @@ class RequestsCounter(object):
|
|
|
30
28
|
cls.requests = []
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
@implements_iterator
|
|
34
31
|
class MambuStructIterator:
|
|
35
32
|
"""Enables iteration for some Mambu objects that may want to have iterators.
|
|
36
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: MambuPy
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: A python library for using Mambu APIs.
|
|
5
5
|
Author-email: "Javier Novoa C." <jstitch@gmail.com>
|
|
6
6
|
License: LICENSE
|
|
@@ -694,14 +694,13 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
|
|
|
694
694
|
Classifier: Operating System :: OS Independent
|
|
695
695
|
Classifier: Programming Language :: Python :: 3
|
|
696
696
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
697
|
-
Requires-Python: >=3.
|
|
697
|
+
Requires-Python: >=3.7
|
|
698
698
|
Description-Content-Type: text/markdown
|
|
699
699
|
License-File: LICENSE
|
|
700
700
|
Requires-Dist: PyYAML==6.0.1
|
|
701
701
|
Requires-Dist: requests==2.31.0
|
|
702
702
|
Requires-Dist: requests_toolbelt==1.0.0
|
|
703
703
|
Requires-Dist: dateutils==0.6.12
|
|
704
|
-
Requires-Dist: future==0.18.3
|
|
705
704
|
Provides-Extra: full
|
|
706
705
|
Requires-Dist: SQLAlchemy==1.3.6; extra == "full"
|
|
707
706
|
Requires-Dist: mysqlclient==2.1.0; extra == "full"
|
|
@@ -722,6 +721,8 @@ Requires-Dist: twine; extra == "deploy"
|
|
|
722
721
|
Provides-Extra: devtools
|
|
723
722
|
Requires-Dist: ipython; extra == "devtools"
|
|
724
723
|
Requires-Dist: ipdb; extra == "devtools"
|
|
724
|
+
Requires-Dist: devpi-client>=7.2.0; extra == "devtools"
|
|
725
|
+
Dynamic: license-file
|
|
725
726
|
|
|
726
727
|
MambuPy
|
|
727
728
|
=======
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: MambuPy
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: A python library for using Mambu APIs.
|
|
5
5
|
Author-email: "Javier Novoa C." <jstitch@gmail.com>
|
|
6
6
|
License: LICENSE
|
|
@@ -694,14 +694,13 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
|
|
|
694
694
|
Classifier: Operating System :: OS Independent
|
|
695
695
|
Classifier: Programming Language :: Python :: 3
|
|
696
696
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
697
|
-
Requires-Python: >=3.
|
|
697
|
+
Requires-Python: >=3.7
|
|
698
698
|
Description-Content-Type: text/markdown
|
|
699
699
|
License-File: LICENSE
|
|
700
700
|
Requires-Dist: PyYAML==6.0.1
|
|
701
701
|
Requires-Dist: requests==2.31.0
|
|
702
702
|
Requires-Dist: requests_toolbelt==1.0.0
|
|
703
703
|
Requires-Dist: dateutils==0.6.12
|
|
704
|
-
Requires-Dist: future==0.18.3
|
|
705
704
|
Provides-Extra: full
|
|
706
705
|
Requires-Dist: SQLAlchemy==1.3.6; extra == "full"
|
|
707
706
|
Requires-Dist: mysqlclient==2.1.0; extra == "full"
|
|
@@ -722,6 +721,8 @@ Requires-Dist: twine; extra == "deploy"
|
|
|
722
721
|
Provides-Extra: devtools
|
|
723
722
|
Requires-Dist: ipython; extra == "devtools"
|
|
724
723
|
Requires-Dist: ipdb; extra == "devtools"
|
|
724
|
+
Requires-Dist: devpi-client>=7.2.0; extra == "devtools"
|
|
725
|
+
Dynamic: license-file
|
|
725
726
|
|
|
726
727
|
MambuPy
|
|
727
728
|
=======
|
|
@@ -36,12 +36,82 @@ from MambuPy.mambuutil import (
|
|
|
36
36
|
apiurl,
|
|
37
37
|
apiuser,
|
|
38
38
|
setup_logging,
|
|
39
|
+
activate_request_session_objects,
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
logger = setup_logging(__name__)
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _configure_retry_strategy(session, retries=5):
|
|
47
|
+
"""Configure retry strategy for a session.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
session (requests.Session): The session to configure
|
|
51
|
+
retries (int, optional): Number of retries. Defaults to 5.
|
|
52
|
+
"""
|
|
53
|
+
retry_strategy = Retry(
|
|
54
|
+
total=retries,
|
|
55
|
+
status_forcelist=[429, 500, 502, 503, 504],
|
|
56
|
+
backoff_factor=1,
|
|
57
|
+
allowed_methods=[
|
|
58
|
+
"HEAD",
|
|
59
|
+
"GET",
|
|
60
|
+
"OPTIONS",
|
|
61
|
+
"POST",
|
|
62
|
+
"PUT",
|
|
63
|
+
"DELETE",
|
|
64
|
+
"TRACE",
|
|
65
|
+
"PATCH",
|
|
66
|
+
],
|
|
67
|
+
)
|
|
68
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
69
|
+
session.mount("https://", adapter)
|
|
70
|
+
session.mount("http://", adapter)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SessionSingleton:
|
|
74
|
+
"""Singleton class to manage HTTP sessions for MambuPy.
|
|
75
|
+
|
|
76
|
+
This class ensures that only one requests.Session object is created and reused
|
|
77
|
+
across all requests to the Mambu API. This helps improve performance by reusing
|
|
78
|
+
TCP connections.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
>>> session = SessionSingleton()
|
|
82
|
+
>>> session.get_session() # Returns a requests.Session object
|
|
83
|
+
>>> session2 = SessionSingleton()
|
|
84
|
+
>>> session2.get_session() # Returns the same requests.Session object
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
__instance = None
|
|
88
|
+
__session = None
|
|
89
|
+
_RETRIES = 5
|
|
90
|
+
|
|
91
|
+
def __new__(cls):
|
|
92
|
+
"""Create a new instance of SessionSingleton if one doesn't exist.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
SessionSingleton: The singleton instance.
|
|
96
|
+
"""
|
|
97
|
+
if cls.__instance is None:
|
|
98
|
+
cls.__instance = super(SessionSingleton, cls).__new__(cls)
|
|
99
|
+
return cls.__instance
|
|
100
|
+
|
|
101
|
+
def get_session(self):
|
|
102
|
+
"""Get the requests.Session object.
|
|
103
|
+
|
|
104
|
+
If no session exists, create a new one. Otherwise, return the existing one.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
requests.Session: The session object to use for HTTP requests.
|
|
108
|
+
"""
|
|
109
|
+
if self.__session is None:
|
|
110
|
+
self.__session = requests.Session()
|
|
111
|
+
_configure_retry_strategy(self.__session, self._RETRIES)
|
|
112
|
+
return self.__session
|
|
113
|
+
|
|
114
|
+
|
|
45
115
|
class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWriter):
|
|
46
116
|
"""A connector for Mambu REST API"""
|
|
47
117
|
|
|
@@ -55,6 +125,9 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
|
|
|
55
125
|
}
|
|
56
126
|
self.__set_authorization_header(user, pwd)
|
|
57
127
|
self.__set_url(url)
|
|
128
|
+
self._session = None
|
|
129
|
+
if activate_request_session_objects.lower() == "true":
|
|
130
|
+
self._session = SessionSingleton().get_session()
|
|
58
131
|
|
|
59
132
|
def __set_authorization_header(self, user, pwd):
|
|
60
133
|
self._headers["Authorization"] = "Basic {}".format(
|
|
@@ -108,26 +181,6 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
|
|
|
108
181
|
params = self.__request_params(params)
|
|
109
182
|
data = self.__request_data(data)
|
|
110
183
|
|
|
111
|
-
retry_strategy = Retry(
|
|
112
|
-
total=self._RETRIES,
|
|
113
|
-
status_forcelist=[429, 500, 502, 503, 504],
|
|
114
|
-
backoff_factor=1,
|
|
115
|
-
allowed_methods=[
|
|
116
|
-
"HEAD",
|
|
117
|
-
"GET",
|
|
118
|
-
"OPTIONS",
|
|
119
|
-
"POST",
|
|
120
|
-
"PUT",
|
|
121
|
-
"DELETE",
|
|
122
|
-
"TRACE",
|
|
123
|
-
"PATCH",
|
|
124
|
-
],
|
|
125
|
-
)
|
|
126
|
-
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
127
|
-
http = requests.Session()
|
|
128
|
-
http.mount("https://", adapter)
|
|
129
|
-
http.mount("http://", adapter)
|
|
130
|
-
|
|
131
184
|
resp = ""
|
|
132
185
|
try:
|
|
133
186
|
logger.debug(
|
|
@@ -139,10 +192,15 @@ url %s, params %s, data %s, headers %s",
|
|
|
139
192
|
data,
|
|
140
193
|
[(k, v) for k, v in headers.items() if k != "Authorization"],
|
|
141
194
|
)
|
|
142
|
-
|
|
195
|
+
if self._session:
|
|
196
|
+
resp = self._session.request(method, url, params=params, data=data, headers=headers)
|
|
197
|
+
else:
|
|
198
|
+
http = requests.Session()
|
|
199
|
+
_configure_retry_strategy(http, self._RETRIES)
|
|
200
|
+
resp = http.request(method, url, params=params, data=data, headers=headers)
|
|
143
201
|
resp.raise_for_status()
|
|
144
202
|
except requests.exceptions.HTTPError as httperr:
|
|
145
|
-
logger.
|
|
203
|
+
logger.warning(
|
|
146
204
|
"%s on %s request: params %s, data %s, headers %s",
|
|
147
205
|
str(httperr),
|
|
148
206
|
method,
|
|
@@ -151,7 +209,7 @@ url %s, params %s, data %s, headers %s",
|
|
|
151
209
|
[(k, v) for k, v in headers.items() if k != "Authorization"],
|
|
152
210
|
)
|
|
153
211
|
if hasattr(resp, "content"): # pragma: no cover
|
|
154
|
-
logger.
|
|
212
|
+
logger.warning("HTTPError, resp content: %s", resp.content)
|
|
155
213
|
try:
|
|
156
214
|
content = json.loads(resp.content.decode())
|
|
157
215
|
except ValueError:
|
|
@@ -24,6 +24,7 @@ RC files must have the following format:
|
|
|
24
24
|
apiuser=API_user
|
|
25
25
|
apipwd=API_password
|
|
26
26
|
apipagination=API_pagination_limit
|
|
27
|
+
activate_request_session_objects=API_persistent_session
|
|
27
28
|
[DB]
|
|
28
29
|
dbname=Database_name
|
|
29
30
|
dbuser=Database_user
|
|
@@ -75,6 +76,10 @@ user on your Mambu instance
|
|
|
75
76
|
|
|
76
77
|
The db* configs refer to Database configurations which hold a backup of
|
|
77
78
|
your Mambu Database on some server.
|
|
79
|
+
|
|
80
|
+
The activate_request_session_objects config enables or disables HTTP persistent sessions
|
|
81
|
+
for API requests. When enabled, it will reuse the same TCP connection for
|
|
82
|
+
multiple requests, improving performance. Default is False.
|
|
78
83
|
"""
|
|
79
84
|
|
|
80
85
|
default_configs = {
|
|
@@ -83,6 +88,7 @@ default_configs = {
|
|
|
83
88
|
"apiuser": "mambu_api_user",
|
|
84
89
|
"apipwd": "mambu_api_password",
|
|
85
90
|
"apipagination": "50",
|
|
91
|
+
"activate_request_session_objects": "False",
|
|
86
92
|
# Mambu DB configurations
|
|
87
93
|
"dbname": "mambu_db",
|
|
88
94
|
"dbuser": "mambu_db_user",
|
|
@@ -123,6 +129,7 @@ argparser.add_argument("--mambupy_apiurl")
|
|
|
123
129
|
argparser.add_argument("--mambupy_apiuser")
|
|
124
130
|
argparser.add_argument("--mambupy_apipwd")
|
|
125
131
|
argparser.add_argument("--mambupy_apipagination")
|
|
132
|
+
argparser.add_argument("--mambupy_activate_request_session_objects")
|
|
126
133
|
argparser.add_argument("--mambupy_dbname")
|
|
127
134
|
argparser.add_argument("--mambupy_dbuser")
|
|
128
135
|
argparser.add_argument("--mambupy_dbpwd")
|
|
@@ -184,6 +191,8 @@ apipwd = get_conf(config, "API", "apipwd")
|
|
|
184
191
|
"""Password to access Mambu API"""
|
|
185
192
|
apipagination = get_conf(config, "API", "apipagination")
|
|
186
193
|
"""Pagination default limit for requests to Mambu API"""
|
|
194
|
+
activate_request_session_objects = get_conf(config, "API", "activate_request_session_objects")
|
|
195
|
+
"""Whether to use persistent HTTP sessions for API requests"""
|
|
187
196
|
dbname = get_conf(config, "DB", "dbname")
|
|
188
197
|
"""Name of the DB with a backup of Mambu's DB"""
|
|
189
198
|
dbuser = get_conf(config, "DB", "dbuser")
|
|
@@ -28,7 +28,7 @@ from codecs import open as copen
|
|
|
28
28
|
|
|
29
29
|
import yaml
|
|
30
30
|
|
|
31
|
-
from .mambuconfig import apipagination, apipwd, apiurl, apiuser, loggingconf
|
|
31
|
+
from .mambuconfig import apipagination, apipwd, apiurl, apiuser, loggingconf, activate_request_session_objects
|
|
32
32
|
from .mambugeturl import getmambuurl
|
|
33
33
|
|
|
34
34
|
try:
|
|
@@ -258,7 +258,7 @@ def strip_consecutive_repeated_char(s, ch):
|
|
|
258
258
|
|
|
259
259
|
if sys.version_info >= (3, 0):
|
|
260
260
|
# python3
|
|
261
|
-
from
|
|
261
|
+
from urllib import parse as urlparse
|
|
262
262
|
else: # pragma: no cover
|
|
263
263
|
# python2
|
|
264
264
|
import urlparse
|
|
@@ -13,7 +13,7 @@ Uses mambugeturl.getclienturl as default urlfunc
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
unicode = str
|
|
17
17
|
|
|
18
18
|
from ..mambugeturl import getclientcustominformationurl, getclienturl
|
|
19
19
|
from ..mambuutil import strip_consecutive_repeated_char as scrc
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from future.utils import implements_iterator
|
|
2
|
-
|
|
3
1
|
from ..mambuutil import MambuError
|
|
4
2
|
|
|
5
3
|
|
|
@@ -30,7 +28,6 @@ class RequestsCounter(object):
|
|
|
30
28
|
cls.requests = []
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
@implements_iterator
|
|
34
31
|
class MambuStructIterator:
|
|
35
32
|
"""Enables iteration for some Mambu objects that may want to have iterators.
|
|
36
33
|
|
|
@@ -4,9 +4,14 @@ authors = [{name = "Javier Novoa C.", email = "jstitch@gmail.com"}]
|
|
|
4
4
|
license = {file = "LICENSE"}
|
|
5
5
|
description="A python library for using Mambu APIs."
|
|
6
6
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
7
|
-
requires-python = ">=3.
|
|
7
|
+
requires-python = ">=3.7"
|
|
8
8
|
dynamic = ["version"]
|
|
9
|
-
dependencies = [
|
|
9
|
+
dependencies = [
|
|
10
|
+
"PyYAML==6.0.1",
|
|
11
|
+
"requests==2.31.0",
|
|
12
|
+
"requests_toolbelt==1.0.0",
|
|
13
|
+
"dateutils==0.6.12",
|
|
14
|
+
]
|
|
10
15
|
keywords = ["mambu"]
|
|
11
16
|
classifiers = [
|
|
12
17
|
"Development Status :: 5 - Production/Stable",
|
|
@@ -23,7 +28,7 @@ full = ["SQLAlchemy==1.3.6", "mysqlclient==2.1.0"]
|
|
|
23
28
|
doc = ["sphinx==5.0.0", "sphinx_rtd_theme"]
|
|
24
29
|
dev = ["freezegun==1.1.0", "mock", "coverage", "pylint", "ruff", "black", "isort"]
|
|
25
30
|
deploy = ["build", "twine"]
|
|
26
|
-
devtools = ["ipython", "ipdb"]
|
|
31
|
+
devtools = ["ipython", "ipdb", "devpi-client>=7.2.0"]
|
|
27
32
|
|
|
28
33
|
[project.urls]
|
|
29
34
|
Homepage = "https://mambupydocs.readthedocs.io"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|