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.
Files changed (85) hide show
  1. drawio_python-0.1.3/HISTORY.md +26 -0
  2. drawio_python-0.1.3/MANIFEST.in +11 -0
  3. drawio_python-0.1.3/PKG-INFO +199 -0
  4. drawio_python-0.1.3/README.md +166 -0
  5. drawio_python-0.1.3/docs/index.md +109 -0
  6. drawio_python-0.1.3/drawio/VERSION +1 -0
  7. drawio_python-0.1.3/drawio/__init__.py +5 -0
  8. drawio_python-0.1.3/drawio/__main__.py +6 -0
  9. drawio_python-0.1.3/drawio/cli.py +60 -0
  10. drawio_python-0.1.3/drawio/document.py +556 -0
  11. drawio_python-0.1.3/drawio/entities/__init__.py +4 -0
  12. drawio_python-0.1.3/drawio/entities/base_entity.py +9 -0
  13. drawio_python-0.1.3/drawio/entities/config.py +1 -0
  14. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio.py +4 -2
  15. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_app.py +3 -9
  16. drawio_python-0.1.3/drawio/entities/drawio_browser.py +235 -0
  17. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/abstract_config.py +2 -2
  18. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/drawio_config.py +13 -1
  19. drawio_python-0.1.3/drawio/entities/drawio_config/label_config.py +5 -0
  20. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/column.py +2 -1
  21. drawio_python-0.1.3/drawio/entities/erd/erd.py +67 -0
  22. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/table.py +3 -3
  23. drawio_python-0.1.3/drawio/entities/graph/__init__.py +5 -0
  24. drawio_python-0.1.3/drawio/entities/graph/edge.py +33 -0
  25. drawio_python-0.1.3/drawio/entities/graph/graph.py +147 -0
  26. drawio_python-0.1.3/drawio/entities/graph/node.py +92 -0
  27. drawio_python-0.1.3/drawio/entities/logger.py +8 -0
  28. drawio_python-0.1.3/drawio/entities/renderers/__init__.py +7 -0
  29. drawio_python-0.1.3/drawio/entities/renderers/base_render.py +24 -0
  30. drawio_python-0.1.3/drawio/entities/renderers/drawio_render.py +16 -0
  31. drawio_python-0.1.3/drawio/entities/renderers/pdf_render.py +59 -0
  32. drawio_python-0.1.3/drawio/itergrations/mermaid/mermaid_controller.py +108 -0
  33. drawio_python-0.1.3/drawio_python.egg-info/PKG-INFO +199 -0
  34. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/SOURCES.txt +29 -1
  35. drawio_python-0.1.3/drawio_python.egg-info/requires.txt +20 -0
  36. drawio_python-0.1.3/examples/complex-example.py +16 -0
  37. drawio_python-0.1.3/examples/draw-flow-diagrams.png +0 -0
  38. drawio_python-0.1.3/examples/draw-flow-diagrams.py +18 -0
  39. drawio_python-0.1.3/examples/mermaid-to-drawio.py +19 -0
  40. drawio_python-0.1.3/examples/native_document.py +65 -0
  41. drawio_python-0.1.3/mkdocs.yml +2 -0
  42. drawio_python-0.1.3/pyproject.toml +16 -0
  43. drawio_python-0.1.3/requirements-test.txt +4 -0
  44. drawio_python-0.1.3/requirements.txt +2 -0
  45. {drawio-python-0.1.0 → drawio_python-0.1.3}/setup.py +14 -6
  46. drawio_python-0.1.3/tests/conftest.py +6 -0
  47. drawio_python-0.1.3/tests/test_cli.py +46 -0
  48. drawio_python-0.1.3/tests/test_document.py +335 -0
  49. drawio_python-0.1.3/tests/test_examples.py +27 -0
  50. drawio_python-0.1.3/tests/test_graph.py +20 -0
  51. drawio_python-0.1.3/tests/test_graph_native.py +126 -0
  52. drawio_python-0.1.3/tests/test_imports.py +8 -0
  53. drawio_python-0.1.3/tests/test_mermaid.py +85 -0
  54. drawio-python-0.1.0/HISTORY.md +0 -13
  55. drawio-python-0.1.0/MANIFEST.in +0 -5
  56. drawio-python-0.1.0/PKG-INFO +0 -23
  57. drawio-python-0.1.0/README.md +0 -14
  58. drawio-python-0.1.0/drawio/VERSION +0 -1
  59. drawio-python-0.1.0/drawio/__main__.py +0 -6
  60. drawio-python-0.1.0/drawio/cli.py +0 -28
  61. drawio-python-0.1.0/drawio/entities/config.py +0 -2
  62. drawio-python-0.1.0/drawio/entities/drawio_browser.py +0 -89
  63. drawio-python-0.1.0/drawio/entities/erd/erd.py +0 -22
  64. drawio-python-0.1.0/drawio/entities/graph/__init__.py +0 -1
  65. drawio-python-0.1.0/drawio/entities/graph/edge.py +0 -30
  66. drawio-python-0.1.0/drawio/entities/graph/graph.py +0 -134
  67. drawio-python-0.1.0/drawio/entities/graph/node.py +0 -91
  68. drawio-python-0.1.0/drawio_python.egg-info/PKG-INFO +0 -23
  69. drawio-python-0.1.0/drawio_python.egg-info/requires.txt +0 -12
  70. drawio-python-0.1.0/tests/conftest.py +0 -14
  71. {drawio-python-0.1.0 → drawio_python-0.1.3}/Containerfile +0 -0
  72. {drawio-python-0.1.0 → drawio_python-0.1.3}/LICENSE +0 -0
  73. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/base.py +0 -0
  74. {drawio-python-0.1.0/drawio → drawio_python-0.1.3/drawio/controllers}/__init__.py +0 -0
  75. {drawio-python-0.1.0/drawio/controllers → drawio_python-0.1.3/drawio/entities/drawio_config}/__init__.py +0 -0
  76. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/drawio_config/connect_config.py +0 -0
  77. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio/entities/erd/__init__.py +0 -0
  78. {drawio-python-0.1.0/drawio/entities → drawio_python-0.1.3/drawio/itergrations}/__init__.py +0 -0
  79. {drawio-python-0.1.0/drawio/entities/drawio_config → drawio_python-0.1.3/drawio/itergrations/mermaid}/__init__.py +0 -0
  80. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/dependency_links.txt +0 -0
  81. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/entry_points.txt +0 -0
  82. {drawio-python-0.1.0 → drawio_python-0.1.3}/drawio_python.egg-info/top_level.txt +0 -0
  83. {drawio-python-0.1.0 → drawio_python-0.1.3}/setup.cfg +0 -0
  84. {drawio-python-0.1.0 → drawio_python-0.1.3}/tests/__init__.py +0 -0
  85. {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,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,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,5 @@
1
+ from .document import Cell, Document, Page, Theme
2
+ from .entities.graph.graph import Graph
3
+ from .entities.graph.node import Node
4
+
5
+ __all__ = ["Cell", "Document", "Graph", "Node", "Page", "Theme"]
@@ -0,0 +1,6 @@
1
+ """Entry point for python -m drawio."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -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