Skip to content

Commit 8b9fb93

Browse files
author
Tania Mathern
committed
fix: Refactor
1 parent e2621df commit 8b9fb93

5 files changed

Lines changed: 177 additions & 162 deletions

File tree

docs/usage.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Import the objects needed from the API:
1010

1111
```py
1212
from c2pa import Builder, Reader, Signer, C2paSigningAlg, C2paSignerInfo
13-
from c2pa import Settings, Context, ContextProvider
13+
from c2pa import Settings, Context, ContextBuilder, ContextProvider
1414
```
1515

1616
You can use both `Builder`, `Reader` and `Signer` classes with context managers by using a `with` statement.
@@ -122,6 +122,62 @@ except Exception as e:
122122

123123
The `Settings` and `Context` classes provide **per-instance configuration** for Reader and Builder operations. This replaces the global `load_settings()` function, which is now deprecated.
124124

125+
```mermaid
126+
classDiagram
127+
class ContextProvider {
128+
<<abstract>>
129+
+is_valid bool
130+
+execution_context
131+
}
132+
133+
class Settings {
134+
+set(path, value) Settings
135+
+update(data) Settings
136+
+from_json(json_str)$ Settings
137+
+from_dict(config)$ Settings
138+
+close()
139+
}
140+
141+
class Context {
142+
+has_signer bool
143+
+builder()$ ContextBuilder
144+
+from_json(json_str, signer)$ Context
145+
+from_dict(config, signer)$ Context
146+
+close()
147+
}
148+
149+
class ContextBuilder {
150+
+with_settings(settings) ContextBuilder
151+
+with_signer(signer) ContextBuilder
152+
+build() Context
153+
}
154+
155+
class Signer {
156+
+from_info(signer_info)$ Signer
157+
+from_callback(callback, alg, certs, tsa_url)$ Signer
158+
+close()
159+
}
160+
161+
class Reader {
162+
+json() str
163+
+resource_to_stream(uri, stream)
164+
+close()
165+
}
166+
167+
class Builder {
168+
+add_ingredient(json, format, stream)
169+
+sign(signer, format, source, dest) bytes
170+
+close()
171+
}
172+
173+
ContextProvider <|-- Context
174+
ContextBuilder --> Context : builds
175+
Context o-- Settings : optional
176+
Context o-- Signer : optional, consumed
177+
Reader ..> ContextProvider : uses
178+
Builder ..> ContextProvider : uses
179+
```
180+
125181
### Settings
126182

127183
`Settings` controls behavior such as thumbnail generation, trust lists, and verification flags.
@@ -176,6 +232,28 @@ reader = Reader("path/to/media_file.jpg", context=ctx)
176232
builder = Builder(manifest_json, context=ctx)
177233
```
178234

235+
### ContextBuilder (fluent API)
236+
237+
`ContextBuilder` provides a fluent interface for constructing a `Context`, matching the c2pa-rs `ContextBuilder` pattern. Use `Context.builder()` to get started.
238+
239+
```py
240+
from c2pa import Context, ContextBuilder, Settings, Signer
241+
242+
# Fluent construction with settings and signer
243+
ctx = (
244+
Context.builder()
245+
.with_settings(settings)
246+
.with_signer(signer)
247+
.build()
248+
)
249+
250+
# Settings only
251+
ctx = Context.builder().with_settings(settings).build()
252+
253+
# Default context (equivalent to Context())
254+
ctx = Context.builder().build()
255+
```
256+
179257
### Context with a Signer
180258

181259
When a `Signer` is passed to `Context`, the `Signer` object becomes invalid after this call and must not be reused directly anymore as it became part of the Context. The `Context` takes ownership of the underlying native signer. This allows signing without passing an explicit signer to `Builder.sign()`.

review_2.md

Lines changed: 0 additions & 160 deletions
This file was deleted.

src/c2pa/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
Stream,
3030
Settings,
3131
Context,
32+
ContextBuilder,
3233
ContextProvider,
3334
sdk_version,
3435
read_ingredient_file,
@@ -48,6 +49,7 @@
4849
'Stream',
4950
'Settings',
5051
'Context',
52+
'ContextBuilder',
5153
'ContextProvider',
5254
'sdk_version',
5355
'read_ingredient_file',

src/c2pa/c2pa.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,39 @@ def __del__(self):
14351435
self._cleanup_resources()
14361436

14371437

1438+
class ContextBuilder:
1439+
"""Fluent builder for Context.
1440+
1441+
Matches the c2pa-rs ContextBuilder pattern.
1442+
Use Context.builder() to create an instance.
1443+
"""
1444+
1445+
def __init__(self):
1446+
self._settings = None
1447+
self._signer = None
1448+
1449+
def with_settings(
1450+
self, settings: 'Settings',
1451+
) -> 'ContextBuilder':
1452+
"""Attach Settings to the context being built."""
1453+
self._settings = settings
1454+
return self
1455+
1456+
def with_signer(
1457+
self, signer: 'Signer',
1458+
) -> 'ContextBuilder':
1459+
"""Attach a Signer (will be consumed on build)."""
1460+
self._signer = signer
1461+
return self
1462+
1463+
def build(self) -> 'Context':
1464+
"""Build and return a configured Context."""
1465+
return Context(
1466+
settings=self._settings,
1467+
signer=self._signer,
1468+
)
1469+
1470+
14381471
class Context(ContextProvider):
14391472
"""Per-instance context for C2PA operations.
14401473
@@ -1556,6 +1589,11 @@ def __init__(
15561589

15571590
self._state = LifecycleState.ACTIVE
15581591

1592+
@classmethod
1593+
def builder(cls) -> 'ContextBuilder':
1594+
"""Return a fluent ContextBuilder."""
1595+
return ContextBuilder()
1596+
15591597
@classmethod
15601598
def from_json(
15611599
cls,

0 commit comments

Comments
 (0)