Skip to content

Commit 532e3f7

Browse files
committed
Add timeout as an option at both the object level and function level
1 parent 32d5cfa commit 532e3f7

2 files changed

Lines changed: 108 additions & 25 deletions

File tree

‎vaultapi_client/main.py‎

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def __init__(
2323
vault_secret: str | None = None,
2424
vault_transit_time_bucket: int | None = None,
2525
vault_transit_key_length: int | None = None,
26+
timeout: int | float | tuple | None = (5, 30),
2627
):
2728
"""Instantiates the VaultAPIClient object."""
2829
self.env_config = resolve_secrets(
@@ -35,15 +36,20 @@ def __init__(
3536
)
3637
self.transit_shield = TransitShield(self.env_config)
3738
self.SESSION = Session(self.env_config)
39+
self.timeout = timeout
3840

3941
def _get_cipher(
40-
self, endpoint: EndpointMapping, query_params: Dict[str, str]
42+
self,
43+
endpoint: EndpointMapping,
44+
query_params: Dict[str, str],
45+
timeout: int | float | tuple | None = None,
4146
) -> str:
4247
"""Get ciphertext from the server.
4348
4449
Args:
4550
endpoint: API endpoint to request.
4651
query_params: Query parameters to send with the request.
52+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
4753
4854
Returns:
4955
str:
@@ -52,14 +58,21 @@ def _get_cipher(
5258
return self.SESSION.get(
5359
endpoint,
5460
params=query_params,
61+
timeout=timeout or self.timeout,
5562
)
5663

57-
def dotenv_to_table(self, table_name: str, dotenv_file: str) -> Dict[str, str]:
64+
def dotenv_to_table(
65+
self,
66+
table_name: str,
67+
dotenv_file: str,
68+
timeout: int | float | tuple | None = None,
69+
) -> Dict[str, str]:
5870
"""Store all the env vars from a .env file into the database.
5971
6072
Args:
6173
table_name: Name of the table to store secrets.
6274
dotenv_file: Dot env filename.
75+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
6376
"""
6477
try:
6578
assert os.path.isfile(dotenv_file)
@@ -68,34 +81,48 @@ def dotenv_to_table(self, table_name: str, dotenv_file: str) -> Dict[str, str]:
6881
env_vars = {
6982
k: v for k, v in dotenv.dotenv_values(dotenv_file).items() if v is not None
7083
}
71-
return self.update_secret(secrets=env_vars, table_name=table_name)
84+
return self.update_secret(
85+
secrets=env_vars, table_name=table_name, timeout=timeout or self.timeout
86+
)
7287

73-
def table_to_env(self, table_name: str, dotenv_file: str | None = None) -> None:
88+
def table_to_env(
89+
self,
90+
table_name: str,
91+
dotenv_file: str | None = None,
92+
timeout: int | float | tuple | None = None,
93+
) -> None:
7494
"""Retrieve all secrets from the database and store them as env vars.
7595
7696
Args:
7797
table_name: Vault table name,
7898
dotenv_file: Dot env filename to store secrets in addition to env vars.
99+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
79100
"""
80101
if dotenv_file:
81102
try:
82103
assert os.path.isfile(dotenv_file)
83104
except AssertionError:
84105
raise FileNotFoundError(dotenv_file)
85-
secrets = self.get_table(table_name)
106+
secrets = self.get_table(table_name, timeout=timeout or self.timeout)
86107
for key, value in secrets.items():
87108
os.environ[key] = value
88109
if dotenv_file:
89110
dotenv.set_key(
90111
dotenv_path=dotenv_file, key_to_set=key, value_to_set=value
91112
)
92113

93-
def update_secret(self, secrets: Dict[str, str], table_name: str) -> Dict[str, str]:
114+
def update_secret(
115+
self,
116+
secrets: Dict[str, str],
117+
table_name: str,
118+
timeout: int | float | tuple | None = None,
119+
) -> Dict[str, str]:
94120
"""Update or create secrets in the vault.
95121
96122
Args:
97123
secrets: Key value pairs with multiple secrets.
98124
table_name: Table name.
125+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
99126
100127
Returns:
101128
Dict[str, str]:
@@ -107,14 +134,18 @@ def update_secret(self, secrets: Dict[str, str], table_name: str) -> Dict[str, s
107134
"secrets": self.transit_shield.encrypt(payload=secrets),
108135
"table_name": table_name,
109136
},
137+
timeout=timeout or self.timeout,
110138
)
111139

112-
def delete_secret(self, key: str, table_name: str) -> Dict[str, str]:
140+
def delete_secret(
141+
self, key: str, table_name: str, timeout: int | float | tuple | None = None
142+
) -> Dict[str, str]:
113143
"""Delete a secret from the vault.
114144
115145
Args:
116146
key: Key for the secret.
117147
table_name: Table name.
148+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
118149
119150
Returns:
120151
Dict[str, str]:
@@ -126,37 +157,51 @@ def delete_secret(self, key: str, table_name: str) -> Dict[str, str]:
126157
"key": key,
127158
"table_name": table_name,
128159
},
160+
timeout=timeout or self.timeout,
129161
)
130162

131-
def list_tables(self) -> List[str]:
163+
def list_tables(self, timeout: int | float | tuple | None = None) -> List[str]:
132164
"""List all available tables.
133165
166+
Args:
167+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
168+
134169
Returns:
135170
List[str]:
136171
Returns the available table names as a list of strings.
137172
"""
138-
return self.SESSION.get(EndpointMapping.list_tables)
173+
return self.SESSION.get(
174+
EndpointMapping.list_tables, timeout=timeout or self.timeout
175+
)
139176

140-
def create_table(self, table_name: str) -> Dict[str, str]:
177+
def create_table(
178+
self, table_name: str, timeout: int | float | tuple | None = None
179+
) -> Dict[str, str]:
141180
"""Creates a new table in the vault database.
142181
143182
Args:
144183
table_name: Table name.
184+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
145185
146186
Returns:
147187
Dict[str, str]:
148188
Returns the server response.
149189
"""
150190
return self.SESSION.post(
151-
EndpointMapping.create_table, params={"table_name": table_name}
191+
EndpointMapping.create_table,
192+
params={"table_name": table_name},
193+
timeout=timeout or self.timeout,
152194
)
153195

154-
def rename_table(self, table_name: str, new_name: str) -> str:
196+
def rename_table(
197+
self, table_name: str, new_name: str, timeout: int | float | tuple | None = None
198+
) -> str:
155199
"""Renames a table in the vault database.
156200
157201
Args:
158202
table_name: Table name to rename.
159203
new_name: New table name.
204+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
160205
161206
Returns:
162207
str:
@@ -166,63 +211,81 @@ def rename_table(self, table_name: str, new_name: str) -> str:
166211
EndpointMapping.rename_table,
167212
params={"table_name": table_name},
168213
json=dict(new_name=new_name),
214+
timeout=timeout or self.timeout,
169215
)
170216

171-
def delete_table(self, table_name: str) -> Dict[str, str]:
217+
def delete_table(
218+
self, table_name: str, timeout: int | float | tuple | None = None
219+
) -> Dict[str, str]:
172220
"""Deletes an existing table.
173221
174222
Args:
175223
table_name: Table name.
224+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
176225
177226
Returns:
178227
Dict[str, str]:
179228
Returns the server response.
180229
"""
181230
return self.SESSION.delete(
182-
EndpointMapping.delete_table, params={"table_name": table_name}
231+
EndpointMapping.delete_table,
232+
params={"table_name": table_name},
233+
timeout=timeout or self.timeout,
183234
)
184235

185-
def get_secret(self, key: str, table_name: str) -> Dict[str, str]:
236+
def get_secret(
237+
self, key: str, table_name: str, timeout: int | float | tuple | None = None
238+
) -> Dict[str, str]:
186239
"""Retrieves multiple secrets from a table.
187240
188241
Args:
189242
key: Comma separated list of secret names to be retrieved.
190243
table_name: Table name.
244+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
191245
192246
Returns:
193247
Dict[str, str]:
194248
Returns a dictionary of decrypted values.
195249
"""
196250
cipher_text = self._get_cipher(
197-
EndpointMapping.get_secret, {"key": key, "table_name": table_name}
251+
EndpointMapping.get_secret,
252+
query_params={"key": key, "table_name": table_name},
253+
timeout=timeout or self.timeout,
198254
)
199255
return self.transit_shield.decrypt(ciphertext=cipher_text)
200256

201-
def get_table(self, table_name: str) -> Dict[str, str]:
257+
def get_table(
258+
self, table_name: str, timeout: int | float | tuple | None = None
259+
) -> Dict[str, str]:
202260
"""Retrieves all the secrets stored in a table.
203261
204262
Args:
205263
table_name: Table name.
264+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
206265
207266
Returns:
208267
Dict[str, str]:
209268
Returns a dictionary of decrypted values.
210269
"""
211270
cipher_text = self._get_cipher(
212-
EndpointMapping.get_table, {"table_name": table_name}
271+
EndpointMapping.get_table,
272+
query_params={"table_name": table_name},
273+
timeout=timeout or self.timeout,
213274
)
214275
return self.transit_shield.decrypt(ciphertext=cipher_text)
215276

216277
def decrypt(
217278
self,
218279
table: str,
219280
get_secret: str | None = None,
281+
timeout: int | float | tuple | None = None,
220282
) -> Dict[str, str] | str:
221283
"""Decrypt function.
222284
223285
Args:
224286
table: Table name to retrieve.
225287
get_secret: Comma separated list of secret keys to retrieve.
288+
timeout: Timeout for the request in seconds. Can be a float or a tuple (connect_timeout, read_timeout).
226289
227290
Returns:
228291
Dict[str, str]:
@@ -237,5 +300,9 @@ def decrypt(
237300
else:
238301
endpoint = EndpointMapping.get_table
239302
return self.transit_shield.decrypt(
240-
self._get_cipher(endpoint=EndpointMapping(endpoint), query_params=params)
303+
self._get_cipher(
304+
endpoint=EndpointMapping(endpoint),
305+
query_params=params,
306+
timeout=timeout or self.timeout,
307+
)
241308
)

‎vaultapi_client/session.py‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def request(
8787
endpoint: EndpointMapping,
8888
params: Dict[str, Any] | None = None,
8989
json: Dict[str, Any] | None = None,
90+
timeout: int | float | tuple | None = None,
9091
) -> Any:
9192
"""Intercepts all HTTP requests and applies centralized error handling.
9293
@@ -95,6 +96,7 @@ def request(
9596
endpoint: Endpoint to make a request.
9697
params: Query parameters to pass to the request.
9798
json: JSON data to pass to the request.
99+
timeout: Timeout in seconds.
98100
99101
Returns:
100102
Any:
@@ -107,7 +109,12 @@ def request(
107109
headers = self.headers(token=f"{self.apikey}.{self.secret}")
108110
try:
109111
response = self.session.request(
110-
method=method, url=url, headers=headers, params=params, json=json
112+
method=method,
113+
url=url,
114+
headers=headers,
115+
params=params,
116+
json=json,
117+
timeout=timeout,
111118
)
112119
response.raise_for_status()
113120
return process_response(response)
@@ -119,42 +126,51 @@ def get(
119126
endpoint: EndpointMapping,
120127
params: Dict[str, Any] | None = None,
121128
json: Dict[str, Any] | None = None,
129+
timeout: int | float | tuple | None = None,
122130
) -> Any:
123131
"""Make GET request to the server and process the response."""
124-
return self.request("GET", endpoint, params=params, json=json)
132+
return self.request("GET", endpoint, params=params, json=json, timeout=timeout)
125133

126134
def put(
127135
self,
128136
endpoint: EndpointMapping,
129137
params: Dict[str, Any] | None = None,
130138
json: Dict[str, Any] | None = None,
139+
timeout: int | float | tuple | None = None,
131140
) -> Any:
132141
"""Make PUT request to the server and process the response."""
133-
return self.request("PUT", endpoint, params=params, json=json)
142+
return self.request("PUT", endpoint, params=params, json=json, timeout=timeout)
134143

135144
def post(
136145
self,
137146
endpoint: EndpointMapping,
138147
params: Dict[str, Any] | None = None,
139148
json: Dict[str, Any] | None = None,
149+
timeout: int | float | tuple | None = None,
140150
) -> Any:
141151
"""Make POST request to the server and process the response."""
142-
return self.request("POST", endpoint, params=params, json=json)
152+
return self.request("POST", endpoint, params=params, json=json, timeout=timeout)
143153

144154
def patch(
145155
self,
146156
endpoint: EndpointMapping,
147157
params: Dict[str, Any] | None = None,
148158
json: Dict[str, Any] | None = None,
159+
timeout: int | float | tuple | None = None,
149160
) -> Any:
150161
"""Make PATCH request to the server and process the response."""
151-
return self.request("PATCH", endpoint, params=params, json=json)
162+
return self.request(
163+
"PATCH", endpoint, params=params, json=json, timeout=timeout
164+
)
152165

153166
def delete(
154167
self,
155168
endpoint: EndpointMapping,
156169
params: Dict[str, Any] | None = None,
157170
json: Dict[str, Any] | None = None,
171+
timeout: int | float | tuple | None = None,
158172
) -> Any:
159173
"""Make DELETE request to the server and process the response."""
160-
return self.request("DELETE", endpoint, params=params, json=json)
174+
return self.request(
175+
"DELETE", endpoint, params=params, json=json, timeout=timeout
176+
)

0 commit comments

Comments
 (0)