vtexpy 0.0.0b25__py3-none-any.whl → 0.0.0b27__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 vtexpy might be problematic. Click here for more details.

vtex/_api/__init__.py CHANGED
@@ -6,4 +6,5 @@ from .logistics import LogisticsAPI
6
6
  from .master_data import MasterDataAPI
7
7
  from .orders import OrdersAPI
8
8
  from .payments_gateway import PaymentsGatewayAPI
9
+ from .pricing import PricingAPI
9
10
  from .promotions_and_taxes import PromotionsAndTaxesAPI
vtex/_api/base.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from http import HTTPStatus
2
2
  from json import JSONDecodeError
3
+ from time import sleep
3
4
  from typing import Any, Type, Union, cast
4
- from urllib.parse import urljoin
5
5
 
6
6
  from httpx import (
7
7
  Client,
@@ -18,6 +18,7 @@ from httpx._types import (
18
18
  RequestData,
19
19
  RequestFiles,
20
20
  )
21
+ from limits import RateLimitItem, storage, strategies
21
22
  from tenacity import (
22
23
  retry,
23
24
  retry_if_exception_type,
@@ -31,7 +32,7 @@ from .._dto import VTEXDataResponse, VTEXResponseType
31
32
  from .._exceptions import VTEXRequestError, VTEXResponseError
32
33
  from .._logging import disable_loggers, get_logger, log_before_retry
33
34
  from .._types import HTTPMethodType
34
- from .._utils import redact_headers, to_snake_case, to_snake_case_deep
35
+ from .._utils import join_url, redact_headers, to_snake_case, to_snake_case_deep
35
36
  from .._vtex import VTEX
36
37
 
37
38
 
@@ -50,8 +51,8 @@ class BaseAPI:
50
51
  def _request(
51
52
  self,
52
53
  method: HTTPMethodType,
53
- environment: str,
54
54
  endpoint: str,
55
+ environment: Union[str, None] = None,
55
56
  headers: Union[HeaderTypes, None] = None,
56
57
  cookies: Union[CookieTypes, None] = None,
57
58
  params: Union[QueryParamTypes, None] = None,
@@ -60,15 +61,23 @@ class BaseAPI:
60
61
  content: Union[RequestContent, None] = None,
61
62
  files: Union[RequestFiles, None] = None,
62
63
  config: Union[VTEXConfig, None] = None,
64
+ rate_limit: Union[RateLimitItem, None] = None,
63
65
  response_class: Union[Type[VTEXResponseType], None] = None,
64
66
  **kwargs: Any,
65
67
  ) -> VTEXResponseType:
66
68
  request_config = (config or self.client.config).with_overrides(**kwargs)
67
69
 
68
- url = urljoin(
69
- f"https://{request_config.account_name}.{environment}.com.br",
70
- endpoint,
71
- )
70
+ if environment:
71
+ url = join_url(
72
+ f"https://{request_config.account_name}.{environment}.com.br",
73
+ endpoint,
74
+ )
75
+ else:
76
+ url = join_url(
77
+ "https://api.vtex.com/",
78
+ request_config.account_name,
79
+ endpoint,
80
+ )
72
81
 
73
82
  headers = Headers(headers=headers)
74
83
  headers[APP_KEY_HEADER] = request_config.app_key.get_secret_value()
@@ -76,6 +85,14 @@ class BaseAPI:
76
85
  headers["Content-Type"] = "application/json; charset=utf-8"
77
86
  headers["Accept"] = "application/json"
78
87
 
88
+ rate_limiter = (
89
+ None
90
+ if not (rate_limit and request_config.rate_limit_storage_url)
91
+ else strategies.MovingWindowRateLimiter(
92
+ storage.storage_from_string(request_config.rate_limit_storage_url),
93
+ )
94
+ )
95
+
79
96
  @retry(
80
97
  stop=stop_after_attempt(
81
98
  max_attempt_number=request_config.retry_attempts + 1,
@@ -102,17 +119,36 @@ class BaseAPI:
102
119
  def send_vtex_request() -> Response:
103
120
  with Client(timeout=request_config.timeout) as client:
104
121
  with disable_loggers(["httpcore", "httpx"]):
105
- response = client.request(
106
- method.upper(),
107
- url,
108
- headers=headers,
109
- cookies=cookies,
110
- params=params,
111
- json=json,
112
- data=data,
113
- content=content,
114
- files=files,
115
- )
122
+ while (
123
+ rate_limiter
124
+ and rate_limit
125
+ and not rate_limiter.test(
126
+ rate_limit,
127
+ request_config.account_name,
128
+ endpoint,
129
+ )
130
+ ):
131
+ sleep(1)
132
+
133
+ try:
134
+ response = client.request(
135
+ method.upper(),
136
+ url,
137
+ headers=headers,
138
+ cookies=cookies,
139
+ params=params,
140
+ json=json,
141
+ data=data,
142
+ content=content,
143
+ files=files,
144
+ )
145
+ finally:
146
+ if rate_limiter and rate_limit:
147
+ rate_limiter.hit(
148
+ rate_limit,
149
+ request_config.account_name,
150
+ endpoint,
151
+ )
116
152
 
117
153
  response.request.headers = Headers(
118
154
  redact_headers(dict(response.request.headers)),
@@ -183,7 +219,7 @@ class BaseAPI:
183
219
  method=str(response.request.method).upper(),
184
220
  url=str(response.request.url),
185
221
  request_headers=response.request.headers,
186
- status=response.status_code,
222
+ status_code=response.status_code,
187
223
  data=data,
188
224
  response_headers=response.headers,
189
225
  ) from None
vtex/_api/catalog.py CHANGED
@@ -32,8 +32,8 @@ class CatalogAPI(BaseAPI):
32
32
  ) -> VTEXItemsResponse[List[Seller], Seller]:
33
33
  return self._request(
34
34
  method="GET",
35
- environment=self.ENVIRONMENT,
36
35
  endpoint="/api/catalog_system/pvt/seller/list",
36
+ environment=self.ENVIRONMENT,
37
37
  params=omitting_undefined({
38
38
  "sc": sales_channel,
39
39
  "sellerType": seller_type,
@@ -49,8 +49,8 @@ class CatalogAPI(BaseAPI):
49
49
  ) -> VTEXItemsResponse[List[SalesChannel], SalesChannel]:
50
50
  return self._request(
51
51
  method="GET",
52
- environment=self.ENVIRONMENT,
53
52
  endpoint="/api/catalog_system/pvt/saleschannel/list",
53
+ environment=self.ENVIRONMENT,
54
54
  config=self.client.config.with_overrides(**kwargs),
55
55
  response_class=VTEXItemsResponse[Any, Any],
56
56
  )
@@ -63,8 +63,8 @@ class CatalogAPI(BaseAPI):
63
63
  ) -> VTEXItemsResponse[List[int], int]:
64
64
  return self._request(
65
65
  method="GET",
66
- environment=self.ENVIRONMENT,
67
66
  endpoint="/api/catalog_system/pvt/sku/stockkeepingunitids",
67
+ environment=self.ENVIRONMENT,
68
68
  params={
69
69
  "page": max(page, LIST_SKU_IDS_START_PAGE),
70
70
  "pagesize": max(
@@ -83,8 +83,8 @@ class CatalogAPI(BaseAPI):
83
83
  ) -> VTEXDataResponse[Any]:
84
84
  return self._request(
85
85
  method="GET",
86
- environment=self.ENVIRONMENT,
87
86
  endpoint=f"/api/catalog_system/pvt/sku/stockkeepingunitbyid/{sku_id}",
87
+ environment=self.ENVIRONMENT,
88
88
  config=self.client.config.with_overrides(**kwargs),
89
89
  response_class=VTEXDataResponse[Any],
90
90
  )
@@ -97,8 +97,8 @@ class CatalogAPI(BaseAPI):
97
97
  ) -> VTEXPaginatedItemsResponse[Any, Any]:
98
98
  return self._request(
99
99
  method="GET",
100
- environment=self.ENVIRONMENT,
101
100
  endpoint="/api/catalog/pvt/category",
101
+ environment=self.ENVIRONMENT,
102
102
  params={
103
103
  "page": max(page, LIST_CATEGORIES_START_PAGE),
104
104
  "pagesize": max(
@@ -117,8 +117,8 @@ class CatalogAPI(BaseAPI):
117
117
  ) -> VTEXDataResponse[Any]:
118
118
  return self._request(
119
119
  method="GET",
120
- environment=self.ENVIRONMENT,
121
120
  endpoint=f"/api/catalog_system/pub/category/tree/{levels}",
121
+ environment=self.ENVIRONMENT,
122
122
  config=self.client.config.with_overrides(**kwargs),
123
123
  response_class=VTEXDataResponse[Any],
124
124
  )
@@ -130,8 +130,8 @@ class CatalogAPI(BaseAPI):
130
130
  ) -> VTEXDataResponse[Any]:
131
131
  return self._request(
132
132
  method="GET",
133
- environment=self.ENVIRONMENT,
134
133
  endpoint=f"/api/catalog/pvt/category/{category_id}",
134
+ environment=self.ENVIRONMENT,
135
135
  config=self.client.config.with_overrides(**kwargs),
136
136
  response_class=VTEXDataResponse[Any],
137
137
  )
vtex/_api/checkout.py CHANGED
@@ -27,8 +27,8 @@ class CheckoutAPI(BaseAPI):
27
27
  ) -> VTEXDataResponse[Any]:
28
28
  return self._request(
29
29
  method="POST",
30
- environment=self.ENVIRONMENT,
31
30
  endpoint="/api/checkout/pub/orderForms/simulation",
31
+ environment=self.ENVIRONMENT,
32
32
  params=omitting_undefined({
33
33
  "RnbBehavior": rnb_behavior,
34
34
  "sc": sales_channel,
vtex/_api/custom.py CHANGED
@@ -28,8 +28,8 @@ class CustomAPI(BaseAPI):
28
28
  def request(
29
29
  self,
30
30
  method: HTTPMethodType,
31
- environment: str,
32
31
  endpoint: str,
32
+ environment: Union[str, None] = None,
33
33
  headers: Union[HeaderTypes, None] = None,
34
34
  cookies: Union[CookieTypes, None] = None,
35
35
  params: Union[QueryParamTypes, None] = None,
@@ -42,8 +42,8 @@ class CustomAPI(BaseAPI):
42
42
  ) -> VTEXResponseType:
43
43
  return self._request(
44
44
  method=method,
45
- environment=environment,
46
45
  endpoint=endpoint,
46
+ environment=environment,
47
47
  headers=headers,
48
48
  cookies=cookies,
49
49
  params=params,
@@ -27,8 +27,8 @@ class LicenseManagerAPI(BaseAPI):
27
27
  def get_account(self, **kwargs: Any) -> VTEXDataResponse[GetAccountData]:
28
28
  return self._request(
29
29
  method="GET",
30
- environment=self.ENVIRONMENT,
31
30
  endpoint="/api/vlm/account",
31
+ environment=self.ENVIRONMENT,
32
32
  config=self.client.config.with_overrides(**kwargs),
33
33
  response_class=VTEXDataResponse[GetAccountData],
34
34
  )
@@ -50,8 +50,8 @@ class LicenseManagerAPI(BaseAPI):
50
50
 
51
51
  return self._request(
52
52
  method="GET",
53
- environment=self.ENVIRONMENT,
54
53
  endpoint=f"/api/license-manager/users/{user_id}/roles",
54
+ environment=self.ENVIRONMENT,
55
55
  config=config,
56
56
  response_class=VTEXItemsResponse[List[UserRole], UserRole],
57
57
  )
@@ -66,8 +66,8 @@ class LicenseManagerAPI(BaseAPI):
66
66
  ) -> VTEXPaginatedItemsResponse[ListRolesData, Role]:
67
67
  return self._request(
68
68
  method="GET",
69
- environment=self.ENVIRONMENT,
70
69
  endpoint="/api/license-manager/site/pvt/roles/list/paged",
70
+ environment=self.ENVIRONMENT,
71
71
  params={
72
72
  "sort": order_by_field,
73
73
  "sortType": order_by_direction,
vtex/_api/logistics.py CHANGED
@@ -29,8 +29,8 @@ class LogisticsAPI(BaseAPI):
29
29
  ) -> VTEXPaginatedItemsResponse[Any, Any]:
30
30
  return self._request(
31
31
  method="GET",
32
- environment=self.ENVIRONMENT,
33
32
  endpoint="/api/logistics/pvt/shipping-policies",
33
+ environment=self.ENVIRONMENT,
34
34
  params={
35
35
  "page": max(page, LIST_SHIPPING_POLICIES_START_PAGE),
36
36
  "perPage": max(
@@ -49,8 +49,8 @@ class LogisticsAPI(BaseAPI):
49
49
  ) -> VTEXDataResponse[Any]:
50
50
  return self._request(
51
51
  method="GET",
52
- environment=self.ENVIRONMENT,
53
52
  endpoint=f"/api/logistics/pvt/shipping-policies/{shipping_policy_id}",
53
+ environment=self.ENVIRONMENT,
54
54
  config=self.client.config.with_overrides(**kwargs),
55
55
  response_class=VTEXDataResponse[Any],
56
56
  )
@@ -63,8 +63,8 @@ class LogisticsAPI(BaseAPI):
63
63
  ) -> VTEXPaginatedItemsResponse[Any, Any]:
64
64
  return self._request(
65
65
  method="GET",
66
- environment=self.ENVIRONMENT,
67
66
  endpoint="/api/logistics/pvt/configuration/carriers",
67
+ environment=self.ENVIRONMENT,
68
68
  params={
69
69
  "page": max(page, LIST_CARRIERS_START_PAGE),
70
70
  "perPage": max(
@@ -83,8 +83,8 @@ class LogisticsAPI(BaseAPI):
83
83
  ) -> VTEXDataResponse[Any]:
84
84
  return self._request(
85
85
  method="GET",
86
- environment=self.ENVIRONMENT,
87
86
  endpoint=f"/api/logistics/pvt/configuration/carriers/{carrier_id}",
87
+ environment=self.ENVIRONMENT,
88
88
  config=self.client.config.with_overrides(**kwargs),
89
89
  response_class=VTEXDataResponse[Any],
90
90
  )
@@ -97,8 +97,8 @@ class LogisticsAPI(BaseAPI):
97
97
  ) -> VTEXPaginatedItemsResponse[Any, Any]:
98
98
  return self._request(
99
99
  method="GET",
100
- environment=self.ENVIRONMENT,
101
100
  endpoint="/api/logistics/pvt/configuration/docks",
101
+ environment=self.ENVIRONMENT,
102
102
  params={
103
103
  "page": max(page, LIST_DOCKS_START_PAGE),
104
104
  "perPage": max(
@@ -113,8 +113,8 @@ class LogisticsAPI(BaseAPI):
113
113
  def get_dock(self, dock_id: str, **kwargs: Any) -> VTEXDataResponse[Any]:
114
114
  return self._request(
115
115
  method="GET",
116
- environment=self.ENVIRONMENT,
117
116
  endpoint=f"/api/logistics/pvt/configuration/docks/{dock_id}",
117
+ environment=self.ENVIRONMENT,
118
118
  config=self.client.config.with_overrides(**kwargs),
119
119
  response_class=VTEXDataResponse[Any],
120
120
  )
@@ -127,11 +127,11 @@ class LogisticsAPI(BaseAPI):
127
127
  ) -> VTEXItemsResponse[Any, Any]:
128
128
  return self._request(
129
129
  method="GET",
130
- environment=self.ENVIRONMENT,
131
130
  endpoint=(
132
131
  f"/api/logistics/pvt/configuration/freights/{carrier_id}/{zip_code}"
133
132
  f"/values"
134
133
  ),
134
+ environment=self.ENVIRONMENT,
135
135
  config=self.client.config.with_overrides(**kwargs),
136
136
  response_class=VTEXItemsResponse[Any, Any],
137
137
  )
@@ -143,8 +143,8 @@ class LogisticsAPI(BaseAPI):
143
143
  ) -> VTEXDataResponse[Any]:
144
144
  return self._request(
145
145
  method="GET",
146
- environment=self.ENVIRONMENT,
147
146
  endpoint=f"/api/logistics/pvt/inventory/skus/{sku_id}",
147
+ environment=self.ENVIRONMENT,
148
148
  config=self.client.config.with_overrides(**kwargs),
149
149
  response_class=VTEXDataResponse[Any],
150
150
  )
vtex/_api/master_data.py CHANGED
@@ -51,8 +51,8 @@ class MasterDataAPI(BaseAPI):
51
51
 
52
52
  return self._request(
53
53
  method="GET",
54
- environment=self.ENVIRONMENT,
55
54
  endpoint=f"/api/dataentities/{entity_name}/search",
55
+ environment=self.ENVIRONMENT,
56
56
  params=omitting_undefined(params),
57
57
  headers={
58
58
  "REST-Range": f"resources={(page - 1) * page_size}-{page * page_size}",
vtex/_api/orders.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from datetime import datetime, timedelta, timezone
2
2
  from typing import Any, Dict, List, Union
3
3
 
4
+ from limits import parse
5
+
4
6
  from .._constants import (
5
7
  LIST_FEED_ORDERS_MAX_PAGE_SIZE,
6
8
  LIST_ORDERS_MAX_PAGE,
@@ -82,10 +84,11 @@ class OrdersAPI(BaseAPI):
82
84
 
83
85
  response = self._request(
84
86
  method="GET",
85
- environment=self.ENVIRONMENT,
86
87
  endpoint="/api/oms/pvt/orders/",
88
+ environment=self.ENVIRONMENT,
87
89
  params=params,
88
90
  config=self.client.config.with_overrides(**kwargs),
91
+ rate_limit=parse("80 per second"),
89
92
  response_class=VTEXPaginatedItemsResponse[Any, Any],
90
93
  )
91
94
 
@@ -98,8 +101,8 @@ class OrdersAPI(BaseAPI):
98
101
  def get_order(self, order_id: str, **kwargs: Any) -> VTEXDataResponse[Any]:
99
102
  return self._request(
100
103
  method="GET",
101
- environment=self.ENVIRONMENT,
102
104
  endpoint=f"/api/oms/pvt/orders/{order_id}",
105
+ environment=self.ENVIRONMENT,
103
106
  config=self.client.config.with_overrides(**kwargs),
104
107
  response_class=VTEXDataResponse[Any],
105
108
  )
@@ -111,8 +114,8 @@ class OrdersAPI(BaseAPI):
111
114
  ) -> VTEXItemsResponse[Any, Any]:
112
115
  return self._request(
113
116
  method="GET",
114
- environment=self.ENVIRONMENT,
115
117
  endpoint="/api/orders/feed/",
118
+ environment=self.ENVIRONMENT,
116
119
  params={
117
120
  "maxlot": max(
118
121
  min(page_size, LIST_FEED_ORDERS_MAX_PAGE_SIZE),
@@ -140,8 +143,8 @@ class OrdersAPI(BaseAPI):
140
143
 
141
144
  return self._request(
142
145
  method="POST",
143
- environment=self.ENVIRONMENT,
144
146
  endpoint="/api/orders/feed/",
147
+ environment=self.ENVIRONMENT,
145
148
  json={"handles": handles},
146
149
  config=self.client.config.with_overrides(**kwargs),
147
150
  response_class=VTEXDataResponse[Any],
@@ -1,5 +1,7 @@
1
1
  from typing import Any
2
2
 
3
+ from limits import parse
4
+
3
5
  from .._dto import VTEXDataResponse, VTEXItemsResponse
4
6
  from .base import BaseAPI
5
7
 
@@ -19,8 +21,8 @@ class PaymentsGatewayAPI(BaseAPI):
19
21
  ) -> VTEXDataResponse[Any]:
20
22
  return self._request(
21
23
  method="GET",
22
- environment=self.ENVIRONMENT,
23
24
  endpoint=f"/api/pvt/transactions/{transaction_id}",
25
+ environment=self.ENVIRONMENT,
24
26
  config=self.client.config.with_overrides(**kwargs),
25
27
  response_class=VTEXDataResponse[Any],
26
28
  )
@@ -32,9 +34,10 @@ class PaymentsGatewayAPI(BaseAPI):
32
34
  ) -> VTEXItemsResponse[Any, Any]:
33
35
  return self._request(
34
36
  method="GET",
35
- environment=self.ENVIRONMENT,
36
37
  endpoint=f"/api/pvt/transactions/{transaction_id}/interactions",
38
+ environment=self.ENVIRONMENT,
37
39
  config=self.client.config.with_overrides(**kwargs),
40
+ rate_limit=parse("60 per second"),
38
41
  response_class=VTEXItemsResponse[Any, Any],
39
42
  )
40
43
 
@@ -45,8 +48,8 @@ class PaymentsGatewayAPI(BaseAPI):
45
48
  ) -> VTEXItemsResponse[Any, Any]:
46
49
  return self._request(
47
50
  method="GET",
48
- environment=self.ENVIRONMENT,
49
51
  endpoint=f"/api/pvt/transactions/{transaction_id}/payments",
52
+ environment=self.ENVIRONMENT,
50
53
  config=self.client.config.with_overrides(**kwargs),
51
54
  response_class=VTEXItemsResponse[Any, Any],
52
55
  )
@@ -59,8 +62,8 @@ class PaymentsGatewayAPI(BaseAPI):
59
62
  ) -> VTEXDataResponse[Any]:
60
63
  return self._request(
61
64
  method="GET",
62
- environment=self.ENVIRONMENT,
63
65
  endpoint=f"/api/pvt/transactions/{transaction_id}/payments/{payment_id}",
66
+ environment=self.ENVIRONMENT,
64
67
  config=self.client.config.with_overrides(**kwargs),
65
68
  response_class=VTEXDataResponse[Any],
66
69
  )
@@ -72,8 +75,8 @@ class PaymentsGatewayAPI(BaseAPI):
72
75
  ) -> VTEXDataResponse[Any]:
73
76
  return self._request(
74
77
  method="GET",
75
- environment=self.ENVIRONMENT,
76
78
  endpoint=f"/api/pvt/transactions/{transaction_id}/capabilities",
79
+ environment=self.ENVIRONMENT,
77
80
  config=self.client.config.with_overrides(**kwargs),
78
81
  response_class=VTEXDataResponse[Any],
79
82
  )
@@ -85,8 +88,8 @@ class PaymentsGatewayAPI(BaseAPI):
85
88
  ) -> VTEXDataResponse[Any]:
86
89
  return self._request(
87
90
  method="GET",
88
- environment=self.ENVIRONMENT,
89
91
  endpoint=f"/api/pvt/transactions/{transaction_id}/cancellations",
92
+ environment=self.ENVIRONMENT,
90
93
  config=self.client.config.with_overrides(**kwargs),
91
94
  response_class=VTEXDataResponse[Any],
92
95
  )
@@ -98,8 +101,8 @@ class PaymentsGatewayAPI(BaseAPI):
98
101
  ) -> VTEXDataResponse[Any]:
99
102
  return self._request(
100
103
  method="GET",
101
- environment=self.ENVIRONMENT,
102
104
  endpoint=f"/api/pvt/transactions/{transaction_id}/refunds",
105
+ environment=self.ENVIRONMENT,
103
106
  config=self.client.config.with_overrides(**kwargs),
104
107
  response_class=VTEXDataResponse[Any],
105
108
  )
@@ -111,8 +114,8 @@ class PaymentsGatewayAPI(BaseAPI):
111
114
  ) -> VTEXDataResponse[Any]:
112
115
  return self._request(
113
116
  method="GET",
114
- environment=self.ENVIRONMENT,
115
117
  endpoint=f"/api/pvt/transactions/{transaction_id}/settlements",
118
+ environment=self.ENVIRONMENT,
116
119
  config=self.client.config.with_overrides(**kwargs),
117
120
  response_class=VTEXDataResponse[Any],
118
121
  )
vtex/_api/pricing.py ADDED
@@ -0,0 +1,19 @@
1
+ from typing import Any
2
+
3
+ from .._dto import VTEXDataResponse
4
+ from .base import BaseAPI
5
+
6
+
7
+ class PricingAPI(BaseAPI):
8
+ """
9
+ Client for the Pricing API.
10
+ https://developers.vtex.com/docs/api-reference/pricing-api
11
+ """
12
+
13
+ def get_price(self, sku_id: str, **kwargs: Any) -> VTEXDataResponse[Any]:
14
+ return self._request(
15
+ method="GET",
16
+ endpoint=f"/pricing/prices/{sku_id}",
17
+ config=self.client.config.with_overrides(**kwargs),
18
+ response_class=VTEXDataResponse[Any],
19
+ )
@@ -18,8 +18,8 @@ class PromotionsAndTaxesAPI(BaseAPI):
18
18
  ) -> VTEXItemsResponse[Any, Any]:
19
19
  return self._request(
20
20
  method="GET",
21
- environment=self.ENVIRONMENT,
22
21
  endpoint="api/rnb/pvt/archive/benefits/calculatorconfiguration",
22
+ environment=self.ENVIRONMENT,
23
23
  config=self.client.config.with_overrides(**kwargs),
24
24
  response_class=VTEXItemsResponse[Any, Any],
25
25
  )
@@ -27,8 +27,8 @@ class PromotionsAndTaxesAPI(BaseAPI):
27
27
  def get_promotions(self, **kwargs: Any) -> VTEXDataResponse[Any]:
28
28
  return self._request(
29
29
  method="GET",
30
- environment=self.ENVIRONMENT,
31
30
  endpoint="api/rnb/pvt/benefits/calculatorconfiguration",
31
+ environment=self.ENVIRONMENT,
32
32
  config=self.client.config.with_overrides(**kwargs),
33
33
  response_class=VTEXDataResponse[Any],
34
34
  )
@@ -36,8 +36,8 @@ class PromotionsAndTaxesAPI(BaseAPI):
36
36
  def get_taxes(self, **kwargs: Any) -> VTEXDataResponse[Any]:
37
37
  return self._request(
38
38
  method="GET",
39
- environment=self.ENVIRONMENT,
40
39
  endpoint="api/rnb/pvt/taxes/calculatorconfiguration",
40
+ environment=self.ENVIRONMENT,
41
41
  config=self.client.config.with_overrides(**kwargs),
42
42
  response_class=VTEXDataResponse[Any],
43
43
  )
@@ -49,8 +49,8 @@ class PromotionsAndTaxesAPI(BaseAPI):
49
49
  ) -> VTEXDataResponse[Any]:
50
50
  return self._request(
51
51
  method="GET",
52
- environment=self.ENVIRONMENT,
53
52
  endpoint=f"/api/rnb/pvt/calculatorconfiguration/{promotion_or_tax_id}",
53
+ environment=self.ENVIRONMENT,
54
54
  config=self.client.config.with_overrides(**kwargs),
55
55
  response_class=VTEXDataResponse[Any],
56
56
  )
vtex/_config.py CHANGED
@@ -15,6 +15,7 @@ from ._constants import (
15
15
  DEFAULT_LOG_5XX,
16
16
  DEFAULT_LOG_RETRIES,
17
17
  DEFAULT_RAISE_FOR_STATUS_CODE,
18
+ DEFAULT_RATE_LIMIT_STORAGE_URL,
18
19
  DEFAULT_RETRY_ATTEMPTS,
19
20
  DEFAULT_RETRY_BACKOFF_MAX,
20
21
  DEFAULT_RETRY_BACKOFF_MIN,
@@ -27,6 +28,7 @@ from ._constants import (
27
28
  LOG_5XX_ENV_VAR,
28
29
  LOG_RETRIES_ENV_VAR,
29
30
  RAISE_FOR_STATUS_CODE_ENV_VAR,
31
+ RATE_LIMIT_STORAGE_URL_ENV_VAR,
30
32
  RETRY_ATTEMPTS_ENV_VAR,
31
33
  RETRY_BACKOFF_MAX_ENV_VAR,
32
34
  RETRY_BACKOFF_MIN_ENV_VAR,
@@ -55,6 +57,8 @@ class VTEXConfig(BaseModel):
55
57
 
56
58
  raise_for_status_code: bool = Field(UNDEFINED, validate_default=True)
57
59
 
60
+ rate_limit_storage_url: Union[str, None] = Field(UNDEFINED, validate_default=True)
61
+
58
62
  log_retries: FalseOrLogLevel = Field(UNDEFINED, validate_default=True)
59
63
  log_1xx: FalseOrLogLevel = Field(UNDEFINED, validate_default=True)
60
64
  log_2xx: FalseOrLogLevel = Field(UNDEFINED, validate_default=True)
@@ -73,6 +77,7 @@ class VTEXConfig(BaseModel):
73
77
  retry_backoff_max: Union[float, int, UndefinedSentinel] = UNDEFINED,
74
78
  retry_status_codes: Union[List[int], UndefinedSentinel] = UNDEFINED,
75
79
  raise_for_status_code: Union[bool, UndefinedSentinel] = UNDEFINED,
80
+ rate_limit_storage_url: Union[str, UndefinedSentinel] = UNDEFINED,
76
81
  log_retries: FalseOrLogLevelOrUndefined = UNDEFINED,
77
82
  log_1xx: FalseOrLogLevelOrUndefined = UNDEFINED,
78
83
  log_2xx: FalseOrLogLevelOrUndefined = UNDEFINED,
@@ -93,6 +98,7 @@ class VTEXConfig(BaseModel):
93
98
  "retry_backoff_max": retry_backoff_max,
94
99
  "retry_status_codes": retry_status_codes,
95
100
  "raise_for_status_code": raise_for_status_code,
101
+ "rate_limit_storage_url": rate_limit_storage_url,
96
102
  "log_retries": log_retries,
97
103
  "log_1xx": log_1xx,
98
104
  "log_2xx": log_2xx,
@@ -218,6 +224,25 @@ class VTEXConfig(BaseModel):
218
224
 
219
225
  raise cls._prepare_value_error(value, RAISE_FOR_STATUS_CODE_ENV_VAR)
220
226
 
227
+ @field_validator("rate_limit_storage_url", mode="before")
228
+ @classmethod
229
+ def validate_rate_limit_storage_url(cls, value: Any) -> Union[str, None]:
230
+ if isinstance(value, UndefinedSentinel):
231
+ value = getenv(
232
+ RATE_LIMIT_STORAGE_URL_ENV_VAR,
233
+ DEFAULT_RATE_LIMIT_STORAGE_URL,
234
+ )
235
+
236
+ if value is None:
237
+ return None
238
+ elif isinstance(value, str):
239
+ if value.lower() in {"", "none", "null"}:
240
+ return None
241
+
242
+ return value
243
+
244
+ raise cls._prepare_value_error(value, RATE_LIMIT_STORAGE_URL_ENV_VAR)
245
+
221
246
  @field_validator("log_retries", mode="before")
222
247
  @classmethod
223
248
  def validate_log_retries(cls, value: Any) -> FalseOrLogLevel:
vtex/_constants.py CHANGED
@@ -20,6 +20,7 @@ RETRY_BACKOFF_MIN_ENV_VAR = "VTEX_RETRY_BACKOFF_MIN"
20
20
  RETRY_BACKOFF_MAX_ENV_VAR = "VTEX_RETRY_BACKOFF_MAX"
21
21
  RETRY_STATUS_CODES_ENV_VAR = "VTEX_RETRY_STATUS_CODES"
22
22
  RAISE_FOR_STATUS_CODE_ENV_VAR = "VTEX_RAISE_FOR_STATUS_CODE"
23
+ RATE_LIMIT_STORAGE_URL_ENV_VAR = "VTEX_RATE_LIMIT_STORAGE_URL"
23
24
  LOG_RETRIES_ENV_VAR = "VTEX_LOG_RETRIES"
24
25
  LOG_1XX_ENV_VAR = "VTEX_LOG_1XX"
25
26
  LOG_2XX_ENV_VAR = "VTEX_LOG_2XX"
@@ -46,6 +47,7 @@ DEFAULT_RETRY_STATUS_CODES = [
46
47
  525,
47
48
  ]
48
49
  DEFAULT_RAISE_FOR_STATUS_CODE = True
50
+ DEFAULT_RATE_LIMIT_STORAGE_URL = None
49
51
  DEFAULT_LOG_RETRIES = WARNING
50
52
  DEFAULT_LOG_1XX = INFO
51
53
  DEFAULT_LOG_2XX = INFO
vtex/_utils.py CHANGED
@@ -109,3 +109,7 @@ def redact_headers(headers: Mapping[str, str]) -> Dict[str, str]:
109
109
  redacted_headers[key] = value
110
110
 
111
111
  return redacted_headers
112
+
113
+
114
+ def join_url(base: str, *paths: str) -> str:
115
+ return "/".join(part.strip("/") for part in [base, *paths])
vtex/_vtex.py CHANGED
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
14
14
  MasterDataAPI,
15
15
  OrdersAPI,
16
16
  PaymentsGatewayAPI,
17
+ PricingAPI,
17
18
  PromotionsAndTaxesAPI,
18
19
  )
19
20
 
@@ -76,6 +77,12 @@ class VTEX:
76
77
 
77
78
  return OrdersAPI(client=self)
78
79
 
80
+ @cached_property
81
+ def pricing(self) -> "PricingAPI":
82
+ from ._api import PricingAPI
83
+
84
+ return PricingAPI(client=self)
85
+
79
86
  @cached_property
80
87
  def payments_gateway(self) -> "PaymentsGatewayAPI":
81
88
  from ._api import PaymentsGatewayAPI
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vtexpy
3
- Version: 0.0.0b25
3
+ Version: 0.0.0b27
4
4
  Summary: Unofficial VTEX API's Python SDK
5
5
  Home-page: https://github.com/lvieirajr/vtex-python
6
6
  License: Apache
@@ -27,6 +27,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
27
  Classifier: Typing :: Typed
28
28
  Requires-Dist: cachetools (>=5.0,<6.0)
29
29
  Requires-Dist: httpx (>=0.17,<1.0)
30
+ Requires-Dist: limits (>=3.7,<4.0)
30
31
  Requires-Dist: pydantic (>=2.0,<3.0)
31
32
  Requires-Dist: python-dateutil (>=2.9,<3.0)
32
33
  Requires-Dist: tenacity (>=8.0,<10.0)
@@ -0,0 +1,31 @@
1
+ vtex/__init__.py,sha256=SLnqpZa19ISSQ9LDaCVLDAj-OxFlgVkQyEknydu20VU,636
2
+ vtex/_api/__init__.py,sha256=2OarRhTDq1Oj65v7WkMr3Bi7EAnQMPm2Ypgv9flzE6c,385
3
+ vtex/_api/base.py,sha256=E9Daq7El9wb2df9kjG4RtERchVfYPxgGJR19QM8WIyk,8225
4
+ vtex/_api/catalog.py,sha256=UaVWI9Vhhu6wHejO851hVSDmcLUDtfwcnsGasZGEKiw,4661
5
+ vtex/_api/checkout.py,sha256=ViFJq2GZRAA6yyjaFC3rz0oMYKxzBIsi8tzGKCWRxQ0,1693
6
+ vtex/_api/custom.py,sha256=3yIwTj1Ikf30oq0GzdNz0P9APYxjBeoRvdlbh0rT9gs,2930
7
+ vtex/_api/license_manager.py,sha256=GAdRpizeGUFem-up-SYNzehs5uBY0elTElJ9bEQUlFo,2805
8
+ vtex/_api/logistics.py,sha256=bd55wipbnql3OFnDCBsjP0-jp7OY6FP10Yz5acOsG2o,5052
9
+ vtex/_api/master_data.py,sha256=HGoWr908iQYb0kzq_KNvKyWKtaNQ9vTv7CXxvKey0AM,2046
10
+ vtex/_api/orders.py,sha256=hItiCL79ZnhrjrEwm3oMzc0bu2qezTIyq2uZMHUnaog,5209
11
+ vtex/_api/payments_gateway.py,sha256=06X8XkkfijeMMI3nUPhpceg2sC5V-l9ChWGsjg9HQtw,3877
12
+ vtex/_api/pricing.py,sha256=gZX9MmUKsj0iPjJKT2-Ko9dzT6rZR_DR4ruqs1c9IdY,535
13
+ vtex/_api/promotions_and_taxes.py,sha256=wtNxTrc36u10AMbOq2NMtOVp1HLzrBWxqJDmBYpdXXY,1893
14
+ vtex/_api/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ vtex/_api/types/catalog.py,sha256=O_qLoiGMyBxRdmxPclbbPobUxJSzViqzHiKf8tgfm_I,394
16
+ vtex/_api/types/generic.py,sha256=m1lFTPeyBNi-K0shvK4uxE5SUyvhTTX_5Ls2VockkdI,344
17
+ vtex/_api/types/license_manager.py,sha256=KYISnKdQ548g6x5cNieoaN6gh9C1LQVFv4sH-II1maI,1015
18
+ vtex/_config.py,sha256=UwKVinxMqpLsJAStqTmNZutDO9x9tT0ADUNX1hzZxI0,12631
19
+ vtex/_constants.py,sha256=H-Yz57uzb-nG8bj5zQJck3KFWkQJf8Cc2VZ3dqSnbKY,2148
20
+ vtex/_dto.py,sha256=6CSgQfQp94tA5M9rKxgWf_ftRyoZB804iABIpB5Ff6Y,6479
21
+ vtex/_exceptions.py,sha256=dNRhdk6k4capnsUSHPOKsvACwLfG8cwTNXltao3t344,2152
22
+ vtex/_logging.py,sha256=zahPJIk10YvNs6qoNqhUy7OoDG7dr634CPwiGjT0aEk,2246
23
+ vtex/_sentinels.py,sha256=HLkYBJVHTx9GoyACPO1SuINaGlU2YiqOPuFXUa7iG8A,1120
24
+ vtex/_types.py,sha256=xrqHzmrc0IhE5fc1aGf0StCm3BQbVFyk3LG4Hd7Wd2Q,631
25
+ vtex/_utils.py,sha256=ngC2rRdhBO5cjAAByS0_2LMeXKsI6rnfiHGP96U0m88,3215
26
+ vtex/_vtex.py,sha256=IBPVQ__xiQGJEoht4oCnd-pAYKNJDrKoU06yieQL84o,2342
27
+ vtex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ vtexpy-0.0.0b27.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
29
+ vtexpy-0.0.0b27.dist-info/METADATA,sha256=-4f37ForqFRK7IZcu29zliSA7PIo7QtfLwatbnLftyc,3528
30
+ vtexpy-0.0.0b27.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
31
+ vtexpy-0.0.0b27.dist-info/RECORD,,
@@ -1,30 +0,0 @@
1
- vtex/__init__.py,sha256=SLnqpZa19ISSQ9LDaCVLDAj-OxFlgVkQyEknydu20VU,636
2
- vtex/_api/__init__.py,sha256=V4n0SQrqCcVFWtm8J7jbmwIRI9mCSURwdD_8uHGueAI,353
3
- vtex/_api/base.py,sha256=8KKUfM5S32oaBNqHkLqb-2tW45Jw9XfxlY06vYuTnbs,6854
4
- vtex/_api/catalog.py,sha256=0nYieUaEe2marzyDVpa23-XgtIXciK7n9rw8UqI9MU4,4661
5
- vtex/_api/checkout.py,sha256=AMhSzyjAu5sZUpqevRorV706yXjNafqGDgbnq2wxVpg,1693
6
- vtex/_api/custom.py,sha256=oW4dkHr1xuqVD7oby7ca9Qlhfzq7AeAIzcuKQ3eiUdc,2910
7
- vtex/_api/license_manager.py,sha256=rzsQnxUT96EBmj3G6Fxy4pWH_wmLObGR6XsEhqTyr2c,2805
8
- vtex/_api/logistics.py,sha256=wKSbV2BnDxfhj04d3yQ39errOwml3zNYlXkqcIE2fqI,5052
9
- vtex/_api/master_data.py,sha256=JdMA_dWpbSY7TAJY5MobmQ7OsnoofJA60Qbx8IA6pe0,2046
10
- vtex/_api/orders.py,sha256=klT9cMWTr0bjyyGCAVoFhYICi3vwpzWdbVMg9sS02y4,5136
11
- vtex/_api/payments_gateway.py,sha256=5XkxbXGI7OEQEaykL-y-3PKnfloy380fjUQ18Ctts9E,3804
12
- vtex/_api/promotions_and_taxes.py,sha256=yi9EDlOTop77_DqUF-E9SjblfgF4FyXyerA0_QZplJ4,1893
13
- vtex/_api/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- vtex/_api/types/catalog.py,sha256=O_qLoiGMyBxRdmxPclbbPobUxJSzViqzHiKf8tgfm_I,394
15
- vtex/_api/types/generic.py,sha256=m1lFTPeyBNi-K0shvK4uxE5SUyvhTTX_5Ls2VockkdI,344
16
- vtex/_api/types/license_manager.py,sha256=KYISnKdQ548g6x5cNieoaN6gh9C1LQVFv4sH-II1maI,1015
17
- vtex/_config.py,sha256=0wKEGQWiNv8WrvMqleqglZPF_eJFfAZeUt7to5HU0FI,11706
18
- vtex/_constants.py,sha256=Oijo8dlWaC9m_liGlqFMWdh0HN7pPtFs75sTA2CjJOA,2047
19
- vtex/_dto.py,sha256=6CSgQfQp94tA5M9rKxgWf_ftRyoZB804iABIpB5Ff6Y,6479
20
- vtex/_exceptions.py,sha256=dNRhdk6k4capnsUSHPOKsvACwLfG8cwTNXltao3t344,2152
21
- vtex/_logging.py,sha256=zahPJIk10YvNs6qoNqhUy7OoDG7dr634CPwiGjT0aEk,2246
22
- vtex/_sentinels.py,sha256=HLkYBJVHTx9GoyACPO1SuINaGlU2YiqOPuFXUa7iG8A,1120
23
- vtex/_types.py,sha256=xrqHzmrc0IhE5fc1aGf0StCm3BQbVFyk3LG4Hd7Wd2Q,631
24
- vtex/_utils.py,sha256=slBhhZN3h2S_qopVLGP0MS6nTfsoOcsqaOhLwbCiFwQ,3104
25
- vtex/_vtex.py,sha256=yr8ICPX0gDpPdcoSDJaokMuwFZWWEQ7Wi8z6XibYdos,2184
26
- vtex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- vtexpy-0.0.0b25.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
28
- vtexpy-0.0.0b25.dist-info/METADATA,sha256=GS4YmEp6ATaL77x6_x_SU7lwusWC2T9fNOnUz_8xsKA,3493
29
- vtexpy-0.0.0b25.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
30
- vtexpy-0.0.0b25.dist-info/RECORD,,