Emacs Python FFI

Emacs dynamic module that implements foreign function interface for python.
It allows usage of python modules in Elisp.

https://github.com/813gan/emacs-python-ffi

Table of Contents


1 Installation

There is no binary distribution now, so you need development tools to compile this module.

System dependencies:

If you compiled Python yourself and want to use it, then compile Emacs Python FFI with venv activated,
or export PYTHON= with path to your exeutable before compilation.
Custom Python build needs to be ./configure d with --enable-shared flag.

Elisp dependencies:


2 Usage

NOTE for GitHub users: As of beginning of 2025 GitHub don’t display function definitions in repository overview.
See rendered github page instead.

This module is going to (See Bugs and limitations) utilize Python sub-interpreters to isolate Emacs modes using this module from each other.
See Pyhton documentation for details.

Most of functions in this module takes subinterpreter as first argument.

Function: python-ffi-python-environment-make subinterpreter &optional packages virtualenv

Function: python-ffi-call subinterpreter name &rest args &key as kwargs

Call functionn or method referenced by name.
name can either take form of function_name or object_name.method_name.
Pass non-keyword arguments will be passed as positional arguments.
Pass property list from :keyword argument kwargs as keyword arguments.
Bind result in global scope under name from :keyword argument as or return it if as is nil.

Function: python-ffi-get-variable-global subinterpreter name

Get global variable named name from subinterpreter.

Function: python-ffi-set-variable-global subinterpreter name value

Set global variable named name from subinterpreter to value.
Return NAME unchanged.

Function: python-ffi-get-object-attr subinterpreter name &optional field_name &key as

Get attribute named field_name from object named name in global scope
in sub-interpreter subinterpreter.
name can have python-like form obj.field. In such case field is used and field_name is ignored.
Bind result in global scope under name from :keyword argument as or return it if as is nil.

Function: python-ffi-set-object-attr subinterpreter name value &optional field_name

Get attribute named field_name from object named name in global scope
in sub-interpreter subinterpreter.
name can have python-like form obj.field. In such case field is used and field_name is ignored.
Bind result in global scope under name from :keyword argument as or return it if as is nil.

Function: python-ffi-exec-string subinterpreter string

Warning: This function executes arbitrary code. Calling it with user-supplied input may lead to security vulnerabilities.
Exec string in subinterpreter.
Return value is always 't.
Internally it uses PyObject_Call on build-in exec.
This function

Function: python-ffi-eval-string subinterpreter string &key as

Warning: This function executes arbitrary code. Calling it with user-supplied input may lead to security vulnerabilities.
"Eval string in subinterpreter.
Bind result in global scope under name from :keyword argument as or return it if as is nil.
Internally it uses PyObject_Call on build-in eval.

Function: python-ffi-alist2hash alist

Convert alist to hash.
It’s handy as only hash is converted to python dictionary.

Function: python-ffi-kwargs-plist2hash plist

Convert plist to hash for easy creation of Python dicts.
Plist keys are assumed to be symbols.
It’s handy as only hash is converted to python dictionary.


3 Examples of usage


4 Troubleshooting


4.1 Python-FFI fails to load


4.1.1 Error 1

Mismatch of module API version between Emacs and python-ffi.
Update python-ffi to newest version.
If problem persist file bug report.


4.1.2 Error 2

attemted loading python-ffi more then once.
This shouldn’t have any effect.


4.1.3 Error 3

Starting of Python thread failed (pthread_create).
Try restart. If problem persist file bug report.


4.1.4 Error 6

One of pthread functions failed.
It’s possible if Emacs was running on system with low memory.
Try restart. If problem persist file bug report.


5 Bugs and limitations

As of Python 3.13 only Main python interpreter handles signals.
It means it’s impossible to send KeyboardInterrupt to subinterpreter; (See related GH issue)
Consequently, it is impossible (or, at least i have no idea how) to implement keyboard-quit.
Thus, any long running python code could "hang" Emacs and even C-g would not work.
In my opinion it’s far more severe issue then theoretical problems of multiple Emacs modes that break each other.
I didn’t want to neither delay release of this module or change API in some undefined future so,
all revelant functions take argument subinterpreter anyway. It just don’t have any effect now.