File size: 7,137 Bytes
d015b2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"""Pipe DOT code objects through Graphviz ``dot``."""

import codecs
import logging
import typing

from . import _tools
from . import backend
from . import exceptions
from . import base
from . import encoding

__all__ = ['Pipe']


log = logging.getLogger(__name__)


class Pipe(encoding.Encoding, base.Base, backend.Pipe):
    """Pipe source lines through the Graphviz layout command."""

    @typing.overload
    def pipe(self,

             format: typing.Optional[str] = ...,

             renderer: typing.Optional[str] = ...,

             formatter: typing.Optional[str] = ...,

             neato_no_op: typing.Union[bool, int, None] = ...,

             quiet: bool = ..., *,

             engine: typing.Optional[str] = ...,

             encoding: None = ...) -> bytes:
        """Return bytes with default ``encoding=None``."""

    @typing.overload
    def pipe(self,

             format: typing.Optional[str] = ...,

             renderer: typing.Optional[str] = ...,

             formatter: typing.Optional[str] = ...,

             neato_no_op: typing.Union[bool, int, None] = ...,

             quiet: bool = ..., *,

             engine: typing.Optional[str] = ...,

             encoding: str) -> str:
        """Return string when given encoding."""

    @typing.overload
    def pipe(self,

             format: typing.Optional[str] = ...,

             renderer: typing.Optional[str] = ...,

             formatter: typing.Optional[str] = ...,

             neato_no_op: typing.Union[bool, int, None] = ...,

             quiet: bool = ..., *,

             engine: typing.Optional[str] = ...,

             encoding: typing.Optional[str]) -> typing.Union[bytes, str]:
        """Return bytes or string depending on encoding argument."""

    def pipe(self,

             format: typing.Optional[str] = None,

             renderer: typing.Optional[str] = None,

             formatter: typing.Optional[str] = None,

             neato_no_op: typing.Union[bool, int, None] = None,

             quiet: bool = False, *,

             engine: typing.Optional[str] = None,

             encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
        """Return the source piped through the Graphviz layout command.



        Args:

            format: The output format used for rendering

                (``'pdf'``, ``'png'``, etc.).

            renderer: The output renderer used for rendering

                (``'cairo'``, ``'gd'``, ...).

            formatter: The output formatter used for rendering

                (``'cairo'``, ``'gd'``, ...).

            neato_no_op: Neato layout engine no-op flag.

            quiet (bool): Suppress ``stderr`` output

                from the layout subprocess.

            engine: Layout engine for rendering

                (``'dot'``, ``'neato'``, ...).

            encoding: Encoding for decoding the stdout.



        Returns:

            Bytes or if encoding is given decoded string

                (stdout of the layout command).



        Raises:

            ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter``

                are unknown.

            graphviz.RequiredArgumentError: If ``formatter`` is given

                but ``renderer`` is None.

            graphviz.ExecutableNotFound: If the Graphviz ``dot`` executable

                is not found.

            graphviz.CalledProcessError: If the returncode (exit status)

                of the rendering ``dot`` subprocess is non-zero.



        Example:

            >>> doctest_mark_exe()

            >>> import graphviz

            >>> source = 'graph { spam }'

            >>> graphviz.Source(source, format='svg').pipe()[:14]

            b'<?xml version='

            >>> graphviz.Source(source, format='svg').pipe(encoding='ascii')[:14]

            '<?xml version='

            >>> graphviz.Source(source, format='svg').pipe(encoding='utf-8')[:14]

            '<?xml version='

        """
        return self._pipe_legacy(format,
                                 renderer=renderer,
                                 formatter=formatter,
                                 neato_no_op=neato_no_op,
                                 quiet=quiet,
                                 engine=engine,
                                 encoding=encoding)

    @_tools.deprecate_positional_args(supported_number=2)
    def _pipe_legacy(self,

                     format: typing.Optional[str] = None,

                     renderer: typing.Optional[str] = None,

                     formatter: typing.Optional[str] = None,

                     neato_no_op: typing.Union[bool, int, None] = None,

                     quiet: bool = False, *,

                     engine: typing.Optional[str] = None,

                     encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
        return self._pipe_future(format,
                                 renderer=renderer,
                                 formatter=formatter,
                                 neato_no_op=neato_no_op,
                                 quiet=quiet,
                                 engine=engine,
                                 encoding=encoding)

    def _pipe_future(self, format: typing.Optional[str] = None, *,

                     renderer: typing.Optional[str] = None,

                     formatter: typing.Optional[str] = None,

                     neato_no_op: typing.Union[bool, int, None] = None,

                     quiet: bool = False,

                     engine: typing.Optional[str] = None,

                     encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
        args, kwargs = self._get_pipe_parameters(engine=engine,
                                                 format=format,
                                                 renderer=renderer,
                                                 formatter=formatter,
                                                 neato_no_op=neato_no_op,
                                                 quiet=quiet,
                                                 verify=True)

        args.append(iter(self))

        if encoding is not None:
            if codecs.lookup(encoding) is codecs.lookup(self.encoding):
                # common case: both stdin and stdout need the same encoding
                return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
            try:
                raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)
            except exceptions.CalledProcessError as e:
                *args, output, stderr = e.args
                if output is not None:
                    output = output.decode(self.encoding)
                if stderr is not None:
                    stderr = stderr.decode(self.encoding)
                raise e.__class__(*args, output=output, stderr=stderr)
            else:
                return raw.decode(encoding)
        return self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)