stepxmlclient 1.0.0__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.
- stepxmlclient/__init__.py +22 -0
- stepxmlclient/client.py +373 -0
- stepxmlclient/creator.py +317 -0
- stepxmlclient/model/__init__.py +418 -0
- stepxmlclient/model/asset.py +250 -0
- stepxmlclient/model/attribute.py +288 -0
- stepxmlclient/model/business.py +233 -0
- stepxmlclient/model/classification.py +409 -0
- stepxmlclient/model/complex_elements.py +260 -0
- stepxmlclient/model/deletion.py +87 -0
- stepxmlclient/model/entity.py +368 -0
- stepxmlclient/model/metadata.py +199 -0
- stepxmlclient/model/organization.py +167 -0
- stepxmlclient/model/product.py +519 -0
- stepxmlclient/model/relations.py +105 -0
- stepxmlclient/model/replacement.py +417 -0
- stepxmlclient/parser.py +2805 -0
- stepxmlclient/rest_client/__init__.py +16 -0
- stepxmlclient/rest_client/base.py +388 -0
- stepxmlclient/rest_client/client.py +127 -0
- stepxmlclient/rest_client/exceptions.py +97 -0
- stepxmlclient/rest_client/models/__init__.py +175 -0
- stepxmlclient/rest_client/models/asset.py +253 -0
- stepxmlclient/rest_client/models/attribute.py +112 -0
- stepxmlclient/rest_client/models/background_process.py +23 -0
- stepxmlclient/rest_client/models/batch.py +41 -0
- stepxmlclient/rest_client/models/classification.py +57 -0
- stepxmlclient/rest_client/models/collection.py +26 -0
- stepxmlclient/rest_client/models/common.py +192 -0
- stepxmlclient/rest_client/models/context.py +16 -0
- stepxmlclient/rest_client/models/data_type_group.py +15 -0
- stepxmlclient/rest_client/models/entity.py +63 -0
- stepxmlclient/rest_client/models/event_processor.py +15 -0
- stepxmlclient/rest_client/models/import_export.py +43 -0
- stepxmlclient/rest_client/models/integration_endpoint.py +16 -0
- stepxmlclient/rest_client/models/product.py +200 -0
- stepxmlclient/rest_client/models/relations.py +280 -0
- stepxmlclient/rest_client/models/system_information.py +11 -0
- stepxmlclient/rest_client/models/user.py +28 -0
- stepxmlclient/rest_client/models/workflow.py +30 -0
- stepxmlclient/rest_client/operations/__init__.py +54 -0
- stepxmlclient/rest_client/operations/assets.py +652 -0
- stepxmlclient/rest_client/operations/attributes.py +252 -0
- stepxmlclient/rest_client/operations/background_processes.py +84 -0
- stepxmlclient/rest_client/operations/batch.py +28 -0
- stepxmlclient/rest_client/operations/classifications.py +248 -0
- stepxmlclient/rest_client/operations/collection_groups.py +46 -0
- stepxmlclient/rest_client/operations/collections.py +67 -0
- stepxmlclient/rest_client/operations/contexts.py +88 -0
- stepxmlclient/rest_client/operations/data_type_groups.py +68 -0
- stepxmlclient/rest_client/operations/entities.py +295 -0
- stepxmlclient/rest_client/operations/event_processors.py +109 -0
- stepxmlclient/rest_client/operations/exports.py +153 -0
- stepxmlclient/rest_client/operations/gateway.py +53 -0
- stepxmlclient/rest_client/operations/inbound.py +472 -0
- stepxmlclient/rest_client/operations/outbound.py +64 -0
- stepxmlclient/rest_client/operations/products.py +489 -0
- stepxmlclient/rest_client/operations/relations.py +349 -0
- stepxmlclient/rest_client/operations/reports.py +27 -0
- stepxmlclient/rest_client/operations/system_information.py +28 -0
- stepxmlclient/rest_client/operations/user_groups.py +79 -0
- stepxmlclient/rest_client/operations/users.py +119 -0
- stepxmlclient/rest_client/operations/workflow_tasks.py +61 -0
- stepxmlclient/rest_client/operations/workflows.py +50 -0
- stepxmlclient/upload.py +293 -0
- stepxmlclient-1.0.0.dist-info/METADATA +666 -0
- stepxmlclient-1.0.0.dist-info/RECORD +70 -0
- stepxmlclient-1.0.0.dist-info/WHEEL +5 -0
- stepxmlclient-1.0.0.dist-info/licenses/LICENSE +21 -0
- stepxmlclient-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
STEP XML Client Library.
|
|
3
|
+
|
|
4
|
+
A Python client library for integrating with Stibo Systems STEP MDM (Master Data Management).
|
|
5
|
+
Supports standard STEP-XML protocol (OIEP/IIEP) for parsing and creating STEP-XML documents,
|
|
6
|
+
and wraps the STEP REST API v2 for direct system integration.
|
|
7
|
+
|
|
8
|
+
This library provides:
|
|
9
|
+
- Parser: Deserialize STEP-XML documents into Python dictionaries
|
|
10
|
+
- Creator: Serialize Python objects into STEP-XML documents
|
|
11
|
+
- REST Client: Direct integration with STEP REST API v2
|
|
12
|
+
- Asset Uploader: Binary file upload support for asset management
|
|
13
|
+
|
|
14
|
+
Namespaces:
|
|
15
|
+
STEPXML_NS: Dictionary mapping namespace prefixes to their URIs used throughout STEP-XML documents
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
#: XML namespace URIs used in STEP documents
|
|
19
|
+
STEPXML_NS = {
|
|
20
|
+
'step' : 'http://www.stibosystems.com/step',
|
|
21
|
+
'outputtemplate' : 'http://www.stibosystems.com/step/outputtemplate'
|
|
22
|
+
}
|
stepxmlclient/client.py
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import requests_openapi as roa
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _lazy_import_inbound_operations():
|
|
11
|
+
"""Lazy import InboundOperations to avoid circular imports.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
InboundOperations class or None if import fails
|
|
15
|
+
"""
|
|
16
|
+
try:
|
|
17
|
+
from stepxmlclient.rest_client.operations.inbound import InboundOperations
|
|
18
|
+
return InboundOperations
|
|
19
|
+
except ImportError:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
class StiboStepRestClient:
|
|
23
|
+
|
|
24
|
+
_OPENAPI_CACHE_FILE = "openapi.json"
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self, location_base, authorisation,
|
|
28
|
+
openapi_file=None, logger=None,
|
|
29
|
+
proxies = None, ssl_version = None,
|
|
30
|
+
cache_openapi = False, nocert=False,
|
|
31
|
+
context=None, workspace=None):
|
|
32
|
+
self.ssl_version = ssl_version
|
|
33
|
+
self.context = context
|
|
34
|
+
self.workspace = workspace
|
|
35
|
+
|
|
36
|
+
if logger is None:
|
|
37
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
38
|
+
else:
|
|
39
|
+
self.logger = logger
|
|
40
|
+
# build location base
|
|
41
|
+
location_base = location_base.lower()
|
|
42
|
+
if not location_base.startswith('http'):
|
|
43
|
+
location_base = '%s://%s' % ('https', location_base)
|
|
44
|
+
if location_base.endswith('/'):
|
|
45
|
+
location_base = location_base[:-1]
|
|
46
|
+
# create client
|
|
47
|
+
self.__create_client(location_base, openapi_file, cache_openapi)
|
|
48
|
+
# set server
|
|
49
|
+
self.client.set_server(roa.Server(url=location_base))
|
|
50
|
+
if isinstance(self.client.requestor, requests.Session):
|
|
51
|
+
# no ssl verify?
|
|
52
|
+
if nocert or os.path.exists('nocert'):
|
|
53
|
+
self.client.requestor.verify=False
|
|
54
|
+
# proxies
|
|
55
|
+
if isinstance(proxies, dict):
|
|
56
|
+
self.client.requestor.proxies.update(proxies)
|
|
57
|
+
self.proxies = proxies
|
|
58
|
+
# authorisation (Always after creating client!)
|
|
59
|
+
authorisation.adapt_client(self.client)
|
|
60
|
+
authorisation.do_authorisation(self.client)
|
|
61
|
+
|
|
62
|
+
# Initialize inbound operations (lazy import to avoid circular dependencies)
|
|
63
|
+
InboundOperations = _lazy_import_inbound_operations()
|
|
64
|
+
if InboundOperations:
|
|
65
|
+
self.inbound = InboundOperations(
|
|
66
|
+
self.client,
|
|
67
|
+
logger=self.logger,
|
|
68
|
+
context=context,
|
|
69
|
+
workspace=workspace
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
self.inbound = None
|
|
73
|
+
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _get_bundled_openapi_file():
|
|
78
|
+
"""Get the path to the bundled openapi.json file.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Path to bundled openapi.json if it exists, None otherwise
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
# Get the directory of this module
|
|
85
|
+
module_dir = Path(__file__).parent
|
|
86
|
+
bundled_file = module_dir / 'openapi.json'
|
|
87
|
+
if bundled_file.exists():
|
|
88
|
+
return str(bundled_file)
|
|
89
|
+
except Exception:
|
|
90
|
+
pass
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
def __create_client(self, location_base, openapi_file, cache_openapi):
|
|
94
|
+
"""Create and initialize the OpenAPI client.
|
|
95
|
+
|
|
96
|
+
Internal method that loads the OpenAPI specification and creates the
|
|
97
|
+
requests-openapi client instance.
|
|
98
|
+
|
|
99
|
+
Priority order for loading spec:
|
|
100
|
+
1. Specified openapi_file (if exists)
|
|
101
|
+
2. Cache file (if caching enabled and exists)
|
|
102
|
+
3. Bundled openapi.json (shipped with package)
|
|
103
|
+
4. Fetch from STEP server (if caching enabled, save to cache)
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
location_base: Base URL of the STEP API server
|
|
107
|
+
openapi_file: Path to OpenAPI specification file (if available)
|
|
108
|
+
cache_openapi: Whether to cache the OpenAPI spec if fetched
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
FileNotFoundError: If specified openapi_file doesn't exist and no other source available
|
|
112
|
+
"""
|
|
113
|
+
# Determine which file to try to load
|
|
114
|
+
cache_file = self._OPENAPI_CACHE_FILE if cache_openapi else None
|
|
115
|
+
bundled_file = self._get_bundled_openapi_file()
|
|
116
|
+
|
|
117
|
+
# Try specified openapi_file first
|
|
118
|
+
if openapi_file:
|
|
119
|
+
if os.path.exists(openapi_file):
|
|
120
|
+
self.client = roa.Client().load_spec_from_file(openapi_file)
|
|
121
|
+
return
|
|
122
|
+
elif not cache_openapi:
|
|
123
|
+
# User specified a file that doesn't exist and isn't caching, so fail
|
|
124
|
+
raise FileNotFoundError(
|
|
125
|
+
f"Open API JSON File '{openapi_file}' not found!")
|
|
126
|
+
# else: continue to try other sources
|
|
127
|
+
|
|
128
|
+
# Try cache file if caching is enabled
|
|
129
|
+
if cache_file and os.path.exists(cache_file):
|
|
130
|
+
self.logger.debug(f"Loading OpenAPI spec from cache: {cache_file}")
|
|
131
|
+
self.client = roa.Client().load_spec_from_file(cache_file)
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
# Try bundled file (always available as fallback)
|
|
135
|
+
if bundled_file:
|
|
136
|
+
self.logger.debug(f"Loading OpenAPI spec from bundled file: {bundled_file}")
|
|
137
|
+
self.client = roa.Client().load_spec_from_file(bundled_file)
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
# Last resort: fetch from server
|
|
141
|
+
self.logger.debug(f"Loading OpenAPI spec from server: {location_base}/specification/openapi.json")
|
|
142
|
+
spec = roa.core.load_spec_from_url(
|
|
143
|
+
f'{location_base}/specification/openapi.json')
|
|
144
|
+
|
|
145
|
+
# If caching is enabled, save the spec
|
|
146
|
+
if cache_openapi and cache_file:
|
|
147
|
+
self.logger.debug(f"Caching OpenAPI spec to: {cache_file}")
|
|
148
|
+
with open(cache_file, 'w') as f:
|
|
149
|
+
json.dump(spec, f)
|
|
150
|
+
|
|
151
|
+
self.client = roa.Client()
|
|
152
|
+
self.client.load_spec(spec)
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
def _get_server_base_url(self):
|
|
156
|
+
"""Get configured server base URL from the OpenAPI client.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Configured server URL
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
ValueError: If server URL cannot be determined
|
|
163
|
+
"""
|
|
164
|
+
server = getattr(self.client, 'server', None) or getattr(self.client, '_server', None)
|
|
165
|
+
base_url = getattr(server, 'url', None)
|
|
166
|
+
if not base_url:
|
|
167
|
+
raise ValueError("Cannot determine server URL from client configuration")
|
|
168
|
+
return base_url
|
|
169
|
+
|
|
170
|
+
def resolve_download_url(self, uri_or_url):
|
|
171
|
+
"""Resolve absolute URL or STEP-relative ResultURI to absolute URL.
|
|
172
|
+
|
|
173
|
+
STEP OIEP REST delivery often returns a payload such as:
|
|
174
|
+
``{"ResultURI": "restapi/integrationendpoints/<endpoint>/<job>/result.zip"}``
|
|
175
|
+
This helper converts that relative URI into an absolute URL using the
|
|
176
|
+
configured server host while preserving already absolute URLs.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
uri_or_url: Absolute URL or relative ResultURI
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Absolute download URL
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
ValueError: If uri_or_url is empty or server URL is unavailable
|
|
186
|
+
"""
|
|
187
|
+
if not uri_or_url or not str(uri_or_url).strip():
|
|
188
|
+
raise ValueError("uri_or_url must not be empty")
|
|
189
|
+
|
|
190
|
+
value = str(uri_or_url).strip()
|
|
191
|
+
parsed = urlparse(value)
|
|
192
|
+
if parsed.scheme in ('http', 'https'):
|
|
193
|
+
return value
|
|
194
|
+
|
|
195
|
+
base_url = self._get_server_base_url()
|
|
196
|
+
base_parts = urlparse(base_url)
|
|
197
|
+
if not base_parts.scheme or not base_parts.netloc:
|
|
198
|
+
raise ValueError(f"Invalid server URL: {base_url}")
|
|
199
|
+
|
|
200
|
+
root_url = f"{base_parts.scheme}://{base_parts.netloc}"
|
|
201
|
+
return f"{root_url}/{value.lstrip('/')}"
|
|
202
|
+
|
|
203
|
+
def download_result_uri(self, uri_or_url, target_dir,
|
|
204
|
+
filename=None, overwrite=False,
|
|
205
|
+
chunk_size=1024 * 1024, timeout=120):
|
|
206
|
+
"""Download a file from OIEP ResultURI/URL using configured credentials.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
uri_or_url: Absolute URL or relative ResultURI from STEP
|
|
210
|
+
target_dir: Directory where the file should be stored
|
|
211
|
+
filename: Optional output filename (defaults to URL basename)
|
|
212
|
+
overwrite: Whether to overwrite an existing local file
|
|
213
|
+
chunk_size: Download chunk size in bytes
|
|
214
|
+
timeout: HTTP timeout in seconds
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Absolute path to the downloaded file
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
ValueError: If input parameters are invalid
|
|
221
|
+
FileExistsError: If destination exists and overwrite is False
|
|
222
|
+
requests.exceptions.RequestException: On HTTP/network failures
|
|
223
|
+
OSError: On file system write errors
|
|
224
|
+
"""
|
|
225
|
+
if not target_dir or not str(target_dir).strip():
|
|
226
|
+
raise ValueError("target_dir must not be empty")
|
|
227
|
+
if chunk_size <= 0:
|
|
228
|
+
raise ValueError("chunk_size must be > 0")
|
|
229
|
+
|
|
230
|
+
download_url = self.resolve_download_url(uri_or_url)
|
|
231
|
+
parsed_url = urlparse(download_url)
|
|
232
|
+
default_name = os.path.basename(parsed_url.path.rstrip('/')) or 'download.bin'
|
|
233
|
+
output_name = filename or default_name
|
|
234
|
+
|
|
235
|
+
os.makedirs(target_dir, exist_ok=True)
|
|
236
|
+
output_path = os.path.abspath(os.path.join(target_dir, output_name))
|
|
237
|
+
if os.path.exists(output_path) and not overwrite:
|
|
238
|
+
raise FileExistsError(f"Target file already exists: {output_path}")
|
|
239
|
+
|
|
240
|
+
requestor = getattr(self.client, 'requestor', None)
|
|
241
|
+
if requestor is None or not hasattr(requestor, 'get'):
|
|
242
|
+
raise ValueError("Client requestor does not support HTTP GET")
|
|
243
|
+
|
|
244
|
+
self.logger.info(f"Downloading result from {download_url} to {output_path}")
|
|
245
|
+
response = requestor.get(
|
|
246
|
+
download_url,
|
|
247
|
+
stream=True,
|
|
248
|
+
allow_redirects=True,
|
|
249
|
+
timeout=timeout
|
|
250
|
+
)
|
|
251
|
+
response.raise_for_status()
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
with open(output_path, 'wb') as f:
|
|
255
|
+
for chunk in response.iter_content(chunk_size=chunk_size):
|
|
256
|
+
if chunk:
|
|
257
|
+
f.write(chunk)
|
|
258
|
+
finally:
|
|
259
|
+
response.close()
|
|
260
|
+
|
|
261
|
+
return output_path
|
|
262
|
+
|
|
263
|
+
def download_oiep_result(self, result_payload, target_dir,
|
|
264
|
+
filename=None, overwrite=False,
|
|
265
|
+
chunk_size=1024 * 1024, timeout=120):
|
|
266
|
+
"""Download OIEP REST delivery result from response payload.
|
|
267
|
+
|
|
268
|
+
Expects payload containing ``ResultURI``, for example:
|
|
269
|
+
``{"ResultURI": "restapi/integrationendpoints/<endpoint>/<job>/result.zip"}``
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
result_payload: Dict payload returned by OIEP REST delivery endpoint
|
|
273
|
+
target_dir: Directory where the file should be stored
|
|
274
|
+
filename: Optional output filename override
|
|
275
|
+
overwrite: Whether to overwrite an existing local file
|
|
276
|
+
chunk_size: Download chunk size in bytes
|
|
277
|
+
timeout: HTTP timeout in seconds
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Absolute path to the downloaded file
|
|
281
|
+
|
|
282
|
+
Raises:
|
|
283
|
+
ValueError: If payload is invalid or missing ResultURI
|
|
284
|
+
FileExistsError: If destination exists and overwrite is False
|
|
285
|
+
requests.exceptions.RequestException: On HTTP/network failures
|
|
286
|
+
OSError: On file system write errors
|
|
287
|
+
"""
|
|
288
|
+
if not isinstance(result_payload, dict):
|
|
289
|
+
raise ValueError("result_payload must be a dict containing ResultURI")
|
|
290
|
+
|
|
291
|
+
result_uri = (
|
|
292
|
+
result_payload.get("ResultURI")
|
|
293
|
+
or result_payload.get("resultURI")
|
|
294
|
+
or result_payload.get("result_uri")
|
|
295
|
+
)
|
|
296
|
+
if not result_uri:
|
|
297
|
+
raise ValueError("result_payload does not contain ResultURI")
|
|
298
|
+
|
|
299
|
+
return self.download_result_uri(
|
|
300
|
+
uri_or_url=result_uri,
|
|
301
|
+
target_dir=target_dir,
|
|
302
|
+
filename=filename,
|
|
303
|
+
overwrite=overwrite,
|
|
304
|
+
chunk_size=chunk_size,
|
|
305
|
+
timeout=timeout,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
class __Authorisation:
|
|
309
|
+
"""Abstract base class for authentication handlers.
|
|
310
|
+
|
|
311
|
+
Provides the interface that all authentication implementations must follow.
|
|
312
|
+
Subclasses should override adapt_client() and do_authorisation() as needed.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
#: Authentication type identifier (override in subclasses)
|
|
316
|
+
TYPE = None
|
|
317
|
+
|
|
318
|
+
def adapt_client(self, client):
|
|
319
|
+
"""Adapt the client with authentication-specific configuration.
|
|
320
|
+
|
|
321
|
+
Called to modify the client's request session or configuration
|
|
322
|
+
before making authenticated requests.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
client: The requests_openapi.Client instance to configure
|
|
326
|
+
"""
|
|
327
|
+
return
|
|
328
|
+
|
|
329
|
+
def do_authorisation(self, client):
|
|
330
|
+
"""Perform any post-initialization authorization setup.
|
|
331
|
+
|
|
332
|
+
Called after client creation and adaptation to perform additional
|
|
333
|
+
authorization steps if needed (e.g., token refresh, permission checks).
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
client: The requests_openapi.Client instance
|
|
337
|
+
"""
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
def get_type(self):
|
|
341
|
+
"""Get the authentication type identifier.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
String identifying the authentication type (e.g., 'BASIC')
|
|
345
|
+
"""
|
|
346
|
+
return self.TYPE
|
|
347
|
+
|
|
348
|
+
class BasicAuthorisation(__Authorisation):
|
|
349
|
+
"""HTTP Basic Authentication handler.
|
|
350
|
+
|
|
351
|
+
Implements Basic Authentication (username/password) for STEP REST API requests.
|
|
352
|
+
Credentials are sent in the Authorization header with each request.
|
|
353
|
+
"""
|
|
354
|
+
|
|
355
|
+
#: Authentication type identifier
|
|
356
|
+
TYPE = "BASIC"
|
|
357
|
+
|
|
358
|
+
def __init__(self, user, pwd):
|
|
359
|
+
"""Initialize BasicAuthorisation with credentials.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
user: Username for Basic Auth
|
|
363
|
+
pwd: Password for Basic Auth
|
|
364
|
+
"""
|
|
365
|
+
self.user = user
|
|
366
|
+
self.pwd = pwd
|
|
367
|
+
return
|
|
368
|
+
|
|
369
|
+
def adapt_client(self, client):
|
|
370
|
+
client.requestor.auth = (self.user, self.pwd)
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
|