22import platform
33import subprocess
44from pathlib import Path
5- from typing import Optional
5+ from typing import Optional , Union
6+ try :
7+ from typing import Literal
8+ except ImportError :
9+ from typing_extensions import Literal
10+
611import tempfile
712
813
914class D2 :
15+ """
16+ Python wrapper for the D2 diagram scripting language.
17+ Supports multiple output formats, themes, and layout options.
18+ """
19+
1020 def __init__ (self ):
1121 system = platform .system ().lower ()
1222 if system == "linux" :
@@ -31,29 +41,91 @@ def __init__(self):
3141 def render (self ,
3242 input_source : str ,
3343 output_file : str ,
34- format : str = "svg" ,
35- theme : Optional [str ] = None ,
36- layout : str = "dagre" ,
37- pad : int = 100 ) -> None :
44+ format : Literal ["svg" , "png" , "pdf" ] = "svg" ,
45+ theme : Optional [Union [int , str ]] = None ,
46+ layout : Literal ["dagre" , "elk" ] = "dagre" ,
47+ pad : int = 100 ,
48+ dark_theme : Optional [int ] = None ,
49+ sketch : bool = False ,
50+ center : bool = False ,
51+ scale : float = - 1 ,
52+ bundle : bool = True ,
53+ force_appendix : bool = False ,
54+ timeout : int = 120 ,
55+ animate_interval : int = 0 ,
56+ target : str = "*" ,
57+ font_regular : Optional [str ] = None ,
58+ font_italic : Optional [str ] = None ,
59+ font_bold : Optional [str ] = None ,
60+ font_semibold : Optional [str ] = None ) -> None :
3861 """
3962 Render D2 diagram to specified format.
4063
4164 Args:
4265 input_source: Input D2 file path or string content
4366 output_file: Output file path
4467 format: Output format (svg, png, pdf)
45- theme: Theme name (dark, light)
68+ theme: Theme ID (0-11) or name. See https://github.com/terrastruct/d2/tree/master/d2themes
69+ dark_theme: Theme ID to use when in dark mode. -1 uses the same theme as light mode
4670 layout: Layout engine (dagre, elk)
4771 pad: Padding in pixels
72+ sketch: Render the diagram to look like it was sketched by hand
73+ center: Center the SVG in the containing viewbox
74+ scale: Scale the output. -1 means SVGs fit to screen, others use default size
75+ bundle: When outputting SVG, bundle all assets and layers into the output file
76+ force_appendix: Force addition of appendix for tooltips and links in SVG exports
77+ timeout: Maximum number of seconds D2 runs before timing out
78+ animate_interval: Milliseconds between transitions when using multiple boards (SVG only)
79+ target: Target board to render. Use '*' for all scenarios, '' for root only
80+ font_regular: Path to .ttf file for regular font
81+ font_italic: Path to .ttf file for italic font
82+ font_bold: Path to .ttf file for bold font
83+ font_semibold: Path to .ttf file for semibold font
4884 """
4985 cmd = [self .binary_path ]
5086
51- if theme :
52- cmd .extend (["--theme" , theme ])
87+ if theme is not None :
88+ cmd .extend (["--theme" , str (theme )])
89+
90+ if dark_theme is not None :
91+ cmd .extend (["--dark-theme" , str (dark_theme )])
5392
5493 cmd .extend (["--layout" , layout ])
5594 cmd .extend (["--pad" , str (pad )])
5695
96+ if sketch :
97+ cmd .append ("--sketch" )
98+
99+ if center :
100+ cmd .append ("--center" )
101+
102+ if scale != - 1 :
103+ cmd .extend (["--scale" , str (scale )])
104+
105+ if not bundle :
106+ cmd .extend (["--bundle" , "false" ])
107+
108+ if force_appendix :
109+ cmd .append ("--force-appendix" )
110+
111+ if timeout != 120 :
112+ cmd .extend (["--timeout" , str (timeout )])
113+
114+ if animate_interval > 0 :
115+ cmd .extend (["--animate-interval" , str (animate_interval )])
116+
117+ if target != "*" :
118+ cmd .extend (["--target" , target ])
119+
120+ for font_type , font_path in [
121+ ("regular" , font_regular ),
122+ ("italic" , font_italic ),
123+ ("bold" , font_bold ),
124+ ("semibold" , font_semibold )
125+ ]:
126+ if font_path :
127+ cmd .extend ([f"--font-{ font_type } " , str (font_path )])
128+
57129 if format != "svg" :
58130 cmd .extend (["--format" , format ])
59131
0 commit comments