Type-safe Ctypes bindings using Pydantic models.
Project description
C-Dantic
Type-Safe Foreign Function Interface for Python (Pydantic + ctypes)
"It would’ve been a segfault, it’s now a Pydantic error."
C-Dantic is a production-grade safety layer that bridges Python's Pydantic data modeling with standard ctypes. It transforms the fragile "trust me" nature of FFI into a robust, validated, and ABI-faithful engineering discipline.
Born from Fire
C-Dantic was extracted from a high-stakes native integration for the pytron engine—an environment involving opaque handles, cross-thread callbacks, and sensitive memory layouts. In such environments, a single misaligned byte or an early-garbage-collected callback doesn't just throw an exception; it crashes the entire process.
C-Dantic places a Pydantic-powered protection at the Python-C boundary to stop these crashes before they happen.
Why C-Dantic?
- Runtime Integrity: Pydantic validates data types before they touch C memory.
- ABI Fidelity: Precise control over memory layout with
__pack__and__align__. - Execution Safety: Detects null pointers, symbol misses, and unbound libraries before they cause Access Violations.
- Lifetime Management: Automatically pins Python callbacks to memory so they aren't garbage collected while the C side is still using them.
- Modern Ergonomics: Use
Annotatedand standard type hints instead of arcanectypessyntax.
Core Features
1. Type-Safe Structures (CStruct)
Define memory-mapped structures using Pydantic. Use Annotated to provide ABI-level representation.
from typing import Annotated
from cdantic import CStruct
import ctypes
class PackedData(CStruct):
__pack__ = 1 # Force byte-alignment (Pragma Pack)
id: Annotated[int, ctypes.c_byte]
value: Annotated[int, ctypes.c_int]
# ABI Introspection
print(f"Size: {PackedData.sizeof()} bytes") # Outputs: 5
print(f"Offset.id: {PackedData.offsetof('id')}") # Outputs: 0
print(f"Offset.val: {PackedData.offsetof('value')}") # Outputs: 1
2. Binding Safety (CFunction)
Define signatures on methods and enforce library binding. Calling a native function before the library is bound raises a descriptive LibraryNotBoundError instead of a crash.
from cdantic import CFunction, bind_library
class NativeEngine:
@CFunction(func_name="webview_create")
def create(self, debug: int, window: int) -> int: ...
engine = NativeEngine()
# engine.create(0, 0) -> Raises LibraryNotBoundError
bind_library(engine, "webview.dll")
engine.create(0, 0) # Now safe to call
3. Protected Callbacks (CCallback)
Convert Python functions to C-compatible pointers. C-Dantic automatically pins these callbacks to a global registry to prevent early garbage collection.
from cdantic import CCallback
@CCallback
def on_event(msg: str) -> int:
print(f"Received: {msg}")
return 1
4. Handle Ergonomics
Simplified NULL checks for pointers and opaque handles.
from cdantic import is_null, assert_not_null
handle = lib.create_entity()
if is_null(handle):
logger.error("Failed to create entity")
# Or enforce with an exception
assert_not_null(handle, "EntityHandle") # Raises ValidationBoundaryError if NULL
The "Safety Shield" in Action
Without C-Dantic, this mistake crashes your interpreter:
# Raw ctypes would likely segfault here
lib.webview_create(debug="yes", window="oops")
With C-Dantic, you get a clean, actionable validation report:
pydantic_core._pydantic_core.ValidationError: 2 validation errors for create
debug
Input should be a valid integer [type=int_parsing, input_value='yes', input_type=str]
window
Input should be a valid integer [type=int_parsing, input_value='oops', input_type=str]
Production Error Hierarchy
LibraryNotBoundError: Called a function before its library was loaded.SymbolNotFoundError: Function name doesn't exist in the DLL/SO.ValidationBoundaryError: Access Violations (e.g., NULL pointer dereference attempts).CallbackLifetimeError: Callback GC protection failure.
Installation
pip install cdantic
License
MIT License.
Project details
Release history Release notifications | RSS feed
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 cdantic-0.1.9.tar.gz.
File metadata
- Download URL: cdantic-0.1.9.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee5bbfe200d1fadfcccd9f69d753a64708e4ace45b7e8e1b74083851390787bd
|
|
| MD5 |
5c0ccc0ea1d1953f222da2094227e19c
|
|
| BLAKE2b-256 |
48a13bafd39d0d324c010a7da7e420e4d44a371fc9f2efce08e3e7ec9cb1805c
|
Provenance
The following attestation bundles were made for cdantic-0.1.9.tar.gz:
Publisher:
publish.yml on Ghua8088/cdantic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdantic-0.1.9.tar.gz -
Subject digest:
ee5bbfe200d1fadfcccd9f69d753a64708e4ace45b7e8e1b74083851390787bd - Sigstore transparency entry: 833196340
- Sigstore integration time:
-
Permalink:
Ghua8088/cdantic@4d53721bc426f5ac2baaf120e64c9e37ce3b0426 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/Ghua8088
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d53721bc426f5ac2baaf120e64c9e37ce3b0426 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cdantic-0.1.9-py3-none-any.whl.
File metadata
- Download URL: cdantic-0.1.9-py3-none-any.whl
- Upload date:
- Size: 7.7 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 |
9eb1c574a361069182741d4a79b1d58202e90adabca76af68a63a366dd5d2ef4
|
|
| MD5 |
63993be6f52d6c7b3b43c3994ca099b5
|
|
| BLAKE2b-256 |
d1635a91b9f1d0f74d90fd9b7538da28589348ff581bf4add1ecc06334ae6c81
|
Provenance
The following attestation bundles were made for cdantic-0.1.9-py3-none-any.whl:
Publisher:
publish.yml on Ghua8088/cdantic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdantic-0.1.9-py3-none-any.whl -
Subject digest:
9eb1c574a361069182741d4a79b1d58202e90adabca76af68a63a366dd5d2ef4 - Sigstore transparency entry: 833196378
- Sigstore integration time:
-
Permalink:
Ghua8088/cdantic@4d53721bc426f5ac2baaf120e64c9e37ce3b0426 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/Ghua8088
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d53721bc426f5ac2baaf120e64c9e37ce3b0426 -
Trigger Event:
workflow_dispatch
-
Statement type: