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"])
# Start from nothing: a new drawing has no file until you save it
n = ed.new_drawing("Plan")
lyr = ed.layers(n["uuid"])[0]["uuid"]
box = ed.add_shape(n["uuid"], lyr, shape="rectangle",
bounds={"x": 72, "y": 72, "width": 200, "height": 100}, name="frame")
ed.set_lock(n["uuid"], lyr, box["graphicUUID"], delete=True) # Format > Lock, by script
ed.undo(n["uuid"]) # every call is one undo step
ed.set_selection(n["uuid"], [box["graphicUUID"]]) # show the user what you mean
ed.save_drawing(n["uuid"], path="~/Documents/plan.ezdjson") # Save As; autosaves from then on
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.5
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.5.tar.gz | 63.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eazydraw-1.1.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 126.4 kB
Release files / eazydraw-1.1.5.tar.gz
| Download URL | eazydraw-1.1.5.tar.gz |
|---|---|
| Size | 63.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bf97c4adfe42981b8a107320762dd95731b5b8a7ca83b91095825e6833eb5e6d
|
|
BLAKE2b-256 checksum How to use checksums |
65475c664c292b14a6ee1ef2df8fa59623c59d67b46bc5f2fe31002b6ad4287b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|
Release files / eazydraw-1.1.5-py3-none-any.whl
| Download URL | eazydraw-1.1.5-py3-none-any.whl |
|---|---|
| Size | 62.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9ed66ff818362a149469db62ae801ce913dd5797e38999c952c6aabaf4b0b036
|
|
BLAKE2b-256 checksum How to use checksums |
260e26faa302f875ec346c134385979d97c934f883703fcc04120793c72d6f42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|