Skip to content
Open
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
100 changes: 65 additions & 35 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,110 +3,140 @@
# Version of C2PA to use
C2PA_VERSION := $(shell cat c2pa-native-version.txt)

# Python interpreter. Honors an active virtualenv ($VIRTUAL_ENV), then a local
# ./.venv, then falls back to python3 on PATH. Override with: make <target> PYTHON=...
ifndef PYTHON
ifdef VIRTUAL_ENV
PYTHON := $(VIRTUAL_ENV)/bin/python
else ifneq ($(wildcard .venv/bin/python),)
PYTHON := .venv/bin/python
$(warning .venv exists but is not activated; using ./.venv/bin/python. Run 'source .venv/bin/activate' or override with PYTHON=...)
else
PYTHON := python3
endif
endif

# Start from clean env: Delete `.venv`, then `python3 -m venv .venv`
# Pre-requisite: Python virtual environment is active (source .venv/bin/activate)
# Run Pytest tests in virtualenv: .venv/bin/pytest tests/test_unit_tests.py -v

# Creates the local virtualenv at the canonical ./.venv path if it does not exist.
# Activation must happen in shell independently:
# make create-venv && source .venv/bin/activate
create-venv:
test -d .venv || python3 -m venv .venv
@echo "Virtualenv ready at ./.venv -- activate with: source .venv/bin/activate"

# Removes build artifacts, distribution files, and other generated content
clean:
rm -rf artifacts/ build/ dist/

# Performs a complete cleanup including uninstalling the c2pa package and clearing pip cache
clean-c2pa-env: clean
python3 -m pip uninstall -y c2pa
python3 -m pip cache purge
$(PYTHON) -m pip uninstall -y c2pa
$(PYTHON) -m pip cache purge

# Installs all required dependencies from requirements.txt and requirements-dev.txt
install-deps:
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements-dev.txt
$(PYTHON) -m pip install -r requirements.txt
$(PYTHON) -m pip install -r requirements-dev.txt

# Installs the package in development mode
build-python:
python3 -m pip install -e .
$(PYTHON) -m pip install -e .

# Performs a complete rebuild of the development environment
rebuild: clean-c2pa-env install-deps download-native-artifacts build-python
@echo "Development rebuild done"

run-examples:
python3 ./examples/sign.py
python3 ./examples/sign_info.py
python3 ./examples/no_thumbnails.py
python3 ./examples/training.py
$(PYTHON) ./examples/sign.py
$(PYTHON) ./examples/sign_info.py
$(PYTHON) ./examples/no_thumbnails.py
$(PYTHON) ./examples/training.py
rm -rf output/

# Runs the examples, then the unit tests
test:
make run-examples
python3 ./tests/test_unit_tests.py
python3 ./tests/test_unit_tests_threaded.py
$(PYTHON) ./tests/test_unit_tests.py
$(PYTHON) ./tests/test_unit_tests_threaded.py

# Runs benchmarks in the venv
benchmark:
python3 -m pytest tests/benchmark.py -v
$(PYTHON) -m pytest tests/benchmark.py -v

# Tests building and installing a local wheel package
# Downloads required artifacts, builds the wheel, installs it, and verifies the installation
test-local-wheel-build:
# Clean any existing builds
rm -rf build/ dist/
# Download artifacts and place them where they should go
python3 scripts/download_artifacts.py $(C2PA_VERSION)
$(PYTHON) scripts/download_artifacts.py $(C2PA_VERSION)
# Install Python
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements-dev.txt
python3 -m build --wheel
$(PYTHON) -m pip install -r requirements.txt
$(PYTHON) -m pip install -r requirements-dev.txt
$(PYTHON) -m build --wheel
# Install local build in venv
pip install $$(ls dist/*.whl)
$(PYTHON) -m pip install $$(ls dist/*.whl)
# Verify installation in local venv
python3 -c "import c2pa; print('C2PA package installed at:', c2pa.__file__)"
$(PYTHON) -c "import c2pa; print('C2PA package installed at:', c2pa.__file__)"
# Verify wheel structure
twine check dist/*
$(PYTHON) -m twine check dist/*

# Tests building and installing a local source distribution package
# Downloads required artifacts, builds the sdist, installs it, and verifies the installation
test-local-sdist-build:
# Clean any existing builds
rm -rf build/ dist/
# Download artifacts and place them where they should go
python3 scripts/download_artifacts.py $(C2PA_VERSION)
$(PYTHON) scripts/download_artifacts.py $(C2PA_VERSION)
# Install Python
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements-dev.txt
$(PYTHON) -m pip install -r requirements.txt
$(PYTHON) -m pip install -r requirements-dev.txt
# Build sdist package
python3 setup.py sdist
$(PYTHON) setup.py sdist
# Install local build in venv
pip install $$(ls dist/*.tar.gz)
$(PYTHON) -m pip install $$(ls dist/*.tar.gz)
# Verify installation in local venv
python3 -c "import c2pa; print('C2PA package installed at:', c2pa.__file__)"
$(PYTHON) -c "import c2pa; print('C2PA package installed at:', c2pa.__file__)"
# Verify sdist structure
twine check dist/*
$(PYTHON) -m twine check dist/*

# Verifies the wheel build process and checks the built package and its metadata
verify-wheel-build:
rm -rf build/ dist/ src/*.egg-info/
python3 -m build
twine check dist/*
$(PYTHON) -m build
$(PYTHON) -m twine check dist/*

# Manually publishes the package to PyPI after creating a release
publish: release
python3 -m pip install twine
python3 -m twine upload dist/*
$(PYTHON) -m pip install twine
$(PYTHON) -m twine upload dist/*

# Code analysis
check-format:
python3 -m py_compile src/c2pa/c2pa.py
flake8 src/c2pa/c2pa.py
$(PYTHON) -m py_compile src/c2pa/c2pa.py
$(PYTHON) -m flake8 --extend-ignore=E501 src/c2pa/c2pa.py

# Formats Python source code using autopep8 with aggressive settings
format:
autopep8 --aggressive --aggressive --in-place src/c2pa/c2pa.py
$(PYTHON) -m autopep8 --aggressive --aggressive --in-place src/c2pa/c2pa.py

# Downloads the required native artifacts for the specified version
download-native-artifacts:
python3 scripts/download_artifacts.py $(C2PA_VERSION)
$(PYTHON) scripts/download_artifacts.py $(C2PA_VERSION)

# Builds the native library from local c2pa-rs checkout and install it.
# Requires C2PA_RS_PATH to point at the c2pa-rs sources and a working Rust toolchain.
# Replaces the prebuilt artifacts from download-native-artifacts.
# --clean forces a full `cargo clean`, drop it for faster incremental rebuilds.
# Pass EXTRA_BUILD_ARGS="--debug" to build the debug profile (release is the default).
# Usage: make build-from-source C2PA_RS_PATH=/path/to/c2pa-rs
build-from-source:
$(PYTHON) scripts/build_local_artifacts.py --clean $(EXTRA_BUILD_ARGS)
$(PYTHON) -m pip install -e .

# Build API documentation with Sphinx
docs:
python3 scripts/generate_api_docs.py
$(PYTHON) scripts/generate_api_docs.py
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,48 @@ To use the module in Python code, import the module like this:
import c2pa
```

## Building from local c2pa-rs sources

### Using a virtual environment with local builds

The `make` targets honor an active virtualenv. Create a virtual environment `./.venv` and activate it before running them so commands use the project interpreter rather than the global Python interpreter:

```sh
make create-venv && source .venv/bin/activate
```

### Build steps

By default the build downloads a prebuilt native library from a [c2pa-rs](https://github.com/contentauth/c2pa-rs) release. To test the Python bindings against a local, unreleased c2pa-rs checkout, you can instead build the native library from source.

Prerequisites:

- A local clone of [c2pa-rs](https://github.com/contentauth/c2pa-rs).
- The [Rust toolchain](https://rust-lang.org/tools/install/) (`cargo` on your `PATH`).

Point `C2PA_RS_PATH` at your c2pa-rs checkout and run the `build-from-source` target:

```sh
export C2PA_RS_PATH=/path/to/c2pa-rs
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH
```

This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`. The release profile is used by default; to build the debug profile instead, pass `EXTRA_BUILD_ARGS="--debug"`:

```sh
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH EXTRA_BUILD_ARGS="--debug"
```

### Note on targets for macOS

On macOS this produces a universal (arm64+x86_64) library by default, which requires both Rust targets:

```sh
rustup target add aarch64-apple-darwin x86_64-apple-darwin
```

To build a single-architecture library instead, set `C2PA_LIBS_PLATFORM` to a specific platform (for example `aarch64-apple-darwin`).

## Examples

See the [`examples` directory](https://github.com/contentauth/c2pa-python/tree/main/examples) for some helpful examples:
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ pytest-benchmark>=5.1.0
requests>=2.0.0

# Code formatting
autopep8==2.0.4 # For automatic code formatting
autopep8>=2.3.0
flake8==7.3.0

# Test dependencies (for callback signers)
cryptography==47.0.0
cryptography>=47.0.0

# Documentation
Sphinx>=7.3.0
sphinx-autoapi>=3.0.0
Expand Down
Loading
Loading