Code map
View SourceEvery 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.
Erlang (src/)
| 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 |
C (c_src/)
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).
Python (priv/)
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 |
Tests (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).
Build and docs
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.