mpt-api-client 0.0.1__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.
- mpt_api_client/__init__.py +4 -0
- mpt_api_client/exceptions.py +69 -0
- mpt_api_client/http/__init__.py +11 -0
- mpt_api_client/http/async_client.py +106 -0
- mpt_api_client/http/async_service.py +74 -0
- mpt_api_client/http/base_service.py +58 -0
- mpt_api_client/http/client.py +108 -0
- mpt_api_client/http/mixins.py +463 -0
- mpt_api_client/http/query_state.py +72 -0
- mpt_api_client/http/service.py +79 -0
- mpt_api_client/http/types.py +42 -0
- mpt_api_client/models/__init__.py +6 -0
- mpt_api_client/models/collection.py +34 -0
- mpt_api_client/models/file_model.py +55 -0
- mpt_api_client/models/meta.py +56 -0
- mpt_api_client/models/model.py +62 -0
- mpt_api_client/mpt_client.py +130 -0
- mpt_api_client/resources/__init__.py +21 -0
- mpt_api_client/resources/accounts/__init__.py +3 -0
- mpt_api_client/resources/accounts/account.py +76 -0
- mpt_api_client/resources/accounts/account_user_groups.py +38 -0
- mpt_api_client/resources/accounts/account_users.py +66 -0
- mpt_api_client/resources/accounts/accounts.py +145 -0
- mpt_api_client/resources/accounts/accounts_user_groups.py +38 -0
- mpt_api_client/resources/accounts/accounts_users.py +68 -0
- mpt_api_client/resources/accounts/api_tokens.py +41 -0
- mpt_api_client/resources/accounts/buyers.py +91 -0
- mpt_api_client/resources/accounts/cloud_tenants.py +38 -0
- mpt_api_client/resources/accounts/erp_links.py +49 -0
- mpt_api_client/resources/accounts/licensees.py +41 -0
- mpt_api_client/resources/accounts/mixins.py +272 -0
- mpt_api_client/resources/accounts/modules.py +32 -0
- mpt_api_client/resources/accounts/sellers.py +60 -0
- mpt_api_client/resources/accounts/user_groups.py +38 -0
- mpt_api_client/resources/accounts/users.py +111 -0
- mpt_api_client/resources/audit/__init__.py +3 -0
- mpt_api_client/resources/audit/audit.py +40 -0
- mpt_api_client/resources/audit/event_types.py +42 -0
- mpt_api_client/resources/audit/records.py +42 -0
- mpt_api_client/resources/billing/__init__.py +3 -0
- mpt_api_client/resources/billing/billing.py +101 -0
- mpt_api_client/resources/billing/credit_memo_attachments.py +42 -0
- mpt_api_client/resources/billing/credit_memos.py +64 -0
- mpt_api_client/resources/billing/custom_ledger_attachments.py +42 -0
- mpt_api_client/resources/billing/custom_ledger_charges.py +38 -0
- mpt_api_client/resources/billing/custom_ledger_upload.py +31 -0
- mpt_api_client/resources/billing/custom_ledgers.py +95 -0
- mpt_api_client/resources/billing/invoice_attachments.py +42 -0
- mpt_api_client/resources/billing/invoices.py +64 -0
- mpt_api_client/resources/billing/journal_attachments.py +42 -0
- mpt_api_client/resources/billing/journal_charges.py +38 -0
- mpt_api_client/resources/billing/journal_sellers.py +38 -0
- mpt_api_client/resources/billing/journal_upload.py +38 -0
- mpt_api_client/resources/billing/journals.py +107 -0
- mpt_api_client/resources/billing/ledger_attachments.py +42 -0
- mpt_api_client/resources/billing/ledger_charges.py +38 -0
- mpt_api_client/resources/billing/ledgers.py +78 -0
- mpt_api_client/resources/billing/manual_overrides.py +46 -0
- mpt_api_client/resources/billing/mixins.py +394 -0
- mpt_api_client/resources/billing/statement_charges.py +38 -0
- mpt_api_client/resources/billing/statements.py +63 -0
- mpt_api_client/resources/catalog/__init__.py +3 -0
- mpt_api_client/resources/catalog/authorizations.py +38 -0
- mpt_api_client/resources/catalog/catalog.py +104 -0
- mpt_api_client/resources/catalog/items.py +44 -0
- mpt_api_client/resources/catalog/listings.py +38 -0
- mpt_api_client/resources/catalog/mixins.py +130 -0
- mpt_api_client/resources/catalog/price_list_items.py +38 -0
- mpt_api_client/resources/catalog/price_lists.py +54 -0
- mpt_api_client/resources/catalog/pricing_policies.py +111 -0
- mpt_api_client/resources/catalog/pricing_policy_attachments.py +45 -0
- mpt_api_client/resources/catalog/product_term_variants.py +48 -0
- mpt_api_client/resources/catalog/product_terms.py +59 -0
- mpt_api_client/resources/catalog/products.py +214 -0
- mpt_api_client/resources/catalog/products_documents.py +45 -0
- mpt_api_client/resources/catalog/products_item_groups.py +38 -0
- mpt_api_client/resources/catalog/products_media.py +113 -0
- mpt_api_client/resources/catalog/products_parameter_groups.py +38 -0
- mpt_api_client/resources/catalog/products_parameters.py +38 -0
- mpt_api_client/resources/catalog/products_templates.py +38 -0
- mpt_api_client/resources/catalog/units_of_measure.py +38 -0
- mpt_api_client/resources/commerce/__init__.py +3 -0
- mpt_api_client/resources/commerce/agreements.py +94 -0
- mpt_api_client/resources/commerce/agreements_attachments.py +46 -0
- mpt_api_client/resources/commerce/commerce.py +51 -0
- mpt_api_client/resources/commerce/orders.py +220 -0
- mpt_api_client/resources/commerce/orders_subscription.py +38 -0
- mpt_api_client/resources/commerce/subscriptions.py +97 -0
- mpt_api_client/resources/notifications/__init__.py +3 -0
- mpt_api_client/resources/notifications/accounts.py +27 -0
- mpt_api_client/resources/notifications/batches.py +128 -0
- mpt_api_client/resources/notifications/categories.py +74 -0
- mpt_api_client/resources/notifications/contacts.py +54 -0
- mpt_api_client/resources/notifications/messages.py +38 -0
- mpt_api_client/resources/notifications/notifications.py +111 -0
- mpt_api_client/resources/notifications/subscribers.py +38 -0
- mpt_api_client/rql/__init__.py +3 -0
- mpt_api_client/rql/constants.py +7 -0
- mpt_api_client/rql/query_builder.py +519 -0
- mpt_api_client-0.0.1.dist-info/METADATA +19 -0
- mpt_api_client-0.0.1.dist-info/RECORD +103 -0
- mpt_api_client-0.0.1.dist-info/WHEEL +4 -0
- mpt_api_client-0.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from httpx import HTTPStatusError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MPTError(Exception):
|
|
8
|
+
"""Represents a generic MPT error."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MPTHttpError(MPTError):
|
|
12
|
+
"""Represents an HTTP error."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, status_code: int, message: str, body: str):
|
|
15
|
+
self.status_code = status_code
|
|
16
|
+
self.body = body
|
|
17
|
+
super().__init__(f"HTTP {status_code}: {message}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MPTAPIError(MPTHttpError):
|
|
21
|
+
"""Represents an API error."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, status_code: int, message: str, payload: dict[str, str]):
|
|
24
|
+
super().__init__(status_code, message, json.dumps(payload))
|
|
25
|
+
self.payload = payload
|
|
26
|
+
self.status: str | None = payload.get("status") or payload.get("statusCode")
|
|
27
|
+
self.title: str | None = payload.get("title") or payload.get("message")
|
|
28
|
+
self.detail: str | None = payload.get("detail") or message
|
|
29
|
+
self.trace_id: str | None = payload.get("traceId")
|
|
30
|
+
self.errors: str | None = payload.get("errors")
|
|
31
|
+
|
|
32
|
+
@override
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
base = f"{self.status} {self.title} - {self.detail} ({self.trace_id or 'no-trace-id'})" # noqa: WPS221 WPS237
|
|
35
|
+
|
|
36
|
+
if self.errors:
|
|
37
|
+
return f"{base}\n{json.dumps(self.errors, indent=2)}"
|
|
38
|
+
return base
|
|
39
|
+
|
|
40
|
+
@override
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return str(self.payload)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def transform_http_status_exception(http_status_exception: HTTPStatusError) -> MPTError:
|
|
46
|
+
"""Transforms httpx exceptions into MPT exceptions.
|
|
47
|
+
|
|
48
|
+
Attempts to extract API related information from HTTPStatusError and
|
|
49
|
+
raises MPTAPIError or MPTHttpError.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
http_status_exception: Native httpx exception
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
MPTError
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
return MPTAPIError(
|
|
59
|
+
status_code=http_status_exception.response.status_code,
|
|
60
|
+
message=http_status_exception.args[0],
|
|
61
|
+
payload=http_status_exception.response.json(),
|
|
62
|
+
)
|
|
63
|
+
except json.JSONDecodeError:
|
|
64
|
+
body = http_status_exception.response.content.decode()
|
|
65
|
+
return MPTHttpError(
|
|
66
|
+
status_code=http_status_exception.response.status_code,
|
|
67
|
+
message=http_status_exception.args[0],
|
|
68
|
+
body=body,
|
|
69
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from mpt_api_client.http.async_client import AsyncHTTPClient
|
|
2
|
+
from mpt_api_client.http.async_service import AsyncService
|
|
3
|
+
from mpt_api_client.http.client import HTTPClient
|
|
4
|
+
from mpt_api_client.http.service import Service
|
|
5
|
+
|
|
6
|
+
__all__ = [ # noqa: WPS410
|
|
7
|
+
"AsyncHTTPClient",
|
|
8
|
+
"AsyncService",
|
|
9
|
+
"HTTPClient",
|
|
10
|
+
"Service",
|
|
11
|
+
]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from httpx import (
|
|
5
|
+
AsyncClient,
|
|
6
|
+
AsyncHTTPTransport,
|
|
7
|
+
HTTPError,
|
|
8
|
+
HTTPStatusError,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from mpt_api_client.exceptions import MPTError, transform_http_status_exception
|
|
12
|
+
from mpt_api_client.http.types import (
|
|
13
|
+
HeaderTypes,
|
|
14
|
+
QueryParam,
|
|
15
|
+
RequestFiles,
|
|
16
|
+
Response,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AsyncHTTPClient:
|
|
21
|
+
"""Async HTTP client for interacting with SoftwareOne Marketplace Platform API."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
base_url: str | None = None,
|
|
27
|
+
api_token: str | None = None,
|
|
28
|
+
timeout: float = 5.0,
|
|
29
|
+
retries: int = 5,
|
|
30
|
+
):
|
|
31
|
+
api_token = api_token or os.getenv("MPT_TOKEN")
|
|
32
|
+
if not api_token:
|
|
33
|
+
raise ValueError(
|
|
34
|
+
"API token is required. "
|
|
35
|
+
"Set it up as env variable MPT_TOKEN or pass it as `api_token` "
|
|
36
|
+
"argument to MPTClient."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
base_url = base_url or os.getenv("MPT_URL")
|
|
40
|
+
if not base_url:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
"Base URL is required. "
|
|
43
|
+
"Set it up as env variable MPT_URL or pass it as `base_url` "
|
|
44
|
+
"argument to MPTClient."
|
|
45
|
+
)
|
|
46
|
+
base_headers = {
|
|
47
|
+
"User-Agent": "swo-marketplace-client/1.0",
|
|
48
|
+
"Authorization": f"Bearer {api_token}",
|
|
49
|
+
"Accept": "application/json",
|
|
50
|
+
}
|
|
51
|
+
self.httpx_client = AsyncClient(
|
|
52
|
+
base_url=base_url,
|
|
53
|
+
headers=base_headers,
|
|
54
|
+
timeout=timeout,
|
|
55
|
+
transport=AsyncHTTPTransport(retries=retries),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
async def request( # noqa: WPS211
|
|
59
|
+
self,
|
|
60
|
+
method: str,
|
|
61
|
+
url: str,
|
|
62
|
+
*,
|
|
63
|
+
files: RequestFiles | None = None,
|
|
64
|
+
json: Any | None = None,
|
|
65
|
+
query_params: QueryParam | None = None,
|
|
66
|
+
headers: HeaderTypes | None = None,
|
|
67
|
+
) -> Response:
|
|
68
|
+
"""Perform an HTTP request.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
method: HTTP method.
|
|
72
|
+
url: URL to send the request to.
|
|
73
|
+
files: Request files.
|
|
74
|
+
json: Request JSON data.
|
|
75
|
+
query_params: Query parameters.
|
|
76
|
+
headers: Request headers.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Response object.
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
MPTError: If the request fails.
|
|
83
|
+
MPTApiError: If the response contains an error.
|
|
84
|
+
MPTHttpError: If the response contains an HTTP error.
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
response = await self.httpx_client.request(
|
|
88
|
+
method,
|
|
89
|
+
url,
|
|
90
|
+
files=files,
|
|
91
|
+
json=json,
|
|
92
|
+
params=query_params,
|
|
93
|
+
headers=headers,
|
|
94
|
+
)
|
|
95
|
+
except HTTPError as err:
|
|
96
|
+
raise MPTError(f"HTTP Error: {err}") from err
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
response.raise_for_status()
|
|
100
|
+
except HTTPStatusError as http_status_exception:
|
|
101
|
+
raise transform_http_status_exception(http_status_exception) from http_status_exception
|
|
102
|
+
return Response(
|
|
103
|
+
headers=dict(response.headers),
|
|
104
|
+
status_code=response.status_code,
|
|
105
|
+
content=response.content,
|
|
106
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from urllib.parse import urljoin
|
|
2
|
+
|
|
3
|
+
from mpt_api_client.http.async_client import AsyncHTTPClient
|
|
4
|
+
from mpt_api_client.http.base_service import ServiceBase
|
|
5
|
+
from mpt_api_client.http.types import QueryParam, Response
|
|
6
|
+
from mpt_api_client.models import Model as BaseModel
|
|
7
|
+
from mpt_api_client.models import ResourceData
|
|
8
|
+
from mpt_api_client.models.collection import ResourceList
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AsyncService[Model: BaseModel](ServiceBase[AsyncHTTPClient, Model]): # noqa: WPS214
|
|
12
|
+
"""Immutable Service for RESTful resource collections.
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
active_orders_cc = order_collection.filter(RQLQuery(status="active"))
|
|
16
|
+
active_orders = active_orders_cc.order_by("created").iterate()
|
|
17
|
+
product_active_orders = active_orders_cc.filter(RQLQuery(product__id="PRD-1")).iterate()
|
|
18
|
+
|
|
19
|
+
new_order = order_collection.create(order_data)
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
async def _resource_do_request( # noqa: WPS211
|
|
24
|
+
self,
|
|
25
|
+
resource_id: str,
|
|
26
|
+
method: str = "GET",
|
|
27
|
+
action: str | None = None,
|
|
28
|
+
json: ResourceData | ResourceList | None = None,
|
|
29
|
+
query_params: QueryParam | None = None,
|
|
30
|
+
headers: dict[str, str] | None = None,
|
|
31
|
+
) -> Response:
|
|
32
|
+
"""Perform an action on a specific resource using.
|
|
33
|
+
|
|
34
|
+
Request with action: `HTTP_METHOD /endpoint/{resource_id}/{action}`.
|
|
35
|
+
Request without action: `HTTP_METHOD /endpoint/{resource_id}`.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
resource_id: The resource ID to operate on.
|
|
39
|
+
method: The HTTP method to use.
|
|
40
|
+
action: The action name to use.
|
|
41
|
+
json: The updated resource data.
|
|
42
|
+
query_params: Additional query parameters.
|
|
43
|
+
headers: Additional headers.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
HTTPError: If the action fails.
|
|
47
|
+
"""
|
|
48
|
+
resource_url = urljoin(f"{self.path}/", resource_id)
|
|
49
|
+
url = urljoin(f"{resource_url}/", action) if action else resource_url
|
|
50
|
+
return await self.http_client.request(
|
|
51
|
+
method, url, json=json, query_params=query_params, headers=headers
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async def _resource_action(
|
|
55
|
+
self,
|
|
56
|
+
resource_id: str,
|
|
57
|
+
method: str = "GET",
|
|
58
|
+
action: str | None = None,
|
|
59
|
+
json: ResourceData | ResourceList | None = None,
|
|
60
|
+
query_params: QueryParam | None = None,
|
|
61
|
+
) -> Model:
|
|
62
|
+
"""Perform an action on a specific resource using `HTTP_METHOD /endpoint/{resource_id}`.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
resource_id: The resource ID to operate on.
|
|
66
|
+
method: The HTTP method to use.
|
|
67
|
+
action: The action name to use.
|
|
68
|
+
json: The updated resource data.
|
|
69
|
+
query_params: Additional query parameters.
|
|
70
|
+
"""
|
|
71
|
+
response = await self._resource_do_request(
|
|
72
|
+
resource_id, method, action, json=json, query_params=query_params
|
|
73
|
+
)
|
|
74
|
+
return self._model_class.from_response(response)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from mpt_api_client.http.query_state import QueryState
|
|
4
|
+
from mpt_api_client.http.types import Response
|
|
5
|
+
from mpt_api_client.models import Collection, Meta
|
|
6
|
+
from mpt_api_client.models import Model as BaseModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ServiceBase[Client, Model: BaseModel]: # noqa: WPS214
|
|
10
|
+
"""Service base with agnostic HTTP client."""
|
|
11
|
+
|
|
12
|
+
_endpoint: str
|
|
13
|
+
_model_class: type[Model]
|
|
14
|
+
_collection_key = "data"
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
*,
|
|
19
|
+
http_client: Client,
|
|
20
|
+
query_state: QueryState | None = None,
|
|
21
|
+
endpoint_params: dict[str, str] | None = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.http_client = http_client
|
|
24
|
+
self.query_state = query_state or QueryState()
|
|
25
|
+
self.endpoint_params = endpoint_params or {}
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def path(self) -> str:
|
|
29
|
+
"""Service endpoint URL."""
|
|
30
|
+
return self._endpoint.format(**self.endpoint_params)
|
|
31
|
+
|
|
32
|
+
def build_path(
|
|
33
|
+
self,
|
|
34
|
+
query_params: dict[str, Any] | None = None,
|
|
35
|
+
) -> str:
|
|
36
|
+
"""Builds the endpoint URL with all the query parameters.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Complete URL with query parameters.
|
|
40
|
+
"""
|
|
41
|
+
query = self.query_state.build(query_params)
|
|
42
|
+
return f"{self.path}?{query}" if query else self.path
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def make_collection(cls, response: Response) -> Collection[Model]:
|
|
46
|
+
"""Builds a collection from a response.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
response: The response object.
|
|
50
|
+
"""
|
|
51
|
+
meta = Meta.from_response(response)
|
|
52
|
+
return Collection(
|
|
53
|
+
resources=[
|
|
54
|
+
cls._model_class.new(resource, meta)
|
|
55
|
+
for resource in response.json().get(cls._collection_key)
|
|
56
|
+
],
|
|
57
|
+
meta=meta,
|
|
58
|
+
)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from httpx import (
|
|
5
|
+
Client,
|
|
6
|
+
HTTPError,
|
|
7
|
+
HTTPStatusError,
|
|
8
|
+
HTTPTransport,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from mpt_api_client.exceptions import (
|
|
12
|
+
MPTError,
|
|
13
|
+
transform_http_status_exception,
|
|
14
|
+
)
|
|
15
|
+
from mpt_api_client.http.types import (
|
|
16
|
+
HeaderTypes,
|
|
17
|
+
QueryParam,
|
|
18
|
+
RequestFiles,
|
|
19
|
+
Response,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class HTTPClient:
|
|
24
|
+
"""Sync HTTP client for interacting with SoftwareOne Marketplace Platform API."""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
base_url: str | None = None,
|
|
30
|
+
api_token: str | None = None,
|
|
31
|
+
timeout: float = 5.0,
|
|
32
|
+
retries: int = 5,
|
|
33
|
+
):
|
|
34
|
+
api_token = api_token or os.getenv("MPT_TOKEN")
|
|
35
|
+
if not api_token:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"API token is required. "
|
|
38
|
+
"Set it up as env variable MPT_TOKEN or pass it as `api_token` "
|
|
39
|
+
"argument to MPTClient."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
base_url = base_url or os.getenv("MPT_URL")
|
|
43
|
+
if not base_url:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
"Base URL is required. "
|
|
46
|
+
"Set it up as env variable MPT_URL or pass it as `base_url` "
|
|
47
|
+
"argument to MPTClient."
|
|
48
|
+
)
|
|
49
|
+
base_headers = {
|
|
50
|
+
"User-Agent": "swo-marketplace-client/1.0",
|
|
51
|
+
"Authorization": f"Bearer {api_token}",
|
|
52
|
+
}
|
|
53
|
+
self.httpx_client = Client(
|
|
54
|
+
base_url=base_url,
|
|
55
|
+
headers=base_headers,
|
|
56
|
+
timeout=timeout,
|
|
57
|
+
transport=HTTPTransport(retries=retries),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def request( # noqa: WPS211
|
|
61
|
+
self,
|
|
62
|
+
method: str,
|
|
63
|
+
url: str,
|
|
64
|
+
*,
|
|
65
|
+
files: RequestFiles | None = None,
|
|
66
|
+
json: Any | None = None,
|
|
67
|
+
query_params: QueryParam | None = None,
|
|
68
|
+
headers: HeaderTypes | None = None,
|
|
69
|
+
) -> Response:
|
|
70
|
+
"""Perform an HTTP request.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
method: HTTP method.
|
|
74
|
+
url: URL to send the request to.
|
|
75
|
+
files: Request files.
|
|
76
|
+
json: Request JSON data.
|
|
77
|
+
query_params: Query parameters.
|
|
78
|
+
headers: Request headers.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Response object.
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
MPTError: If the request fails.
|
|
85
|
+
MPTApiError: If the response contains an error.
|
|
86
|
+
MPTHttpError: If the response contains an HTTP error.
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
response = self.httpx_client.request(
|
|
90
|
+
method,
|
|
91
|
+
url,
|
|
92
|
+
files=files,
|
|
93
|
+
json=json,
|
|
94
|
+
params=query_params,
|
|
95
|
+
headers=headers,
|
|
96
|
+
)
|
|
97
|
+
except HTTPError as err:
|
|
98
|
+
raise MPTError(f"HTTP Error: {err}") from err
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
response.raise_for_status()
|
|
102
|
+
except HTTPStatusError as http_status_exception:
|
|
103
|
+
raise transform_http_status_exception(http_status_exception) from http_status_exception
|
|
104
|
+
return Response(
|
|
105
|
+
headers=dict(response.headers),
|
|
106
|
+
status_code=response.status_code,
|
|
107
|
+
content=response.content,
|
|
108
|
+
)
|