paperforge-diagrams 0.1.0__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.
@@ -0,0 +1,408 @@
1
+ Metadata-Version: 2.4
2
+ Name: paperforge-diagrams
3
+ Version: 0.1.0
4
+ Summary: Vector-native PDF diagram toolkit for ReportLab Platypus
5
+ Author: Bharat Dangi
6
+ License-Expression: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: reportlab>=4.5.1
12
+ Requires-Dist: pydantic>=2.13.4
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=9.0.3; extra == "dev"
15
+ Requires-Dist: pytest-cov>=6.0; extra == "dev"
16
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
17
+ Requires-Dist: mypy>=1.11.0; extra == "dev"
18
+
19
+ ![PaperForge](../assets/paperforge_logo_black.svg)
20
+ # 📊 paperforge_diagrams
21
+
22
+ [![Python Version](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/)
23
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
24
+ [![Format](https://img.shields.io/badge/format-ReportLab%20Drawing-orange.svg)](#)
25
+
26
+ Vector-native PDF diagram toolkit for ReportLab Platypus. Draw complex diagrams natively inside your ReportLab documents with a clean, pythonic API.
27
+
28
+ No raster images, no external command-line tools, and no internet connection required. All diagram types compile directly to `reportlab.graphics.shapes.Drawing` objects that wrap seamlessly as Platypus Flowables.
29
+
30
+ ---
31
+
32
+ ## 🚀 Features
33
+
34
+ * **Flowchart**: ANSI/ISO flowchart symbols (terminals, processes, decisions, io, connectors).
35
+ * **SequenceDiagram**: UML sequence diagrams (actors, lifelines, activation bars, message arrows, dividers).
36
+ * **ClassDiagram**: UML class diagrams (class boxes, headers, attributes, methods, relations).
37
+ * **ERDiagram**: Entity-Relationship diagrams (entities, relations, primary key and multi-value attributes).
38
+ * **StateMachine**: DFA/NFA and process state diagrams (states, transitions, initial/accepting indicators).
39
+ * **NetworkDiagram**: Network topology (hosts, servers, databases, links).
40
+ * **ArchitectureDiagram**: System architecture topologies with clients, services, databases, queues, and auto-routed connections.
41
+ * **AWSDiagram**: Cloud infrastructure architecture with AWS icons (EC2, S3, RDS, Lambda, SQS).
42
+ * **GitDiagram**: Git branch timeline diagrams with commits, merges, and distinct branch lanes.
43
+ * **SchemaDiagram**: Database table schema definition diagrams with field types, primary keys, and foreign-key links.
44
+ * **C4ContainerDiagram**: C4 Model container diagrams with System Context, Container, Component layers, and descriptive relationships.
45
+ * **TimingDiagram**: Digital waveform timing diagrams.
46
+ * **LayeredStack**: OSI model, TCP/IP stack, memory hierarchy.
47
+ * **Standalone Export**: Save drawings directly to PDF, SVG, and PNG/JPG formats.
48
+
49
+ ---
50
+
51
+ ## 📦 Installation
52
+
53
+ Install the package locally:
54
+
55
+ ```bash
56
+ pip install ./paperforge_diagrams
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 🎨 Supported Diagram Types & Examples
62
+
63
+ ### 1. Flowchart
64
+ Draw processes, decisions, and connectors with auto-layout or manual coordinates.
65
+
66
+ ```python
67
+ import paperforge_diagrams as pd
68
+
69
+ # Create a horizontal flowchart with a custom scale factor
70
+ fc = pd.Flowchart(
71
+ width=400,
72
+ height=150,
73
+ direction="LR", # 'TB' (top-to-bottom, default) or 'LR' (left-to-right)
74
+ scale_factor=1.0, # Optional manual override for text/box sizing (default: auto-computed)
75
+ )
76
+ fc.terminal("start", "START")
77
+ fc.process("calc", "Compute Sum")
78
+ fc.decision("check", "Sum > 100?")
79
+ fc.terminal("end", "END")
80
+
81
+ fc.edge("start", "calc")
82
+ fc.edge("calc", "check")
83
+ fc.edge("check", "end", branch="yes")
84
+ fc.edge("check", "calc", branch="no", orthogonal=True)
85
+ ```
86
+
87
+ ### 2. Sequence Diagram
88
+ Draw actor interactions over lifelines.
89
+
90
+ ```python
91
+ import paperforge_diagrams as pd
92
+
93
+ seq = pd.SequenceDiagram(width=400, height=220)
94
+ seq.actor("c", "Client")
95
+ seq.actor("s", "Server")
96
+
97
+ seq.activate("c")
98
+ seq.message("c", "s", "HTTP GET /index.html")
99
+ seq.activate("s")
100
+ seq.divider("Internal Processing")
101
+ # Arrow styles: 'solid' (default), 'dashed', 'solid_open', 'dashed_open'
102
+ seq.message("s", "c", "200 OK (HTML Document)", arrow="dashed")
103
+ seq.deactivate("s")
104
+ seq.deactivate("c")
105
+ ```
106
+
107
+
108
+ ### 3. Layered Stack
109
+ Draw OSI stacks, memory hierarchies, or layered architectures.
110
+
111
+ ```python
112
+ import paperforge_diagrams as pd
113
+
114
+ stack = pd.LayeredStack(width=300, height=180)
115
+ stack.layer("Application", sublabel="HTTP, DNS")
116
+ stack.layer("Transport", sublabel="TCP, UDP")
117
+ stack.divider() # Draw a thicker divider line after Transport layer
118
+ stack.layer("Network", sublabel="IP, ICMP")
119
+ stack.layer("Link", sublabel="Ethernet")
120
+ ```
121
+
122
+
123
+ ### 4. Network Diagram
124
+ Draw network topologies with hosts, clouds, switches, routers, and firewalls.
125
+
126
+ ```python
127
+ import paperforge_diagrams as pd
128
+
129
+ net = pd.NetworkDiagram(width=500, height=220)
130
+ net.node("inet", "Internet", x=50, y=110, kind="cloud")
131
+ net.node("fw", "Firewall", x=160, y=110, kind="firewall")
132
+ net.node("sw", "Core Switch", x=270, y=110, kind="switch")
133
+ net.node("srv", "Web Server", x=380, y=150, kind="server")
134
+ net.node("db", "Database", x=380, y=70, kind="database")
135
+
136
+ net.link("inet", "fw")
137
+ net.link("fw", "sw")
138
+ net.link("sw", "srv")
139
+ net.link("sw", "db")
140
+
141
+ # Also supports building standard topologies programmatically:
142
+ # net.star_topology(center_id="sw", center_label="Switch", spoke_ids=["h1", "h2", "h3"])
143
+ # net.bus_topology(node_ids=["n1", "n2", "n3"])
144
+ # net.ring_topology(node_ids=["r1", "r2", "r3"])
145
+ # net.mesh_topology(node_ids=["m1", "m2", "m3"])
146
+ # net.tree_topology(parent_child_map={"root": ["child1", "child2"]})
147
+ ```
148
+
149
+
150
+ ### 5. UML Class Diagram
151
+ Draw UML class diagrams with visibility, attributes, and methods.
152
+
153
+ ```python
154
+ import paperforge_diagrams as pd
155
+
156
+ cd = pd.ClassDiagram(width=400, height=250, class_w=120)
157
+ cd.uml_class("Shape", "Shape", stereotype="abstract", methods=["+ area(): double"])
158
+ cd.uml_class("Circle", "Circle", attributes=["- radius: double"], methods=["+ area(): double"])
159
+ # Relationship kinds: 'inheritance', 'realization', 'composition', 'aggregation', 'association', 'dependency'
160
+ cd.relate("Circle", "Shape", kind="inheritance")
161
+ ```
162
+
163
+
164
+ ### 6. Entity-Relationship Diagram (ER)
165
+ Draw entity-relationship diagrams (Chen notation) with cardinalities.
166
+
167
+ ```python
168
+ import paperforge_diagrams as pd
169
+
170
+ er = pd.ERDiagram(width=450, height=200)
171
+ er.entity("Customer")
172
+ er.relationship("Buys")
173
+ er.entity("Product")
174
+ er.entity_attributes("Customer", [("ID", {"pk": True}), "Name"])
175
+ er.entity_attributes("Product", [("SKU", {"pk": True}), "Price"])
176
+ er.connect("Customer", "Buys", card_from="1", card_to="N")
177
+ er.connect("Product", "Buys", card_from="1", card_to="N")
178
+ ```
179
+
180
+ ### 7. State Machine (DFA / Process Transitions)
181
+ Draw finite state automata or lifecycle models.
182
+
183
+ ```python
184
+ import paperforge_diagrams as pd
185
+
186
+ sm = pd.StateMachine(width=400, height=180)
187
+ sm.state("s0", "Init", x=70, y=90, initial=True)
188
+ sm.state("s1", "Active", x=200, y=90)
189
+ sm.state("s2", "Success", x=330, y=90, accepting=True)
190
+
191
+ sm.transition("s0", "s1", label="start")
192
+ sm.transition("s1", "s1", label="process")
193
+ sm.transition("s1", "s2", label="complete")
194
+ ```
195
+
196
+ ### 8. Timing Diagram
197
+ Draw digital timing signal waveforms.
198
+
199
+ ```python
200
+ import paperforge_diagrams as pd
201
+
202
+ td = pd.TimingDiagram(width=400, height=150)
203
+ td.clock("CLK", period=20.0, cycles=6)
204
+ td.signal("RESET", transitions=[(0, 1), (15, 0)])
205
+ td.signal("DATA", transitions=[(0, 0), (35, 1), (75, 0)])
206
+ ```
207
+
208
+ ### 9. Database Schema Diagram
209
+ Draw database table structures with primary/foreign keys and relationships.
210
+
211
+ ```python
212
+ import paperforge_diagrams as pd
213
+
214
+ schema = pd.SchemaDiagram(width=450, height=200)
215
+ schema.table("users", [
216
+ ("id", "INTEGER", {"pk": True}),
217
+ ("email", "VARCHAR", {}),
218
+ ("created_at", "TIMESTAMP", {})
219
+ ])
220
+ schema.table("orders", [
221
+ ("id", "INTEGER", {"pk": True}),
222
+ ("user_id", "INTEGER", {"fk": True}),
223
+ ("total", "DECIMAL", {})
224
+ ])
225
+ schema.relation("orders", "user_id", "users", "id")
226
+ ```
227
+
228
+ ### 10. Service Architecture Diagram
229
+ Draw multi-tier system topologies (clients, microservices, databases, queues) with automatic or manual layouts.
230
+
231
+ ```python
232
+ import paperforge_diagrams as pd
233
+
234
+ # Supports orientation: 'horizontal' (default) or 'vertical'
235
+ arch = pd.ArchitectureDiagram(width=450, height=220, orientation="horizontal")
236
+ arch.client("web", "Web Client")
237
+ arch.service("api", "Gateway API")
238
+ arch.database("db", "Main Database")
239
+ arch.queue("q", "Message Broker")
240
+
241
+ arch.connect("web", "api", "HTTPS")
242
+ arch.connect("api", "db", "TCP/3306")
243
+ arch.connect("api", "q", "AMQP")
244
+ ```
245
+
246
+
247
+ ### 11. C4 Container Diagram
248
+ Draw C4 Model Container views to document software systems, containers, technologies, and relationships.
249
+
250
+ ```python
251
+ import paperforge_diagrams as pd
252
+
253
+ c4 = pd.C4ContainerDiagram(width=400, height=200)
254
+ c4.system("user", "Customer")
255
+ c4.container("web", "SPA (React)", "Provides shopping UI")
256
+ c4.container("api", "API Application (Go)", "Handles business logic")
257
+ c4.container("db", "Database (Postgres)", "Stores order data")
258
+
259
+ c4.relate("user", "web", "Uses")
260
+ c4.relate("web", "api", "Makes API calls to")
261
+ c4.relate("api", "db", "Reads/Writes to")
262
+ ```
263
+
264
+ ### 12. Git Branch Flow Diagram
265
+ Draw commits, branch lanes, merges, and timelines horizontally.
266
+
267
+ ```python
268
+ import paperforge_diagrams as pd
269
+
270
+ git = pd.GitDiagram(width=400, height=150)
271
+ git.commit("main", "C1: Initial Commit")
272
+ git.branch("main", "feature")
273
+ git.commit("feature", "C2: Implement login")
274
+ git.commit("main", "C3: Hotfix bug")
275
+ git.merge("feature", "main", "C4: Merge feature/login")
276
+ ```
277
+
278
+ ### 13. AWS Diagram
279
+ Draw AWS cloud infrastructure diagrams using vector-native AWS icons.
280
+
281
+ ```python
282
+ import paperforge_diagrams as pd
283
+
284
+ # Supports orientation: 'horizontal' (default) or 'vertical'
285
+ aws = pd.AWSDiagram(width=450, height=220, orientation="horizontal")
286
+ # Supported node methods: ec2(), rds(), s3(), lambda_fn(), sqs()
287
+ aws.ec2("web", "Web Server")
288
+ aws.rds("db", "RDS PostgreSQL")
289
+ aws.s3("bucket", "S3 Storage")
290
+ aws.sqs("queue", "Job Queue")
291
+
292
+ aws.connect("web", "db", "SQL Connection")
293
+ aws.connect("web", "bucket", "Uploads")
294
+ aws.connect("web", "queue", "Events")
295
+ ```
296
+
297
+
298
+ ---
299
+
300
+ ## 🎨 Diagram Theming & Integration
301
+
302
+ `paperforge_diagrams` comes with built-in dark and light themes, and can dynamically inherit themes from `paperforge_notes` for consistent visual layouts.
303
+
304
+ ### 1. Using Preset Diagram Themes
305
+ Apply a theme directly to your builder instance:
306
+
307
+ ```python
308
+ import paperforge_diagrams as pd
309
+
310
+ # Use preset theme (pd.DARK or pd.LIGHT)
311
+ diagram = pd.Flowchart(width=300, height=200, theme=pd.LIGHT)
312
+ ```
313
+
314
+ ### 2. Matching Notes Theme (Integration)
315
+ Derive matching diagram settings from the active document notes theme:
316
+
317
+ ```python
318
+ import paperforge_notes as pn
319
+ import paperforge_diagrams as pd
320
+
321
+ # 1. Set the notes theme
322
+ pn.set_theme(pn.OCEAN_DARK)
323
+
324
+ # 2. Derive the matching diagram theme
325
+ diag_theme = pd.DiagramTheme.from_notes_theme(pn.get_theme())
326
+
327
+ # 3. Apply it to your diagrams
328
+ fc = pd.Flowchart(width=400, height=200, theme=diag_theme)
329
+ ```
330
+
331
+ ### 3. Customizing & Overriding Themes
332
+ Modify a theme on the fly using `model_copy(update={...})`:
333
+
334
+ ```python
335
+ # Create a print-optimized black-and-white diagram theme
336
+ bw_theme = pd.DiagramTheme.from_notes_theme(pn.get_theme()).model_copy(
337
+ update={
338
+ "stack_colors": ("#ffffff", "#ffffff", "#ffffff"),
339
+ "stack_stroke": "#000000",
340
+ "stack_text": "#000000",
341
+ "stack_sublabel_text": "#000000",
342
+ "bg": "#ffffff",
343
+ "text": "#000000",
344
+ "node_fill": "#ffffff",
345
+ "node_stroke": "#000000",
346
+ "node_text": "#000000",
347
+ "font_name": "Times-Roman",
348
+ "font_name_bold": "Times-Bold",
349
+ "font_name_italic": "Times-Italic",
350
+ }
351
+ )
352
+ # Apply to stack diagram
353
+ stack = pd.LayeredStack(width=300, height=180, theme=bw_theme)
354
+ ```
355
+
356
+ ---
357
+
358
+ ## 💾 Standalone Export
359
+
360
+ Export your diagrams directly to vector or raster formats without a ReportLab story:
361
+
362
+ ```python
363
+ diagram = pd.Flowchart(width=300, height=200)
364
+ diagram.terminal("s", "START").terminal("e", "END").edge("s", "e")
365
+
366
+ # Save to PDF (vector)
367
+ diagram.save("output.pdf")
368
+
369
+ # Save to SVG (vector)
370
+ diagram.save("output.svg")
371
+
372
+ # Save to PNG (raster)
373
+ diagram.save("output.png")
374
+ ```
375
+
376
+ ---
377
+
378
+ ## 📝 Integration with `paperforge_notes`
379
+
380
+ To embed a vector diagram into a PaperForge notes document, call `.as_flowable()` and pass it to `pn.add(...)`:
381
+
382
+ ```python
383
+ import paperforge_notes as pn
384
+ import paperforge_diagrams as pd
385
+
386
+ fc = pd.Flowchart(width=pn.CW, height=200)
387
+ fc.terminal("s", "START").terminal("e", "END").edge("s", "e")
388
+
389
+ # Add the diagram flowables directly
390
+ pn.add(fc.as_flowable())
391
+ ```
392
+
393
+ ### Static Type-Checking (Pyright / Pylance)
394
+ If you see static type warnings in your IDE:
395
+ > `Argument of type "list[Unknown]" cannot be assigned to parameter "x" of type "Flowable" in function "add"`
396
+
397
+ This happens because `.as_flowable()` returns a `list[Flowable]` (which packages the drawing flowable along with its optional caption `Paragraph` flowable) rather than a single raw `Flowable`.
398
+
399
+ `paperforge_notes` handles this union type cleanly. Calling `pn.add(diagram.as_flowable())` is type-safe and fully compliant.
400
+
401
+ ---
402
+
403
+ ## 📋 Requirements & License
404
+
405
+ * **Python** >= 3.11
406
+ * **reportlab** >= 4.5.1
407
+ * **pydantic** >= 2.13.4
408
+ * Licensed under the **MIT License**.