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.
Files changed (128) hide show
  1. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/__init__.py +1 -1
  2. {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/api/connector/rest.py +81 -23
  3. {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/mambuconfig.py +9 -0
  4. {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/mambuutil.py +2 -2
  5. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuclient.py +1 -1
  6. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburestutils.py +0 -3
  7. {mambupy-2.1.0/mambupy → mambupy-2.1.1/MambuPy}/rest/mambustruct.py +1 -1
  8. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/PKG-INFO +5 -4
  9. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/requires.txt +1 -1
  10. {mambupy-2.1.0 → mambupy-2.1.1}/PKG-INFO +5 -4
  11. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/__init__.py +1 -1
  12. {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/api/connector/rest.py +81 -23
  13. {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/mambuconfig.py +9 -0
  14. {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/mambuutil.py +2 -2
  15. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuclient.py +1 -1
  16. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburestutils.py +0 -3
  17. {mambupy-2.1.0/MambuPy → mambupy-2.1.1/mambupy}/rest/mambustruct.py +1 -1
  18. {mambupy-2.1.0 → mambupy-2.1.1}/pyproject.toml +8 -3
  19. {mambupy-2.1.0 → mambupy-2.1.1}/LICENSE +0 -0
  20. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/__init__.py +0 -0
  21. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/classes.py +0 -0
  22. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/connector/__init__.py +0 -0
  23. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/connector/mambuconnector.py +0 -0
  24. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/entities.py +0 -0
  25. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/interfaces.py +0 -0
  26. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambubranch.py +0 -0
  27. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambucentre.py +0 -0
  28. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuclient.py +0 -0
  29. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambucustomfield.py +0 -0
  30. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambugroup.py +0 -0
  31. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuloan.py +0 -0
  32. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuproduct.py +0 -0
  33. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mamburole.py +0 -0
  34. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambustruct.py +0 -0
  35. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambutask.py +0 -0
  36. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambutransaction.py +0 -0
  37. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/mambuuser.py +0 -0
  38. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/api/vos.py +0 -0
  39. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/mambugeturl.py +0 -0
  40. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/__init__.py +0 -0
  41. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_activities.py +0 -0
  42. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_addresses.py +0 -0
  43. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_branches.py +0 -0
  44. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_centres.py +0 -0
  45. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_clients.py +0 -0
  46. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_customfields.py +0 -0
  47. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_dummies.py +0 -0
  48. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_groups.py +0 -0
  49. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_loans.py +0 -0
  50. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_mambu.py +0 -0
  51. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_orm.py +0 -0
  52. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_tasks.py +0 -0
  53. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/orm/schema_users.py +0 -0
  54. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/__init__.py +0 -0
  55. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuactivity.py +0 -0
  56. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambubranch.py +0 -0
  57. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambucentre.py +0 -0
  58. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambugroup.py +0 -0
  59. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuloan.py +0 -0
  60. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuproduct.py +0 -0
  61. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburepayment.py +0 -0
  62. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mamburoles.py +0 -0
  63. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusaving.py +0 -0
  64. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusavingfundingrepayment.py +0 -0
  65. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambusavingtransaction.py +0 -0
  66. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutask.py +0 -0
  67. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutransaction.py +0 -0
  68. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambutransactionchannel.py +0 -0
  69. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/rest/mambuuser.py +0 -0
  70. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/utils/__init__.py +0 -0
  71. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy/utils/userdeactivate.py +0 -0
  72. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/SOURCES.txt +0 -0
  73. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/dependency_links.txt +0 -0
  74. {mambupy-2.1.0 → mambupy-2.1.1}/MambuPy.egg-info/top_level.txt +0 -0
  75. {mambupy-2.1.0 → mambupy-2.1.1}/README.md +0 -0
  76. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/__init__.py +0 -0
  77. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/classes.py +0 -0
  78. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/connector/__init__.py +0 -0
  79. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/connector/mambuconnector.py +0 -0
  80. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/entities.py +0 -0
  81. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/interfaces.py +0 -0
  82. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambubranch.py +0 -0
  83. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambucentre.py +0 -0
  84. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuclient.py +0 -0
  85. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambucustomfield.py +0 -0
  86. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambugroup.py +0 -0
  87. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuloan.py +0 -0
  88. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuproduct.py +0 -0
  89. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mamburole.py +0 -0
  90. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambustruct.py +0 -0
  91. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambutask.py +0 -0
  92. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambutransaction.py +0 -0
  93. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/mambuuser.py +0 -0
  94. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/api/vos.py +0 -0
  95. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/mambugeturl.py +0 -0
  96. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/__init__.py +0 -0
  97. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_activities.py +0 -0
  98. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_addresses.py +0 -0
  99. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_branches.py +0 -0
  100. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_centres.py +0 -0
  101. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_clients.py +0 -0
  102. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_customfields.py +0 -0
  103. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_dummies.py +0 -0
  104. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_groups.py +0 -0
  105. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_loans.py +0 -0
  106. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_mambu.py +0 -0
  107. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_orm.py +0 -0
  108. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_tasks.py +0 -0
  109. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/orm/schema_users.py +0 -0
  110. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/__init__.py +0 -0
  111. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuactivity.py +0 -0
  112. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambubranch.py +0 -0
  113. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambucentre.py +0 -0
  114. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambugroup.py +0 -0
  115. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuloan.py +0 -0
  116. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuproduct.py +0 -0
  117. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburepayment.py +0 -0
  118. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mamburoles.py +0 -0
  119. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusaving.py +0 -0
  120. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusavingfundingrepayment.py +0 -0
  121. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambusavingtransaction.py +0 -0
  122. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutask.py +0 -0
  123. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutransaction.py +0 -0
  124. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambutransactionchannel.py +0 -0
  125. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/rest/mambuuser.py +0 -0
  126. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/utils/__init__.py +0 -0
  127. {mambupy-2.1.0 → mambupy-2.1.1}/mambupy/utils/userdeactivate.py +0 -0
  128. {mambupy-2.1.0 → mambupy-2.1.1}/setup.cfg +0 -0
@@ -39,7 +39,7 @@ import sys
39
39
  from importlib.abc import MetaPathFinder
40
40
  from importlib.util import spec_from_file_location
41
41
 
42
- __version__ = "2.1.0"
42
+ __version__ = "2.1.1"
43
43
  """The version of this module."""
44
44
 
45
45
 
@@ -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
- resp = http.request(method, url, params=params, data=data, headers=headers)
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.error(
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.error("HTTPError, resp content: %s", resp.content)
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 future.moves.urllib import parse as urlparse
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
- from builtins import str as unicode
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
 
@@ -31,7 +31,7 @@ Some basic definitions:
31
31
  relational database but the term table is preferred in this case.
32
32
  """
33
33
  import json
34
- from builtins import str as unicode
34
+ unicode = str
35
35
  from datetime import datetime
36
36
 
37
37
  import requests
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: MambuPy
3
- Version: 2.1.0
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.8
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
  =======
@@ -2,7 +2,6 @@ PyYAML==6.0.1
2
2
  requests==2.31.0
3
3
  requests_toolbelt==1.0.0
4
4
  dateutils==0.6.12
5
- future==0.18.3
6
5
 
7
6
  [deploy]
8
7
  build
@@ -20,6 +19,7 @@ isort
20
19
  [devtools]
21
20
  ipython
22
21
  ipdb
22
+ devpi-client>=7.2.0
23
23
 
24
24
  [doc]
25
25
  sphinx==5.0.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: MambuPy
3
- Version: 2.1.0
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.8
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
  =======
@@ -39,7 +39,7 @@ import sys
39
39
  from importlib.abc import MetaPathFinder
40
40
  from importlib.util import spec_from_file_location
41
41
 
42
- __version__ = "2.1.0"
42
+ __version__ = "2.1.1"
43
43
  """The version of this module."""
44
44
 
45
45
 
@@ -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
- resp = http.request(method, url, params=params, data=data, headers=headers)
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.error(
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.error("HTTPError, resp content: %s", resp.content)
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 future.moves.urllib import parse as urlparse
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
- from builtins import str as unicode
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
 
@@ -31,7 +31,7 @@ Some basic definitions:
31
31
  relational database but the term table is preferred in this case.
32
32
  """
33
33
  import json
34
- from builtins import str as unicode
34
+ unicode = str
35
35
  from datetime import datetime
36
36
 
37
37
  import requests
@@ -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.8"
7
+ requires-python = ">=3.7"
8
8
  dynamic = ["version"]
9
- dependencies = ["PyYAML==6.0.1", "requests==2.31.0", "requests_toolbelt==1.0.0", "dateutils==0.6.12", "future==0.18.3"]
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