EazyDraw Automation API — Python client
Python wrapper around the HTTP API documented in ../../API.md and
../../spec/openapi.yaml. A developer tool, not (yet) a shipped SDK.
Packaged as the eazydraw module:
eazydraw/
__init__.py public exports (EazyDraw, EazyDrawError, models)
client.py the EazyDraw HTTP client (returns raw dicts)
models.py pydantic v2 models mirroring spec/openapi.yaml
eazydraw_api.py backward-compat shim (re-exports from eazydraw)
Setup
pip install -r requirements.txt # requests + pydantic (+ dev: pyyaml, openapi-spec-validator)
# or, to install the package itself (editable): pip install -e .
cp config.example.py config.py
# edit config.py and paste your bearer token from API Settings -> Reveal
Python 3.10+. config.py is gitignored so your real token stays on your
machine; config.example.py is the committed placeholder.
Transport: TCP or UNIX socket
The direct EazyDraw build serves the API on localhost:52737. The App Store
build is sandboxed and serves the same API on a UNIX-domain socket in its
container instead. Pass socket_path to use it (API Settings shows the path;
DEFAULT_SOCKET is the App Store app's):
from eazydraw import EazyDraw, DEFAULT_SOCKET
ed = EazyDraw(token="...", socket_path=DEFAULT_SOCKET)
Everything else is identical. The script tests run over the socket with
EAZYDRAW_SOCKET=<path> python test_smoke.py (see conftest.py).
Quickstart
from eazydraw import EazyDraw # (the old `from eazydraw_api import EazyDraw` still works)
# Paste your bearer token from API Settings -> Reveal
ed = EazyDraw(token="7b3f...")
ed.status()
# {'status': 'OK', 'version': '12.3.6', 'build': '51059'}
# Open a drawing, capture its uuid
d = ed.open_drawing("~/Documents/sketch.ezdjson")
print(d["uuid"], "newly opened" if ed.last_response.status_code == 201 else "already open")
# Walk down to graphics on the active layer
layers = ed.layers(d["uuid"])
gs = ed.layer_graphics(d["uuid"], layers[0]["uuid"])
print(len(gs), "graphics on layer 0")
# Place a library element into the drawing
libs = ed.libraries()
math_lib = next(l for l in libs if l["DisplayName"] == "Math")
els = ed.library_elements(math_lib["uuid"])
graphic_el = next(e for e in els if e["elementType"] == "graphic")
placed = ed.use_library_element(
d["uuid"], layers[0]["uuid"], math_lib["uuid"], graphic_el["uuid"]
)
print("Placed", placed["class"], "as", placed["graphicUUID"])
# Export the drawing as a PNG to disk
ed.export_drawing(d["uuid"], "png", save_to="/tmp/sketch.png")
# Close it
ed.close_drawing(d["uuid"])
Typed models (optional)
The client returns raw dicts. For validation / IDE support, parse them with the
pydantic models in eazydraw.models (these mirror spec/openapi.yaml):
from eazydraw import EazyDraw, Graphic, Text
ed = EazyDraw(token="7b3f...")
g = Graphic.model_validate(ed.graphic(D, L, G))
print(g.graphic_uuid, g.hidden_bounds.width, g.is_group) # snake_case fields
# round-trips back to wire form (camelCase / PascalCase keys)
g.model_dump(by_alias=True)
Field names are snake_case with the wire keys as aliases; unknown server keys
are preserved (extra="allow"), so a newer server field won't break parsing.
Error handling
Non-2xx responses raise EazyDrawError(status_code, message, body):
from eazydraw import EazyDraw, EazyDrawError
ed = EazyDraw(token="wrong-token")
try:
ed.status()
except EazyDrawError as exc:
print(exc.status_code, exc.message) # 401 "Missing or invalid bearer token"
Status codes
Every method calls self.last_response = resp, so when the server's status
code carries semantic meaning (201 vs 200 on POST, etc.), inspect it
afterward:
d = ed.open_drawing(path)
already_open = (ed.last_response.status_code == 200)
Conventions
- Methods take UUIDs as positional strings, in path order:
ed.layer(D, L),ed.layer_graphics(D, L), etc. - Recursive group-traversal methods take a variadic list of UUIDs in chain
order:
ed.group_graphics(D, L, G1, G2, G3)reads as "drilling down". export_*methods takefmtas a keyword argument (so the call site stays readable when there's a long UUID chain) and accept an optionalsave_topath; if given, bytes are written to that path and the path is returned. Otherwise raw bytes are returned.- Collection endpoints unwrap the envelope:
ed.drawings()returns the list directly, not{"drawings": [...]}. client.pyis single-class; as we add API endpoints we add a method — no inheritance, no abstractions.models.pyis plain pydantic data classes.
Not shipped
This lives in the repo for convenience but is not part of the EazyDraw app
bundle. A versioned, published Python SDK is a future product decision; the
eazydraw package here is the working basis for it (and for the semantic
resolver + MCP server layers to come).
Release files for eazydraw 1.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| eazydraw-1.1.3.tar.gz | 57.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eazydraw-1.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 114.6 kB
Release files / eazydraw-1.1.3.tar.gz
| Download URL | eazydraw-1.1.3.tar.gz |
|---|---|
| Size | 57.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ead100c6f6e5ea0f3fcdf958e328dac937f1d38e48a734a58fdb87b27885776a
|
|
BLAKE2b-256 checksum How to use checksums |
ded8b6d3e966e0003e323c41de854c6f9844e2f443491f1ed7771e79fe32f220
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / eazydraw-1.1.3-py3-none-any.whl
| Download URL | eazydraw-1.1.3-py3-none-any.whl |
|---|---|
| Size | 56.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f34633700031bc6353c244315896ae180cf3de652b00178e10a9053fbce1ab27
|
|
BLAKE2b-256 checksum How to use checksums |
2a1d038708a1b01a41418a6134aa0245c361adab34900cbae8b8407f686699f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|