pyxecm 1.3.0__py3-none-any.whl → 1.5__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.
Potentially problematic release.
This version of pyxecm might be problematic. Click here for more details.
- pyxecm/__init__.py +3 -0
- pyxecm/coreshare.py +2636 -0
- pyxecm/customizer/__init__.py +6 -0
- pyxecm/customizer/browser_automation.py +231 -56
- pyxecm/customizer/customizer.py +466 -235
- pyxecm/customizer/k8s.py +49 -27
- pyxecm/customizer/m365.py +1183 -263
- pyxecm/customizer/payload.py +13854 -5368
- pyxecm/customizer/pht.py +503 -0
- pyxecm/customizer/salesforce.py +1782 -0
- pyxecm/customizer/sap.py +5 -5
- pyxecm/customizer/servicenow.py +1221 -0
- pyxecm/customizer/successfactors.py +1056 -0
- pyxecm/customizer/translate.py +2 -2
- pyxecm/helper/__init__.py +2 -0
- pyxecm/helper/assoc.py +27 -7
- pyxecm/helper/data.py +1527 -0
- pyxecm/helper/web.py +189 -25
- pyxecm/helper/xml.py +244 -40
- pyxecm/otac.py +311 -25
- pyxecm/otcs.py +3866 -1103
- pyxecm/otds.py +397 -150
- pyxecm/otiv.py +1 -1
- pyxecm/otmm.py +808 -0
- pyxecm/otpd.py +17 -12
- {pyxecm-1.3.0.dist-info → pyxecm-1.5.dist-info}/METADATA +4 -1
- pyxecm-1.5.dist-info/RECORD +30 -0
- {pyxecm-1.3.0.dist-info → pyxecm-1.5.dist-info}/WHEEL +1 -1
- pyxecm-1.3.0.dist-info/RECORD +0 -23
- {pyxecm-1.3.0.dist-info → pyxecm-1.5.dist-info}/LICENSE +0 -0
- {pyxecm-1.3.0.dist-info → pyxecm-1.5.dist-info}/top_level.txt +0 -0
pyxecm/customizer/pht.py
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PHT is an OpenText internal application aiming at creating a common naming reference for Engineering Products and
|
|
3
|
+
track all product-related data. It also provides an approved reporting hierarchy.
|
|
4
|
+
See: https://pht.opentext.com
|
|
5
|
+
|
|
6
|
+
Class: PHT
|
|
7
|
+
Methods:
|
|
8
|
+
|
|
9
|
+
__init__ : class initializer
|
|
10
|
+
config : Returns config data set
|
|
11
|
+
get_data: Get the Data object that holds all processed PHT products
|
|
12
|
+
request_header: Returns the request header for ServiceNow API calls
|
|
13
|
+
parse_request_response: Parse the REST API responses and convert
|
|
14
|
+
them to Python dict in a safe way
|
|
15
|
+
|
|
16
|
+
authenticate : Authenticates at ServiceNow API
|
|
17
|
+
|
|
18
|
+
get_attributes: Get a list of all product attributes (schema) of PHT
|
|
19
|
+
get_business_units: Get the list of PHT Business Units
|
|
20
|
+
get_product_families: Get the list of PHT product families
|
|
21
|
+
get_products: Get the list of PHT products
|
|
22
|
+
get_master_products: Get the list of PHT master products
|
|
23
|
+
filter_products: Get a list of filtered PHT products
|
|
24
|
+
load_products: Load products into a data frame.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
__author__ = "Dr. Marc Diefenbruch"
|
|
29
|
+
__copyright__ = "Copyright 2024, OpenText"
|
|
30
|
+
__credits__ = ["Kai-Philip Gatzweiler"]
|
|
31
|
+
__maintainer__ = "Dr. Marc Diefenbruch"
|
|
32
|
+
__email__ = "mdiefenb@opentext.com"
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
import logging
|
|
36
|
+
|
|
37
|
+
import requests
|
|
38
|
+
from requests.auth import HTTPBasicAuth
|
|
39
|
+
from pyxecm.helper.data import Data
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger("pyxecm.customizer.pht")
|
|
42
|
+
|
|
43
|
+
REQUEST_HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}
|
|
44
|
+
|
|
45
|
+
REQUEST_TIMEOUT = 60
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PHT(object):
|
|
49
|
+
"""Used to retrieve data from OpenText PHT."""
|
|
50
|
+
|
|
51
|
+
_config: dict
|
|
52
|
+
_session = None
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
base_url: str,
|
|
57
|
+
username: str,
|
|
58
|
+
password: str,
|
|
59
|
+
):
|
|
60
|
+
"""Initialize the PHT object
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
base_url (str): base URL of the ServiceNow tenant
|
|
64
|
+
username (str): user name in Saleforce
|
|
65
|
+
password (str): password of the user
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
pht_config = {}
|
|
69
|
+
|
|
70
|
+
# Store the credentials and parameters in a config dictionary:
|
|
71
|
+
pht_config["baseUrl"] = base_url
|
|
72
|
+
pht_config["username"] = username
|
|
73
|
+
pht_config["password"] = password
|
|
74
|
+
|
|
75
|
+
pht_config["restUrl"] = pht_config["baseUrl"] + "/api"
|
|
76
|
+
pht_config["attributeUrl"] = pht_config["restUrl"] + "/attribute"
|
|
77
|
+
pht_config["businessUnitUrl"] = pht_config["restUrl"] + "/business-unit"
|
|
78
|
+
pht_config["productFamilyUrl"] = pht_config["restUrl"] + "/product-family"
|
|
79
|
+
pht_config["productUrl"] = pht_config["restUrl"] + "/product"
|
|
80
|
+
pht_config["searchUrl"] = pht_config["productUrl"] + "/product/search"
|
|
81
|
+
pht_config["teamUrl"] = pht_config["restUrl"] + "/team"
|
|
82
|
+
pht_config["componentUrl"] = pht_config["restUrl"] + "/component"
|
|
83
|
+
pht_config["masterProductUrl"] = pht_config["restUrl"] + "/master-product"
|
|
84
|
+
|
|
85
|
+
self._config = pht_config
|
|
86
|
+
|
|
87
|
+
self._session = requests.Session()
|
|
88
|
+
|
|
89
|
+
self._data = Data()
|
|
90
|
+
|
|
91
|
+
# end method definition
|
|
92
|
+
|
|
93
|
+
def config(self) -> dict:
|
|
94
|
+
"""Returns the configuration dictionary
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
dict: Configuration dictionary
|
|
98
|
+
"""
|
|
99
|
+
return self._config
|
|
100
|
+
|
|
101
|
+
# end method definition
|
|
102
|
+
|
|
103
|
+
def get_data(self) -> Data:
|
|
104
|
+
"""Get the Data object that holds all processed PHT products
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Data: Datastructure with all processed PHT product data.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
return self._data
|
|
111
|
+
|
|
112
|
+
# end method definition
|
|
113
|
+
|
|
114
|
+
def request_header(self, content_type: str = "") -> dict:
|
|
115
|
+
"""Returns the request header used for Application calls.
|
|
116
|
+
Consists of Bearer access token and Content Type
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
content_type (str, optional): custom content type for the request
|
|
120
|
+
Return:
|
|
121
|
+
dict: request header values
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
request_header = {}
|
|
125
|
+
|
|
126
|
+
request_header = REQUEST_HEADERS
|
|
127
|
+
|
|
128
|
+
if content_type:
|
|
129
|
+
request_header["Content-Type"] = content_type
|
|
130
|
+
|
|
131
|
+
return request_header
|
|
132
|
+
|
|
133
|
+
# end method definition
|
|
134
|
+
|
|
135
|
+
def parse_request_response(
|
|
136
|
+
self,
|
|
137
|
+
response_object: requests.Response,
|
|
138
|
+
additional_error_message: str = "",
|
|
139
|
+
show_error: bool = True,
|
|
140
|
+
) -> list | None:
|
|
141
|
+
"""Converts the request response (JSon) to a Python list in a safe way
|
|
142
|
+
that also handles exceptions. It first tries to load the response.text
|
|
143
|
+
via json.loads() that produces a dict output. Only if response.text is
|
|
144
|
+
not set or is empty it just converts the response_object to a dict using
|
|
145
|
+
the vars() built-in method.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
response_object (object): this is reponse object delivered by the request call
|
|
149
|
+
additional_error_message (str, optional): use a more specific error message
|
|
150
|
+
in case of an error
|
|
151
|
+
show_error (bool): True: write an error to the log file
|
|
152
|
+
False: write a warning to the log file
|
|
153
|
+
Returns:
|
|
154
|
+
list: response information or None in case of an error
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
if not response_object:
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
if response_object.text:
|
|
162
|
+
list_object = json.loads(response_object.text)
|
|
163
|
+
else:
|
|
164
|
+
list_object = vars(response_object)
|
|
165
|
+
except json.JSONDecodeError as exception:
|
|
166
|
+
if additional_error_message:
|
|
167
|
+
message = "Cannot decode response as JSON. {}; error -> {}".format(
|
|
168
|
+
additional_error_message, exception
|
|
169
|
+
)
|
|
170
|
+
else:
|
|
171
|
+
message = "Cannot decode response as JSON; error -> {}".format(
|
|
172
|
+
exception
|
|
173
|
+
)
|
|
174
|
+
if show_error:
|
|
175
|
+
logger.error(message)
|
|
176
|
+
else:
|
|
177
|
+
logger.warning(message)
|
|
178
|
+
return None
|
|
179
|
+
else:
|
|
180
|
+
return list_object
|
|
181
|
+
|
|
182
|
+
# end method definition
|
|
183
|
+
|
|
184
|
+
def authenticate(self) -> str | None:
|
|
185
|
+
"""Authenticate at PHT with basic authentication."""
|
|
186
|
+
|
|
187
|
+
self._session.headers.update(self.request_header())
|
|
188
|
+
|
|
189
|
+
username = self.config()["username"]
|
|
190
|
+
password = self.config()["password"]
|
|
191
|
+
if not self._session:
|
|
192
|
+
self._session = requests.Session()
|
|
193
|
+
self._session.auth = HTTPBasicAuth(username, password)
|
|
194
|
+
|
|
195
|
+
return self._session.auth
|
|
196
|
+
|
|
197
|
+
# end method definition
|
|
198
|
+
|
|
199
|
+
def get_attributes(self) -> list | None:
|
|
200
|
+
"""Get a list of all product attributes (schema) of PHT
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
list | None: list of product attributes
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
[
|
|
207
|
+
{
|
|
208
|
+
'id': 28,
|
|
209
|
+
'uuid': '43ba5852-eb83-11ed-a752-00505682262c',
|
|
210
|
+
'name': 'UBM SCM Migration JIRA/ValueEdge',
|
|
211
|
+
'description': 'Identifies the Issue to track work for the SCM migration for this project.\nIts a free text field and no validation with JIRA/ValueEdge will take place',
|
|
212
|
+
'type': 'TEXT',
|
|
213
|
+
'attributeCategory': {
|
|
214
|
+
'id': 2,
|
|
215
|
+
'name': 'Auxiliary assignment'
|
|
216
|
+
},
|
|
217
|
+
'showDefault': False,
|
|
218
|
+
'restricted': True,
|
|
219
|
+
'allowScopeChain': True,
|
|
220
|
+
'visibleToAll': False,
|
|
221
|
+
'deleted': False,
|
|
222
|
+
'attributeOptions': [],
|
|
223
|
+
'attributeScopes': [],
|
|
224
|
+
'allowedTeams': []
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
request_header = self.request_header()
|
|
230
|
+
request_url = self.config()["attributeUrl"]
|
|
231
|
+
|
|
232
|
+
retries = 0
|
|
233
|
+
|
|
234
|
+
while True:
|
|
235
|
+
response = self._session.get(url=request_url, headers=request_header)
|
|
236
|
+
if response.ok:
|
|
237
|
+
return self.parse_request_response(response)
|
|
238
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
239
|
+
elif response.status_code == 401 and retries == 0:
|
|
240
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
241
|
+
self.authenticate()
|
|
242
|
+
retries += 1
|
|
243
|
+
else:
|
|
244
|
+
logger.error(
|
|
245
|
+
"Failed to get PHT attributes; error -> %s (%s)",
|
|
246
|
+
response.text,
|
|
247
|
+
response.status_code,
|
|
248
|
+
)
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
# end method definition
|
|
252
|
+
|
|
253
|
+
def get_business_units(self) -> list | None:
|
|
254
|
+
"""Get the list of PHT Business Units
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
list | None: list of the known business units.
|
|
258
|
+
|
|
259
|
+
Example:
|
|
260
|
+
[
|
|
261
|
+
{
|
|
262
|
+
'id': 1,
|
|
263
|
+
'name': 'Content Services',
|
|
264
|
+
'leaderModel': {
|
|
265
|
+
'id': 219,
|
|
266
|
+
'domain': 'mcybala',
|
|
267
|
+
'email': 'mcybala@opentext.com',
|
|
268
|
+
'name': 'Michael Cybala',
|
|
269
|
+
'role': None,
|
|
270
|
+
'status': 'ACTIVE',
|
|
271
|
+
'location': 'Kempten, DEU',
|
|
272
|
+
'title': 'VP, Software Engineering',
|
|
273
|
+
'type': 'OTHERS'
|
|
274
|
+
},
|
|
275
|
+
'pmLeaderModel': {
|
|
276
|
+
'id': 350,
|
|
277
|
+
'domain': 'mdiefenb',
|
|
278
|
+
'email': 'mdiefenb@opentext.com',
|
|
279
|
+
'name': 'Marc Diefenbruch',
|
|
280
|
+
'role': None,
|
|
281
|
+
'status': 'ACTIVE',
|
|
282
|
+
'location': 'Virtual, DEU',
|
|
283
|
+
'title': 'VP, Product Management',
|
|
284
|
+
'type': 'OTHERS'
|
|
285
|
+
},
|
|
286
|
+
'sltOwnerModel': {
|
|
287
|
+
'id': 450,
|
|
288
|
+
'domain': 'jradko',
|
|
289
|
+
'email': 'jradko@opentext.com',
|
|
290
|
+
'name': 'John Radko',
|
|
291
|
+
'role': None,
|
|
292
|
+
'status': 'ACTIVE',
|
|
293
|
+
'location': 'Gaithersburg, MD, USA',
|
|
294
|
+
'title': 'SVP, Software Engineering',
|
|
295
|
+
'type': 'OTHERS'
|
|
296
|
+
},
|
|
297
|
+
'status': 'ACTIVE',
|
|
298
|
+
'engineering': True,
|
|
299
|
+
'attributes': [{...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}],
|
|
300
|
+
'leader': 'Michael Cybala',
|
|
301
|
+
'leaderDomain': 'mcybala',
|
|
302
|
+
'pmLeader': 'Marc Diefenbruch',
|
|
303
|
+
'pmLeaderDomain': 'mdiefenb',
|
|
304
|
+
'sltOwner': 'John Radko',
|
|
305
|
+
'sltOwnerDomain': 'jradko'
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
request_header = self.request_header()
|
|
311
|
+
request_url = self.config()["businessUnitUrl"]
|
|
312
|
+
|
|
313
|
+
retries = 0
|
|
314
|
+
|
|
315
|
+
while True:
|
|
316
|
+
response = self._session.get(url=request_url, headers=request_header)
|
|
317
|
+
if response.ok:
|
|
318
|
+
return self.parse_request_response(response)
|
|
319
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
320
|
+
elif response.status_code == 401 and retries == 0:
|
|
321
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
322
|
+
self.authenticate()
|
|
323
|
+
retries += 1
|
|
324
|
+
else:
|
|
325
|
+
logger.error(
|
|
326
|
+
"Failed to get PHT business units; error -> %s (%s)",
|
|
327
|
+
response.text,
|
|
328
|
+
response.status_code,
|
|
329
|
+
)
|
|
330
|
+
return None
|
|
331
|
+
|
|
332
|
+
# end method definition
|
|
333
|
+
|
|
334
|
+
def get_product_families(self) -> list | None:
|
|
335
|
+
"""Get the list of PHT product families
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
list | None: list of the known product families.
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
request_header = self.request_header()
|
|
342
|
+
request_url = self.config()["productFamilyUrl"]
|
|
343
|
+
|
|
344
|
+
retries = 0
|
|
345
|
+
|
|
346
|
+
while True:
|
|
347
|
+
response = self._session.get(url=request_url, headers=request_header)
|
|
348
|
+
if response.ok:
|
|
349
|
+
return self.parse_request_response(response)
|
|
350
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
351
|
+
elif response.status_code == 401 and retries == 0:
|
|
352
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
353
|
+
self.authenticate()
|
|
354
|
+
retries += 1
|
|
355
|
+
else:
|
|
356
|
+
logger.error(
|
|
357
|
+
"Failed to get PHT product families; error -> %s (%s)",
|
|
358
|
+
response.text,
|
|
359
|
+
response.status_code,
|
|
360
|
+
)
|
|
361
|
+
return None
|
|
362
|
+
|
|
363
|
+
# end method definition
|
|
364
|
+
|
|
365
|
+
def get_products(self) -> list | None:
|
|
366
|
+
"""Get the list of PHT products
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
list | None: list of the known products.
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
request_header = self.request_header()
|
|
373
|
+
request_url = self.config()["productUrl"]
|
|
374
|
+
|
|
375
|
+
retries = 0
|
|
376
|
+
|
|
377
|
+
while True:
|
|
378
|
+
response = self._session.get(url=request_url, headers=request_header)
|
|
379
|
+
if response.ok:
|
|
380
|
+
return self.parse_request_response(response)
|
|
381
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
382
|
+
elif response.status_code == 401 and retries == 0:
|
|
383
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
384
|
+
self.authenticate()
|
|
385
|
+
retries += 1
|
|
386
|
+
else:
|
|
387
|
+
logger.error(
|
|
388
|
+
"Failed to get PHT products; error -> %s (%s)",
|
|
389
|
+
response.text,
|
|
390
|
+
response.status_code,
|
|
391
|
+
)
|
|
392
|
+
return None
|
|
393
|
+
|
|
394
|
+
# end method definition
|
|
395
|
+
|
|
396
|
+
def get_master_products(self) -> list | None:
|
|
397
|
+
"""Get the list of PHT master products
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
list | None: list of the known master products.
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
request_header = self.request_header()
|
|
404
|
+
request_url = self.config()["masterProductUrl"]
|
|
405
|
+
|
|
406
|
+
retries = 0
|
|
407
|
+
|
|
408
|
+
while True:
|
|
409
|
+
response = self._session.get(url=request_url, headers=request_header)
|
|
410
|
+
if response.ok:
|
|
411
|
+
return self.parse_request_response(response)
|
|
412
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
413
|
+
elif response.status_code == 401 and retries == 0:
|
|
414
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
415
|
+
self.authenticate()
|
|
416
|
+
retries += 1
|
|
417
|
+
else:
|
|
418
|
+
logger.error(
|
|
419
|
+
"Failed to get PHT master products; error -> %s (%s)",
|
|
420
|
+
response.text,
|
|
421
|
+
response.status_code,
|
|
422
|
+
)
|
|
423
|
+
return None
|
|
424
|
+
|
|
425
|
+
# end method definition
|
|
426
|
+
|
|
427
|
+
def filter_products(self, filter_definition: dict | None = None) -> list | None:
|
|
428
|
+
"""Get a list of filtered PHT products
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
filter_definition (dict): a dictionary of filter conditions.
|
|
432
|
+
Example filters:
|
|
433
|
+
businessUnitName: <String>
|
|
434
|
+
productFamilyName: <String>
|
|
435
|
+
productName: <String>
|
|
436
|
+
productSyncId: <String>
|
|
437
|
+
productStatus: ACTIVE | INACTIVE | MAINTENANCE
|
|
438
|
+
productManager: <String>
|
|
439
|
+
developmentManager: <String>
|
|
440
|
+
attributeOperator: AND | OR
|
|
441
|
+
attributes: {
|
|
442
|
+
"<AttributeName>": {
|
|
443
|
+
"compare": CONTAINS | EXISTS | DOES_NOT_EXISTS,
|
|
444
|
+
"values": List<String>
|
|
445
|
+
},
|
|
446
|
+
...
|
|
447
|
+
},
|
|
448
|
+
includeAttributes: true | false
|
|
449
|
+
Returns:
|
|
450
|
+
list | None: list of matching products.
|
|
451
|
+
"""
|
|
452
|
+
|
|
453
|
+
if not filter_definition:
|
|
454
|
+
return self.get_products()
|
|
455
|
+
|
|
456
|
+
request_header = self.request_header()
|
|
457
|
+
request_url = self.config()["productUrl"] + "/filtered"
|
|
458
|
+
request_data = filter_definition
|
|
459
|
+
|
|
460
|
+
retries = 0
|
|
461
|
+
|
|
462
|
+
while True:
|
|
463
|
+
response = self._session.post(
|
|
464
|
+
url=request_url, headers=request_header, json=request_data
|
|
465
|
+
)
|
|
466
|
+
if response.ok:
|
|
467
|
+
return self.parse_request_response(response)
|
|
468
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
469
|
+
elif response.status_code == 401 and retries == 0:
|
|
470
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
471
|
+
self.authenticate()
|
|
472
|
+
retries += 1
|
|
473
|
+
else:
|
|
474
|
+
logger.error(
|
|
475
|
+
"Failed to get PHT master products; error -> %s (%s)",
|
|
476
|
+
response.text,
|
|
477
|
+
response.status_code,
|
|
478
|
+
)
|
|
479
|
+
return None
|
|
480
|
+
|
|
481
|
+
# end method definition
|
|
482
|
+
|
|
483
|
+
def load_products(self, product_list: list = None) -> bool:
|
|
484
|
+
"""Load products into a data frame in the self._data object
|
|
485
|
+
|
|
486
|
+
Args:
|
|
487
|
+
product_list (list, optional): listn of products - if already avaiable. Defaults to None.
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
bool: True if successful, False otherwise.
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
if not product_list:
|
|
494
|
+
product_list = self.get_products()
|
|
495
|
+
|
|
496
|
+
self._data = Data(product_list)
|
|
497
|
+
|
|
498
|
+
if self._data:
|
|
499
|
+
return True
|
|
500
|
+
|
|
501
|
+
return False
|
|
502
|
+
|
|
503
|
+
# end method definition
|