drawio-python 0.1.0__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. drawio_python-0.1.4/HISTORY.md +41 -0
  2. drawio_python-0.1.4/MANIFEST.in +11 -0
  3. drawio_python-0.1.4/PKG-INFO +286 -0
  4. drawio_python-0.1.4/README.md +248 -0
  5. drawio_python-0.1.4/docs/index.md +111 -0
  6. drawio_python-0.1.4/drawio/VERSION +1 -0
  7. drawio_python-0.1.4/drawio/__init__.py +5 -0
  8. drawio_python-0.1.4/drawio/__main__.py +6 -0
  9. drawio_python-0.1.4/drawio/cli.py +399 -0
  10. drawio_python-0.1.4/drawio/doctor.py +144 -0
  11. drawio_python-0.1.4/drawio/document.py +985 -0
  12. drawio_python-0.1.4/drawio/entities/__init__.py +4 -0
  13. drawio_python-0.1.4/drawio/entities/base_entity.py +9 -0
  14. drawio_python-0.1.4/drawio/entities/config.py +1 -0
  15. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/drawio.py +4 -2
  16. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/drawio_app.py +3 -9
  17. drawio_python-0.1.4/drawio/entities/drawio_browser.py +235 -0
  18. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/drawio_config/abstract_config.py +2 -2
  19. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/drawio_config/drawio_config.py +13 -1
  20. drawio_python-0.1.4/drawio/entities/drawio_config/label_config.py +5 -0
  21. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/erd/column.py +2 -1
  22. drawio_python-0.1.4/drawio/entities/erd/erd.py +67 -0
  23. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/erd/table.py +3 -3
  24. drawio_python-0.1.4/drawio/entities/graph/__init__.py +5 -0
  25. drawio_python-0.1.4/drawio/entities/graph/edge.py +33 -0
  26. drawio_python-0.1.4/drawio/entities/graph/graph.py +147 -0
  27. drawio_python-0.1.4/drawio/entities/graph/node.py +92 -0
  28. drawio_python-0.1.4/drawio/entities/logger.py +8 -0
  29. drawio_python-0.1.4/drawio/entities/renderers/__init__.py +7 -0
  30. drawio_python-0.1.4/drawio/entities/renderers/base_render.py +24 -0
  31. drawio_python-0.1.4/drawio/entities/renderers/drawio_render.py +16 -0
  32. drawio_python-0.1.4/drawio/entities/renderers/pdf_render.py +59 -0
  33. drawio_python-0.1.4/drawio/itergrations/mermaid/mermaid_controller.py +108 -0
  34. drawio_python-0.1.4/drawio/layout.py +283 -0
  35. drawio_python-0.1.4/drawio/lint.py +531 -0
  36. drawio_python-0.1.4/drawio/render/__init__.py +223 -0
  37. drawio_python-0.1.4/drawio/render/browser.py +169 -0
  38. drawio_python-0.1.4/drawio/render/desktop.py +104 -0
  39. drawio_python-0.1.4/drawio/render/fonts.py +239 -0
  40. drawio_python-0.1.4/drawio/render/native.py +638 -0
  41. drawio_python-0.1.4/drawio/scene.py +658 -0
  42. drawio_python-0.1.4/drawio/shapes.py +82 -0
  43. drawio_python-0.1.4/drawio/skill/SKILL.md +155 -0
  44. drawio_python-0.1.4/drawio/skill/references/api.md +101 -0
  45. drawio_python-0.1.4/drawio/skill.py +40 -0
  46. drawio_python-0.1.4/drawio/text.py +127 -0
  47. drawio_python-0.1.4/drawio_python.egg-info/PKG-INFO +286 -0
  48. drawio_python-0.1.4/drawio_python.egg-info/SOURCES.txt +84 -0
  49. drawio_python-0.1.4/drawio_python.egg-info/requires.txt +27 -0
  50. drawio_python-0.1.4/examples/agent_workflow.py +36 -0
  51. drawio_python-0.1.4/examples/complex-example.py +16 -0
  52. drawio_python-0.1.4/examples/draw-flow-diagrams.png +0 -0
  53. drawio_python-0.1.4/examples/draw-flow-diagrams.py +18 -0
  54. drawio_python-0.1.4/examples/mermaid-to-drawio.py +19 -0
  55. drawio_python-0.1.4/examples/native_document.py +65 -0
  56. drawio_python-0.1.4/mkdocs.yml +2 -0
  57. drawio_python-0.1.4/pyproject.toml +16 -0
  58. drawio_python-0.1.4/requirements-test.txt +5 -0
  59. drawio_python-0.1.4/requirements.txt +2 -0
  60. {drawio-python-0.1.0 → drawio_python-0.1.4}/setup.py +18 -6
  61. drawio_python-0.1.4/tests/conftest.py +6 -0
  62. drawio_python-0.1.4/tests/test_cli.py +110 -0
  63. drawio_python-0.1.4/tests/test_document.py +335 -0
  64. drawio_python-0.1.4/tests/test_examples.py +28 -0
  65. drawio_python-0.1.4/tests/test_graph.py +20 -0
  66. drawio_python-0.1.4/tests/test_graph_native.py +126 -0
  67. drawio_python-0.1.4/tests/test_imports.py +8 -0
  68. drawio_python-0.1.4/tests/test_layout_text.py +76 -0
  69. drawio_python-0.1.4/tests/test_lint_render.py +220 -0
  70. drawio_python-0.1.4/tests/test_mermaid.py +85 -0
  71. drawio_python-0.1.4/tests/test_toolkit_api.py +141 -0
  72. drawio-python-0.1.0/HISTORY.md +0 -13
  73. drawio-python-0.1.0/MANIFEST.in +0 -5
  74. drawio-python-0.1.0/PKG-INFO +0 -23
  75. drawio-python-0.1.0/README.md +0 -14
  76. drawio-python-0.1.0/drawio/VERSION +0 -1
  77. drawio-python-0.1.0/drawio/__main__.py +0 -6
  78. drawio-python-0.1.0/drawio/cli.py +0 -28
  79. drawio-python-0.1.0/drawio/entities/config.py +0 -2
  80. drawio-python-0.1.0/drawio/entities/drawio_browser.py +0 -89
  81. drawio-python-0.1.0/drawio/entities/erd/erd.py +0 -22
  82. drawio-python-0.1.0/drawio/entities/graph/__init__.py +0 -1
  83. drawio-python-0.1.0/drawio/entities/graph/edge.py +0 -30
  84. drawio-python-0.1.0/drawio/entities/graph/graph.py +0 -134
  85. drawio-python-0.1.0/drawio/entities/graph/node.py +0 -91
  86. drawio-python-0.1.0/drawio_python.egg-info/PKG-INFO +0 -23
  87. drawio-python-0.1.0/drawio_python.egg-info/SOURCES.txt +0 -38
  88. drawio-python-0.1.0/drawio_python.egg-info/requires.txt +0 -12
  89. drawio-python-0.1.0/tests/conftest.py +0 -14
  90. {drawio-python-0.1.0 → drawio_python-0.1.4}/Containerfile +0 -0
  91. {drawio-python-0.1.0 → drawio_python-0.1.4}/LICENSE +0 -0
  92. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/base.py +0 -0
  93. {drawio-python-0.1.0/drawio → drawio_python-0.1.4/drawio/controllers}/__init__.py +0 -0
  94. {drawio-python-0.1.0/drawio/controllers → drawio_python-0.1.4/drawio/entities/drawio_config}/__init__.py +0 -0
  95. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/drawio_config/connect_config.py +0 -0
  96. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio/entities/erd/__init__.py +0 -0
  97. {drawio-python-0.1.0/drawio/entities → drawio_python-0.1.4/drawio/itergrations}/__init__.py +0 -0
  98. {drawio-python-0.1.0/drawio/entities/drawio_config → drawio_python-0.1.4/drawio/itergrations/mermaid}/__init__.py +0 -0
  99. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio_python.egg-info/dependency_links.txt +0 -0
  100. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio_python.egg-info/entry_points.txt +0 -0
  101. {drawio-python-0.1.0 → drawio_python-0.1.4}/drawio_python.egg-info/top_level.txt +0 -0
  102. {drawio-python-0.1.0 → drawio_python-0.1.4}/setup.cfg +0 -0
  103. {drawio-python-0.1.0 → drawio_python-0.1.4}/tests/__init__.py +0 -0
  104. {drawio-python-0.1.0 → drawio_python-0.1.4}/tests/test_base.py +0 -0
@@ -0,0 +1,41 @@
1
+ # Unreleased
2
+
3
+ - Render pages to PNG, SVG, PDF and JPEG on any OS: a built-in native renderer (SVG
4
+ with no dependencies, raster through Pillow), the draw.io desktop exporter, or the
5
+ official diagrams.net viewer in a headless browser.
6
+ - Add layout checks (`drawio lint`): overflowing text, overlaps, connectors through
7
+ shapes or labels, children outside containers, small text and aspect ratio for a
8
+ target size.
9
+ - Add automatic layout (`drawio.layout`: layered, row, column, grid), `page.fit()`,
10
+ `page.autosize()`, text metrics, named shapes, images, colour presets,
11
+ `Theme.drawio()`, arrow ends, absolute coordinates, cell geometry accessors,
12
+ `page.remove()`, `page.find()`, `Document.import_page()` and `remove_page()`.
13
+ - New CLI commands for agents, all with `--json`: render, lint, inspect, fit, layout,
14
+ merge, shapes, doctor and skill; ship an agent skill installable with
15
+ `drawio skill install`.
16
+ - Fix `save()` creating files with mode 0600; explain duplicate-ID clashes with
17
+ generated IDs.
18
+ - Add a standard-library XML API for documents, pages, nested containers,
19
+ editable shapes, port anchors and connector waypoints.
20
+ - Load existing uncompressed/compressed diagrams and append pages while retaining
21
+ existing XML and metadata.
22
+ - Render legacy Graph output to `.drawio` / `.xml` without Selenium; retain CSV,
23
+ text, optional PDF export and explicit browser helpers.
24
+ - Fix graph edge identity, child registration, repeated CSV output and CSV quoting.
25
+ - Preserve labels and circular nodes in the basic Mermaid importer; reject
26
+ unsupported syntax instead of silently dropping edges.
27
+ - Add an offline CLI, native examples, tests and a Python/OS CI matrix.
28
+
29
+ Changelog
30
+ =========
31
+
32
+
33
+ 0.1.2 (2021-08-14)
34
+ ------------------
35
+ - Fix release, README and windows CI. [Bruno Rocha]
36
+ - Release: version 0.1.0. [Bruno Rocha]
37
+
38
+
39
+ 0.1.0 (2021-08-14)
40
+ ------------------
41
+ - Add release command. [Bruno Rocha]
@@ -0,0 +1,11 @@
1
+ include LICENSE
2
+ include HISTORY.md
3
+ include Containerfile
4
+ include README.md
5
+ include requirements*.txt
6
+ include mkdocs.yml
7
+ graft examples
8
+ graft docs
9
+ graft tests
10
+ graft drawio
11
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.4
2
+ Name: drawio-python
3
+ Version: 0.1.4
4
+ Summary: Build, check and export editable draw.io diagrams in Python; made for people and agents
5
+ Home-page: https://github.com/maycuatroi1/drawio/
6
+ Author: Nguyen Anh Binh
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Provides-Extra: test
11
+ Requires-Dist: pytest>=7; extra == "test"
12
+ Requires-Dist: pytest-cov>=4; extra == "test"
13
+ Requires-Dist: ruff>=0.9; extra == "test"
14
+ Requires-Dist: build>=1; extra == "test"
15
+ Requires-Dist: Pillow>=9.1; extra == "test"
16
+ Provides-Extra: render
17
+ Requires-Dist: Pillow>=9.1; extra == "render"
18
+ Provides-Extra: browser-render
19
+ Requires-Dist: playwright>=1.40; extra == "browser-render"
20
+ Provides-Extra: browser
21
+ Requires-Dist: selenium>=4; extra == "browser"
22
+ Requires-Dist: webdriver-manager>=4; extra == "browser"
23
+ Provides-Extra: pdf
24
+ Requires-Dist: graphviz>=0.20; extra == "pdf"
25
+ Provides-Extra: excel
26
+ Requires-Dist: pandas>=1.5; extra == "excel"
27
+ Requires-Dist: xlsxwriter>=3; extra == "excel"
28
+ Provides-Extra: docs
29
+ Requires-Dist: mkdocs>=1.5; extra == "docs"
30
+ Dynamic: author
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license-file
35
+ Dynamic: provides-extra
36
+ Dynamic: requires-python
37
+ Dynamic: summary
38
+
39
+ # drawio-python
40
+
41
+ Build, check and export editable draw.io diagrams in Python. The library writes
42
+ native draw.io XML (every shape stays editable in draw.io), measures labels, finds
43
+ layout problems, lays shapes out, and renders PNG, SVG or PDF on Linux, macOS and
44
+ Windows. The core needs only the Python standard library; Python 3.9 or newer.
45
+
46
+ It is built to be driven by coding agents as much as by people: every command has
47
+ `--json` output, and an agent skill ships with the package.
48
+
49
+ ## Install
50
+
51
+ ```sh
52
+ pip install 'drawio-python[render]' # core + PNG/JPEG/PDF output (Pillow)
53
+ pip install drawio-python # core only: build, lint, SVG
54
+ pip install 'drawio-python[browser-render]' # exact rendering of any draw.io file
55
+ ```
56
+
57
+ From a checkout: `python -m pip install -e '.[render,test]'`. Check what the machine
58
+ can render with `drawio doctor`.
59
+
60
+ ## Agents
61
+
62
+ ```sh
63
+ drawio skill install # into ~/.claude/skills, ~/.codex/skills and/or ~/.agents/skills
64
+ drawio skill show # print the skill
65
+ ```
66
+
67
+ The skill (`drawio/skill/SKILL.md`) teaches the loop **build, `drawio lint`,
68
+ `drawio render`, look, fix**, the API, slide sizing and the common errors.
69
+
70
+ ## Create a diagram
71
+
72
+ ```python
73
+ from drawio import Document
74
+
75
+ document = Document()
76
+ page = document.add_page("Publishing", id="publishing")
77
+
78
+ source = page.box("Draft", 40, 180, id="draft")
79
+ library = page.container("Library", 500, 80, 350, 350, id="library")
80
+ articles = page.box("Articles", 20, 70, 310, 70, parent=library)
81
+ page.box("Images", 20, 180, 310, 70, parent=library)
82
+
83
+ page.connect(
84
+ source, articles, "publish",
85
+ source_port=(1, 0.5), target_port=(0, 0.5),
86
+ waypoints=[(370, 225), (370, 185)],
87
+ )
88
+
89
+ document.add_page("Notes").text("A second editable tab", 40, 40)
90
+ document.validate(check_bounds=True)
91
+ document.save("publishing.drawio")
92
+ ```
93
+
94
+ Open the file in draw.io or diagrams.net. Each block and connector remains a
95
+ native editable object. Child coordinates are relative to the parent container;
96
+ connector waypoints use page coordinates.
97
+
98
+ `save()` refuses to replace an existing file. Pass `overwrite=True` when you
99
+ intend to update it. File writing uses an atomic replace or exclusive creation.
100
+
101
+ ## Add a page to an existing file
102
+
103
+ ```python
104
+ from drawio import Document
105
+
106
+ document = Document.load("publishing.drawio")
107
+ page = document.add_page("Review Details", id="review-details")
108
+ page.box("Editorial review", 40, 80)
109
+ document.save("publishing-v2.drawio")
110
+ ```
111
+
112
+ The loader accepts uncompressed and compressed draw.io XML. It retains existing
113
+ page IDs, cells, geometry and metadata; it expands compressed pages on output.
114
+ It does not preserve byte-for-byte formatting, signatures or compression.
115
+
116
+ ## Style and labels
117
+
118
+ ```python
119
+ from drawio import Document, Theme
120
+
121
+ document = Document(theme=Theme(font_family="Arial", font_size=20))
122
+ page = document.add_page("Styled")
123
+ page.box("Plain text: A & B < C", 40, 40,
124
+ style={"fillColor": "#e7effb", "fontStyle": 1})
125
+ page.box("<b>Trusted HTML</b><br/>Subtitle", 300, 40, html=True)
126
+ ```
127
+
128
+ Labels default to plain text. Use `html=True` only for markup you trust. Style
129
+ mappings use draw.io property names such as `fillColor`, `shape` and `fontSize`.
130
+ XML escaping is handled by the writer.
131
+
132
+ ## Shapes, layout and fitting text
133
+
134
+ ```python
135
+ from drawio import Document, Theme
136
+ from drawio.layout import layered
137
+ from drawio.shapes import color
138
+
139
+ doc = Document(theme=Theme.drawio()) # the draw.io editor's own look
140
+ page = doc.add_page("Flow")
141
+ start = page.box("Start", 0, 0, 120, 50, shape="rounded", style=color("green"))
142
+ check = page.box("Valid?", 0, 0, 120, 80, shape="rhombus")
143
+ store = page.box("Orders", 0, 0, 120, 80, shape="cylinder", style=color("yellow"))
144
+ page.connect(start, check)
145
+ page.connect(check, store, "yes")
146
+ layered(page, direction="down") # ranks along the connectors; also row/column/grid
147
+ page.fit() # grow containers and the page around the shapes
148
+ doc.save("flow.drawio", overwrite=True)
149
+ ```
150
+
151
+ - `shape=` accepts `rounded, ellipse, circle, rhombus, cylinder, hexagon, triangle,
152
+ parallelogram, document, cloud, process, note, card, step, actor` or any draw.io
153
+ shape name; `page.image()` embeds a picture file.
154
+ - `connect(..., arrow=None)` draws an undirected line; `arrow` and `start_arrow` take
155
+ any draw.io marker (`drawio shapes` lists them).
156
+ - `box(..., absolute=True)` takes page coordinates inside a container;
157
+ `box(..., autosize=True)` or `page.autosize(cell)` grows a box to fit its label.
158
+ - Cells expose `x`, `y`, `width`, `height`, `bounds`, `style`, `text`, `move()`,
159
+ `resize()`, `set_style()`; pages offer `find()`, `children()`, `remove()`;
160
+ documents offer `import_page()` and `remove_page()`.
161
+
162
+ ## Check the layout
163
+
164
+ ```sh
165
+ drawio lint flow.drawio # exit status 1 when something is wrong
166
+ drawio lint deck.drawio --fit 8.15x4.85in # also: text below 12 pt once placed on a slide
167
+ drawio inspect flow.drawio --json # every shape box and connector route
168
+ ```
169
+
170
+ Lint reports overflowing labels, overlapping shapes and labels, connectors that run
171
+ through shapes or labels, children outside containers, and (with `--fit`) text that
172
+ ends up too small and aspect-ratio mismatches. Text widths are estimated from
173
+ Helvetica/Arial metrics, close to draw.io's wrapping.
174
+
175
+ ## Render
176
+
177
+ ```sh
178
+ drawio render flow.drawio -o flow.png --scale 2
179
+ drawio render flow.drawio -o flow.svg # plain SVG text, no foreignObject
180
+ drawio render deck.drawio -o slide.png --aspect 16:9
181
+ drawio render big.drawio --all-pages -f pdf
182
+ ```
183
+
184
+ | Backend | Requirements | Output |
185
+ |---|---|---|
186
+ | `native` | none for SVG; Pillow for PNG, JPEG, PDF | shapes this library makes and common draw.io shapes |
187
+ | `desktop` | [draw.io desktop](https://github.com/jgraph/drawio-desktop/releases) | exact |
188
+ | `browser` | `[browser-render]` extra plus Chrome, Edge or `playwright install chromium` | exact, including stencils and icons |
189
+ | `auto` | | desktop when installed, otherwise native |
190
+
191
+ The browser backend loads the official diagrams.net viewer, downloaded once to the
192
+ user cache (set `DRAWIO_VIEWER_JS` to work offline). On Linux the desktop backend
193
+ needs a display or `xvfb-run`. Native PDF is vector when `cairosvg` or `rsvg-convert`
194
+ is available, otherwise a raster image. `drawio doctor` reports all of this.
195
+
196
+ ## CLI
197
+
198
+ ```sh
199
+ drawio new empty.drawio --name Overview
200
+ drawio validate publishing.drawio --check-bounds
201
+ drawio info publishing.drawio
202
+ drawio url publishing.drawio
203
+ drawio render | lint | inspect | fit | layout | merge | shapes | doctor | skill
204
+ ```
205
+
206
+ `python -m drawio` runs the same commands, which helps when the draw.io desktop
207
+ app also installed a `drawio` command. Commands that report take `--json`. `url` prints an editor
208
+ link containing the complete diagram. Generating the URL makes no network
209
+ request; anyone with the link can read its embedded content.
210
+
211
+ For an open editor's **Extras > Edit Diagram** dialog, use `page.to_xml()` to
212
+ obtain that page's `mxGraphModel`. Importing through that dialog may retain the
213
+ editor's current Grid, Page View and Background settings.
214
+
215
+ ## Existing Graph / Node API
216
+
217
+ ```python
218
+ from drawio import Graph, Node
219
+
220
+ graph = Graph(name="Review")
221
+ a = Node("Draft", shape="rectangle", x=40, y=80)
222
+ b = Node("Published", shape="rectangle", x=400, y=80)
223
+ graph.add_nodes([a, b])
224
+ a >> "approve" >> b
225
+
226
+ graph.render("review.drawio", show=False)
227
+ ```
228
+
229
+ `.drawio` and `.xml` rendering now uses the native writer and returns the output
230
+ path. `Graph.render()` retains its overwrite behavior. `show=True` saves first,
231
+ then asks the default browser to open an encoded editor URL; it no longer waits
232
+ for console input. Tests and examples use `show=False`.
233
+
234
+ Unpositioned legacy nodes use a simple grid, including disconnected graphs and
235
+ cycles. Use `Node(x=..., y=...)` or the native `Page` API with `drawio.layout` for
236
+ an authored or automatic layout.
237
+
238
+ `to_draw_io_csv()` and `to_draw_io()` still return the legacy CSV and text forms.
239
+ The basic Mermaid importer retains the historical import path:
240
+
241
+ ```python
242
+ from drawio.itergrations.mermaid.mermaid_controller import MermaidController
243
+
244
+ graph = MermaidController().load("flowchart LR; A[Draft] -->|approve| B[Published]")
245
+ graph.render("mermaid.drawio")
246
+ ```
247
+
248
+ Supported Mermaid input includes node declarations, `-->`, `-->|label|`, chained
249
+ edges, and rectangular, circular, parenthesized and diamond node labels. Direction
250
+ headers are accepted, but the legacy renderer uses the grid described above.
251
+ Subgraphs, styling directives and other edge syntax raise errors rather than
252
+ silently dropping content. This importer is not a complete Mermaid parser.
253
+
254
+ ## Examples and optional integrations
255
+
256
+ ```sh
257
+ python examples/native_document.py
258
+ python examples/complex-example.py
259
+ ```
260
+
261
+ The first example writes `output/publishing.drawio` with two tabs and nested
262
+ containers. The second demonstrates loading a file and adding a page.
263
+
264
+ Optional extras:
265
+
266
+ - `.[render]`: Pillow, for PNG, JPEG and PDF output of the native renderer.
267
+ - `.[browser-render]`: Playwright, for the exact `browser` render backend.
268
+ - `.[pdf]`: Python Graphviz binding; also install the Graphviz `dot` executable.
269
+ - `.[browser]`: legacy Selenium helpers for callers importing `DrawIOBrowser`
270
+ directly. They are not part of native rendering and are not live-browser
271
+ tested by the default suite.
272
+ - `.[excel]`: dependencies for the existing ERD spreadsheet exporter.
273
+ - `.[docs]`: MkDocs.
274
+
275
+ ## Development
276
+
277
+ ```sh
278
+ make lint
279
+ make test
280
+ make build
281
+ ```
282
+
283
+ Tests write real XML, render with the native backend and run examples in
284
+ temporary directories. They do not install packages, download browser drivers, or
285
+ launch Chrome. See
286
+ [the API reference](docs/index.md) and [contribution guide](CONTRIBUTING.md).
@@ -0,0 +1,248 @@
1
+ # drawio-python
2
+
3
+ Build, check and export editable draw.io diagrams in Python. The library writes
4
+ native draw.io XML (every shape stays editable in draw.io), measures labels, finds
5
+ layout problems, lays shapes out, and renders PNG, SVG or PDF on Linux, macOS and
6
+ Windows. The core needs only the Python standard library; Python 3.9 or newer.
7
+
8
+ It is built to be driven by coding agents as much as by people: every command has
9
+ `--json` output, and an agent skill ships with the package.
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ pip install 'drawio-python[render]' # core + PNG/JPEG/PDF output (Pillow)
15
+ pip install drawio-python # core only: build, lint, SVG
16
+ pip install 'drawio-python[browser-render]' # exact rendering of any draw.io file
17
+ ```
18
+
19
+ From a checkout: `python -m pip install -e '.[render,test]'`. Check what the machine
20
+ can render with `drawio doctor`.
21
+
22
+ ## Agents
23
+
24
+ ```sh
25
+ drawio skill install # into ~/.claude/skills, ~/.codex/skills and/or ~/.agents/skills
26
+ drawio skill show # print the skill
27
+ ```
28
+
29
+ The skill (`drawio/skill/SKILL.md`) teaches the loop **build, `drawio lint`,
30
+ `drawio render`, look, fix**, the API, slide sizing and the common errors.
31
+
32
+ ## Create a diagram
33
+
34
+ ```python
35
+ from drawio import Document
36
+
37
+ document = Document()
38
+ page = document.add_page("Publishing", id="publishing")
39
+
40
+ source = page.box("Draft", 40, 180, id="draft")
41
+ library = page.container("Library", 500, 80, 350, 350, id="library")
42
+ articles = page.box("Articles", 20, 70, 310, 70, parent=library)
43
+ page.box("Images", 20, 180, 310, 70, parent=library)
44
+
45
+ page.connect(
46
+ source, articles, "publish",
47
+ source_port=(1, 0.5), target_port=(0, 0.5),
48
+ waypoints=[(370, 225), (370, 185)],
49
+ )
50
+
51
+ document.add_page("Notes").text("A second editable tab", 40, 40)
52
+ document.validate(check_bounds=True)
53
+ document.save("publishing.drawio")
54
+ ```
55
+
56
+ Open the file in draw.io or diagrams.net. Each block and connector remains a
57
+ native editable object. Child coordinates are relative to the parent container;
58
+ connector waypoints use page coordinates.
59
+
60
+ `save()` refuses to replace an existing file. Pass `overwrite=True` when you
61
+ intend to update it. File writing uses an atomic replace or exclusive creation.
62
+
63
+ ## Add a page to an existing file
64
+
65
+ ```python
66
+ from drawio import Document
67
+
68
+ document = Document.load("publishing.drawio")
69
+ page = document.add_page("Review Details", id="review-details")
70
+ page.box("Editorial review", 40, 80)
71
+ document.save("publishing-v2.drawio")
72
+ ```
73
+
74
+ The loader accepts uncompressed and compressed draw.io XML. It retains existing
75
+ page IDs, cells, geometry and metadata; it expands compressed pages on output.
76
+ It does not preserve byte-for-byte formatting, signatures or compression.
77
+
78
+ ## Style and labels
79
+
80
+ ```python
81
+ from drawio import Document, Theme
82
+
83
+ document = Document(theme=Theme(font_family="Arial", font_size=20))
84
+ page = document.add_page("Styled")
85
+ page.box("Plain text: A & B < C", 40, 40,
86
+ style={"fillColor": "#e7effb", "fontStyle": 1})
87
+ page.box("<b>Trusted HTML</b><br/>Subtitle", 300, 40, html=True)
88
+ ```
89
+
90
+ Labels default to plain text. Use `html=True` only for markup you trust. Style
91
+ mappings use draw.io property names such as `fillColor`, `shape` and `fontSize`.
92
+ XML escaping is handled by the writer.
93
+
94
+ ## Shapes, layout and fitting text
95
+
96
+ ```python
97
+ from drawio import Document, Theme
98
+ from drawio.layout import layered
99
+ from drawio.shapes import color
100
+
101
+ doc = Document(theme=Theme.drawio()) # the draw.io editor's own look
102
+ page = doc.add_page("Flow")
103
+ start = page.box("Start", 0, 0, 120, 50, shape="rounded", style=color("green"))
104
+ check = page.box("Valid?", 0, 0, 120, 80, shape="rhombus")
105
+ store = page.box("Orders", 0, 0, 120, 80, shape="cylinder", style=color("yellow"))
106
+ page.connect(start, check)
107
+ page.connect(check, store, "yes")
108
+ layered(page, direction="down") # ranks along the connectors; also row/column/grid
109
+ page.fit() # grow containers and the page around the shapes
110
+ doc.save("flow.drawio", overwrite=True)
111
+ ```
112
+
113
+ - `shape=` accepts `rounded, ellipse, circle, rhombus, cylinder, hexagon, triangle,
114
+ parallelogram, document, cloud, process, note, card, step, actor` or any draw.io
115
+ shape name; `page.image()` embeds a picture file.
116
+ - `connect(..., arrow=None)` draws an undirected line; `arrow` and `start_arrow` take
117
+ any draw.io marker (`drawio shapes` lists them).
118
+ - `box(..., absolute=True)` takes page coordinates inside a container;
119
+ `box(..., autosize=True)` or `page.autosize(cell)` grows a box to fit its label.
120
+ - Cells expose `x`, `y`, `width`, `height`, `bounds`, `style`, `text`, `move()`,
121
+ `resize()`, `set_style()`; pages offer `find()`, `children()`, `remove()`;
122
+ documents offer `import_page()` and `remove_page()`.
123
+
124
+ ## Check the layout
125
+
126
+ ```sh
127
+ drawio lint flow.drawio # exit status 1 when something is wrong
128
+ drawio lint deck.drawio --fit 8.15x4.85in # also: text below 12 pt once placed on a slide
129
+ drawio inspect flow.drawio --json # every shape box and connector route
130
+ ```
131
+
132
+ Lint reports overflowing labels, overlapping shapes and labels, connectors that run
133
+ through shapes or labels, children outside containers, and (with `--fit`) text that
134
+ ends up too small and aspect-ratio mismatches. Text widths are estimated from
135
+ Helvetica/Arial metrics, close to draw.io's wrapping.
136
+
137
+ ## Render
138
+
139
+ ```sh
140
+ drawio render flow.drawio -o flow.png --scale 2
141
+ drawio render flow.drawio -o flow.svg # plain SVG text, no foreignObject
142
+ drawio render deck.drawio -o slide.png --aspect 16:9
143
+ drawio render big.drawio --all-pages -f pdf
144
+ ```
145
+
146
+ | Backend | Requirements | Output |
147
+ |---|---|---|
148
+ | `native` | none for SVG; Pillow for PNG, JPEG, PDF | shapes this library makes and common draw.io shapes |
149
+ | `desktop` | [draw.io desktop](https://github.com/jgraph/drawio-desktop/releases) | exact |
150
+ | `browser` | `[browser-render]` extra plus Chrome, Edge or `playwright install chromium` | exact, including stencils and icons |
151
+ | `auto` | | desktop when installed, otherwise native |
152
+
153
+ The browser backend loads the official diagrams.net viewer, downloaded once to the
154
+ user cache (set `DRAWIO_VIEWER_JS` to work offline). On Linux the desktop backend
155
+ needs a display or `xvfb-run`. Native PDF is vector when `cairosvg` or `rsvg-convert`
156
+ is available, otherwise a raster image. `drawio doctor` reports all of this.
157
+
158
+ ## CLI
159
+
160
+ ```sh
161
+ drawio new empty.drawio --name Overview
162
+ drawio validate publishing.drawio --check-bounds
163
+ drawio info publishing.drawio
164
+ drawio url publishing.drawio
165
+ drawio render | lint | inspect | fit | layout | merge | shapes | doctor | skill
166
+ ```
167
+
168
+ `python -m drawio` runs the same commands, which helps when the draw.io desktop
169
+ app also installed a `drawio` command. Commands that report take `--json`. `url` prints an editor
170
+ link containing the complete diagram. Generating the URL makes no network
171
+ request; anyone with the link can read its embedded content.
172
+
173
+ For an open editor's **Extras > Edit Diagram** dialog, use `page.to_xml()` to
174
+ obtain that page's `mxGraphModel`. Importing through that dialog may retain the
175
+ editor's current Grid, Page View and Background settings.
176
+
177
+ ## Existing Graph / Node API
178
+
179
+ ```python
180
+ from drawio import Graph, Node
181
+
182
+ graph = Graph(name="Review")
183
+ a = Node("Draft", shape="rectangle", x=40, y=80)
184
+ b = Node("Published", shape="rectangle", x=400, y=80)
185
+ graph.add_nodes([a, b])
186
+ a >> "approve" >> b
187
+
188
+ graph.render("review.drawio", show=False)
189
+ ```
190
+
191
+ `.drawio` and `.xml` rendering now uses the native writer and returns the output
192
+ path. `Graph.render()` retains its overwrite behavior. `show=True` saves first,
193
+ then asks the default browser to open an encoded editor URL; it no longer waits
194
+ for console input. Tests and examples use `show=False`.
195
+
196
+ Unpositioned legacy nodes use a simple grid, including disconnected graphs and
197
+ cycles. Use `Node(x=..., y=...)` or the native `Page` API with `drawio.layout` for
198
+ an authored or automatic layout.
199
+
200
+ `to_draw_io_csv()` and `to_draw_io()` still return the legacy CSV and text forms.
201
+ The basic Mermaid importer retains the historical import path:
202
+
203
+ ```python
204
+ from drawio.itergrations.mermaid.mermaid_controller import MermaidController
205
+
206
+ graph = MermaidController().load("flowchart LR; A[Draft] -->|approve| B[Published]")
207
+ graph.render("mermaid.drawio")
208
+ ```
209
+
210
+ Supported Mermaid input includes node declarations, `-->`, `-->|label|`, chained
211
+ edges, and rectangular, circular, parenthesized and diamond node labels. Direction
212
+ headers are accepted, but the legacy renderer uses the grid described above.
213
+ Subgraphs, styling directives and other edge syntax raise errors rather than
214
+ silently dropping content. This importer is not a complete Mermaid parser.
215
+
216
+ ## Examples and optional integrations
217
+
218
+ ```sh
219
+ python examples/native_document.py
220
+ python examples/complex-example.py
221
+ ```
222
+
223
+ The first example writes `output/publishing.drawio` with two tabs and nested
224
+ containers. The second demonstrates loading a file and adding a page.
225
+
226
+ Optional extras:
227
+
228
+ - `.[render]`: Pillow, for PNG, JPEG and PDF output of the native renderer.
229
+ - `.[browser-render]`: Playwright, for the exact `browser` render backend.
230
+ - `.[pdf]`: Python Graphviz binding; also install the Graphviz `dot` executable.
231
+ - `.[browser]`: legacy Selenium helpers for callers importing `DrawIOBrowser`
232
+ directly. They are not part of native rendering and are not live-browser
233
+ tested by the default suite.
234
+ - `.[excel]`: dependencies for the existing ERD spreadsheet exporter.
235
+ - `.[docs]`: MkDocs.
236
+
237
+ ## Development
238
+
239
+ ```sh
240
+ make lint
241
+ make test
242
+ make build
243
+ ```
244
+
245
+ Tests write real XML, render with the native backend and run examples in
246
+ temporary directories. They do not install packages, download browser drivers, or
247
+ launch Chrome. See
248
+ [the API reference](docs/index.md) and [contribution guide](CONTRIBUTING.md).