4
4
5
5
import os
6
6
import io
7
- import errno
8
7
import codecs
9
- import platform
10
- import subprocess
11
8
12
9
from ._compat import text_type
13
10
14
- from . import tools
11
+ from . import backend , tools
15
12
16
13
__all__ = ['File' , 'Source' ]
17
14
18
- FORMATS = set ([ # http://www.graphviz.org/doc/info/output.html
19
- 'bmp' ,
20
- 'canon' , 'dot' , 'gv' , 'xdot' , 'xdot1.2' , 'xdot1.4' ,
21
- 'cgimage' ,
22
- 'cmap' ,
23
- 'eps' ,
24
- 'exr' ,
25
- 'fig' ,
26
- 'gd' , 'gd2' ,
27
- 'gif' ,
28
- 'gtk' ,
29
- 'ico' ,
30
- 'imap' , 'cmapx' ,
31
- 'imap_np' , 'cmapx_np' ,
32
- 'ismap' ,
33
- 'jp2' ,
34
- 'jpg' , 'jpeg' , 'jpe' ,
35
- 'pct' , 'pict' ,
36
- 'pdf' ,
37
- 'pic' ,
38
- 'plain' , 'plain-ext' ,
39
- 'png' ,
40
- 'pov' ,
41
- 'ps' ,
42
- 'ps2' ,
43
- 'psd' ,
44
- 'sgi' ,
45
- 'svg' , 'svgz' ,
46
- 'tga' ,
47
- 'tif' , 'tiff' ,
48
- 'tk' ,
49
- 'vml' , 'vmlz' ,
50
- 'vrml' ,
51
- 'wbmp' ,
52
- 'webp' ,
53
- 'xlib' ,
54
- 'x11' ,
55
- ])
56
-
57
- ENGINES = set ([ # http://www.graphviz.org/cgi-bin/man?dot
58
- 'dot' , 'neato' , 'twopi' , 'circo' , 'fdp' , 'sfdp' , 'patchwork' , 'osage' ,
59
- ])
60
-
61
- PLATFORM = platform .system ().lower ()
62
-
63
- STARTUPINFO = None
64
-
65
- if PLATFORM == 'windows' : # pragma: no cover
66
- STARTUPINFO = subprocess .STARTUPINFO ()
67
- STARTUPINFO .dwFlags |= subprocess .STARTF_USESHOWWINDOW
68
- STARTUPINFO .wShowWindow = subprocess .SW_HIDE
69
-
70
15
71
16
class Base (object ):
72
17
@@ -76,25 +21,25 @@ class Base(object):
76
21
77
22
@property
78
23
def format (self ):
79
- """The output format used for rendering ('pdf', 'png', etc .)."""
24
+ """The output format used for rendering ('pdf', 'png', .. .)."""
80
25
return self ._format
81
26
82
27
@format .setter
83
28
def format (self , format ):
84
29
format = format .lower ()
85
- if format not in FORMATS :
30
+ if format not in backend . FORMATS :
86
31
raise ValueError ('unknown format: %r' % format )
87
32
self ._format = format
88
33
89
34
@property
90
35
def engine (self ):
91
- """The layout commmand used for rendering ('dot', 'neato', ...)"""
36
+ """The layout commmand used for rendering ('dot', 'neato', ...). """
92
37
return self ._engine
93
38
94
39
@engine .setter
95
40
def engine (self , engine ):
96
41
engine = engine .lower ()
97
- if engine not in ENGINES :
42
+ if engine not in backend . ENGINES :
98
43
raise ValueError ('unknown engine: %r' % engine )
99
44
self ._engine = engine
100
45
@@ -116,13 +61,6 @@ class File(Base):
116
61
117
62
_default_extension = 'gv'
118
63
119
- @staticmethod
120
- def _cmd (engine , format , filepath = None ):
121
- result = [engine , '-T%s' % format ]
122
- if filepath is not None :
123
- result .extend (['-O' , filepath ])
124
- return result
125
-
126
64
def __init__ (self , filename = None , directory = None , format = None , engine = None , encoding = None ):
127
65
if filename is None :
128
66
name = getattr (self , 'name' , None ) or self .__class__ .__name__
@@ -150,27 +88,14 @@ def pipe(self, format=None):
150
88
Args:
151
89
format: The output format used for rendering ('pdf', 'png', etc.).
152
90
Returns:
153
- Stdout of the layout command.
91
+ Binary (encoded) stdout of the layout command.
154
92
"""
155
93
if format is None :
156
94
format = self ._format
157
95
158
- cmd = self ._cmd (self ._engine , format )
159
-
160
96
data = text_type (self .source ).encode (self ._encoding )
161
97
162
- try :
163
- proc = subprocess .Popen (cmd , stdin = subprocess .PIPE ,
164
- stdout = subprocess .PIPE , startupinfo = STARTUPINFO )
165
- except OSError as e :
166
- if e .errno == errno .ENOENT :
167
- raise RuntimeError ('failed to execute %r, '
168
- 'make sure the Graphviz executables '
169
- 'are on your systems\' path' % cmd )
170
- else : # pragma: no cover
171
- raise
172
-
173
- outs , errs = proc .communicate (data )
98
+ outs = backend .pipe (self ._engine , format , data )
174
99
175
100
return outs
176
101
@@ -215,25 +140,11 @@ def render(self, filename=None, directory=None, view=False, cleanup=False):
215
140
"""
216
141
filepath = self .save (filename , directory )
217
142
218
- cmd = self ._cmd (self ._engine , self ._format , filepath )
219
-
220
- try :
221
- proc = subprocess .Popen (cmd , startupinfo = STARTUPINFO )
222
- except OSError as e :
223
- if e .errno == errno .ENOENT :
224
- raise RuntimeError ('failed to execute %r, '
225
- 'make sure the Graphviz executables '
226
- 'are on your systems\' path' % cmd )
227
- else : # pragma: no cover
228
- raise
229
-
230
- returncode = proc .wait ()
143
+ rendered = backend .render (self ._engine , self ._format , filepath )
231
144
232
145
if cleanup :
233
146
os .remove (filepath )
234
147
235
- rendered = '%s.%s' % (filepath , self ._format )
236
-
237
148
if view :
238
149
self ._view (rendered , self ._format )
239
150
@@ -252,8 +163,8 @@ def view(self):
252
163
def _view (self , filepath , format ):
253
164
"""Start the right viewer based on file format and platform."""
254
165
methods = [
255
- '_view_%s_%s' % (format , PLATFORM ),
256
- '_view_%s' % PLATFORM ,
166
+ '_view_%s_%s' % (format , backend . PLATFORM ),
167
+ '_view_%s' % backend . PLATFORM ,
257
168
]
258
169
for name in methods :
259
170
method = getattr (self , name , None )
@@ -262,22 +173,11 @@ def _view(self, filepath, format):
262
173
break
263
174
else :
264
175
raise RuntimeError ('%r has no built-in viewer support for %r '
265
- 'on %r platform' % (self .__class__ , format , PLATFORM ))
266
-
267
- @staticmethod
268
- def _view_linux (filepath ):
269
- """Open filepath in the user's preferred application (linux)."""
270
- subprocess .Popen (['xdg-open' , filepath ])
271
-
272
- @staticmethod
273
- def _view_windows (filepath ):
274
- """Start filepath with its associated application (windows)."""
275
- os .startfile (os .path .normpath (filepath ))
276
-
277
- @staticmethod
278
- def _view_darwin (filepath ):
279
- """Open filepath with its default application (mac)."""
280
- subprocess .Popen (['open' , filepath ])
176
+ 'on %r platform' % (self .__class__ , format , backend .PLATFORM ))
177
+
178
+ _view_linux = staticmethod (backend .view_linux )
179
+ _view_windows = staticmethod (backend .view_windows )
180
+ _view_darwin = staticmethod (backend .view_darwin )
281
181
282
182
283
183
class Source (File ):
0 commit comments