Core Python SDK for the Internet Computer: agent, candid, identity, principal, certificate.
Project description
๐ ICP-PY-CORE
๐ About This Project
ICP-PY-CORE is a maintained and extended fork of ic-py.
This version introduces a modular architecture, protocol upgrades, and new APIs while preserving compatibility with the IC ecosystem.
Highlights:
- โ
Modular structure under
src/(icp_agent,icp_identity,icp_candid, etc.) - โ
Updated boundary node endpoints (v3/v4:
/api/v3/canister/.../query,/api/v4/canister/.../call) - โ
Optional certificate verification via
blst - โ Type-safe Candid encoding/decoding
- โ
Pythonic high-level
Agent.update()andAgent.query()methods
๐ Special thanks to the original ic-py author for their foundational work.
๐ค Community & Contribution
- Contributing Guidelines - How to contribute to the project
- Code of Conduct - Community standards and expectations
- Security Policy - How to report security vulnerabilities
๐ง Installation
pip install icp-py-core
The Candid parser uses a Rust extension with pre-built binary wheels for all platforms.
No Rust compiler is required for installation.
For optional certificate verification, see the blst section below.
๐ Key Improvements
โณ๏ธ Modular Codebase
Each component is isolated for clarity and extensibility:
src/
โโโ icp_agent/ # Agent & HTTP Client
โโโ icp_identity/ # ed25519 / secp256k1 identities
โโโ icp_candid/ # Candid encoder/decoder
โโโ icp_principal/ # Principal utilities
โโโ icp_certificate/ # Certificate validation
โโโ icp_core/ # Unified facade (one-line import)
๐ Unified Facade (icp_core)
Import everything from a single entrypoint:
from icp_core import (
Agent, Client,
Identity, DelegateIdentity,
Principal, Certificate,
Canister, Ledger, Governance, Management, CyclesWallet,
encode, decode, Types,
)
โก Endpoint Upgrade
All endpoints now target the latest Boundary Node versions:
- Query:
/api/v3/canister/<canister_id>/query - Call:
/api/v4/canister/<canister_id>/call - Read State:
/api/v3/canister/<canister_id>/read_state - Read Subnet State:
/api/v3/subnet/<subnet_id>/read_state
๐ Certificate Verification
Certificate verification is enabled by default for security. Verifies responses via BLS12-381 signatures with blst:
With Agent directly:
# Default: verification enabled
agent.update("canister-id", "method_name", [{'type': Types.Nat, 'value': 2}])
# To disable (for compatibility/testing):
agent.update("canister-id", "method_name", [{'type': Types.Nat, 'value': 2}], verify_certificate=False)
With Canister wrapper:
# Default: verification enabled (matches Agent.update() behavior)
canister.set_value(42)
# Explicitly enable (same as default)
canister.set_value(42, verify_certificate=True)
# Disable verification (when blst is not installed)
canister.set_value(42, verify_certificate=False)
Note: Both
Agent.update()andCanistermethods default toverify_certificate=Truefor security. Ifblstis not installed, you must explicitly passverify_certificate=Falseto avoid errors.
๐งฉ Example Usage
Identity
from icp_core import Identity
iden = Identity(privkey="833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42")
print(iden.sender().to_str())
Client & Agent
from icp_core import Agent, Client, Identity
iden = Identity()
client = Client("https://ic0.app")
agent = Agent(iden, client)
Update (auto-encode)
from icp_core import Types
result = agent.update(
"wcrzb-2qaaa-aaaap-qhpgq-cai",
"set",
[{'type': Types.Nat, 'value': 2}],
return_type=[Types.Nat],
)
Query (auto-encode empty args)
reply = agent.query("wcrzb-2qaaa-aaaap-qhpgq-cai", "get", [])
print(reply)
Canister Wrapper (Type-Safe Method Calls)
The Canister class provides a high-level, type-safe interface for interacting with canisters. It automatically parses Candid DID files and creates Python methods that match your canister's interface.
Creating a Canister instance:
from icp_core import Agent, Client, Identity, Canister
# Setup agent
client = Client("https://ic0.app")
identity = Identity()
agent = Agent(identity, client)
# Define Candid interface
COUNTER_DID = """
service : {
get : () -> (nat) query;
set : (nat) -> (nat)
}
"""
# Create Canister wrapper
counter = Canister(agent, "wcrzb-2qaaa-aaaap-qhpgq-cai", COUNTER_DID)
Calling canister methods:
# Query call (no arguments)
value = counter.get()
print(f"Current value: {value[0]['value']}")
# Update call (with positional argument)
result = counter.set(42)
print(f"Set to: {result[0]['value']}")
# Update call with keyword arguments (for record types)
# If your method takes a single record parameter, you can use kwargs:
# result = counter.update_profile(name="Alice", age=30)
Certificate Verification with Canister:
By default, Canister methods enable certificate verification (verify_certificate=True) to match Agent.update() behavior for security. You can control this per method call:
# Default: certificate verification enabled (requires blst)
result = counter.set(42) # Uses verify_certificate=True by default
# Explicitly enable verification (same as default)
result = counter.set(42, verify_certificate=True)
# Disable verification (useful when blst is not installed)
result = counter.set(42, verify_certificate=False)
Important Notes:
verify_certificateis a control parameter, not a method argument. It's extracted from kwargs before processing method arguments.- Default value is
Trueto matchAgent.update()default behavior for security. - If
blstis not installed and you don't passverify_certificate=False, update calls will fail. - For query calls, certificate verification is not applicable (queries don't return certificates).
Example: Complete Canister Usage
from icp_core import Agent, Client, Identity, Canister
# Setup
client = Client("https://ic0.app")
identity = Identity(anonymous=True)
agent = Agent(identity, client)
# Define interface
DID = """
service : {
get : () -> (nat) query;
set : (nat) -> (nat);
increment : () -> (nat)
}
"""
# Create canister wrapper
counter = Canister(agent, "wcrzb-2qaaa-aaaap-qhpgq-cai", DID)
# Query (no verification needed)
current = counter.get()
print(f"Current: {current[0]['value']}")
# Update with verification enabled (default, requires blst)
try:
result = counter.set(100)
print(f"Set to: {result[0]['value']}")
except Exception as e:
if "blst" in str(e).lower():
# Fallback: disable verification if blst not available
result = counter.set(100, verify_certificate=False)
print(f"Set to: {result[0]['value']} (verification disabled)")
else:
raise
# Update with verification explicitly disabled
result = counter.increment(verify_certificate=False)
print(f"Incremented: {result[0]['value']}")
โ ๏ธ Error Handling
ICP-PY-CORE provides a structured error hierarchy for better error handling and debugging. All errors inherit from ICError and are categorized by type.
Error Classes
from icp_core import (
ICError, # Base class for all errors
TransportError, # HTTP/network errors
SecurityError, # Base class for security errors
SignatureVerificationFailed,
CertificateVerificationError,
ReplicaReject, # Canister rejection
PayloadEncodingError,
IngressExpiryError,
)
Common Error Scenarios
Transport Errors (Network Issues):
from icp_core import Client, TransportError
client = Client()
try:
data = client.query("canister-id", b"data")
except TransportError as e:
print(f"Failed to connect to {e.url}")
print(f"Error: {e.original_error}")
Replica Rejections (Canister Errors):
from icp_core import Agent, Client, Identity, ReplicaReject
agent = Agent(identity, client)
try:
result = agent.update("canister-id", "method", args)
except ReplicaReject as e:
print(f"Rejected with code {e.reject_code}")
print(f"Message: {e.reject_message}")
if e.error_code:
print(f"Error code: {e.error_code}")
Security Errors (Certificate Verification):
from icp_core import (
CertificateVerificationError,
SignatureVerificationFailed,
)
try:
certificate.assert_certificate_valid(canister_id)
except CertificateVerificationError as e:
print(f"Certificate verification failed: {e.reason}")
except SignatureVerificationFailed:
print("BLS signature verification failed")
Error Hierarchy
ICError (base class)
โโโ TransportError (HTTP/network errors)
โโโ SecurityError (security errors)
โ โโโ SignatureVerificationFailed
โ โโโ CertificateVerificationError
โ โโโ LookupPathMissing
โ โโโ NodeKeyNotFoundError
โ โโโ ReplicaSignatureVerificationFailed
โโโ ReplicaReject (canister rejections)
โโโ PayloadEncodingError (CBOR encoding errors)
โโโ IngressExpiryError (expiry validation errors)
Best Practices
-
Catch specific errors for better error handling:
try: result = agent.update("canister-id", "method", args) except ReplicaReject as e: # Handle canister rejection handle_rejection(e) except TransportError as e: # Handle network issues handle_network_error(e) except SecurityError as e: # Handle security issues handle_security_error(e)
-
Check error attributes for detailed information:
except ReplicaReject as e: if e.reject_code == 3: # Canister trapped retry_with_different_args() elif e.reject_code == 4: # Canister did not reply check_canister_status()
-
Preserve error context when re-raising:
try: result = agent.update("canister-id", "method", args) except TransportError as e: logger.error(f"Network error: {e.url}", exc_info=True) raise # Re-raise to preserve stack trace
๐ Installing blst (optional)
blst is required for certificate verification (enabled by default). If blst is not installed, you can disable verification with verify_certificate=False.
Prerequisites
macOS:
# Install Xcode Command Line Tools
xcode-select --install
# Install SWIG (required for Python bindings)
brew install swig
Linux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install build-essential swig python3-dev
Linux (Fedora/RHEL):
sudo dnf install gcc gcc-c++ make swig python3-devel
macOS / Linux Installation
Method 1: Build and add to PYTHONPATH (recommended for development)
git clone https://github.com/supranational/blst
cd blst/bindings/python
# For Apple Silicon (M1/M2/M3) if you encounter ABI issues:
# export BLST_PORTABLE=1
python3 run.me
# Temporary (current session only):
export PYTHONPATH="$PWD:$PYTHONPATH"
# Permanent (add to ~/.bashrc or ~/.zshrc):
echo 'export PYTHONPATH="/path/to/blst/bindings/python:$PYTHONPATH"' >> ~/.bashrc
source ~/.bashrc
Method 2: Install to site-packages (recommended for production)
git clone https://github.com/supranational/blst
cd blst/bindings/python
# For Apple Silicon (M1/M2/M3) if needed:
# export BLST_PORTABLE=1
python3 run.me
# Copy to site-packages
BLST_SRC="$PWD"
PYBIN="python3"
SITE_PURE="$($PYBIN -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"
SITE_PLAT="$($PYBIN -c 'import sysconfig; print(sysconfig.get_paths()["platlib"])')"
cp "$BLST_SRC/blst.py" "$SITE_PURE"/
cp "$BLST_SRC"/_blst*.so "$SITE_PLAT"/
Method 3: Install in virtual environment
# Activate your virtual environment first
source venv/bin/activate # or: source .venv/bin/activate
git clone https://github.com/supranational/blst
cd blst/bindings/python
# For Apple Silicon if needed:
# export BLST_PORTABLE=1
python3 run.me
# Copy to virtual environment's site-packages
BLST_SRC="$PWD"
SITE_PURE="$(python3 -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"
SITE_PLAT="$(python3 -c 'import sysconfig; print(sysconfig.get_paths()["platlib"])')"
cp "$BLST_SRC/blst.py" "$SITE_PURE"/
cp "$BLST_SRC"/_blst*.so "$SITE_PLAT"/
Windows Installation
Option 1: WSL2 (Ubuntu) - Recommended
- Install WSL2 and Ubuntu from Microsoft Store
- Follow the Linux installation instructions above in WSL2
Option 2: Native Windows (Advanced)
- Install Visual Studio Build Tools with C++ support
- Install SWIG for Windows from swig.org
- Install Python 3.8+ with development headers
- Follow the Linux build steps in PowerShell or Command Prompt
- Note: Windows support is experimental; WSL2 is recommended
Verify Installation
Test if blst is correctly installed:
try:
import blst
assert all(hasattr(blst, n) for n in ("P1_Affine", "P2_Affine", "Pairing", "BLST_SUCCESS"))
print("โ blst is installed and working correctly")
except (ModuleNotFoundError, AssertionError):
print("โ blst is not available or incomplete")
Or test with icp-py-core:
from icp_certificate.certificate import ensure_blst_available
try:
ensure_blst_available()
print("โ blst is available for certificate verification")
except RuntimeError as e:
print(f"โ {e}")
Troubleshooting
Issue: "No module named 'blst'"
- Ensure
blst.pyand_blst*.soare in your Python path - Check
python3 -c "import sys; print(sys.path)"to see search paths - If using virtual environment, ensure it's activated
Issue: "ABI mismatch" on Apple Silicon
- Set
export BLST_PORTABLE=1before runningpython3 run.me - This builds a portable version compatible with all architectures
Issue: "SWIG not found"
- Install SWIG:
brew install swig(macOS) orsudo apt-get install swig(Linux) - Ensure SWIG is in your PATH:
which swig
Issue: Import succeeds but API is incomplete
- Ensure you're using the official
supranational/blstrepository - Rebuild:
cd blst/bindings/python && python3 run.me - Check that all required symbols exist:
P1_Affine,P2_Affine,Pairing,BLST_SUCCESS
๐ง Features
- ๐งฉ Candid encode & decode
- ๐ ed25519 & secp256k1 identities
- ๐งพ Principal utilities (strict DER mode)
- โ๏ธ High-level canister calls via Agent
- ๐ช Support for Ledger / Governance / Management / Cycles Wallet
- ๐ Sync & async APIs
๐งฐ Example โ End-to-End
from icp_core import Agent, Client, Identity, Types
client = Client("https://ic0.app")
iden = Identity()
agent = Agent(iden, client)
# Update (auto-encode [42], certificate verification enabled by default)
agent.update("wcrzb-2qaaa-aaaap-qhpgq-cai", "set_value", [42])
# Query (auto-encode empty args)
res = agent.query("wcrzb-2qaaa-aaaap-qhpgq-cai", "get_value", None, return_type=[Types.Nat])
print(res)
๐ Migration
Migrating from ic-py? See MIGRATION.md for:
- New package layout (
icp_*subpackages and theicp_corefacade) - Endpoint changes (v3 call)
- Argument auto-encoding in
Agent.update()/Agent.query() - Certificate verification flag
๐ Changelog
We maintain release notes on GitHub Releases:
https://github.com/eliezhao/icp-py-core/releases
๐บ Roadmap
See ROADMAP.md
โ
Milestone 1: v3 endpoint migration & polling stability
โ
Milestone 2: Certificate verification with blst
๐ Milestone 3: ICRC utilities, Candid enhancements, type reflection
๐ Version
- Current release: v2.2.0
๐ Acknowledgments
Special thanks to the IC community and contributors to the original ic-py.
icp-py-core continues this legacy with modern Python standards and long-term maintenance.
๐ Additional Resources
- CONTRIBUTING.md - Guidelines for contributing to the project
- CODE_OF_CONDUCT.md - Community code of conduct
- SECURITY.md - Security policy and vulnerability reporting
- MIGRATION.md - Migration guide from ic-py
- CHANGELOG.md - Release notes and changelog
- ROADMAP.md - Project roadmap and future plans
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file icp_py_core-2.2.1.tar.gz.
File metadata
- Download URL: icp_py_core-2.2.1.tar.gz
- Upload date:
- Size: 74.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b56b53dc2073eaa2ce4d8ddda2ca3ada4c9c2f84330ec6e7cbe28032618cd800
|
|
| MD5 |
171fa719c574101cc80e075039f8fbcb
|
|
| BLAKE2b-256 |
f13aaf5726710adf0eb7e249a695170baca21a3be8a6b50aa4c73b3f0342f57e
|
Provenance
The following attestation bundles were made for icp_py_core-2.2.1.tar.gz:
Publisher:
release.yml on eliezhao/icp-py-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icp_py_core-2.2.1.tar.gz -
Subject digest:
b56b53dc2073eaa2ce4d8ddda2ca3ada4c9c2f84330ec6e7cbe28032618cd800 - Sigstore transparency entry: 844788887
- Sigstore integration time:
-
Permalink:
eliezhao/icp-py-core@eeeb0c1d3320eef1c91e62f3b4b20cee4048db59 -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/eliezhao
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@eeeb0c1d3320eef1c91e62f3b4b20cee4048db59 -
Trigger Event:
push
-
Statement type:
File details
Details for the file icp_py_core-2.2.1-py3-none-any.whl.
File metadata
- Download URL: icp_py_core-2.2.1-py3-none-any.whl
- Upload date:
- Size: 69.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fdee5fda3da55a806f30f398236c27b9583e2b06fa4b16e2488ad1d3a2b355b
|
|
| MD5 |
f6b3eb5316c453d23c382bfc2cb125c8
|
|
| BLAKE2b-256 |
3b0ff3732b729933c9214715979818c8e60ad99e5d8a9a4a853f46806e921f09
|
Provenance
The following attestation bundles were made for icp_py_core-2.2.1-py3-none-any.whl:
Publisher:
release.yml on eliezhao/icp-py-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icp_py_core-2.2.1-py3-none-any.whl -
Subject digest:
5fdee5fda3da55a806f30f398236c27b9583e2b06fa4b16e2488ad1d3a2b355b - Sigstore transparency entry: 844788890
- Sigstore integration time:
-
Permalink:
eliezhao/icp-py-core@eeeb0c1d3320eef1c91e62f3b4b20cee4048db59 -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/eliezhao
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@eeeb0c1d3320eef1c91e62f3b4b20cee4048db59 -
Trigger Event:
push
-
Statement type: