Skip to content

Commit 2e3447c

Browse files
committed
fix: Error cleanup on isntantiate/new use
1 parent 032c5f2 commit 2e3447c

1 file changed

Lines changed: 36 additions & 14 deletions

File tree

src/c2pa/c2pa.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ class C2paStream(ctypes.Structure):
244244
]
245245

246246

247+
def _clear_error_state():
248+
"""Clear any existing error state from the C library.
249+
250+
This function should be called at the beginning of object initialization
251+
and before any operations that could potentially raise an error,
252+
to ensure that stale error states from previous operations don't interfere
253+
with new objects being created.
254+
"""
255+
error = _lib.c2pa_error()
256+
if error:
257+
# Free the error to clear the state
258+
_lib.c2pa_string_free(error)
259+
247260
class C2paSignerInfo(ctypes.Structure):
248261
"""Configuration for a Signer."""
249262
_fields_ = [
@@ -264,6 +277,7 @@ def __init__(self, alg, sign_cert, private_key, ta_url):
264277
private_key: The private key as a string
265278
ta_url: The timestamp authority URL as bytes
266279
"""
280+
_clear_error_state()
267281

268282
if sign_cert is None:
269283
raise ValueError("sign_cert must be set")
@@ -601,19 +615,6 @@ def _convert_to_py_string(value) -> str:
601615
return py_string
602616

603617

604-
def _clear_error_state():
605-
"""Clear any existing error state from the C library.
606-
607-
This function should be called at the beginning of object initialization
608-
to ensure that stale error states from previous operations don't interfere
609-
with new objects being created.
610-
"""
611-
error = _lib.c2pa_error()
612-
if error:
613-
# Free the error to clear the state
614-
_lib.c2pa_string_free(error)
615-
616-
617618
def _parse_operation_result_for_error(
618619
result: ctypes.c_void_p | None,
619620
check_error: bool = True) -> Optional[str]:
@@ -705,6 +706,8 @@ def load_settings(settings: Union[str, dict], format: str = "json") -> None:
705706
Raises:
706707
C2paError: If there was an error loading the settings
707708
"""
709+
_clear_error_state()
710+
708711
# Convert to JSON string as necessary
709712
try:
710713
if isinstance(settings, dict):
@@ -789,6 +792,8 @@ def read_ingredient_file(
789792
stacklevel=2,
790793
)
791794

795+
_clear_error_state()
796+
792797
container = _StringContainer()
793798

794799
container._path_str = str(path).encode('utf-8')
@@ -834,6 +839,8 @@ def read_file(path: Union[str, Path],
834839
stacklevel=2,
835840
)
836841

842+
_clear_error_state()
843+
837844
container = _StringContainer()
838845

839846
container._path_str = str(path).encode('utf-8')
@@ -920,6 +927,8 @@ def sign_file(
920927
stacklevel=2,
921928
)
922929

930+
_clear_error_state()
931+
923932
try:
924933
# Determine if we have a signer or signer info
925934
if isinstance(signer_or_info, C2paSignerInfo):
@@ -1946,6 +1955,10 @@ def from_info(cls, signer_info: C2paSignerInfo) -> 'Signer':
19461955
Raises:
19471956
C2paError: If there was an error creating the signer
19481957
"""
1958+
# Native libs plumbing:
1959+
# Clear any stale error state from previous operations
1960+
_clear_error_state()
1961+
19491962
signer_ptr = _lib.c2pa_signer_from_info(ctypes.byref(signer_info))
19501963

19511964
if not signer_ptr:
@@ -2071,6 +2084,10 @@ def wrapped_callback(
20712084
cls._ERROR_MESSAGES['encoding_error'].format(
20722085
str(e)))
20732086

2087+
# Native libs plumbing:
2088+
# Clear any stale error state from previous operations
2089+
_clear_error_state()
2090+
20742091
# Create the callback object using the callback function
20752092
callback_cb = SignerCallback(wrapped_callback)
20762093

@@ -2114,7 +2131,7 @@ def __init__(self, signer_ptr: ctypes.POINTER(C2paSigner)):
21142131
# Native libs plumbing:
21152132
# Clear any stale error state from previous operations
21162133
_clear_error_state()
2117-
2134+
21182135
# Validate pointer before assignment
21192136
if not signer_ptr:
21202137
raise C2paError("Invalid signer pointer: pointer is null")
@@ -2347,6 +2364,7 @@ def from_archive(cls, stream: Any) -> 'Builder':
23472364
"""
23482365
builder = cls({})
23492366
stream_obj = Stream(stream)
2367+
23502368
builder._builder = _lib.c2pa_builder_from_archive(stream_obj._stream)
23512369

23522370
if not builder._builder:
@@ -2908,6 +2926,8 @@ def format_embeddable(format: str, manifest_bytes: bytes) -> tuple[int, bytes]:
29082926
Raises:
29092927
C2paError: If there was an error converting the manifest
29102928
"""
2929+
_clear_error_state()
2930+
29112931
format_str = format.encode('utf-8')
29122932
manifest_array = (ctypes.c_ubyte * len(manifest_bytes))(*manifest_bytes)
29132933
result_bytes_ptr = ctypes.POINTER(ctypes.c_ubyte)()
@@ -3017,6 +3037,8 @@ def ed25519_sign(data: bytes, private_key: str) -> bytes:
30173037
C2paError: If there was an error signing the data
30183038
C2paError.Encoding: If the private key contains invalid UTF-8 chars
30193039
"""
3040+
_clear_error_state()
3041+
30203042
if not data:
30213043
raise C2paError("Data to sign cannot be empty")
30223044

0 commit comments

Comments
 (0)