infisicalsdk 1.0.7__py3-none-any.whl → 1.0.9__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 infisicalsdk might be problematic. Click here for more details.

@@ -1,9 +1,27 @@
1
- from typing import Any, Dict, Generic, Optional, TypeVar, Type
1
+ from typing import Any, Dict, Generic, Optional, TypeVar, Type, Callable, List
2
+ import socket
2
3
  import requests
4
+ import functools
3
5
  from dataclasses import dataclass
6
+ import time
7
+ import random
4
8
 
5
9
  T = TypeVar("T")
6
10
 
11
+ # List of network-related exceptions that should trigger retries
12
+ NETWORK_ERRORS = [
13
+ requests.exceptions.ConnectionError,
14
+ requests.exceptions.ChunkedEncodingError,
15
+ requests.exceptions.ReadTimeout,
16
+ requests.exceptions.ConnectTimeout,
17
+ socket.gaierror,
18
+ socket.timeout,
19
+ ConnectionResetError,
20
+ ConnectionRefusedError,
21
+ ConnectionError,
22
+ ConnectionAbortedError,
23
+ ]
24
+
7
25
  def join_url(base: str, path: str) -> str:
8
26
  """
9
27
  Join base URL and path properly, handling slashes appropriately.
@@ -49,6 +67,42 @@ class APIResponse(Generic[T]):
49
67
  headers=data['headers']
50
68
  )
51
69
 
70
+ def with_retry(
71
+ max_retries: int = 3,
72
+ base_delay: float = 1.0,
73
+ network_errors: Optional[List[Type[Exception]]] = None
74
+ ) -> Callable:
75
+ """
76
+ Decorator to add retry logic with exponential backoff to requests methods.
77
+ """
78
+ if network_errors is None:
79
+ network_errors = NETWORK_ERRORS
80
+
81
+ def decorator(func: Callable) -> Callable:
82
+ @functools.wraps(func)
83
+ def wrapper(*args, **kwargs):
84
+ retry_count = 0
85
+
86
+ while True:
87
+ try:
88
+ return func(*args, **kwargs)
89
+ except tuple(network_errors) as error:
90
+ retry_count += 1
91
+ if retry_count > max_retries:
92
+ raise
93
+
94
+ base_delay_with_backoff = base_delay * (2 ** (retry_count - 1))
95
+
96
+ # +/-20% jitter
97
+ jitter = random.uniform(-0.2, 0.2) * base_delay_with_backoff
98
+ delay = base_delay_with_backoff + jitter
99
+
100
+ time.sleep(delay)
101
+
102
+ return wrapper
103
+
104
+ return decorator
105
+
52
106
 
53
107
  class InfisicalRequests:
54
108
  def __init__(self, host: str, token: Optional[str] = None):
@@ -93,6 +147,7 @@ class InfisicalRequests:
93
147
  except ValueError:
94
148
  raise InfisicalError("Invalid JSON response")
95
149
 
150
+ @with_retry(max_retries=4, base_delay=1.0)
96
151
  def get(
97
152
  self,
98
153
  path: str,
@@ -119,6 +174,7 @@ class InfisicalRequests:
119
174
  headers=dict(response.headers)
120
175
  )
121
176
 
177
+ @with_retry(max_retries=4, base_delay=1.0)
122
178
  def post(
123
179
  self,
124
180
  path: str,
@@ -143,6 +199,7 @@ class InfisicalRequests:
143
199
  headers=dict(response.headers)
144
200
  )
145
201
 
202
+ @with_retry(max_retries=4, base_delay=1.0)
146
203
  def patch(
147
204
  self,
148
205
  path: str,
@@ -167,6 +224,7 @@ class InfisicalRequests:
167
224
  headers=dict(response.headers)
168
225
  )
169
226
 
227
+ @with_retry(max_retries=4, base_delay=1.0)
170
228
  def delete(
171
229
  self,
172
230
  path: str,
@@ -1,4 +1,4 @@
1
- from typing import List, Union
1
+ from typing import List, Union, Optional, Dict, Any
2
2
 
3
3
  from infisical_sdk.infisical_requests import InfisicalRequests
4
4
  from infisical_sdk.api_types import ListSecretsResponse, SingleSecretResponse, BaseSecret
@@ -14,14 +14,15 @@ class V3RawSecrets:
14
14
 
15
15
  def list_secrets(
16
16
  self,
17
- project_id: str,
18
17
  environment_slug: str,
19
18
  secret_path: str,
19
+ project_id: str = None,
20
20
  expand_secret_references: bool = True,
21
21
  view_secret_value: bool = True,
22
22
  recursive: bool = False,
23
23
  include_imports: bool = True,
24
- tag_filters: List[str] = []) -> ListSecretsResponse:
24
+ tag_filters: List[str] = [],
25
+ project_slug: str = None) -> ListSecretsResponse:
25
26
 
26
27
  params = {
27
28
  "workspaceId": project_id,
@@ -31,8 +32,12 @@ class V3RawSecrets:
31
32
  "expandSecretReferences": str(expand_secret_references).lower(),
32
33
  "recursive": str(recursive).lower(),
33
34
  "include_imports": str(include_imports).lower(),
35
+ "workspaceSlug": project_slug
34
36
  }
35
37
 
38
+ if project_slug is None and project_id is None:
39
+ raise ValueError("project_slug or project_id must be provided")
40
+
36
41
  if tag_filters:
37
42
  params["tagSlugs"] = ",".join(tag_filters)
38
43
 
@@ -58,9 +63,10 @@ class V3RawSecrets:
58
63
  def get_secret_by_name(
59
64
  self,
60
65
  secret_name: str,
61
- project_id: str,
62
66
  environment_slug: str,
63
67
  secret_path: str,
68
+ project_id: str = None,
69
+ project_slug: str = None,
64
70
  expand_secret_references: bool = True,
65
71
  include_imports: bool = True,
66
72
  view_secret_value: bool = True,
@@ -68,6 +74,7 @@ class V3RawSecrets:
68
74
 
69
75
  params = {
70
76
  "workspaceId": project_id,
77
+ "workspaceSlug": project_slug,
71
78
  "viewSecretValue": str(view_secret_value).lower(),
72
79
  "environment": environment_slug,
73
80
  "secretPath": secret_path,
@@ -76,6 +83,9 @@ class V3RawSecrets:
76
83
  "version": version
77
84
  }
78
85
 
86
+ if project_slug is None and project_id is None:
87
+ raise ValueError("project_slug or project_id must be provided")
88
+
79
89
  cache_params = {
80
90
  "project_id": project_id,
81
91
  "environment_slug": environment_slug,
@@ -105,27 +115,37 @@ class V3RawSecrets:
105
115
  def create_secret_by_name(
106
116
  self,
107
117
  secret_name: str,
108
- project_id: str,
109
118
  secret_path: str,
110
119
  environment_slug: str,
120
+ project_id: str = None,
111
121
  secret_value: str = None,
112
122
  secret_comment: str = None,
113
123
  skip_multiline_encoding: bool = False,
114
124
  secret_reminder_repeat_days: Union[float, int] = None,
115
- secret_reminder_note: str = None) -> BaseSecret:
125
+ secret_reminder_note: str = None,
126
+ project_slug: str = None,
127
+ secret_metadata: Optional[List[Dict[str, Any]]] = None,
128
+ tags_ids: Optional[List[str]] = None,
129
+ ) -> BaseSecret:
116
130
 
117
131
  requestBody = {
118
132
  "workspaceId": project_id,
133
+ "projectSlug": project_slug,
119
134
  "environment": environment_slug,
120
135
  "secretPath": secret_path,
121
136
  "secretValue": secret_value,
122
137
  "secretComment": secret_comment,
123
- "tagIds": None,
138
+ "tagIds": tags_ids,
124
139
  "skipMultilineEncoding": skip_multiline_encoding,
125
140
  "type": "shared",
126
141
  "secretReminderRepeatDays": secret_reminder_repeat_days,
127
- "secretReminderNote": secret_reminder_note
142
+ "secretReminderNote": secret_reminder_note,
143
+ "secretMetadata": secret_metadata,
128
144
  }
145
+
146
+ if project_slug is None and project_id is None:
147
+ raise ValueError("project_slug or project_id must be provided")
148
+
129
149
  result = self.requests.post(
130
150
  path=f"/api/v3/secrets/raw/{secret_name}",
131
151
  json=requestBody,
@@ -152,30 +172,39 @@ class V3RawSecrets:
152
172
  def update_secret_by_name(
153
173
  self,
154
174
  current_secret_name: str,
155
- project_id: str,
156
175
  secret_path: str,
157
176
  environment_slug: str,
177
+ project_id: str = None,
158
178
  secret_value: str = None,
159
179
  secret_comment: str = None,
160
180
  skip_multiline_encoding: bool = False,
161
181
  secret_reminder_repeat_days: Union[float, int] = None,
162
182
  secret_reminder_note: str = None,
163
- new_secret_name: str = None) -> BaseSecret:
183
+ new_secret_name: str = None,
184
+ project_slug: str = None,
185
+ secret_metadata: Optional[List[Dict[str, Any]]] = None,
186
+ tags_ids: Optional[List[str]] = None,
187
+ ) -> BaseSecret:
164
188
 
165
189
  requestBody = {
166
190
  "workspaceId": project_id,
191
+ "projectSlug": project_slug,
167
192
  "environment": environment_slug,
168
193
  "secretPath": secret_path,
169
194
  "secretValue": secret_value,
170
195
  "secretComment": secret_comment,
171
196
  "newSecretName": new_secret_name,
172
- "tagIds": None,
197
+ "tagIds": tags_ids,
173
198
  "skipMultilineEncoding": skip_multiline_encoding,
174
199
  "type": "shared",
175
200
  "secretReminderRepeatDays": secret_reminder_repeat_days,
176
- "secretReminderNote": secret_reminder_note
201
+ "secretReminderNote": secret_reminder_note,
202
+ "secretMetadata": secret_metadata,
177
203
  }
178
204
 
205
+ if project_slug is None and project_id is None:
206
+ raise ValueError("project_slug or project_id must be provided")
207
+
179
208
  result = self.requests.patch(
180
209
  path=f"/api/v3/secrets/raw/{current_secret_name}",
181
210
  json=requestBody,
@@ -201,12 +230,17 @@ class V3RawSecrets:
201
230
  def delete_secret_by_name(
202
231
  self,
203
232
  secret_name: str,
204
- project_id: str,
205
233
  secret_path: str,
206
- environment_slug: str) -> BaseSecret:
234
+ environment_slug: str,
235
+ project_id: str = None,
236
+ project_slug: str = None) -> BaseSecret:
237
+
238
+ if project_slug is None and project_id is None:
239
+ raise ValueError("project_slug or project_id must be provided")
207
240
 
208
241
  requestBody = {
209
242
  "workspaceId": project_id,
243
+ "projectSlug": project_slug,
210
244
  "environment": environment_slug,
211
245
  "secretPath": secret_path,
212
246
  "type": "shared",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: infisicalsdk
3
- Version: 1.0.7
3
+ Version: 1.0.9
4
4
  Summary: Infisical API Client
5
5
  Home-page: https://github.com/Infisical/python-sdk-official
6
6
  Author: Infisical
@@ -1,17 +1,17 @@
1
1
  infisical_sdk/__init__.py,sha256=AVQAg_FAQtrofgDpLBXTAas_2j9Fi1n0FXzKyclde5U,204
2
2
  infisical_sdk/api_types.py,sha256=-SFKKhDx0GZGlzZ0kysvEMmBRtbQQXl5vwaH1a4m1Ac,5170
3
3
  infisical_sdk/client.py,sha256=8ElPok-Ao54NgX1bQtWX7ccM7UTvVhXoaWan1iRwc9k,1505
4
- infisical_sdk/infisical_requests.py,sha256=LnWmuKiVzYvrqiSkMBTAaTBy5vNmyxhIXrBSVSTTbMA,5843
4
+ infisical_sdk/infisical_requests.py,sha256=v6GMakywaHbiGV2aZ4oiDsDukHt50PhA1J2xAgNGxMk,7666
5
5
  infisical_sdk/resources/__init__.py,sha256=oq3gcsEqybe0O44wPyoaiRj3TrzaP4X5APJeI4ltPwo,77
6
6
  infisical_sdk/resources/auth.py,sha256=7Wn6uj4idAvwNsStT0ihk-vts6--Rd17lhh6nLtUBK8,458
7
7
  infisical_sdk/resources/kms.py,sha256=4nTXDo3qW5Qk1o1M4K8UG98fgxHoEGm0QkOEUv2SuTc,4712
8
- infisical_sdk/resources/secrets.py,sha256=5aK9sjek-mhIuHrwUBRPlLMxcR7bBY6bD3AjYCDtKVw,7759
8
+ infisical_sdk/resources/secrets.py,sha256=KJyBbPLxZRs5S6Ig6CbuDLAI07eO1OFbaB5WXrQoFVI,9219
9
9
  infisical_sdk/resources/auth_methods/__init__.py,sha256=bpdwKQ_ZxAdf6yzImWlKy1ZhkJxWrSWb0IgcuUF0DEU,72
10
10
  infisical_sdk/resources/auth_methods/aws_auth.py,sha256=NviQc9mE0zculm8Tj-4n38-hJXKjBx65xrKCsDgMYyA,4545
11
11
  infisical_sdk/resources/auth_methods/universal_auth.py,sha256=K5u25c344y82RZatjnDEf619XiiGQBgUS-Aia041hZE,1088
12
12
  infisical_sdk/util/__init__.py,sha256=nPGrsq3vGWfwakfvSs7tzOfztXY16DS5GahTiyrC8tE,39
13
13
  infisical_sdk/util/secrets_cache.py,sha256=LmgxFZEy8194xe4YhA958BJQdcV0Fv2Xmhfc7bwvBfQ,3175
14
- infisicalsdk-1.0.7.dist-info/METADATA,sha256=P3KLRd1aWuVbHPoNf3vh9fI4gKyKFKWMSW_hg0Dis5g,725
15
- infisicalsdk-1.0.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
16
- infisicalsdk-1.0.7.dist-info/top_level.txt,sha256=FvJjMGD1FvxwipO_qFajdH20yNV8n3lJ7G3DkQoPJNU,14
17
- infisicalsdk-1.0.7.dist-info/RECORD,,
14
+ infisicalsdk-1.0.9.dist-info/METADATA,sha256=daLY-6xVigluHbRlnU5dvpQXO4j6X5uE6_bHl7M6riA,725
15
+ infisicalsdk-1.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ infisicalsdk-1.0.9.dist-info/top_level.txt,sha256=FvJjMGD1FvxwipO_qFajdH20yNV8n3lJ7G3DkQoPJNU,14
17
+ infisicalsdk-1.0.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5