Skip to content

Commit 09984b8

Browse files
authored
fix: preserve exception chain (#119)
* fix: run 'pre-commit run -a' * fix: preserve exception chain
1 parent e77571f commit 09984b8

16 files changed

+52
-48
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ repos:
3434

3535
- repo: https://github.com/astral-sh/ruff-pre-commit
3636
# Ruff version.
37-
rev: v0.14.5
37+
rev: v0.14.6
3838
hooks:
3939
# Run the linter.
4040
- id: ruff-check

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ lint.select = [
8686
# pyflakes checks.
8787
"F",
8888
# flake8-bugbear checks.
89-
"B0",
89+
"B",
9090
# flake8-comprehensions checks.
9191
"C4",
9292
# McCabe complexity

src/otdf_python/address_normalizer.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
3434
port_str = host_port_pattern.group(2)
3535
try:
3636
port = int(port_str)
37-
except ValueError:
38-
raise SDKException(f"Invalid port in URL [{url_string}]")
37+
except ValueError as err:
38+
raise SDKException(f"Invalid port in URL [{url_string}]") from err
3939

4040
normalized_url = f"{scheme}://{host}:{port}"
4141
logger.debug(f"normalized url [{url_string}] to [{normalized_url}]")
@@ -66,8 +66,8 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
6666
_, port_str = parsed_url.netloc.split(":", 1)
6767
try:
6868
port = int(port_str)
69-
except ValueError:
70-
raise SDKException(f"Invalid port in URL [{url_string}]")
69+
except ValueError as err:
70+
raise SDKException(f"Invalid port in URL [{url_string}]") from err
7171

7272
# If no port was found or extracted, use the default
7373
if port is None:
@@ -81,4 +81,4 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
8181
except Exception as e:
8282
if isinstance(e, SDKException):
8383
raise e
84-
raise SDKException(f"Error normalizing URL [{url_string}]", e)
84+
raise SDKException(f"Error normalizing URL [{url_string}]: {e}") from e

src/otdf_python/asym_crypto.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def __init__(self, private_key_pem: str | None = None, private_key_obj=None):
6060
decoded, password=None, backend=default_backend()
6161
)
6262
except Exception as e:
63-
raise SDKException(f"Failed to load private key: {e}")
63+
raise SDKException(f"Failed to load private key: {e}") from e
6464
else:
6565
self.private_key = None
6666

@@ -89,7 +89,7 @@ def decrypt(self, data: bytes) -> bytes:
8989
),
9090
)
9191
except Exception as e:
92-
raise SDKException(f"Error performing decryption: {e}")
92+
raise SDKException(f"Error performing decryption: {e}") from e
9393

9494

9595
class AsymEncryption:
@@ -141,7 +141,7 @@ def __init__(self, public_key_pem: str | None = None, public_key_obj=None):
141141
decoded, backend=default_backend()
142142
)
143143
except Exception as e:
144-
raise SDKException(f"Failed to load public key: {e}")
144+
raise SDKException(f"Failed to load public key: {e}") from e
145145
else:
146146
self.public_key = None
147147

@@ -176,7 +176,7 @@ def encrypt(self, data: bytes) -> bytes:
176176
),
177177
)
178178
except Exception as e:
179-
raise SDKException(f"Error performing encryption: {e}")
179+
raise SDKException(f"Error performing encryption: {e}") from e
180180

181181
def public_key_in_pem_format(self) -> str:
182182
"""
@@ -195,4 +195,4 @@ def public_key_in_pem_format(self) -> str:
195195
)
196196
return pem.decode()
197197
except Exception as e:
198-
raise SDKException(f"Error exporting public key to PEM: {e}")
198+
raise SDKException(f"Error exporting public key to PEM: {e}") from e

src/otdf_python/autoconfigure_utils.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ def __init__(self, url: str):
4242
raise AutoConfigureException("invalid type: attribute regex fail")
4343
try:
4444
urllib.parse.unquote(matcher.group(2))
45-
except Exception:
45+
except Exception as err:
4646
raise AutoConfigureException(
4747
f"invalid type: error in attribute name [{matcher.group(2)}]"
48-
)
48+
) from err
4949
self.url = url
5050
self.key = url.lower()
5151

@@ -76,8 +76,8 @@ def name(self):
7676
raise AutoConfigureException("invalid attribute")
7777
try:
7878
return urllib.parse.unquote(matcher.group(1))
79-
except Exception:
80-
raise AutoConfigureException("invalid type")
79+
except Exception as err:
80+
raise AutoConfigureException("invalid type") from err
8181

8282

8383
class AttributeValueFQN:
@@ -96,8 +96,10 @@ def __init__(self, url: str):
9696
try:
9797
urllib.parse.unquote(matcher.group(2))
9898
urllib.parse.unquote(matcher.group(3))
99-
except Exception:
100-
raise AutoConfigureException("invalid type: error in attribute or value")
99+
except Exception as err:
100+
raise AutoConfigureException(
101+
"invalid type: error in attribute or value"
102+
) from err
101103
self.url = url
102104
self.key = url.lower()
103105

src/otdf_python/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ def load_client_credentials(creds_file_path: str) -> tuple[str, str]:
105105
except json.JSONDecodeError as e:
106106
raise CLIError(
107107
"CRITICAL", f"Invalid JSON in credentials file {creds_file_path}: {e}"
108-
)
108+
) from e
109109
except Exception as e:
110110
raise CLIError(
111111
"CRITICAL", f"Error reading credentials file {creds_file_path}: {e}"
112-
)
112+
) from e
113113

114114

115115
def build_sdk(args) -> SDK:

src/otdf_python/ecdh.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def decompress_public_key(
156156

157157
return ec.EllipticCurvePublicKey.from_encoded_point(curve, compressed_key)
158158
except (ValueError, TypeError) as e:
159-
raise InvalidKeyError(f"Failed to decompress public key: {e}")
159+
raise InvalidKeyError(f"Failed to decompress public key: {e}") from e
160160

161161

162162
def derive_shared_secret(
@@ -179,7 +179,7 @@ def derive_shared_secret(
179179
shared_secret = private_key.exchange(ec.ECDH(), public_key)
180180
return shared_secret
181181
except Exception as e:
182-
raise ECDHError(f"Failed to derive shared secret: {e}")
182+
raise ECDHError(f"Failed to derive shared secret: {e}") from e
183183

184184

185185
def derive_key_from_shared_secret(
@@ -216,7 +216,7 @@ def derive_key_from_shared_secret(
216216
)
217217
return hkdf.derive(shared_secret)
218218
except Exception as e:
219-
raise ECDHError(f"Failed to derive key from shared secret: {e}")
219+
raise ECDHError(f"Failed to derive key from shared secret: {e}") from e
220220

221221

222222
def encrypt_key_with_ecdh(
@@ -251,7 +251,7 @@ def encrypt_key_with_ecdh(
251251
if not isinstance(recipient_public_key, ec.EllipticCurvePublicKey):
252252
raise InvalidKeyError("Recipient's public key is not an EC key")
253253
except Exception as e:
254-
raise InvalidKeyError(f"Failed to load recipient's public key: {e}")
254+
raise InvalidKeyError(f"Failed to load recipient's public key: {e}") from e
255255

256256
# Generate ephemeral keypair
257257
ephemeral_private_key, ephemeral_public_key = generate_ephemeral_keypair(curve_name)
@@ -301,7 +301,7 @@ def decrypt_key_with_ecdh(
301301
if not isinstance(recipient_private_key, ec.EllipticCurvePrivateKey):
302302
raise InvalidKeyError("Recipient's private key is not an EC key")
303303
except Exception as e:
304-
raise InvalidKeyError(f"Failed to load recipient's private key: {e}")
304+
raise InvalidKeyError(f"Failed to load recipient's private key: {e}") from e
305305

306306
# Decompress ephemeral public key
307307
ephemeral_public_key = decompress_public_key(

src/otdf_python/kas_client.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def _normalize_kas_url(self, url: str) -> str:
7878
# Parse the URL
7979
parsed = urlparse(url)
8080
except Exception as e:
81-
raise SDKException(f"error trying to parse URL [{url}]", e)
81+
raise SDKException(f"error trying to parse URL [{url}]: {e}") from e
8282

8383
# Check if we have a host or if this is likely a hostname:port combination
8484
if parsed.hostname is None:
@@ -100,10 +100,10 @@ def _handle_missing_scheme(self, url: str) -> str:
100100
try:
101101
port = int(port_str)
102102
return f"{scheme}://{host}:{port}"
103-
except ValueError:
103+
except ValueError as err:
104104
raise SDKException(
105105
f"error trying to create URL for host and port [{url}]"
106-
)
106+
) from err
107107
else:
108108
# Hostname with or without path, add default port
109109
if "/" in url:
@@ -116,7 +116,7 @@ def _handle_missing_scheme(self, url: str) -> str:
116116
except Exception as e:
117117
raise SDKException(
118118
f"error trying to create URL for host and port [{url}]", e
119-
)
119+
) from e
120120

121121
def _handle_existing_scheme(self, parsed) -> str:
122122
"""Handle URLs with existing scheme by normalizing protocol and port."""
@@ -138,7 +138,7 @@ def _handle_existing_scheme(self, parsed) -> str:
138138
logging.debug(f"normalized url [{parsed.geturl()}] to [{normalized_url}]")
139139
return normalized_url
140140
except Exception as e:
141-
raise SDKException("error creating KAS address", e)
141+
raise SDKException(f"error creating KAS address: {e}") from e
142142

143143
def _get_wrapped_key_base64(self, key_access):
144144
"""
@@ -483,7 +483,7 @@ def _get_public_key_with_connect_rpc(self, kas_info):
483483
f"Connect RPC public key request failed: {type(e).__name__}: {e}"
484484
)
485485
logging.error(f"Full traceback: {error_details}")
486-
raise SDKException(f"Connect RPC public key request failed: {e}")
486+
raise SDKException(f"Connect RPC public key request failed: {e}") from e
487487

488488
def _normalize_session_key_type(self, session_key_type):
489489
"""
@@ -608,7 +608,7 @@ def _parse_and_decrypt_response(self, response):
608608
except Exception as e:
609609
logging.error(f"Failed to parse JSON response: {e}")
610610
logging.error(f"Raw response content: {response.content}")
611-
raise SDKException(f"Invalid JSON response from KAS: {e}")
611+
raise SDKException(f"Invalid JSON response from KAS: {e}") from e
612612

613613
entity_wrapped_key = response_data.get("entityWrappedKey")
614614
if not entity_wrapped_key:
@@ -702,7 +702,7 @@ def _unwrap_with_connect_rpc(
702702

703703
except Exception as e:
704704
logging.error(f"Connect RPC rewrap failed: {e}")
705-
raise SDKException(f"Connect RPC rewrap failed: {e}")
705+
raise SDKException(f"Connect RPC rewrap failed: {e}") from e
706706

707707
def get_key_cache(self) -> KASKeyCache:
708708
"""Returns the KAS key cache used for storing and retrieving encryption keys."""

src/otdf_python/kas_connect_rpc_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def get_public_key(self, normalized_kas_url, kas_info, access_token=None):
138138
f"Connect RPC public key request failed: {type(e).__name__}: {e}"
139139
)
140140
logging.error(f"Full traceback: {error_details}")
141-
raise SDKException(f"Connect RPC public key request failed: {e}")
141+
raise SDKException(f"Connect RPC public key request failed: {e}") from e
142142

143143
def unwrap_key(
144144
self, normalized_kas_url, key_access, signed_token, access_token=None
@@ -210,4 +210,4 @@ def unwrap_key(
210210

211211
except Exception as e:
212212
logging.error(f"Connect RPC rewrap failed: {e}")
213-
raise SDKException(f"Connect RPC rewrap failed: {e}")
213+
raise SDKException(f"Connect RPC rewrap failed: {e}") from e

src/otdf_python/nanotdf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def _is_ec_key(self, key_pem: str) -> bool:
260260
else:
261261
raise SDKException("Invalid PEM format - no BEGIN header found")
262262
except Exception as e:
263-
raise SDKException(f"Failed to detect key type: {e}")
263+
raise SDKException(f"Failed to detect key type: {e}") from e
264264

265265
def _derive_key_with_ecdh( # noqa: C901
266266
self, config: NanoTDFConfig
@@ -582,7 +582,7 @@ def read_nano_tdf( # noqa: C901
582582
header_len = Header.peek_length(nano_tdf_data)
583583
header_obj = Header.from_bytes(nano_tdf_data[:header_len])
584584
except Exception as e:
585-
raise InvalidNanoTDFConfig(f"Failed to parse NanoTDF header: {e}")
585+
raise InvalidNanoTDFConfig(f"Failed to parse NanoTDF header: {e}") from e
586586

587587
# Read payload section per NanoTDF spec:
588588
# [3 bytes: length] [3 bytes: IV] [variable: ciphertext] [tag]

0 commit comments

Comments
 (0)