Skip to content

Commit 4c660e5

Browse files
committed
fix: Refactor
1 parent ff11d1c commit 4c660e5

File tree

2 files changed

+1
-350
lines changed

2 files changed

+1
-350
lines changed

src/c2pa/c2pa.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,27 +1764,7 @@ def add_ingredient(self, ingredient_json: str, format: str, source: Any):
17641764
C2paError: If there was an error adding the ingredient
17651765
C2paError.Encoding: If the ingredient JSON contains invalid UTF-8 characters
17661766
"""
1767-
if not self._builder:
1768-
raise C2paError(Builder._ERROR_MESSAGES['closed_error'])
1769-
1770-
try:
1771-
ingredient_str = ingredient_json.encode('utf-8')
1772-
format_str = format.encode('utf-8')
1773-
except UnicodeError as e:
1774-
raise C2paError.Encoding(
1775-
Builder._ERROR_MESSAGES['encoding_error'].format(
1776-
str(e)))
1777-
1778-
source_stream = Stream(source)
1779-
result = _lib.c2pa_builder_add_ingredient_from_stream(
1780-
self._builder, ingredient_str, format_str, source_stream._stream)
1781-
1782-
if result != 0:
1783-
error = _parse_operation_result_for_error(_lib.c2pa_error())
1784-
if error:
1785-
raise C2paError(error)
1786-
raise C2paError(
1787-
Builder._ERROR_MESSAGES['ingredient_error'].format("Unknown error"))
1767+
return self.add_ingredient_from_stream(ingredient_json, format, source)
17881768

17891769
def add_ingredient_from_stream(
17901770
self,

tests/test_unit_tests_threaded.py

Lines changed: 0 additions & 329 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,93 +1469,6 @@ async def run_async_tests():
14691469
# Verify all readers completed
14701470
self.assertEqual(active_readers, 0, "Not all readers completed")
14711471

1472-
def test_builder_sign_with_multiple_ingredient(self):
1473-
"""Test Builder class operations with multiple ingredients added in parallel threads."""
1474-
# Test creating builder from JSON
1475-
builder = Builder.from_json(self.manifestDefinition)
1476-
assert builder._builder is not None
1477-
1478-
# Define paths for test files
1479-
cloud_path = os.path.join(self.data_dir, "cloud.jpg")
1480-
1481-
# Thread synchronization
1482-
ingredient_added = threading.Event()
1483-
add_errors = []
1484-
add_lock = threading.Lock()
1485-
1486-
def add_ingredient(ingredient_json, file_path, thread_id):
1487-
try:
1488-
with open(file_path, 'rb') as f:
1489-
builder.add_ingredient(ingredient_json, "image/jpeg", f)
1490-
with add_lock:
1491-
add_errors.append(None) # Success case
1492-
except Exception as e:
1493-
with add_lock:
1494-
add_errors.append(f"Thread {thread_id} error: {str(e)}")
1495-
finally:
1496-
ingredient_added.set()
1497-
1498-
# Create and start two threads for parallel ingredient addition
1499-
thread1 = threading.Thread(
1500-
target=add_ingredient,
1501-
args=('{"title": "Test Ingredient 1"}', self.testPath3, 1)
1502-
)
1503-
thread2 = threading.Thread(
1504-
target=add_ingredient,
1505-
args=('{"title": "Test Ingredient 2"}', cloud_path, 2)
1506-
)
1507-
1508-
# Start both threads
1509-
thread1.start()
1510-
thread2.start()
1511-
1512-
# Wait for both threads to complete
1513-
thread1.join()
1514-
thread2.join()
1515-
1516-
# Check for errors during ingredient addition
1517-
if any(error for error in add_errors if error is not None):
1518-
self.fail(
1519-
"\n".join(
1520-
error for error in add_errors if error is not None))
1521-
1522-
# Verify both ingredients were added successfully
1523-
self.assertEqual(
1524-
len(add_errors),
1525-
2,
1526-
"Both threads should have completed")
1527-
1528-
# Now sign the manifest with the added ingredients
1529-
with open(self.testPath2, "rb") as file:
1530-
output = io.BytesIO(bytearray())
1531-
builder.sign(self.signer, "image/jpeg", file, output)
1532-
output.seek(0)
1533-
reader = Reader("image/jpeg", output)
1534-
json_data = reader.json()
1535-
manifest_data = json.loads(json_data)
1536-
1537-
# Verify active manifest exists
1538-
self.assertIn("active_manifest", manifest_data)
1539-
active_manifest_id = manifest_data["active_manifest"]
1540-
1541-
# Verify active manifest object exists
1542-
self.assertIn("manifests", manifest_data)
1543-
self.assertIn(active_manifest_id, manifest_data["manifests"])
1544-
active_manifest = manifest_data["manifests"][active_manifest_id]
1545-
1546-
# Verify ingredients array exists in active manifest
1547-
self.assertIn("ingredients", active_manifest)
1548-
self.assertIsInstance(active_manifest["ingredients"], list)
1549-
self.assertEqual(len(active_manifest["ingredients"]), 2)
1550-
1551-
# Verify both ingredients exist in the array (order doesn't matter)
1552-
ingredient_titles = [ing["title"]
1553-
for ing in active_manifest["ingredients"]]
1554-
self.assertIn("Test Ingredient 1", ingredient_titles)
1555-
self.assertIn("Test Ingredient 2", ingredient_titles)
1556-
1557-
builder.close()
1558-
15591472
def test_builder_sign_with_multiple_ingredients_from_stream(self):
15601473
"""Test Builder class operations with multiple ingredients using streams."""
15611474
# Test creating builder from JSON
@@ -1648,248 +1561,6 @@ def add_ingredient_from_stream(ingredient_json, file_path, thread_id):
16481561

16491562
builder.close()
16501563

1651-
def test_builder_sign_with_multiple_ingredient_random(self):
1652-
"""Test Builder class operations with 5 random ingredients added in parallel threads."""
1653-
# Test creating builder from JSON
1654-
builder = Builder.from_json(self.manifestDefinition)
1655-
assert builder._builder is not None
1656-
1657-
# Get list of files from files-for-reading-tests directory
1658-
reading_dir = os.path.join(self.data_dir, "files-for-reading-tests")
1659-
all_files = [
1660-
f for f in os.listdir(reading_dir) if os.path.isfile(
1661-
os.path.join(
1662-
reading_dir, f))]
1663-
1664-
# Select 5 random files
1665-
random.seed(42) # For reproducible testing
1666-
selected_files = random.sample(all_files, 5)
1667-
1668-
# Thread synchronization
1669-
add_errors = []
1670-
add_lock = threading.Lock()
1671-
completed_threads = 0
1672-
completion_lock = threading.Lock()
1673-
1674-
def add_ingredient(file_name, thread_id):
1675-
nonlocal completed_threads
1676-
try:
1677-
file_path = os.path.join(reading_dir, file_name)
1678-
ingredient_json = json.dumps({
1679-
"title": f"Test Ingredient Thread {thread_id} - {file_name}"
1680-
})
1681-
1682-
with open(file_path, 'rb') as f:
1683-
builder.add_ingredient(ingredient_json, "image/jpeg", f)
1684-
1685-
with add_lock:
1686-
add_errors.append(None) # Success case
1687-
except Exception as e:
1688-
with add_lock:
1689-
add_errors.append(
1690-
f"Thread {thread_id} error with file {file_name}: {
1691-
str(e)}")
1692-
finally:
1693-
with completion_lock:
1694-
completed_threads += 1
1695-
1696-
# Create and start 5 threads for parallel ingredient addition
1697-
threads = []
1698-
for i, file_name in enumerate(selected_files, 1):
1699-
thread = threading.Thread(
1700-
target=add_ingredient,
1701-
args=(file_name, i)
1702-
)
1703-
threads.append(thread)
1704-
thread.start()
1705-
1706-
# Wait for all threads to complete
1707-
for thread in threads:
1708-
thread.join()
1709-
1710-
# Check for errors during ingredient addition
1711-
if any(error for error in add_errors if error is not None):
1712-
self.fail(
1713-
"\n".join(
1714-
error for error in add_errors if error is not None))
1715-
1716-
# Verify all ingredients were added successfully
1717-
self.assertEqual(
1718-
completed_threads,
1719-
5,
1720-
"All 5 threads should have completed")
1721-
self.assertEqual(
1722-
len(add_errors),
1723-
5,
1724-
"All 5 threads should have completed without errors")
1725-
1726-
# Now sign the manifest with the added ingredients
1727-
with open(self.testPath2, "rb") as file:
1728-
output = io.BytesIO(bytearray())
1729-
builder.sign(self.signer, "image/jpeg", file, output)
1730-
output.seek(0)
1731-
reader = Reader("image/jpeg", output)
1732-
json_data = reader.json()
1733-
manifest_data = json.loads(json_data)
1734-
1735-
# Verify active manifest exists
1736-
self.assertIn("active_manifest", manifest_data)
1737-
active_manifest_id = manifest_data["active_manifest"]
1738-
1739-
# Verify active manifest object exists
1740-
self.assertIn("manifests", manifest_data)
1741-
self.assertIn(active_manifest_id, manifest_data["manifests"])
1742-
active_manifest = manifest_data["manifests"][active_manifest_id]
1743-
1744-
# Verify ingredients array exists in active manifest
1745-
self.assertIn("ingredients", active_manifest)
1746-
self.assertIsInstance(active_manifest["ingredients"], list)
1747-
self.assertEqual(len(active_manifest["ingredients"]), 5)
1748-
1749-
# Verify all ingredients exist in the array with correct thread IDs
1750-
ingredient_titles = [ing["title"]
1751-
for ing in active_manifest["ingredients"]]
1752-
for i in range(1, 6):
1753-
# Find an ingredient with this thread ID
1754-
thread_ingredients = [
1755-
title for title in ingredient_titles if f"Thread {i}" in title]
1756-
self.assertEqual(
1757-
len(thread_ingredients),
1758-
1,
1759-
f"Should find exactly one ingredient for thread {i}")
1760-
1761-
# Verify the ingredient title contains the file name
1762-
thread_ingredient = thread_ingredients[0]
1763-
file_name = selected_files[i - 1]
1764-
self.assertIn(
1765-
file_name,
1766-
thread_ingredient,
1767-
f"Ingredient for thread {i} should contain its file name")
1768-
1769-
builder.close()
1770-
1771-
def test_builder_sign_with_multiple_ingredient_async_random(self):
1772-
"""Test Builder class operations with 5 random ingredients added in parallel using asyncio."""
1773-
# Test creating builder from JSON
1774-
builder = Builder.from_json(self.manifestDefinition)
1775-
assert builder._builder is not None
1776-
1777-
# Get list of files from files-for-reading-tests directory
1778-
reading_dir = os.path.join(self.data_dir, "files-for-reading-tests")
1779-
all_files = [
1780-
f for f in os.listdir(reading_dir) if os.path.isfile(
1781-
os.path.join(
1782-
reading_dir, f))]
1783-
1784-
# Select 5 random files
1785-
random.seed(42) # For reproducible testing
1786-
selected_files = random.sample(all_files, 5)
1787-
1788-
# Async synchronization
1789-
add_errors = []
1790-
add_lock = asyncio.Lock()
1791-
completed_tasks = 0
1792-
completion_lock = asyncio.Lock()
1793-
# Barrier to synchronize task starts
1794-
start_barrier = asyncio.Barrier(5)
1795-
1796-
async def add_ingredient(file_name, task_id):
1797-
nonlocal completed_tasks
1798-
try:
1799-
# Wait for all tasks to be ready
1800-
await start_barrier.wait()
1801-
1802-
file_path = os.path.join(reading_dir, file_name)
1803-
ingredient_json = json.dumps({
1804-
"title": f"Test Ingredient Task {task_id} - {file_name}"
1805-
})
1806-
1807-
with open(file_path, 'rb') as f:
1808-
builder.add_ingredient(ingredient_json, "image/jpeg", f)
1809-
1810-
async with add_lock:
1811-
add_errors.append(None) # Success case
1812-
except Exception as e:
1813-
async with add_lock:
1814-
add_errors.append(
1815-
f"Task {task_id} error with file {file_name}: {
1816-
str(e)}")
1817-
finally:
1818-
async with completion_lock:
1819-
completed_tasks += 1
1820-
1821-
async def run_async_tests():
1822-
# Create all tasks first
1823-
tasks = []
1824-
for i, file_name in enumerate(selected_files, 1):
1825-
task = asyncio.create_task(add_ingredient(file_name, i))
1826-
tasks.append(task)
1827-
1828-
# Wait for all tasks to complete
1829-
await asyncio.gather(*tasks)
1830-
1831-
# Check for errors during ingredient addition
1832-
if any(error for error in add_errors if error is not None):
1833-
raise Exception(
1834-
"\n".join(
1835-
error for error in add_errors if error is not None))
1836-
1837-
# Verify all ingredients were added successfully
1838-
self.assertEqual(
1839-
completed_tasks,
1840-
5,
1841-
"All 5 tasks should have completed")
1842-
self.assertEqual(
1843-
len(add_errors),
1844-
5,
1845-
"All 5 tasks should have completed without errors")
1846-
1847-
# Now sign the manifest with the added ingredients
1848-
with open(self.testPath2, "rb") as file:
1849-
output = io.BytesIO(bytearray())
1850-
builder.sign(self.signer, "image/jpeg", file, output)
1851-
output.seek(0)
1852-
reader = Reader("image/jpeg", output)
1853-
json_data = reader.json()
1854-
manifest_data = json.loads(json_data)
1855-
1856-
# Verify active manifest exists
1857-
self.assertIn("active_manifest", manifest_data)
1858-
active_manifest_id = manifest_data["active_manifest"]
1859-
1860-
# Verify active manifest object exists
1861-
self.assertIn("manifests", manifest_data)
1862-
self.assertIn(active_manifest_id, manifest_data["manifests"])
1863-
active_manifest = manifest_data["manifests"][active_manifest_id]
1864-
1865-
# Verify ingredients array exists in active manifest
1866-
self.assertIn("ingredients", active_manifest)
1867-
self.assertIsInstance(active_manifest["ingredients"], list)
1868-
self.assertEqual(len(active_manifest["ingredients"]), 5)
1869-
1870-
# Verify all ingredients exist in the array with correct task
1871-
# IDs
1872-
ingredient_titles = [ing["title"]
1873-
for ing in active_manifest["ingredients"]]
1874-
for i in range(1, 6):
1875-
# Find an ingredient with this task ID
1876-
task_ingredients = [
1877-
title for title in ingredient_titles if f"Task {i}" in title]
1878-
self.assertEqual(
1879-
len(task_ingredients),
1880-
1,
1881-
f"Should find exactly one ingredient for task {i}")
1882-
1883-
# Verify the ingredient title contains the file name
1884-
task_ingredient = task_ingredients[0]
1885-
file_name = selected_files[i - 1]
1886-
self.assertIn(file_name, task_ingredient, f"Ingredient for task {
1887-
i} should contain its file name")
1888-
1889-
# Run the async tests
1890-
asyncio.run(run_async_tests())
1891-
builder.close()
1892-
18931564
def test_builder_sign_with_same_ingredient_multiple_times(self):
18941565
"""Test Builder class operations with the same ingredient added multiple times from different threads."""
18951566
# Test creating builder from JSON

0 commit comments

Comments
 (0)