The Problem
Automating WhatsApp interactions from Python requires bridging a high‑performance Go backend (Whatsmeow) with a Python‑friendly API. Existing solutions either expose raw Go bindings, which are cumbersome for Python developers, or provide thin wrappers that lack async support and robust media handling. Teams need a single library that hides the Go complexity while offering a clean, async‑first interface for sending, receiving, and managing messages, groups, and media.
What This Does
neonize/ implements the public Python API. Core client logic lives in neonize/aioze/client.py (132 functions, 5 classes) and neonize/client.py (126 functions, 4 classes). Media utilities such as neonize/utils/ffmpeg.py and neonize/utils/sticker.py wrap external tools for conversion. The Go side (goneonize/) contains the compiled protobuf definitions and a thin wrapper (goneonize/main.go) that builds the Go binary used by the Python extension. Helper scripts in tools/ (e.g., tools/goneonize.py, tools/version.py) automate proto generation and version bumps.
How It Is Wired
Execution starts from the Python examples (e.g., examples/async_basic.py). The script imports neonize.client.NewClient, which instantiates neonize/aioze/client.Client. During initialization the client loads the compiled Go library (built from goneonize/Neonize.proto via goneonize/build_python_proto.py).
Key call chain for sending a message:
- handler (
examples/async_basic.py:56) →neonize/aioze/client.send_message(called 13 times). send_message→neonize/aioze/client.get_bytes/free_bytes(both invoked from 51 places, the widest blast radius).get_bytesreads a file or URL vianeonize/utils/iofile.get_bytes_from_name_or_url(network I/O).- The byte payload is passed to the Go layer (
neonize/aioze/client.call) which ultimately invokes the Whatsmeow‑backed RPC to deliver the message.
Media paths add a filesystem hop: handler → build_sticker_message → neonize/utils/sticker.convert_to_sticker → external ffmpeg command (neonize/utils/ffmpeg.py).
The most connected modules are neonize/aioze/client (21 outgoing imports, part of a circular dependency) and neonize/client (19 outgoing imports, also in a cycle). These cycles inflate the cognitive load when refactoring because changes ripple through both modules.
File‑level responsibilities (selected):
| File | Primary Role | External Effect |
|---|---|---|
neonize/aioze/client.py | Async client core, request routing | Calls external commands, reads/writes files |
neonize/utils/ffmpeg.py | Media conversion wrapper | Executes ffmpeg, writes temporary files |
neonize/utils/iofile.py | Unified byte‑source loader | Performs network fetches |
tools/goneonize.py | Proto generation & Go build orchestration | Runs protoc, writes compiled Go files |
goneonize/main.go | Go entry point (binary) | Provides low‑level WhatsApp RPCs |
Because the import graph shows 4 modules in circular dependencies, any change to shared types (e.g., neonize/types) must consider both sides of the cycle to avoid import errors.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/neonize
cd neonize
# Install Python dependencies (uses the pyproject.toml)
pip install -e . # editable install pulls in all required packages
# Build the Go protobuf layer (requires Go 1.19+)
cd goneonize
go run build_python_proto.py # generates the Go bindings used by the Python package
Run an example to verify the stack:
python ../examples/async_basic.py
The example creates a NewClient, registers event callbacks, and calls handler which ultimately invokes send_message as described above.
Real‑World Use
A support desk could embed the library in a Flask service that receives HTTP tickets, creates a NewClient, and forwards the ticket text as a WhatsApp message:
from neonize.client import NewClient
client = NewClient("my_bot")
client.send_message(to_jid="12345@s.whatsapp.net", text=ticket.body)
The call traverses the same async client → byte loader → Go RPC path, guaranteeing that media handling and encryption are performed by the underlying Whatsmeow backend.
Code Health & Issues
- HIGH – Pin third‑party GitHub Actions to commit SHA (
.github/workflows/*). - HIGH – No test suite present (
109 source files, 0 test files). - HIGH – Missing Python lockfile beside
pyproject.toml. - HIGH –
continue-on-erroron correctness step inrelease.yml. - MEDIUM – Declare least‑privilege
GITHUB_TOKENpermissions (autobump.yml). - MEDIUM – Enable Dependabot or Renovate for automated updates.
- MEDIUM – Add a dependency‑vulnerability scan step in CI.
- MEDIUM – Set
persist-credentials: falseon checkout (autobump.yml). - LOW – Add
timeout-minutesto workflow jobs. - LOW – Add repository convention files (
.editorconfig, formatter config, etc.).
Additional static findings: oversized files (neonize/aioze/client.py, neonize/client.py, neonize/utils/ffmpeg.py), broad exception handling, deep nesting, an import cycle involving neonize/aioze/client.py and neonize/events.py, and duplicated example code blocks.
The Bottom Line
Neonize delivers a functional Python wrapper around a performant Go WhatsApp core, with clear async APIs and media utilities. However, the codebase suffers from high cognitive load, circular imports, and a lack of automated testing and dependency lockfiles. It is suitable for teams comfortable navigating a mixed Python/Go stack and willing to invest in refactoring and test coverage before production use.