Every source file, what it owns, and where to look for its behaviour. Status
is live (on the path of a context created today) or test (only
exercised by suites). Guides are in docs/, suites in test/. Start with
architecture.
| Module | Owns | Status | Guide | Suites |
|---|---|---|---|---|
py |
Public API facade: call/eval/exec, async helpers, memory, function registration; delegates streams, venvs and shared dicts | live | README, getting-started | py_SUITE, py_api_SUITE |
py_stream |
Generator streaming behind py:stream* |
live | streaming | py_stream_SUITE |
py_venv |
Virtual environments behind py:ensure_venv and friends |
live | README (venvs) | py_venv_SUITE |
py_shared_dict |
py:shared_dict_* over the shared dict NIFs |
live | shared-dict | py_SUITE |
py_context |
The API every mode answers (call/eval/exec, interrupt, kill, loops, pass_fd), the reply protocol and the pid to NIF reference table; init/4 hands the process to py_context_embedded or py_isolated |
live | context-affinity, workers, interrupts | py_context_SUITE, py_context_process_SUITE, py_interrupt_SUITE, py_worker_loop_SUITE |
py_context_embedded |
Process body for worker and owngil mode: the receive loop, callbacks (suspension and pipe), worker loops |
live | architecture, state-machines | same |
py_isolated |
gen_statem driving a child process over the socket; restart policy |
live | isolated | py_isolated_*_SUITE |
py_context_router |
Pools and scheduler-affinity routing | live | pools, context-affinity | py_context_router_SUITE, py_pool_SUITE |
py_context_sup, py_context_init |
Supervisor of contexts; starts the default pool at boot | live | pools | (through the above) |
py_nif |
Erlang stubs and docs for every NIF | live | api-reference | all |
py_callback |
Registry of Erlang funs callable as erlang.call('name', ...) |
live | README (callbacks) | py_callback_encoding_SUITE, py_thread_callback_SUITE |
py_thread_handler |
Coordinator that gives each Python thread calling Erlang a handler process and a pipe | live | threading | py_thread_callback_SUITE, py_reentrant_SUITE |
py_event_loop |
Main-interpreter asyncio loop: run, create_task, await, and the loop callbacks Python needs |
live | asyncio | py_event_loop_SUITE, py_async_task_SUITE |
py_event_loop_pool |
Several main-interpreter loops with process affinity | live | asyncio | py_event_loop_pool_SUITE |
py_event_worker |
One process per running loop receiving enif_select readiness and timers |
live | event_loop_architecture | py_event_loop_SUITE, py_fd_ops_SUITE |
py_event_worker_sup, py_event_worker_registry |
Supervisor and name registry of the event workers | live | event_loop_architecture | py_event_loop_SUITE |
py_reactor_context |
FD-owning context for the protocol-based reactor | live | reactor | py_reactor_SUITE |
py_channel, py_byte_channel |
Term and byte queues between Erlang and Python coroutines (NIF resources) | live | channel | py_channel_SUITE, py_byte_channel_SUITE |
py_buffer |
Native streaming input buffer; shared variant delegates to py_shm |
live | buffer, isolated | py_buffer_SUITE, py_isolated_buffer_SUITE |
py_shm |
Shared memory regions over iommap and the ring behind shared buffers | live | isolated | py_isolated_shm_SUITE |
py_import |
Registry of imports and sys.path entries applied to every interpreter |
live | imports | py_import_SUITE |
py_preload |
Code run once per interpreter at start | live | preload | py_preload_SUITE |
py_state |
Shared key/value store visible from Python as erlang.state_get/set/delete/keys |
live | README (shared state) | py_state_SUITE |
py_semaphore |
ETS counting semaphore for rate limiting | live | scalability | (through py_SUITE) |
py_logger, py_tracer |
Python logging into Erlang logger; tracing hooks |
live | logging | py_logging_SUITE |
erlang_python_app, erlang_python_sup |
Application start and the supervision tree | live | architecture | all |
py_util |
Small helpers | live |
py_nif.c is the only translation unit: it #includes the other .c
files. Editing py_convert.c alone does not compile it alone; build with
rebar3 compile. See c_src/README.md.
| File | Owns | Status |
|---|---|---|
py_nif.h |
Every shared type: py_context_t, request types, runtime state machine, atoms, globals |
live |
py_nif.c |
Runtime init, context creation and destruction, the request queue and the two context thread mains, the process-per-context NIFs (nif_context_*), process-local envs, py_ref, the NIF table |
live |
py_convert.c |
py_to_term / term_to_py, the type mapping, tagged tuples ({bytes, B}, shared handles) |
live |
py_exec.c |
Execution mode detection and GIL helpers | live |
py_callback.c |
The erlang Python module: call, send, whereis, Atom/Pid/Ref types, schedule markers, callback pipes, channel and shared dict methods |
live |
py_thread_worker.c |
Python threads calling Erlang through py_thread_handler |
live |
py_subinterp_thread.c |
Sub-interpreter thread pool used by owngil contexts and loop pools | live |
py_event_loop.c |
ErlangEventLoop support: enif_select readers/writers, timers, task injection, reactor dispatch, fd registry; also ~570 lines of test-only fd/TCP/UDP NIFs |
live; test section |
py_channel.c, py_buffer.c, py_reactor_buffer.c, py_shared_dict.c |
The corresponding resources and their Python-facing methods | live |
py_logging.c |
Logging and tracing NIFs | live |
py_mem_limit.c |
Per-interpreter memory caps (owngil) | live |
py_util.c/.h |
Macros and helpers | live |
py_nif.h, py_event_loop.h, py_channel.h, py_buffer.h, py_reactor_buffer.h, py_subinterp_thread.h, py_util.h |
Declarations shared between the included files; the struct comments in py_nif.h and py_event_loop.h carry the lock contracts |
live |
The only code not on a live path is the "Test Helper Functions" section of
py_event_loop.c (fd, pipe, TCP and UDP helpers the suites use).
priv/ is on sys.path of every interpreter. _erlang_impl is the Python
half of the erlang module; the embedded C module delegates to it for the
loop, channels and servers.
| File | Owns | Used by |
|---|---|---|
_erlang_impl/__init__.py |
Public surface of erlang in embedded modes: run, sleep, spawn_task, loop policy, atom, channels, server |
embedded |
_erlang_impl/_loop.py, _policy.py, _transport.py |
ErlangEventLoop (uvloop-compatible) over enif_select |
embedded |
_erlang_impl/_reactor.py |
Protocol-based reactor over fds Erlang owns | embedded |
_erlang_impl/_channel.py, _byte_channel.py |
Python side of channels | embedded |
_erlang_impl/_server.py |
serve, adopt, stop_serving on fds handed over by Erlang; plain asyncio, works in every mode |
all |
_erlang_impl/_sandbox.py, _subprocess.py |
Audit hook blocking fork/exec inside the VM | embedded |
_erlang_impl/_mode.py |
Detects how Python is running (embedded, free-threaded, child) | all |
_erlang_impl/_etf.py |
Pure-Python ETF codec with the py_convert.c mapping |
isolated child |
_erlang_impl/_isolated.py |
Child runtime: socket frames, reader thread, re-entrant main loop, interrupt signal, asyncio loop, the erlang shim |
isolated child |
_erlang_impl/_shm.py |
SharedMemory and SharedBuffer wrappers over mmap |
all |
py_isolated_child.py |
Child launcher: rlimits, parent-death signal, cgroup join, connect | isolated child |
test_erlang_loop.py, test_async_task.py, test_channel_ref.py, tests/ |
Python-side tests of the loop, tasks and channels | test |
Suites named py_<area>_SUITE. Cross-mode suites run the same cases in
worker and isolated groups (py_isolated_SUITE, py_isolated_vm_SUITE,
py_isolated_shm_SUITE, py_isolated_buffer_SUITE). Python helpers used by
suites are test/py_test_*.py. test/coverage_audit.md maps public APIs to
cases and every module to its suites; make check-code-map verifies this
page and that table against the tree. test/test.config holds node-wide settings (memory limits flag).
rebar.config runs do_cmake.sh / do_build.sh (CMake in c_src/) as
compile hooks; the NIF lands in priv/py_nif.so. make lint-docs checks
that Erlang snippets in the guides call real exports and that Python
snippets parse. rebar3 ex_doc builds the guides listed in rebar.config.