SnakeBridge (SnakeBridge v0.7.4)
View SourceUniversal FFI bridge to Python.
SnakeBridge provides two ways to call Python:
Generated wrappers (compile-time): Type-safe, documented Elixir modules generated from Python library introspection.
Dynamic calls (runtime): Direct calls to any Python module without code generation, using string module paths.
Universal FFI API
The universal FFI requires no code generation:
# Call any Python function
{:ok, result} = SnakeBridge.call("math", "sqrt", [16])
# Get module attributes
{:ok, pi} = SnakeBridge.get("math", "pi")
# Work with Python objects
{:ok, path} = SnakeBridge.call("pathlib", "Path", ["/tmp"])
{:ok, exists?} = SnakeBridge.method(path, "exists", [])Sessions
SnakeBridge automatically manages Python object sessions. Each Elixir process gets an isolated session, and refs are automatically cleaned up when the process terminates.
For explicit session control, use SnakeBridge.SessionContext.with_session/1.
Type Mapping
| Elixir | Python |
|---|---|
nil | None |
true/false | True/False |
| integers | int |
| floats | float |
| strings | str |
SnakeBridge.bytes(data) | bytes |
| lists | list |
| maps | dict |
| tuples | tuple |
MapSet | set |
| atoms | tagged atom (decoded to string by default) |
DateTime | datetime |
SnakeBridge.Ref | Python object reference |
Summary
Functions
Get an attribute from a Python object reference.
Get an attribute from a ref, raising on error.
Create a Bytes wrapper for explicit binary data.
Call a Python function.
Call a Python function, raising on error.
Call a helper function.
Get the current session ID.
Get a module-level attribute from Python.
Get a module-level attribute, raising on error.
Call a method on a Python object reference.
Call a method on a ref, raising on error.
Check if a value is a Python object reference.
Release and clear the auto-session for the current process.
Set an attribute on a Python object reference.
Stream results from a Python generator or iterator.
Returns the SnakeBridge version.
Context manager macro for Python with statements.
Functions
Get an attribute from a Python object reference.
Parameters
ref- ASnakeBridge.Reffrom a previous callattr- Attribute name as atom or stringopts- Runtime options
Examples
{:ok, path} = SnakeBridge.call("pathlib", "Path", ["/tmp/file.txt"])
{:ok, name} = SnakeBridge.attr(path, "name")
# => {:ok, "file.txt"}
{:ok, parent} = SnakeBridge.attr(path, "parent")
# => {:ok, %SnakeBridge.Ref{...}} # parent is also a Path
@spec attr!(SnakeBridge.Ref.t(), atom() | String.t(), keyword()) :: term()
Get an attribute from a ref, raising on error.
@spec bytes(binary()) :: SnakeBridge.Bytes.t()
Create a Bytes wrapper for explicit binary data.
By default, SnakeBridge encodes UTF-8 valid strings as Python str.
Use this function to explicitly send data as Python bytes.
Examples
# Crypto
{:ok, hash_ref} = SnakeBridge.call("hashlib", "md5", [SnakeBridge.bytes("abc")])
{:ok, hex} = SnakeBridge.method(hash_ref, "hexdigest", [])
# Binary protocols
{:ok, packed} = SnakeBridge.call("struct", "pack", [">I", 12345])
# Base64
{:ok, encoded} = SnakeBridge.call("base64", "b64encode", [SnakeBridge.bytes("hello")])When to Use
Python distinguishes str (text) from bytes (binary). Use bytes/1 for:
- Cryptographic operations (hashlib, hmac, cryptography)
- Binary packing (struct)
- Base64 encoding
- Network protocols
- File I/O in binary mode
@spec call(module() | String.t(), atom() | String.t(), list(), keyword()) :: {:ok, term()} | {:error, term()}
Call a Python function.
Accepts either a generated SnakeBridge module or a Python module path string.
Parameters
module- A generated module atom (e.g.,Numpy) or a module path string (e.g.,"numpy")function- Function name as atom or stringargs- List of positional arguments (default:[])opts- Keyword arguments passed to Python, plus::idempotent- Mark call as cacheable (default:false):__runtime__- Pass-through options to Snakepit
Examples
# Call stdlib function
{:ok, 4.0} = SnakeBridge.call("math", "sqrt", [16])
# With keyword arguments
{:ok, 3.14} = SnakeBridge.call("builtins", "round", [3.14159], ndigits: 2)
# Submodule
{:ok, path} = SnakeBridge.call("os.path", "join", ["/tmp", "file.txt"])
# Create objects
{:ok, ref} = SnakeBridge.call("pathlib", "Path", ["."])Return Values
{:ok, value}- Decoded Elixir value for JSON-serializable results{:ok, %SnakeBridge.Ref{}}- Reference for non-serializable Python objects{:error, reason}- Error from Python
Notes
- String module paths trigger dynamic dispatch (no codegen required)
- Sessions are automatic; refs are isolated per Elixir process
- Non-JSON-serializable returns are wrapped in refs for safe access
Call a Python function, raising on error.
Same as call/4 but raises on error instead of returning {:error, reason}.
Examples
result = SnakeBridge.call!("math", "sqrt", [16])
# => 4.0
# Raises on error
SnakeBridge.call!("nonexistent_module", "fn", [])
# ** (Snakepit.Error) ...
Call a helper function.
@spec current_session() :: String.t()
Get the current session ID.
Returns the session ID for the current Elixir process. Sessions are automatically created on first Python call.
Examples
session_id = SnakeBridge.current_session()
# => "auto_<0.123.0>_1703944800000"
# With explicit session
SnakeBridge.SessionContext.with_session(session_id: "my_session", fn ->
SnakeBridge.current_session()
end)
# => "my_session"
@spec get(module() | String.t(), atom() | String.t(), keyword()) :: {:ok, term()} | {:error, term()}
Get a module-level attribute from Python.
Retrieves constants, classes, or any attribute from a Python module.
Parameters
module- A generated module atom or a module path stringattr- Attribute name as atom or stringopts- Runtime options
Examples
# Module constant
{:ok, pi} = SnakeBridge.get("math", "pi")
# => {:ok, 3.141592653589793}
# Module-level class (returns ref)
{:ok, path_class} = SnakeBridge.get("pathlib", "Path")
# Nested attribute
{:ok, sep} = SnakeBridge.get("os", "sep")
Get a module-level attribute, raising on error.
@spec method(SnakeBridge.Ref.t(), atom() | String.t(), list(), keyword()) :: {:ok, term()} | {:error, term()}
Call a method on a Python object reference.
Parameters
ref- ASnakeBridge.Reffrom a previous callmethod- Method name as atom or stringargs- Positional arguments (default:[])opts- Keyword arguments
Examples
{:ok, path} = SnakeBridge.call("pathlib", "Path", ["."])
{:ok, exists?} = SnakeBridge.method(path, "exists", [])
{:ok, resolved} = SnakeBridge.method(path, "resolve", [])
# With arguments
{:ok, child} = SnakeBridge.method(path, "joinpath", ["subdir", "file.txt"])Notes
This is equivalent to SnakeBridge.Dynamic.call/4 but with a clearer name
for the universal FFI context.
Call a method on a ref, raising on error.
Check if a value is a Python object reference.
Examples
{:ok, path} = SnakeBridge.call("pathlib", "Path", ["."])
SnakeBridge.ref?(path)
# => true
SnakeBridge.ref?("string")
# => false
@spec release_auto_session() :: :ok
Release and clear the auto-session for the current process.
Call this to eagerly release Python object refs when you're done with Python calls, rather than waiting for process termination.
Examples
{:ok, ref} = SnakeBridge.call("numpy", "array", [[1,2,3]])
# ... use ref ...
SnakeBridge.release_auto_session() # Clean up nowNotes
- This releases all refs in the current process's auto-session
- A new session is created automatically on the next Python call
- Use
SessionContext.with_session/1for more fine-grained control
@spec set_attr(SnakeBridge.Ref.t(), atom() | String.t(), term(), keyword()) :: :ok | {:error, term()}
Set an attribute on a Python object reference.
Parameters
ref- ASnakeBridge.Reffrom a previous callattr- Attribute name as atom or stringvalue- New value for the attributeopts- Runtime options
Examples
{:ok, obj} = SnakeBridge.call("some_module", "SomeClass", [])
:ok = SnakeBridge.set_attr(obj, "property", "new_value")
@spec stream(module() | String.t(), atom() | String.t(), list(), keyword(), (term() -> term())) :: :ok | {:ok, :done} | {:error, term()}
Stream results from a Python generator or iterator.
Calls a Python function that returns an iterable and invokes the callback for each element.
Parameters
module- Module atom or path stringfunction- Function nameargs- Positional argumentsopts- Keyword arguments for the Python functioncallback- Function called with each streamed element
Examples
# Process file in chunks
SnakeBridge.stream("pandas", "read_csv", ["large.csv"], [chunksize: 1000], fn chunk ->
IO.puts("Processing chunk")
end)
# Iterate range
SnakeBridge.stream("builtins", "range", [10], [], fn i ->
IO.puts("Got: #{i}")
end)Return Value
{:ok, :done}- Iteration completed successfully (for string module paths):ok- Iteration completed successfully (for atom modules){:error, reason}- Error during iteration
@spec version() :: String.t()
Returns the SnakeBridge version.
Context manager macro for Python with statements.