Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "c2pa-python"
version = "0.6.1"
version = "0.6.2"
edition = "2021"
authors = ["Gavin Peacock <gpeacock@adobe.com"]

Expand Down
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@
# Start from clean env: Delete `.venv`, then `python3 -m venv .venv`
# Pre-requisite: Python virtual environment is active (source .venv/bin/activate)

release:
cargo build --release

build-python:
rm -rf c2pa/c2pa
python3 -m pip uninstall -y maturin
python3 -m pip uninstall -y uniffi
python3 -m pip install -r requirements.txt
maturin develop

test:
python3 ./tests/test_unit_tests.py
python3 ./tests/test_api.py
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ auditwheel repair target/wheels/c2pa_python-0.4.0-py3-none-linux_aarch64.whl

### Testing

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

Run tests by following these steps:

Expand All @@ -377,6 +377,23 @@ python3 tests/training.py
deactivate
```

#### Testing during bindings development

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).

To run tests while developing bindings, you can run:

```sh
make test
```

If you want to rebuild and test, run:

```sh
make build-python
make test
```

## Release notes

### Version 0.5.2
Expand Down
4 changes: 2 additions & 2 deletions c2pa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@

from .c2pa_api import Reader, Builder, create_signer, create_remote_signer, sign_ps256
from .c2pa import Error, SigningAlg, CallbackSigner, sdk_version, version
from .c2pa.c2pa import _UniffiConverterTypeSigningAlg, _UniffiRustBuffer
from .c2pa.c2pa import _UniffiConverterTypeSigningAlg, _UniffiConverterTypeReader, _UniffiRustBuffer

__all__ = ['Reader', 'Builder', 'CallbackSigner', 'create_signer', 'sign_ps256', 'Error', 'SigningAlg', 'sdk_version', 'version', 'create_remote_signer', '_UniffiConverterTypeSigningAlg', '_UniffiRustBuffer']
__all__ = ['Reader', 'Builder', 'CallbackSigner', 'create_signer', 'sign_ps256', 'Error', 'SigningAlg', 'sdk_version', 'version', 'create_remote_signer', '_UniffiConverterTypeSigningAlg', '_UniffiRustBuffer', '_UniffiConverterTypeReader']
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ impl Reader {
Err(Error::RwLock)
}
}

pub fn get_raw_reader(&self) -> &RwLock<c2pa::Reader>{
&self.reader
}
}

pub struct Builder {
Expand Down
235 changes: 121 additions & 114 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import pytest
import tempfile
import shutil
import unittest

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

Expand Down Expand Up @@ -59,126 +60,132 @@ def getitem(d, key):
}
}

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

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

def test_sdk_version():
assert "c2pa-rs/" in sdk_version()

def test_v2_read():
#example of reading a manifest store from a file
try:
reader = Reader.from_file("tests/fixtures/C.jpg")
class TestReader(unittest.TestCase):
def test_v2_read_cloud_manifest(self):
reader = Reader.from_file("tests/fixtures/cloud.jpg")
manifest = reader.get_active_manifest()
assert manifest is not None
assert "make_test_images" in manifest["claim_generator"]
assert manifest["title"]== "C.jpg"
assert manifest["format"] == "image/jpeg"
# There should be no validation status errors
assert manifest.get("validation_status") == None
# read creative work assertion (author name)
assert getitem(manifest,("assertions",0,"label")) == "stds.schema-org.CreativeWork"
assert getitem(manifest,("assertions",0,"data","author",0,"name")) == "Adobe make_test"
# read Actions assertion
assert getitem(manifest,("assertions",1,"label")) == "c2pa.actions"
assert getitem(manifest,("assertions",1,"data","actions",0,"action")) == "c2pa.created"
# read signature info
assert getitem(manifest,("signature_info","issuer")) == "C2PA Test Signing Cert"
# read thumbnail data from file
assert getitem(manifest,("thumbnail","format")) == "image/jpeg"
# check the thumbnail data
uri = getitem(manifest,("thumbnail","identifier"))
reader.resource_to_file(uri, "target/thumbnail_read_v2.jpg")

except Exception as e:
print("Failed to read manifest store: " + str(e))
exit(1)

def test_reader_from_file_no_store():
with pytest.raises(Error.ManifestNotFound) as err:
reader = Reader.from_file("tests/fixtures/A.jpg")

def test_v2_sign():
# define a source folder for any assets we need to read
data_dir = "tests/fixtures/"
try:
key = open(data_dir + "ps256.pem", "rb").read()
def sign(data: bytes) -> bytes:
return sign_ps256(data, key)

certs = open(data_dir + "ps256.pub", "rb").read()
# Create a local signer from a certificate pem file
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")

builder = Builder(manifest_def)

builder.add_ingredient_file(ingredient_def, data_dir + "A.jpg")

builder.add_resource_file("A.jpg", data_dir + "A.jpg")

builder.to_archive(open("target/archive.zip", "wb"))

builder = Builder.from_archive(open("target/archive.zip", "rb"))

with tempfile.TemporaryDirectory() as output_dir:
output_path = output_dir + "out.jpg"
if os.path.exists(output_path):
os.remove(output_path)
c2pa_data = builder.sign_file(signer, data_dir + "A.jpg", output_dir + "out.jpg")
assert len(c2pa_data) > 0

reader = Reader.from_file(output_dir + "out.jpg")
print(reader.json())
manifest_store = json.loads(reader.json())
manifest = manifest_store["manifests"][manifest_store["active_manifest"]]
assert "python_test" in manifest["claim_generator"]
# check custom title and format
assert manifest["title"]== "My Title"
assert manifest,["format"] == "image/jpeg"
# There should be no validation status errors
assert manifest.get("validation_status") == None
assert manifest["ingredients"][0]["relationship"] == "parentOf"
assert manifest["ingredients"][0]["title"] == "A.jpg"
except Exception as e:
print("Failed to sign manifest store: " + str(e))
exit(1)

# Test signing the same source and destination file
def test_v2_sign_file_same():
data_dir = "tests/fixtures/"
try:
key = open(data_dir + "ps256.pem", "rb").read()
def sign(data: bytes) -> bytes:
return sign_ps256(data, key)

certs = open(data_dir + "ps256.pub", "rb").read()
# Create a local signer from a certificate pem file
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")

builder = Builder(manifest_def)

builder.add_resource_file("A.jpg", data_dir + "A.jpg")

with tempfile.TemporaryDirectory() as output_dir:
path = output_dir + "/A.jpg"
# Copy the file from data_dir to output_dir
shutil.copy(data_dir + "A.jpg", path)
c2pa_data = builder.sign_file(signer, path, path)
assert len(c2pa_data) > 0

reader = Reader.from_file(path)
manifest = reader.get_active_manifest()

def test_v2_read(self):
#example of reading a manifest store from a file
try:
reader = Reader.from_file("tests/fixtures/C.jpg")
manifest = reader.get_active_manifest()
assert manifest is not None
assert "make_test_images" in manifest["claim_generator"]
assert manifest["title"]== "C.jpg"
assert manifest["format"] == "image/jpeg"
# There should be no validation status errors
assert manifest.get("validation_status") == None
# read creative work assertion (author name)
assert getitem(manifest,("assertions",0,"label")) == "stds.schema-org.CreativeWork"
assert getitem(manifest,("assertions",0,"data","author",0,"name")) == "Adobe make_test"
# read Actions assertion
assert getitem(manifest,("assertions",1,"label")) == "c2pa.actions"
assert getitem(manifest,("assertions",1,"data","actions",0,"action")) == "c2pa.created"
# read signature info
assert getitem(manifest,("signature_info","issuer")) == "C2PA Test Signing Cert"
# read thumbnail data from file
assert getitem(manifest,("thumbnail","format")) == "image/jpeg"
# check the thumbnail data
uri = getitem(manifest,("thumbnail","identifier"))
reader.resource_to_file(uri, "target/thumbnail_read_v2.jpg")

except Exception as e:
print("Failed to read manifest store: " + str(e))
exit(1)

def test_reader_from_file_no_store(self):
with pytest.raises(Error.ManifestNotFound) as err:
reader = Reader.from_file("tests/fixtures/A.jpg")

class TestSignerr(unittest.TestCase):
def test_v2_sign(self):
# define a source folder for any assets we need to read
data_dir = "tests/fixtures/"
try:
key = open(data_dir + "ps256.pem", "rb").read()
def sign(data: bytes) -> bytes:
return sign_ps256(data, key)

certs = open(data_dir + "ps256.pub", "rb").read()
# Create a local signer from a certificate pem file
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")

builder = Builder(manifest_def)

builder.add_ingredient_file(ingredient_def, data_dir + "A.jpg")

builder.add_resource_file("A.jpg", data_dir + "A.jpg")

builder.to_archive(open("target/archive.zip", "wb"))

builder = Builder.from_archive(open("target/archive.zip", "rb"))

with tempfile.TemporaryDirectory() as output_dir:
output_path = output_dir + "out.jpg"
if os.path.exists(output_path):
os.remove(output_path)
c2pa_data = builder.sign_file(signer, data_dir + "A.jpg", output_dir + "out.jpg")
assert len(c2pa_data) > 0

reader = Reader.from_file(output_dir + "out.jpg")
print(reader.json())
manifest_store = json.loads(reader.json())
manifest = manifest_store["manifests"][manifest_store["active_manifest"]]
assert "python_test" in manifest["claim_generator"]
# check custom title and format
assert manifest["title"]== "My Title"
assert manifest["format"] == "image/jpeg"
assert manifest,["format"] == "image/jpeg"
# There should be no validation status errors
assert manifest.get("validation_status") == None
except Exception as e:
print("Failed to sign manifest store: " + str(e))
#exit(1)
assert manifest["ingredients"][0]["relationship"] == "parentOf"
assert manifest["ingredients"][0]["title"] == "A.jpg"
except Exception as e:
print("Failed to sign manifest store: " + str(e))
exit(1)

# Test signing the same source and destination file
def test_v2_sign_file_same(self):
data_dir = "tests/fixtures/"
try:
key = open(data_dir + "ps256.pem", "rb").read()
def sign(data: bytes) -> bytes:
return sign_ps256(data, key)

certs = open(data_dir + "ps256.pub", "rb").read()
# Create a local signer from a certificate pem file
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")

builder = Builder(manifest_def)

builder.add_resource_file("A.jpg", data_dir + "A.jpg")

with tempfile.TemporaryDirectory() as output_dir:
path = output_dir + "/A.jpg"
# Copy the file from data_dir to output_dir
shutil.copy(data_dir + "A.jpg", path)
c2pa_data = builder.sign_file(signer, path, path)
assert len(c2pa_data) > 0

reader = Reader.from_file(path)
manifest = reader.get_active_manifest()

# check custom title and format
assert manifest["title"]== "My Title"
assert manifest["format"] == "image/jpeg"
# There should be no validation status errors
assert manifest.get("validation_status") == None
except Exception as e:
print("Failed to sign manifest store: " + str(e))
#exit(1)

if __name__ == '__main__':
unittest.main()
3 changes: 1 addition & 2 deletions tests/test_unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@

class TestC2paSdk(unittest.TestCase):
def test_version(self):
self.assertIn("0.6.1", sdk_version())
self.assertIn("0.6.2", sdk_version())


class TestReader(unittest.TestCase):

def test_stream_read(self):
with open(testPath, "rb") as file:
reader = Reader("image/jpeg",file)
Expand Down