Ic-py Development and Ongoing Maintenance

@C-B-Elite ,
Would you be able to push out a v2.2.0 with the already merged updates?

I have many projects that still use ic-py, and I would be able to upgrade them after that.

Hi, I just got back from vacation.

I’m back to work now, and I’m planning to release a new version this week (likely Friday–Saturday), which will include your PR.

By the way, over the next month, I’m also expecting a larger upgrade. The main focus will be updating the current endpoints (v2 is already outdated), which may introduce some underlying code changes. It will also include a few security-related features that were not previously supported.

Thanks for your attention and support!

Does canister http-outcall in pocket-ic support?

At the moment, icp-py-core doesn’t have support for pocket-ic (and there’s no short-term plan to implement it). As far as I remember, pocket-ic is able to simulate \canister HTTP outcalls.

:snake: icp-py-core v2.1.1 Released - Fixed Candid DID Parser Issue

We’re excited to announce the release of icp-py-core v2.1.1, which fixes an important bug in the Candid DID parser that affected Motoko-generated DID files.

:bug: What Was Fixed

The Candid DID parser now correctly handles service definitions that use type references, a pattern commonly generated by Motoko canisters.

Previously broken pattern (now fixed):


type MyService = service {

hello: () -> (text);

};

service : () -> MyService

This pattern is valid Candid syntax and is frequently used in Motoko-generated DID files, but the parser was failing to parse it correctly.

:sparkles: Improvements

  • :white_check_mark: Support for service : () -> TypeName pattern

  • :white_check_mark: Support for nested type references

  • :white_check_mark: Support for type references with initialization arguments

  • :white_check_mark: Comprehensive test coverage added

:package: Installation


pip install --upgrade icp-py-core

:link: Links

:folded_hands: Acknowledgments

Thanks to @icppWorld for reporting this issue and providing detailed analysis.

:tada: ICP-PY-CORE v2.2.1 Released!

I’m excited to announce the release of ICP-PY-CORE v2.2.1, a significant update that brings structured error handling, HTTP/2 support, and enhanced certificate verification capabilities to the Python SDK for the Internet Computer.

:package: Installation

pip install icp-py-core==2.2.1

PyPI: icp-py-core · PyPI
GitHub: GitHub - eliezhao/icp-py-core: Python Agent Library for the DFINITY Internet Computer


:sparkles: What’s New

:bullseye: Structured Error Handling Hierarchy

v2.2.1 introduces a comprehensive error handling system with 11 specialized error classes, making it easier to handle different types of failures:

from icp_core import (
    TransportError,           # HTTP/network errors
    ReplicaReject,           # Canister rejections
    SecurityError,           # Base for security errors
    SignatureVerificationFailed,
    CertificateVerificationError,
    # ... and more
)

try:
    result = agent.update("canister-id", "method", args)
except ReplicaReject as e:
    print(f"Rejected: {e.reject_code} - {e.reject_message}")
except TransportError as e:
    print(f"Network error: {e.url}")
except SecurityError as e:
    print(f"Security issue: {e}")

Benefits:

  • Better error categorization and handling
  • Improved debugging with error chaining
  • Sanitized error messages for production use
  • Full documentation with examples in README

:high_voltage: HTTP/2 Support

HTTP/2 is now enabled by default in all async methods, providing:

  • Multiplexing: Multiple requests over a single connection
  • Header compression: Reduced bandwidth usage
  • Automatic fallback: Gracefully falls back to HTTP/1.1 if not supported
  • Better performance: Reduced latency for concurrent requests

No code changes required - it’s automatically enabled!

:globe_with_meridians: Latest Boundary Node Endpoints

v2.2.1 now uses the latest Boundary Node API endpoints for optimal performance and compatibility:

  • Read State Operations: Updated to use v3 endpoints (/api/v3/canister/.../read_state and /api/v3/subnet/.../read_state)
  • Call Operations: Full support for v4 call endpoint (/api/v4/canister/.../call) with proper delegation verification
  • Delegation Verification: Enhanced delegation verification logic that works seamlessly with v4 API endpoints
  • Backward Compatibility: All endpoint updates maintain full backward compatibility with existing code

These updates ensure you’re using the most current and efficient endpoints available on the Internet Computer.

:locked_with_key: V4 API Sharded Canister Ranges Support

Added support for the v4 API’s sharded canister_ranges structure:

  • Updated certificate verification to handle sharded paths: [canister_ranges, subnet_id, shard_label]
  • Improved lookup_tree and list_paths methods for shard navigation
  • Updated test certificates to use v4 API format

:locked: Enhanced Certificate Verification

  • Improved certificate delegation path handling
  • Better error messages for verification failures
  • Enhanced subnet-level read_state operations
  • Node key caching for performance optimization
  • Proper delegation verification for v4 call endpoints

:hammer_and_wrench: Improvements & Fixes

Error Handling

  • All Client methods now raise TransportError for network issues
  • All Agent methods raise structured errors (ReplicaReject, SecurityError, etc.)
  • Better error chaining with __cause__ attribute preservation
  • Improved error messages with sanitized stack traces

API Updates

  • Read State: Now uses latest v3 endpoints (/api/v3/canister/.../read_state and /api/v3/subnet/.../read_state)
  • Call Operations: Full support for v4 call endpoint (/api/v4/canister/.../call)
  • Delegation Verification: Restored and enhanced check_delegation logic for proper delegation verification with v4 endpoints
  • Maintained full backward compatibility with existing code

Code Quality

  • Fixed circular import issues using lazy loading pattern
  • Enhanced type annotations throughout codebase
  • Better code organization and maintainability

:clipboard: Migration Guide

Error Handling

If you’re currently catching generic Exception, consider catching specific error types:

# Before
try:
    result = agent.update("canister-id", "method", args)
except Exception as e:
    # Generic handling
    pass

# After (recommended)
try:
    result = agent.update("canister-id", "method", args)
except ReplicaReject as e:
    # Handle canister rejections
    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)

Imports

Error classes are now available from icp_core:

from icp_core import TransportError, ReplicaReject, SecurityError

HTTP/2

No code changes required - HTTP/2 is automatically enabled for async methods.

Endpoint Updates

The endpoint updates are transparent - no code changes required. The library automatically uses:

  • v3 endpoints for read state operations
  • v4 endpoints for call operations with proper delegation verification

:link: Resources


Happy coding with ICP-PY-CORE! :snake:

The Rust extension ic-candid-parser is still at v0.1.0 on PyPI, which predates the fix for the pattern.

Would you be able to push out a new release for that ic-candid-parser package as well?

I issued a bug report too at Bug: VarT service reference fix not published to PyPI · Issue #10 · eliezhao/icp-py-core · GitHub

Thank you!

I’ll check it and update it soon.

I’ve released version v2.2.1, which fixes this issue. Thank you for the feedback — my local environment was affected by the development setup, so I didn’t notice this problem earlier.
@icpp

Everything now works. Thanks for the quick action.

Upcoming Release

I am pleased to preview the next release of icp-py-core. This update adds configurable timeouts, optional replica-signed query verification, automatic Candid (.did) fetching from canisters, and async-friendly Canister methods.

Release timeline: I expect this update to be released in 1–2 weeks. During this period I will collect feedback and issues for version 2.2.1; any fixes will be included in the next release.

Development of the above features is complete. Further testing is in progress on the feature/verify-replica-query-signature-and-canister-timeout branch.


New Features

1. Query and canister call timeouts

  • Query timeout

    • Default timeout for query calls: 30 seconds (DEFAULT_QUERY_TIMEOUT_SEC).
    • You can override it per call via the timeout argument on Agent.query(), Agent.query_async(), and the underlying query endpoint helpers.
    • On timeout, the library raises a unified TimeoutWaitingForResponse exception (with timeout_seconds and optional request_id), so you can handle timeouts consistently.
  • Update (canister call) timeout

    • Polling for update results uses a default of 60 seconds (DEFAULT_POLL_TIMEOUT_SECS).
    • Same timeout parameter and TimeoutWaitingForResponse behavior for Agent.update() and Agent.update_async().

All timeouts are configurable; when not set, the defaults above apply.


2. Verify query response signatures (opt-in)

  • Replica-signed query verification
    When the boundary node returns replica-signed query responses (with signatures), you can optionally verify them before trusting the result.

  • How to use

    • Set verify_query_signatures=True when creating the Agent, or pass it per call to Agent.query() / Agent.query_async().
    • Default is False.
  • What is verified

    • Signable payload is built according to the IC spec (\x0Bic-response + request ID and response fields).
    • Ed25519 signatures are verified using the subnet’s node public keys (fetched on demand and cached).
    • Clear errors: QuerySignatureVerificationFailed, MissingSignature, TooManySignatures, plus existing certificate/node-key errors for easier debugging.

3. Automatically fetch the .did file from the canister

  • Auto-fetch Candid (DID)
    You no longer need to manually provide a .did file for every canister.
    The Canister class can fetch the Candid interface from the Internet Computer when you don’t pass a local definition.

  • How it works

    • Canister(agent, canister_id, candid_str=None, auto_fetch_candid=True)
      • If candid_str is provided, it is used as today.
      • If candid_str is not provided and auto_fetch_candid=True (default), the client:
        • Tries public canister metadata: candid:service (no controller rights required).
        • If that fails, tries private metadata: candid (requires controller or appropriate permissions).
    • If both fail, a clear ValueError is raised, asking you to ensure the canister exposes Candid metadata or to pass candid_str (or set auto_fetch_candid=False and provide candid_str later).
  • Backward compatibility

    • Passing candid_str or setting auto_fetch_candid=False keeps the previous behavior (no fetch, manual DID only).

4. Canister async method support

  • Async variants for every canister method
    For each method defined in the canister’s Candid interface, the library now exposes an async variant: <method_name>_async (e.g. get_async, set_async).

  • Usage

    • Use await canister.get_async() (or your method name) instead of calling the sync version inside an async context.
    • Same type safety and encoding/decoding as the sync methods; only the call pattern is async.
  • Example

    • examples/simple_counter_example_async.py demonstrates async query and update with the Canister wrapper (e.g. get_async, set_async) and aligns with async usage common in other IC agent libraries.

I hope these changes make icp-py-core more robust, secure, and convenient for both sync and async workflows. Feedback and issues are welcome on the repository.

Looking forward to these updates. Especially the auto-pull of did files and the ability to set the timeout are really nice and important :+1:

Hi @C-B-Elite ,

I managed to replace yet another dfx subprocess with an icp-py-core call using the canister interface, but it included a long duration call and the resulting timeout exposed a few bugs.

They’re fixed in this PR: Fix/read state and v4 polling by icppWorld · Pull Request #13 · eliezhao/icp-py-core · GitHub

Let me know how that looks. With these changes, my long duration call is working great.

Thank you for your feedback. Since we updated the endpoint, some issues may have surfaced that were outside my expectations.

It looks like the next release will need to be brought forward. I’m planning to publish a new version this weekend that includes a fix for this bug along with the new features.

icp-py-core v2.3.0 Released

I have released icp-py-core v2.3.0 with new features and bug fixes. Upgrade with:


pip install --upgrade icp-py-core


New features

Configurable timeouts

Query and update calls now have configurable timeouts (defaults: 30s for queries, 60s for update polling). On timeout the library raises TimeoutWaitingForResponse.


# Override per call

result = agent.query(canister_id, "method", arg, timeout=10)

result = await agent.query_async(canister_id, "method", arg, timeout=10)

agent.update(canister_id, "method", arg, timeout=90)

Optional query response signature verification

You can verify replica-signed query responses (opt-in, default off). Uses Ed25519 and subnet node public keys (fetched and cached as needed).


agent = Agent(url, verify_query_signatures=True)

# or per call:

agent.query(canister_id, "method", arg, verify_query_signatures=True)

Auto-fetch Candid from canister

The Canister wrapper can fetch the service’s Candid interface from the IC when you don’t provide it (tries public candid:service, then private candid metadata).


canister = Canister(agent, canister_id) # no candid_str needed

canister.some_method(args)

Canister async methods

For each canister method, an async variant is available (e.g. get_async, set_async) with the same types and encoding as the sync methods.


result = await canister.get_async()

await canister.set_async(value)

Candid composite query support

Candid support for composite query is included.

Canister timeout passthrough

Canister high-level methods now pass the timeout argument through to the underlying query/update calls.


Bug fix

  • Read state and v4 polling – Fixed read-state handling and v4 call polling (see PR #13).

Links

Since taking over the maintenance of the Python agent, I have completed all originally planned milestones along with every additional feature introduced afterward.

icp-py-core now delivers a comprehensive set of core functionalities and has resolved all previously identified security vulnerabilities from the ic-py audit.

Moving forward, maintenance will focus on staying aligned with the latest Internet Computer features, keeping endpoints up to date, optimizing performance, and addressing issues raised by the developer community.

Thank you for using icp-py-core — I remain committed to actively maintaining and improving this repository.

Thank you for getting icp-py-core in good shape. Things are working great and this package is critical for a lot of the things we do.

@C-B-Elite ,

FYI, icp-py-core is an important enabler to make this application possible & secure.

It is python cli that has a locally managed wallet that can now verify the certificates of signed messages using the capabilities of icp-py-core.

Hey @C-B-Elite, can you look at this issue and fix it? We ran into the problem recently when using ic-py-core for preview deployments:

Thanks for opening this issue. I also ran into it.