drawio-python 0.1.0__tar.gz → 0.1.3__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.
- drawio_python-0.1.3/HISTORY.md +26 -0
- drawio_python-0.1.3/MANIFEST.in +11 -0
- drawio_python-0.1.3/PKG-INFO +199 -0
- drawio_python-0.1.3/README.md +166 -0
- drawio_python-0.1.3/docs/index.md +109 -0
- drawio_python-0.1.3/drawio/VERSION +1 -0
- drawio_python-0.1.3/drawio/__init__.py +5 -0
- drawio_python-0.1.3/drawio/__main__.py +6 -0
- drawio_python-0.1.3/drawio/cli.py +60 -0
- drawio_python-0.1.3/drawio/document.py +556 -0
- drawio_python-0.1.3/drawio/entities/__init__.py +4 -0
- drawio_python-0.1.3/drawio/entities/base_entity.py +9 -0
- drawio_python-0.1.3/drawio/entities/config.py +1 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio.py +4 -2
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_app.py +3 -9
- drawio_python-0.1.3/drawio/entities/drawio_browser.py +235 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/abstract_config.py +2 -2
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/drawio_config.py +13 -1
- drawio_python-0.1.3/drawio/entities/drawio_config/label_config.py +5 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/column.py +2 -1
- drawio_python-0.1.3/drawio/entities/erd/erd.py +67 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/table.py +3 -3
- drawio_python-0.1.3/drawio/entities/graph/__init__.py +5 -0
- drawio_python-0.1.3/drawio/entities/graph/edge.py +33 -0
- drawio_python-0.1.3/drawio/entities/graph/graph.py +147 -0
- drawio_python-0.1.3/drawio/entities/graph/node.py +92 -0
- drawio_python-0.1.3/drawio/entities/logger.py +8 -0
- drawio_python-0.1.3/drawio/entities/renderers/__init__.py +7 -0
- drawio_python-0.1.3/drawio/entities/renderers/base_render.py +24 -0
- drawio_python-0.1.3/drawio/entities/renderers/drawio_render.py +16 -0
- drawio_python-0.1.3/drawio/entities/renderers/pdf_render.py +59 -0
- drawio_python-0.1.3/drawio/itergrations/mermaid/mermaid_controller.py +108 -0
- drawio_python-0.1.3/drawio_python.egg-info/PKG-INFO +199 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/SOURCES.txt +29 -1
- drawio_python-0.1.3/drawio_python.egg-info/requires.txt +20 -0
- drawio_python-0.1.3/examples/complex-example.py +16 -0
- drawio_python-0.1.3/examples/draw-flow-diagrams.png +0 -0
- drawio_python-0.1.3/examples/draw-flow-diagrams.py +18 -0
- drawio_python-0.1.3/examples/mermaid-to-drawio.py +19 -0
- drawio_python-0.1.3/examples/native_document.py +65 -0
- drawio_python-0.1.3/mkdocs.yml +2 -0
- drawio_python-0.1.3/pyproject.toml +16 -0
- drawio_python-0.1.3/requirements-test.txt +4 -0
- drawio_python-0.1.3/requirements.txt +2 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/setup.py +14 -6
- drawio_python-0.1.3/tests/conftest.py +6 -0
- drawio_python-0.1.3/tests/test_cli.py +46 -0
- drawio_python-0.1.3/tests/test_document.py +335 -0
- drawio_python-0.1.3/tests/test_examples.py +27 -0
- drawio_python-0.1.3/tests/test_graph.py +20 -0
- drawio_python-0.1.3/tests/test_graph_native.py +126 -0
- drawio_python-0.1.3/tests/test_imports.py +8 -0
- drawio_python-0.1.3/tests/test_mermaid.py +85 -0
- drawio-python-0.1.0/HISTORY.md +0 -13
- drawio-python-0.1.0/MANIFEST.in +0 -5
- drawio-python-0.1.0/PKG-INFO +0 -23
- drawio-python-0.1.0/README.md +0 -14
- drawio-python-0.1.0/drawio/VERSION +0 -1
- drawio-python-0.1.0/drawio/__main__.py +0 -6
- drawio-python-0.1.0/drawio/cli.py +0 -28
- drawio-python-0.1.0/drawio/entities/config.py +0 -2
- drawio-python-0.1.0/drawio/entities/drawio_browser.py +0 -89
- drawio-python-0.1.0/drawio/entities/erd/erd.py +0 -22
- drawio-python-0.1.0/drawio/entities/graph/__init__.py +0 -1
- drawio-python-0.1.0/drawio/entities/graph/edge.py +0 -30
- drawio-python-0.1.0/drawio/entities/graph/graph.py +0 -134
- drawio-python-0.1.0/drawio/entities/graph/node.py +0 -91
- drawio-python-0.1.0/drawio_python.egg-info/PKG-INFO +0 -23
- drawio-python-0.1.0/drawio_python.egg-info/requires.txt +0 -12
- drawio-python-0.1.0/tests/conftest.py +0 -14
- {drawio-python-0.1.0 → drawio_python-0.1.3}/Containerfile +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/LICENSE +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/base.py +0 -0
- {drawio-python-0.1.0/drawio → drawio_python-0.1.3/drawio/controllers}/__init__.py +0 -0
- {drawio-python-0.1.0/drawio/controllers → drawio_python-0.1.3/drawio/entities/drawio_config}/__init__.py +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/connect_config.py +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/__init__.py +0 -0
- {drawio-python-0.1.0/drawio/entities → drawio_python-0.1.3/drawio/itergrations}/__init__.py +0 -0
- {drawio-python-0.1.0/drawio/entities/drawio_config → drawio_python-0.1.3/drawio/itergrations/mermaid}/__init__.py +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/dependency_links.txt +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/entry_points.txt +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/top_level.txt +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/setup.cfg +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/tests/__init__.py +0 -0
- {drawio-python-0.1.0 → drawio_python-0.1.3}/tests/test_base.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Unreleased
|
|
2
|
+
|
|
3
|
+
- Add a standard-library XML API for documents, pages, nested containers,
|
|
4
|
+
editable shapes, port anchors and connector waypoints.
|
|
5
|
+
- Load existing uncompressed/compressed diagrams and append pages while retaining
|
|
6
|
+
existing XML and metadata.
|
|
7
|
+
- Render legacy Graph output to `.drawio` / `.xml` without Selenium; retain CSV,
|
|
8
|
+
text, optional PDF export and explicit browser helpers.
|
|
9
|
+
- Fix graph edge identity, child registration, repeated CSV output and CSV quoting.
|
|
10
|
+
- Preserve labels and circular nodes in the basic Mermaid importer; reject
|
|
11
|
+
unsupported syntax instead of silently dropping edges.
|
|
12
|
+
- Add an offline CLI, native examples, tests and a Python/OS CI matrix.
|
|
13
|
+
|
|
14
|
+
Changelog
|
|
15
|
+
=========
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
0.1.2 (2021-08-14)
|
|
19
|
+
------------------
|
|
20
|
+
- Fix release, README and windows CI. [Bruno Rocha]
|
|
21
|
+
- Release: version 0.1.0. [Bruno Rocha]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
0.1.0 (2021-08-14)
|
|
25
|
+
------------------
|
|
26
|
+
- Add release command. [Bruno Rocha]
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drawio-python
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Create editable, multi-page draw.io diagrams with native Python XML
|
|
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
|
+
Provides-Extra: browser
|
|
16
|
+
Requires-Dist: selenium>=4; extra == "browser"
|
|
17
|
+
Requires-Dist: webdriver-manager>=4; extra == "browser"
|
|
18
|
+
Provides-Extra: pdf
|
|
19
|
+
Requires-Dist: graphviz>=0.20; extra == "pdf"
|
|
20
|
+
Provides-Extra: excel
|
|
21
|
+
Requires-Dist: pandas>=1.5; extra == "excel"
|
|
22
|
+
Requires-Dist: xlsxwriter>=3; extra == "excel"
|
|
23
|
+
Provides-Extra: docs
|
|
24
|
+
Requires-Dist: mkdocs>=1.5; extra == "docs"
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
Dynamic: provides-extra
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
# drawio-python
|
|
35
|
+
|
|
36
|
+
Build editable draw.io diagrams in Python. Save XML files without Selenium,
|
|
37
|
+
Chrome, an export server, or runtime dependencies. Requires Python 3.9 or newer.
|
|
38
|
+
|
|
39
|
+
The native API supports multiple pages, nested containers, styled shapes,
|
|
40
|
+
connector ports and waypoints. The existing `Graph` / `Node` API still works.
|
|
41
|
+
|
|
42
|
+
## Install this checkout
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
python3 -m venv .venv
|
|
46
|
+
source .venv/bin/activate
|
|
47
|
+
python -m pip install -e '.[test]'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
These instructions use the updated source. The version on PyPI may differ.
|
|
51
|
+
|
|
52
|
+
## Create a diagram
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from drawio import Document
|
|
56
|
+
|
|
57
|
+
document = Document()
|
|
58
|
+
page = document.add_page("Publishing", id="publishing")
|
|
59
|
+
|
|
60
|
+
source = page.box("Draft", 40, 180, id="draft")
|
|
61
|
+
library = page.container("Library", 500, 80, 350, 350, id="library")
|
|
62
|
+
articles = page.box("Articles", 20, 70, 310, 70, parent=library)
|
|
63
|
+
page.box("Images", 20, 180, 310, 70, parent=library)
|
|
64
|
+
|
|
65
|
+
page.connect(
|
|
66
|
+
source, articles, "publish",
|
|
67
|
+
source_port=(1, 0.5), target_port=(0, 0.5),
|
|
68
|
+
waypoints=[(370, 225), (370, 185)],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
document.add_page("Notes").text("A second editable tab", 40, 40)
|
|
72
|
+
document.validate(check_bounds=True)
|
|
73
|
+
document.save("publishing.drawio")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Open the file in draw.io or diagrams.net. Each block and connector remains a
|
|
77
|
+
native editable object. Child coordinates are relative to the parent container;
|
|
78
|
+
connector waypoints use page coordinates.
|
|
79
|
+
|
|
80
|
+
`save()` refuses to replace an existing file. Pass `overwrite=True` when you
|
|
81
|
+
intend to update it. File writing uses an atomic replace or exclusive creation.
|
|
82
|
+
|
|
83
|
+
## Add a page to an existing file
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from drawio import Document
|
|
87
|
+
|
|
88
|
+
document = Document.load("publishing.drawio")
|
|
89
|
+
page = document.add_page("Review Details", id="review-details")
|
|
90
|
+
page.box("Editorial review", 40, 80)
|
|
91
|
+
document.save("publishing-v2.drawio")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The loader accepts uncompressed and compressed draw.io XML. It retains existing
|
|
95
|
+
page IDs, cells, geometry and metadata; it expands compressed pages on output.
|
|
96
|
+
It does not preserve byte-for-byte formatting, signatures or compression.
|
|
97
|
+
|
|
98
|
+
## Style and labels
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from drawio import Document, Theme
|
|
102
|
+
|
|
103
|
+
document = Document(theme=Theme(font_family="Arial", font_size=20))
|
|
104
|
+
page = document.add_page("Styled")
|
|
105
|
+
page.box("Plain text: A & B < C", 40, 40,
|
|
106
|
+
style={"fillColor": "#e7effb", "fontStyle": 1})
|
|
107
|
+
page.box("<b>Trusted HTML</b><br/>Subtitle", 300, 40, html=True)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Labels default to plain text. Use `html=True` only for markup you trust. Style
|
|
111
|
+
mappings use draw.io property names such as `fillColor`, `shape` and `fontSize`.
|
|
112
|
+
XML escaping is handled by the writer.
|
|
113
|
+
|
|
114
|
+
## CLI
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
python -m drawio new empty.drawio --name Overview
|
|
118
|
+
python -m drawio validate publishing.drawio --check-bounds
|
|
119
|
+
python -m drawio info publishing.drawio
|
|
120
|
+
python -m drawio url publishing.drawio
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The installed `drawio` command exposes the same interface. `url` prints an editor
|
|
124
|
+
link containing the complete diagram. Generating the URL makes no network
|
|
125
|
+
request; anyone with the link can read its embedded content.
|
|
126
|
+
|
|
127
|
+
For an open editor's **Extras > Edit Diagram** dialog, use `page.to_xml()` to
|
|
128
|
+
obtain that page's `mxGraphModel`. Importing through that dialog may retain the
|
|
129
|
+
editor's current Grid, Page View and Background settings.
|
|
130
|
+
|
|
131
|
+
## Existing Graph / Node API
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from drawio import Graph, Node
|
|
135
|
+
|
|
136
|
+
graph = Graph(name="Review")
|
|
137
|
+
a = Node("Draft", shape="rectangle", x=40, y=80)
|
|
138
|
+
b = Node("Published", shape="rectangle", x=400, y=80)
|
|
139
|
+
graph.add_nodes([a, b])
|
|
140
|
+
a >> "approve" >> b
|
|
141
|
+
|
|
142
|
+
graph.render("review.drawio", show=False)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`.drawio` and `.xml` rendering now uses the native writer and returns the output
|
|
146
|
+
path. `Graph.render()` retains its overwrite behavior. `show=True` saves first,
|
|
147
|
+
then asks the default browser to open an encoded editor URL; it no longer waits
|
|
148
|
+
for console input. Tests and examples use `show=False`.
|
|
149
|
+
|
|
150
|
+
Unpositioned legacy nodes use a simple grid, including disconnected graphs and
|
|
151
|
+
cycles. Use `Node(x=..., y=...)` or the native `Page` API for an authored layout.
|
|
152
|
+
The library does not provide automatic graph layout or SVG/PNG rendering.
|
|
153
|
+
|
|
154
|
+
`to_draw_io_csv()` and `to_draw_io()` still return the legacy CSV and text forms.
|
|
155
|
+
The basic Mermaid importer retains the historical import path:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from drawio.itergrations.mermaid.mermaid_controller import MermaidController
|
|
159
|
+
|
|
160
|
+
graph = MermaidController().load("flowchart LR; A[Draft] -->|approve| B[Published]")
|
|
161
|
+
graph.render("mermaid.drawio")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Supported Mermaid input includes node declarations, `-->`, `-->|label|`, chained
|
|
165
|
+
edges, and rectangular, circular, parenthesized and diamond node labels. Direction
|
|
166
|
+
headers are accepted, but the legacy renderer uses the grid described above.
|
|
167
|
+
Subgraphs, styling directives and other edge syntax raise errors rather than
|
|
168
|
+
silently dropping content. This importer is not a complete Mermaid parser.
|
|
169
|
+
|
|
170
|
+
## Examples and optional integrations
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
python examples/native_document.py
|
|
174
|
+
python examples/complex-example.py
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The first example writes `output/publishing.drawio` with two tabs and nested
|
|
178
|
+
containers. The second demonstrates loading a file and adding a page.
|
|
179
|
+
|
|
180
|
+
Optional extras:
|
|
181
|
+
|
|
182
|
+
- `.[pdf]`: Python Graphviz binding; also install the Graphviz `dot` executable.
|
|
183
|
+
- `.[browser]`: legacy Selenium helpers for callers importing `DrawIOBrowser`
|
|
184
|
+
directly. They are not part of native rendering and are not live-browser
|
|
185
|
+
tested by the default suite.
|
|
186
|
+
- `.[excel]`: dependencies for the existing ERD spreadsheet exporter.
|
|
187
|
+
- `.[docs]`: MkDocs.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
make lint
|
|
193
|
+
make test
|
|
194
|
+
make build
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Tests write real XML and run examples in temporary directories. They do not
|
|
198
|
+
install packages, download browser drivers, or launch Chrome. See
|
|
199
|
+
[the API reference](docs/index.md) and [contribution guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# drawio-python
|
|
2
|
+
|
|
3
|
+
Build editable draw.io diagrams in Python. Save XML files without Selenium,
|
|
4
|
+
Chrome, an export server, or runtime dependencies. Requires Python 3.9 or newer.
|
|
5
|
+
|
|
6
|
+
The native API supports multiple pages, nested containers, styled shapes,
|
|
7
|
+
connector ports and waypoints. The existing `Graph` / `Node` API still works.
|
|
8
|
+
|
|
9
|
+
## Install this checkout
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
python3 -m venv .venv
|
|
13
|
+
source .venv/bin/activate
|
|
14
|
+
python -m pip install -e '.[test]'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
These instructions use the updated source. The version on PyPI may differ.
|
|
18
|
+
|
|
19
|
+
## Create a diagram
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from drawio import Document
|
|
23
|
+
|
|
24
|
+
document = Document()
|
|
25
|
+
page = document.add_page("Publishing", id="publishing")
|
|
26
|
+
|
|
27
|
+
source = page.box("Draft", 40, 180, id="draft")
|
|
28
|
+
library = page.container("Library", 500, 80, 350, 350, id="library")
|
|
29
|
+
articles = page.box("Articles", 20, 70, 310, 70, parent=library)
|
|
30
|
+
page.box("Images", 20, 180, 310, 70, parent=library)
|
|
31
|
+
|
|
32
|
+
page.connect(
|
|
33
|
+
source, articles, "publish",
|
|
34
|
+
source_port=(1, 0.5), target_port=(0, 0.5),
|
|
35
|
+
waypoints=[(370, 225), (370, 185)],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
document.add_page("Notes").text("A second editable tab", 40, 40)
|
|
39
|
+
document.validate(check_bounds=True)
|
|
40
|
+
document.save("publishing.drawio")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Open the file in draw.io or diagrams.net. Each block and connector remains a
|
|
44
|
+
native editable object. Child coordinates are relative to the parent container;
|
|
45
|
+
connector waypoints use page coordinates.
|
|
46
|
+
|
|
47
|
+
`save()` refuses to replace an existing file. Pass `overwrite=True` when you
|
|
48
|
+
intend to update it. File writing uses an atomic replace or exclusive creation.
|
|
49
|
+
|
|
50
|
+
## Add a page to an existing file
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from drawio import Document
|
|
54
|
+
|
|
55
|
+
document = Document.load("publishing.drawio")
|
|
56
|
+
page = document.add_page("Review Details", id="review-details")
|
|
57
|
+
page.box("Editorial review", 40, 80)
|
|
58
|
+
document.save("publishing-v2.drawio")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The loader accepts uncompressed and compressed draw.io XML. It retains existing
|
|
62
|
+
page IDs, cells, geometry and metadata; it expands compressed pages on output.
|
|
63
|
+
It does not preserve byte-for-byte formatting, signatures or compression.
|
|
64
|
+
|
|
65
|
+
## Style and labels
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from drawio import Document, Theme
|
|
69
|
+
|
|
70
|
+
document = Document(theme=Theme(font_family="Arial", font_size=20))
|
|
71
|
+
page = document.add_page("Styled")
|
|
72
|
+
page.box("Plain text: A & B < C", 40, 40,
|
|
73
|
+
style={"fillColor": "#e7effb", "fontStyle": 1})
|
|
74
|
+
page.box("<b>Trusted HTML</b><br/>Subtitle", 300, 40, html=True)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Labels default to plain text. Use `html=True` only for markup you trust. Style
|
|
78
|
+
mappings use draw.io property names such as `fillColor`, `shape` and `fontSize`.
|
|
79
|
+
XML escaping is handled by the writer.
|
|
80
|
+
|
|
81
|
+
## CLI
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
python -m drawio new empty.drawio --name Overview
|
|
85
|
+
python -m drawio validate publishing.drawio --check-bounds
|
|
86
|
+
python -m drawio info publishing.drawio
|
|
87
|
+
python -m drawio url publishing.drawio
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The installed `drawio` command exposes the same interface. `url` prints an editor
|
|
91
|
+
link containing the complete diagram. Generating the URL makes no network
|
|
92
|
+
request; anyone with the link can read its embedded content.
|
|
93
|
+
|
|
94
|
+
For an open editor's **Extras > Edit Diagram** dialog, use `page.to_xml()` to
|
|
95
|
+
obtain that page's `mxGraphModel`. Importing through that dialog may retain the
|
|
96
|
+
editor's current Grid, Page View and Background settings.
|
|
97
|
+
|
|
98
|
+
## Existing Graph / Node API
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from drawio import Graph, Node
|
|
102
|
+
|
|
103
|
+
graph = Graph(name="Review")
|
|
104
|
+
a = Node("Draft", shape="rectangle", x=40, y=80)
|
|
105
|
+
b = Node("Published", shape="rectangle", x=400, y=80)
|
|
106
|
+
graph.add_nodes([a, b])
|
|
107
|
+
a >> "approve" >> b
|
|
108
|
+
|
|
109
|
+
graph.render("review.drawio", show=False)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`.drawio` and `.xml` rendering now uses the native writer and returns the output
|
|
113
|
+
path. `Graph.render()` retains its overwrite behavior. `show=True` saves first,
|
|
114
|
+
then asks the default browser to open an encoded editor URL; it no longer waits
|
|
115
|
+
for console input. Tests and examples use `show=False`.
|
|
116
|
+
|
|
117
|
+
Unpositioned legacy nodes use a simple grid, including disconnected graphs and
|
|
118
|
+
cycles. Use `Node(x=..., y=...)` or the native `Page` API for an authored layout.
|
|
119
|
+
The library does not provide automatic graph layout or SVG/PNG rendering.
|
|
120
|
+
|
|
121
|
+
`to_draw_io_csv()` and `to_draw_io()` still return the legacy CSV and text forms.
|
|
122
|
+
The basic Mermaid importer retains the historical import path:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from drawio.itergrations.mermaid.mermaid_controller import MermaidController
|
|
126
|
+
|
|
127
|
+
graph = MermaidController().load("flowchart LR; A[Draft] -->|approve| B[Published]")
|
|
128
|
+
graph.render("mermaid.drawio")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Supported Mermaid input includes node declarations, `-->`, `-->|label|`, chained
|
|
132
|
+
edges, and rectangular, circular, parenthesized and diamond node labels. Direction
|
|
133
|
+
headers are accepted, but the legacy renderer uses the grid described above.
|
|
134
|
+
Subgraphs, styling directives and other edge syntax raise errors rather than
|
|
135
|
+
silently dropping content. This importer is not a complete Mermaid parser.
|
|
136
|
+
|
|
137
|
+
## Examples and optional integrations
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
python examples/native_document.py
|
|
141
|
+
python examples/complex-example.py
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The first example writes `output/publishing.drawio` with two tabs and nested
|
|
145
|
+
containers. The second demonstrates loading a file and adding a page.
|
|
146
|
+
|
|
147
|
+
Optional extras:
|
|
148
|
+
|
|
149
|
+
- `.[pdf]`: Python Graphviz binding; also install the Graphviz `dot` executable.
|
|
150
|
+
- `.[browser]`: legacy Selenium helpers for callers importing `DrawIOBrowser`
|
|
151
|
+
directly. They are not part of native rendering and are not live-browser
|
|
152
|
+
tested by the default suite.
|
|
153
|
+
- `.[excel]`: dependencies for the existing ERD spreadsheet exporter.
|
|
154
|
+
- `.[docs]`: MkDocs.
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
make lint
|
|
160
|
+
make test
|
|
161
|
+
make build
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Tests write real XML and run examples in temporary directories. They do not
|
|
165
|
+
install packages, download browser drivers, or launch Chrome. See
|
|
166
|
+
[the API reference](docs/index.md) and [contribution guide](CONTRIBUTING.md).
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Native XML API
|
|
2
|
+
|
|
3
|
+
Install the checkout with `python -m pip install -e '.[test]'`.
|
|
4
|
+
See the repository README for the quick start and legacy API migration notes.
|
|
5
|
+
|
|
6
|
+
## Document
|
|
7
|
+
|
|
8
|
+
```python
|
|
9
|
+
from drawio import Document, Theme
|
|
10
|
+
|
|
11
|
+
doc = Document(theme=Theme(font_family="Helvetica", font_size=18))
|
|
12
|
+
page = doc.add_page("Overview", id="overview", width=1600, height=1000)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Method | Result |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `add_page(name, id=None, width=1600, height=1000, background="#ffffff")` | New editable `Page` |
|
|
18
|
+
| `get_page(id)` | Page with that ID, or `ValueError` |
|
|
19
|
+
| `pages` | Tuple of pages in document order |
|
|
20
|
+
| `validate(check_bounds=False)` | Check page/cell IDs, endpoints and parent hierarchy |
|
|
21
|
+
| `to_xml(pretty=True)` | Complete `mxfile` XML string |
|
|
22
|
+
| `save(path, overwrite=False)` | Save UTF-8 XML and return a `Path` |
|
|
23
|
+
| `to_url()` | Encoded diagrams.net editor URL; no network access |
|
|
24
|
+
| `Document.load(path, max_bytes=...)` | Load UTF-8 `.drawio` / `.xml` |
|
|
25
|
+
| `Document.from_xml(xml, max_bytes=...)` | Load an XML string or UTF-8 bytes |
|
|
26
|
+
|
|
27
|
+
Explicit IDs are useful for stable diffs. Generated IDs follow insertion order
|
|
28
|
+
and skip IDs already in use. Page IDs must be unique within a document; cell IDs
|
|
29
|
+
must be unique within a page. Different pages may reuse a cell ID.
|
|
30
|
+
|
|
31
|
+
Loading accepts `mxfile`, a single `diagram`, or a standalone `mxGraphModel`.
|
|
32
|
+
The default input and expanded-model limit is 10 MiB. You can raise `max_bytes`
|
|
33
|
+
for trusted larger documents. The loader rejects DTD/entity declarations and
|
|
34
|
+
invalid compressed data. It preserves supported XML structure and unknown
|
|
35
|
+
metadata, including draw.io `object` wrappers; it is not a full schema validator
|
|
36
|
+
for every draw.io plugin or custom shape.
|
|
37
|
+
|
|
38
|
+
## Page and Cell
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
box = page.box("Input", 40, 80, width=200, height=90, id="input")
|
|
42
|
+
group = page.container("Output", 500, 80, 360, 360, id="output")
|
|
43
|
+
child = page.box("Article", 20, 70, 320, 80, parent=group)
|
|
44
|
+
page.text("Overview", 40, 20, 700, 40, style={"fontSize": 28})
|
|
45
|
+
page.connect(box, child, "publish")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`box`, `container` and `text` accept `id`, `parent`, `style` and `html` keyword
|
|
49
|
+
arguments and return a `Cell`. Use a returned `Cell` or an existing cell ID as a
|
|
50
|
+
parent or connector endpoint. References cannot cross page boundaries.
|
|
51
|
+
|
|
52
|
+
- `box(label, x, y, width=200, height=90, ...)`: native shape.
|
|
53
|
+
- `container(label, x, y, width, height, ...)`: shape with a top-aligned title and
|
|
54
|
+
nested child blocks.
|
|
55
|
+
- `text(label, x, y, width=400, height=40, ...)`: borderless text.
|
|
56
|
+
- `connect(source, target, label="", ...)`: native orthogonal connector.
|
|
57
|
+
- `get(id)`: existing cell reference.
|
|
58
|
+
- `cells`: tuple of cell references, including root/layer cells.
|
|
59
|
+
- `name`: editable tab name.
|
|
60
|
+
- `to_xml()`: the current page's `mxGraphModel` XML.
|
|
61
|
+
|
|
62
|
+
A child's `(x, y)` is relative to its parent. Reserve space for the container
|
|
63
|
+
heading yourself. Nested container coordinates follow the same rule. The writer
|
|
64
|
+
does not pack, resize or align child blocks for you.
|
|
65
|
+
|
|
66
|
+
`validate(check_bounds=True)` also checks ordinary child rectangles against
|
|
67
|
+
parent bounds. Relative ports are exempt from this bounds check. Validation does
|
|
68
|
+
not measure text, detect shape overlaps or guarantee optimal connector routing.
|
|
69
|
+
|
|
70
|
+
`Cell.element`, `Page.model`, `Page.element` and `Document.element` expose the
|
|
71
|
+
underlying ElementTree elements for advanced XML editing. Call `validate()`
|
|
72
|
+
after a manual change; prefer the builder methods for creating cells and pages.
|
|
73
|
+
|
|
74
|
+
## Connectors
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
page.connect(
|
|
78
|
+
box, child, "publish",
|
|
79
|
+
id="publish-edge",
|
|
80
|
+
source_port=(1, 0.5),
|
|
81
|
+
target_port=(0, 0.5),
|
|
82
|
+
waypoints=[(400, 125), (400, 190)],
|
|
83
|
+
dashed=True,
|
|
84
|
+
style={"strokeColor": "#246a52", "fontSize": 16},
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Ports are normalized `(x, y)` pairs in `[0, 1]`. `(1, 0.5)` is the right edge's
|
|
89
|
+
midpoint; `(0.5, 1)` is the bottom midpoint. Omit ports to let draw.io choose them.
|
|
90
|
+
Waypoints use page coordinates even when an endpoint belongs to a container.
|
|
91
|
+
Labels on connectors use plain text.
|
|
92
|
+
|
|
93
|
+
## Styles and text
|
|
94
|
+
|
|
95
|
+
`Theme` sets `font_family`, `font_size`, `fill_color`, `stroke_color`,
|
|
96
|
+
`text_color` and `line_color`. Per-cell style dictionaries override the defaults.
|
|
97
|
+
Style keys use draw.io names; booleans become `1` or `0`. Semicolons in style
|
|
98
|
+
values and delimiters in keys are rejected.
|
|
99
|
+
|
|
100
|
+
Plain-text labels support Unicode, quotes, newlines and XML-significant
|
|
101
|
+
characters. The writer escapes XML. A style dictionary cannot opt into HTML:
|
|
102
|
+
pass `html=True` to a shape method when you intend to render trusted markup.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
page.box("<b>Title</b><br/>Subtitle", 40, 300, html=True)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
XML generation works offline. To inspect the visual result, open the file in
|
|
109
|
+
draw.io. Use that editor or draw.io Desktop for image/PDF exports.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.3
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Offline utilities for editable draw.io files."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from drawio.document import Document
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main(argv=None):
|
|
12
|
+
parser = argparse.ArgumentParser(description="Generate and inspect native draw.io XML")
|
|
13
|
+
version = Path(__file__).with_name("VERSION").read_text(encoding="utf-8").strip()
|
|
14
|
+
parser.add_argument("--version", action="version", version=version)
|
|
15
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
16
|
+
validate = commands.add_parser("validate", help="Check IDs, references and parent hierarchy")
|
|
17
|
+
validate.add_argument("input", type=Path)
|
|
18
|
+
validate.add_argument(
|
|
19
|
+
"--check-bounds", action="store_true", help="Also reject children outside containers"
|
|
20
|
+
)
|
|
21
|
+
info = commands.add_parser("info", help="Print page IDs, names and cell counts as JSON")
|
|
22
|
+
info.add_argument("input", type=Path)
|
|
23
|
+
url = commands.add_parser("url", help="Encode file contents in an editor URL (no upload)")
|
|
24
|
+
url.add_argument("input", type=Path)
|
|
25
|
+
new = commands.add_parser("new", help="Create an empty one-page document")
|
|
26
|
+
new.add_argument("output", type=Path)
|
|
27
|
+
new.add_argument("--name", default="Overview")
|
|
28
|
+
new.add_argument("--overwrite", action="store_true")
|
|
29
|
+
args = parser.parse_args(argv)
|
|
30
|
+
try:
|
|
31
|
+
if args.command == "new":
|
|
32
|
+
document = Document()
|
|
33
|
+
document.add_page(args.name)
|
|
34
|
+
print(document.save(args.output, overwrite=args.overwrite))
|
|
35
|
+
return 0
|
|
36
|
+
document = Document.load(args.input)
|
|
37
|
+
if args.command == "validate":
|
|
38
|
+
document.validate(check_bounds=args.check_bounds)
|
|
39
|
+
print(f"Valid: {len(document.pages)} page(s)")
|
|
40
|
+
elif args.command == "info":
|
|
41
|
+
print(
|
|
42
|
+
json.dumps(
|
|
43
|
+
[
|
|
44
|
+
{
|
|
45
|
+
"id": page.id,
|
|
46
|
+
"name": page.name,
|
|
47
|
+
"shapes": sum(c.element.get("vertex") == "1" for c in page.cells),
|
|
48
|
+
"connectors": sum(c.element.get("edge") == "1" for c in page.cells),
|
|
49
|
+
}
|
|
50
|
+
for page in document.pages
|
|
51
|
+
],
|
|
52
|
+
indent=2,
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
elif args.command == "url":
|
|
56
|
+
print(document.to_url())
|
|
57
|
+
return 0
|
|
58
|
+
except (OSError, ValueError, TypeError) as exc:
|
|
59
|
+
print(f"drawio: {exc}", file=sys.stderr)
|
|
60
|
+
return 1
|