Skip to content

Commit 2c399ab

Browse files
authored
feat: Export Uniffi Reader type (#70)
* Build script * Add getter * Remove getter * More exports * Add back getter * Bump version * Readme notes
1 parent 2d971e3 commit 2c399ab

File tree

7 files changed

+154
-120
lines changed

7 files changed

+154
-120
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "c2pa-python"
3-
version = "0.6.1"
3+
version = "0.6.2"
44
edition = "2021"
55
authors = ["Gavin Peacock <[email protected]"]
66

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
# Start from clean env: Delete `.venv`, then `python3 -m venv .venv`
44
# Pre-requisite: Python virtual environment is active (source .venv/bin/activate)
55

6+
release:
7+
cargo build --release
8+
69
build-python:
710
rm -rf c2pa/c2pa
811
python3 -m pip uninstall -y maturin
912
python3 -m pip uninstall -y uniffi
1013
python3 -m pip install -r requirements.txt
1114
maturin develop
15+
16+
test:
17+
python3 ./tests/test_unit_tests.py
18+
python3 ./tests/test_api.py

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ auditwheel repair target/wheels/c2pa_python-0.4.0-py3-none-linux_aarch64.whl
358358

359359
### Testing
360360

361-
We use [PyTest](https://docs.pytest.org/) for testing.
361+
We use [PyTest](https://docs.pytest.org/) and [unittest](https://docs.python.org/3/library/unittest.html) for testing.
362362

363363
Run tests by following these steps:
364364

@@ -377,6 +377,23 @@ python3 tests/training.py
377377
deactivate
378378
```
379379

380+
#### Testing during bindings development
381+
382+
While developing bindings locally, we recommend you rely on [unittest](https://docs.python.org/3/library/unittest.html), as [PyTest](https://docs.pytest.org/) can get confused by virtual environment redeployments (especially if you bump the version number).
383+
384+
To run tests while developing bindings, you can run:
385+
386+
```sh
387+
make test
388+
```
389+
390+
If you want to rebuild and test, run:
391+
392+
```sh
393+
make build-python
394+
make test
395+
```
396+
380397
## Release notes
381398

382399
### Version 0.5.2

c2pa/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313

1414
from .c2pa_api import Reader, Builder, create_signer, create_remote_signer, sign_ps256
1515
from .c2pa import Error, SigningAlg, CallbackSigner, sdk_version, version
16-
from .c2pa.c2pa import _UniffiConverterTypeSigningAlg, _UniffiRustBuffer
16+
from .c2pa.c2pa import _UniffiConverterTypeSigningAlg, _UniffiConverterTypeReader, _UniffiRustBuffer
1717

18-
__all__ = ['Reader', 'Builder', 'CallbackSigner', 'create_signer', 'sign_ps256', 'Error', 'SigningAlg', 'sdk_version', 'version', 'create_remote_signer', '_UniffiConverterTypeSigningAlg', '_UniffiRustBuffer']
18+
__all__ = ['Reader', 'Builder', 'CallbackSigner', 'create_signer', 'sign_ps256', 'Error', 'SigningAlg', 'sdk_version', 'version', 'create_remote_signer', '_UniffiConverterTypeSigningAlg', '_UniffiRustBuffer', '_UniffiConverterTypeReader']

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ impl Reader {
111111
Err(Error::RwLock)
112112
}
113113
}
114+
115+
pub fn get_raw_reader(&self) -> &RwLock<c2pa::Reader>{
116+
&self.reader
117+
}
114118
}
115119

116120
pub struct Builder {

tests/test_api.py

Lines changed: 121 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import pytest
1616
import tempfile
1717
import shutil
18+
import unittest
1819

1920
from c2pa import Builder, Error, Reader, SigningAlg, create_signer, sdk_version, sign_ps256, version
2021

@@ -59,126 +60,132 @@ def getitem(d, key):
5960
}
6061
}
6162

62-
def test_v2_read_cloud_manifest():
63-
reader = Reader.from_file("tests/fixtures/cloud.jpg")
64-
manifest = reader.get_active_manifest()
65-
assert manifest is not None
63+
class TestC2paSdk(unittest.TestCase):
64+
def test_version(self):
65+
assert version() == "0.6.2"
6666

67-
def test_version():
68-
assert version() == "0.6.1"
67+
def test_sdk_version(self):
68+
assert "c2pa-rs/" in sdk_version()
6969

70-
def test_sdk_version():
71-
assert "c2pa-rs/" in sdk_version()
72-
73-
def test_v2_read():
74-
#example of reading a manifest store from a file
75-
try:
76-
reader = Reader.from_file("tests/fixtures/C.jpg")
70+
class TestReader(unittest.TestCase):
71+
def test_v2_read_cloud_manifest(self):
72+
reader = Reader.from_file("tests/fixtures/cloud.jpg")
7773
manifest = reader.get_active_manifest()
7874
assert manifest is not None
79-
assert "make_test_images" in manifest["claim_generator"]
80-
assert manifest["title"]== "C.jpg"
81-
assert manifest["format"] == "image/jpeg"
82-
# There should be no validation status errors
83-
assert manifest.get("validation_status") == None
84-
# read creative work assertion (author name)
85-
assert getitem(manifest,("assertions",0,"label")) == "stds.schema-org.CreativeWork"
86-
assert getitem(manifest,("assertions",0,"data","author",0,"name")) == "Adobe make_test"
87-
# read Actions assertion
88-
assert getitem(manifest,("assertions",1,"label")) == "c2pa.actions"
89-
assert getitem(manifest,("assertions",1,"data","actions",0,"action")) == "c2pa.created"
90-
# read signature info
91-
assert getitem(manifest,("signature_info","issuer")) == "C2PA Test Signing Cert"
92-
# read thumbnail data from file
93-
assert getitem(manifest,("thumbnail","format")) == "image/jpeg"
94-
# check the thumbnail data
95-
uri = getitem(manifest,("thumbnail","identifier"))
96-
reader.resource_to_file(uri, "target/thumbnail_read_v2.jpg")
97-
98-
except Exception as e:
99-
print("Failed to read manifest store: " + str(e))
100-
exit(1)
101-
102-
def test_reader_from_file_no_store():
103-
with pytest.raises(Error.ManifestNotFound) as err:
104-
reader = Reader.from_file("tests/fixtures/A.jpg")
105-
106-
def test_v2_sign():
107-
# define a source folder for any assets we need to read
108-
data_dir = "tests/fixtures/"
109-
try:
110-
key = open(data_dir + "ps256.pem", "rb").read()
111-
def sign(data: bytes) -> bytes:
112-
return sign_ps256(data, key)
113-
114-
certs = open(data_dir + "ps256.pub", "rb").read()
115-
# Create a local signer from a certificate pem file
116-
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
117-
118-
builder = Builder(manifest_def)
119-
120-
builder.add_ingredient_file(ingredient_def, data_dir + "A.jpg")
121-
122-
builder.add_resource_file("A.jpg", data_dir + "A.jpg")
123-
124-
builder.to_archive(open("target/archive.zip", "wb"))
125-
126-
builder = Builder.from_archive(open("target/archive.zip", "rb"))
127-
128-
with tempfile.TemporaryDirectory() as output_dir:
129-
output_path = output_dir + "out.jpg"
130-
if os.path.exists(output_path):
131-
os.remove(output_path)
132-
c2pa_data = builder.sign_file(signer, data_dir + "A.jpg", output_dir + "out.jpg")
133-
assert len(c2pa_data) > 0
134-
135-
reader = Reader.from_file(output_dir + "out.jpg")
136-
print(reader.json())
137-
manifest_store = json.loads(reader.json())
138-
manifest = manifest_store["manifests"][manifest_store["active_manifest"]]
139-
assert "python_test" in manifest["claim_generator"]
140-
# check custom title and format
141-
assert manifest["title"]== "My Title"
142-
assert manifest,["format"] == "image/jpeg"
143-
# There should be no validation status errors
144-
assert manifest.get("validation_status") == None
145-
assert manifest["ingredients"][0]["relationship"] == "parentOf"
146-
assert manifest["ingredients"][0]["title"] == "A.jpg"
147-
except Exception as e:
148-
print("Failed to sign manifest store: " + str(e))
149-
exit(1)
150-
151-
# Test signing the same source and destination file
152-
def test_v2_sign_file_same():
153-
data_dir = "tests/fixtures/"
154-
try:
155-
key = open(data_dir + "ps256.pem", "rb").read()
156-
def sign(data: bytes) -> bytes:
157-
return sign_ps256(data, key)
158-
159-
certs = open(data_dir + "ps256.pub", "rb").read()
160-
# Create a local signer from a certificate pem file
161-
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
162-
163-
builder = Builder(manifest_def)
164-
165-
builder.add_resource_file("A.jpg", data_dir + "A.jpg")
166-
167-
with tempfile.TemporaryDirectory() as output_dir:
168-
path = output_dir + "/A.jpg"
169-
# Copy the file from data_dir to output_dir
170-
shutil.copy(data_dir + "A.jpg", path)
171-
c2pa_data = builder.sign_file(signer, path, path)
172-
assert len(c2pa_data) > 0
173-
174-
reader = Reader.from_file(path)
175-
manifest = reader.get_active_manifest()
17675

76+
def test_v2_read(self):
77+
#example of reading a manifest store from a file
78+
try:
79+
reader = Reader.from_file("tests/fixtures/C.jpg")
80+
manifest = reader.get_active_manifest()
81+
assert manifest is not None
82+
assert "make_test_images" in manifest["claim_generator"]
83+
assert manifest["title"]== "C.jpg"
84+
assert manifest["format"] == "image/jpeg"
85+
# There should be no validation status errors
86+
assert manifest.get("validation_status") == None
87+
# read creative work assertion (author name)
88+
assert getitem(manifest,("assertions",0,"label")) == "stds.schema-org.CreativeWork"
89+
assert getitem(manifest,("assertions",0,"data","author",0,"name")) == "Adobe make_test"
90+
# read Actions assertion
91+
assert getitem(manifest,("assertions",1,"label")) == "c2pa.actions"
92+
assert getitem(manifest,("assertions",1,"data","actions",0,"action")) == "c2pa.created"
93+
# read signature info
94+
assert getitem(manifest,("signature_info","issuer")) == "C2PA Test Signing Cert"
95+
# read thumbnail data from file
96+
assert getitem(manifest,("thumbnail","format")) == "image/jpeg"
97+
# check the thumbnail data
98+
uri = getitem(manifest,("thumbnail","identifier"))
99+
reader.resource_to_file(uri, "target/thumbnail_read_v2.jpg")
100+
101+
except Exception as e:
102+
print("Failed to read manifest store: " + str(e))
103+
exit(1)
104+
105+
def test_reader_from_file_no_store(self):
106+
with pytest.raises(Error.ManifestNotFound) as err:
107+
reader = Reader.from_file("tests/fixtures/A.jpg")
108+
109+
class TestSignerr(unittest.TestCase):
110+
def test_v2_sign(self):
111+
# define a source folder for any assets we need to read
112+
data_dir = "tests/fixtures/"
113+
try:
114+
key = open(data_dir + "ps256.pem", "rb").read()
115+
def sign(data: bytes) -> bytes:
116+
return sign_ps256(data, key)
117+
118+
certs = open(data_dir + "ps256.pub", "rb").read()
119+
# Create a local signer from a certificate pem file
120+
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
121+
122+
builder = Builder(manifest_def)
123+
124+
builder.add_ingredient_file(ingredient_def, data_dir + "A.jpg")
125+
126+
builder.add_resource_file("A.jpg", data_dir + "A.jpg")
127+
128+
builder.to_archive(open("target/archive.zip", "wb"))
129+
130+
builder = Builder.from_archive(open("target/archive.zip", "rb"))
131+
132+
with tempfile.TemporaryDirectory() as output_dir:
133+
output_path = output_dir + "out.jpg"
134+
if os.path.exists(output_path):
135+
os.remove(output_path)
136+
c2pa_data = builder.sign_file(signer, data_dir + "A.jpg", output_dir + "out.jpg")
137+
assert len(c2pa_data) > 0
138+
139+
reader = Reader.from_file(output_dir + "out.jpg")
140+
print(reader.json())
141+
manifest_store = json.loads(reader.json())
142+
manifest = manifest_store["manifests"][manifest_store["active_manifest"]]
143+
assert "python_test" in manifest["claim_generator"]
177144
# check custom title and format
178145
assert manifest["title"]== "My Title"
179-
assert manifest["format"] == "image/jpeg"
146+
assert manifest,["format"] == "image/jpeg"
180147
# There should be no validation status errors
181148
assert manifest.get("validation_status") == None
182-
except Exception as e:
183-
print("Failed to sign manifest store: " + str(e))
184-
#exit(1)
149+
assert manifest["ingredients"][0]["relationship"] == "parentOf"
150+
assert manifest["ingredients"][0]["title"] == "A.jpg"
151+
except Exception as e:
152+
print("Failed to sign manifest store: " + str(e))
153+
exit(1)
154+
155+
# Test signing the same source and destination file
156+
def test_v2_sign_file_same(self):
157+
data_dir = "tests/fixtures/"
158+
try:
159+
key = open(data_dir + "ps256.pem", "rb").read()
160+
def sign(data: bytes) -> bytes:
161+
return sign_ps256(data, key)
162+
163+
certs = open(data_dir + "ps256.pub", "rb").read()
164+
# Create a local signer from a certificate pem file
165+
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
166+
167+
builder = Builder(manifest_def)
168+
169+
builder.add_resource_file("A.jpg", data_dir + "A.jpg")
170+
171+
with tempfile.TemporaryDirectory() as output_dir:
172+
path = output_dir + "/A.jpg"
173+
# Copy the file from data_dir to output_dir
174+
shutil.copy(data_dir + "A.jpg", path)
175+
c2pa_data = builder.sign_file(signer, path, path)
176+
assert len(c2pa_data) > 0
177+
178+
reader = Reader.from_file(path)
179+
manifest = reader.get_active_manifest()
180+
181+
# check custom title and format
182+
assert manifest["title"]== "My Title"
183+
assert manifest["format"] == "image/jpeg"
184+
# There should be no validation status errors
185+
assert manifest.get("validation_status") == None
186+
except Exception as e:
187+
print("Failed to sign manifest store: " + str(e))
188+
#exit(1)
189+
190+
if __name__ == '__main__':
191+
unittest.main()

tests/test_unit_tests.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@
2525

2626
class TestC2paSdk(unittest.TestCase):
2727
def test_version(self):
28-
self.assertIn("0.6.1", sdk_version())
28+
self.assertIn("0.6.2", sdk_version())
2929

3030

3131
class TestReader(unittest.TestCase):
32-
3332
def test_stream_read(self):
3433
with open(testPath, "rb") as file:
3534
reader = Reader("image/jpeg",file)

0 commit comments

Comments
 (0)