Codebase list python-graphviz / d97c84a
New upstream version 0.20.1 Diane Trout 1 year, 3 months ago
50 changed file(s) with 745 addition(s) and 582 deletion(s). Raw diff Collapse all Expand all
00 Changelog
11 =========
2
3
4 Version 0.20.1
5 --------------
6
7 Fix documentation building: upgrade to Sphinx 5.0.
8
9 Fix broken user guide links in API documentation.
10
11
12 Version 0.20
13 ------------
14
15 Add keyword-only ``neato_no_op`` argument to ``.render()``, ``.pipe()``,
16 and stand-alone ``graphviz.render()`` and ``graphviz.pipe()``.
17
18 When building a ``Graph`` or ``Digraph``,
19 warn about an expected DOT syntax error in rendering
20 when passing a string that ends with an odd number of backslashes
21 (e.g. invalid ``dot.node('spam', label='\\')``
22 instead of correct ``..., label=r'\\'``
23 for a node labled as a backslash).
24
25 Increase visibility of ``graphviz.escape()`` in the documentation.
26
27
28 Version 0.19.2
29 --------------
30
31 Drop Python 3.6 support (end of life 23 Dec 2021).
32
33 Fix ``ExecutableNotFound`` and ``CalledProcessError`` in ``graphviz.__all__``.
34
35 Better document ``0.18`` change of behaviour for the ``body`` argument/attribute
36 (lines need to include their final newline).
237
338
439 Version 0.19.1
146181 the yielded lines now include a final newline (``'\n'``).
147182 This mimics iteration over ``file`` object lines in text mode.
148183
184 Change of behaviour:
185 When adding custom DOT statements using the ``body`` argument
186 of ``Graph`` or ``Digraph`` or appending to the ``body`` attribute
187 of an instance, the lines now need to include their final newline (``'\n'``).
188
149189 When passing invalid parameters such as unknown ``engine``, ``format``, etc.,
150190 ``.render()`` now raises early before writing the file.
151191 Call ``.save()`` explicitly to produce the previous (less safe) behaviour.
00 The MIT License (MIT)
11
2 Copyright (c) 2013-2021 Sebastian Bank
2 Copyright (c) 2013-2022 Sebastian Bank
33
44 Permission is hereby granted, free of charge, to any person obtaining a copy
55 of this software and associated documentation files (the "Software"), to deal
00 Metadata-Version: 2.1
11 Name: graphviz
2 Version: 0.19.1
2 Version: 0.20.1
33 Summary: Simple Python interface for Graphviz
44 Home-page: https://github.com/xflr6/graphviz
55 Author: Sebastian Bank
1818 Classifier: License :: OSI Approved :: MIT License
1919 Classifier: Operating System :: OS Independent
2020 Classifier: Programming Language :: Python :: 3
21 Classifier: Programming Language :: Python :: 3.6
2221 Classifier: Programming Language :: Python :: 3.7
2322 Classifier: Programming Language :: Python :: 3.8
2423 Classifier: Programming Language :: Python :: 3.9
2524 Classifier: Programming Language :: Python :: 3.10
2625 Classifier: Topic :: Scientific/Engineering :: Visualization
27 Requires-Python: >=3.6
26 Requires-Python: >=3.7
2827 Provides-Extra: dev
2928 Provides-Extra: test
3029 Provides-Extra: docs
6968 Installation
7069 ------------
7170
72 This package runs under Python 3.6+, use pip_ to install:
71 This package runs under Python 3.7+, use pip_ to install:
7372
7473 .. code:: bash
7574
156155 :align: center
157156 :alt: round-table.svg
158157
158 **Caveat:**
159 Backslash-escapes and strings of the form ``<...>``
160 have a special meaning in the DOT language.
161 If you need to render arbitrary strings (e.g. from user input),
162 check the details in the `user guide`_.
163
159164
160165 See also
161166 --------
205210 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
206211 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
207212 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
213
214 .. _user guide: https://graphviz.readthedocs.io/en/stable/manual.html
208215
209216 .. _pygraphviz: https://pypi.org/project/pygraphviz/
210217 .. _graphviz-python: https://pypi.org/project/graphviz-python/
249256 .. |Binder-stable| image:: https://img.shields.io/badge/launch-binder%20(stable)-579ACA.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAABZCAMAAABi1XidAAAB8lBMVEX///9XmsrmZYH1olJXmsr1olJXmsrmZYH1olJXmsr1olJXmsrmZYH1olL1olJXmsr1olJXmsrmZYH1olL1olJXmsrmZYH1olJXmsr1olL1olJXmsrmZYH1olL1olJXmsrmZYH1olL1olL0nFf1olJXmsrmZYH1olJXmsq8dZb1olJXmsrmZYH1olJXmspXmspXmsr1olL1olJXmsrmZYH1olJXmsr1olL1olJXmsrmZYH1olL1olLeaIVXmsrmZYH1olL1olL1olJXmsrmZYH1olLna31Xmsr1olJXmsr1olJXmsrmZYH1olLqoVr1olJXmsr1olJXmsrmZYH1olL1olKkfaPobXvviGabgadXmsqThKuofKHmZ4Dobnr1olJXmsr1olJXmspXmsr1olJXmsrfZ4TuhWn1olL1olJXmsqBi7X1olJXmspZmslbmMhbmsdemsVfl8ZgmsNim8Jpk8F0m7R4m7F5nLB6jbh7jbiDirOEibOGnKaMhq+PnaCVg6qWg6qegKaff6WhnpKofKGtnomxeZy3noG6dZi+n3vCcpPDcpPGn3bLb4/Mb47UbIrVa4rYoGjdaIbeaIXhoWHmZYHobXvpcHjqdHXreHLroVrsfG/uhGnuh2bwj2Hxk17yl1vzmljzm1j0nlX1olL3AJXWAAAAbXRSTlMAEBAQHx8gICAuLjAwMDw9PUBAQEpQUFBXV1hgYGBkcHBwcXl8gICAgoiIkJCQlJicnJ2goKCmqK+wsLC4usDAwMjP0NDQ1NbW3Nzg4ODi5+3v8PDw8/T09PX29vb39/f5+fr7+/z8/Pz9/v7+zczCxgAABC5JREFUeAHN1ul3k0UUBvCb1CTVpmpaitAGSLSpSuKCLWpbTKNJFGlcSMAFF63iUmRccNG6gLbuxkXU66JAUef/9LSpmXnyLr3T5AO/rzl5zj137p136BISy44fKJXuGN/d19PUfYeO67Znqtf2KH33Id1psXoFdW30sPZ1sMvs2D060AHqws4FHeJojLZqnw53cmfvg+XR8mC0OEjuxrXEkX5ydeVJLVIlV0e10PXk5k7dYeHu7Cj1j+49uKg7uLU61tGLw1lq27ugQYlclHC4bgv7VQ+TAyj5Zc/UjsPvs1sd5cWryWObtvWT2EPa4rtnWW3JkpjggEpbOsPr7F7EyNewtpBIslA7p43HCsnwooXTEc3UmPmCNn5lrqTJxy6nRmcavGZVt/3Da2pD5NHvsOHJCrdc1G2r3DITpU7yic7w/7Rxnjc0kt5GC4djiv2Sz3Fb2iEZg41/ddsFDoyuYrIkmFehz0HR2thPgQqMyQYb2OtB0WxsZ3BeG3+wpRb1vzl2UYBog8FfGhttFKjtAclnZYrRo9ryG9uG/FZQU4AEg8ZE9LjGMzTmqKXPLnlWVnIlQQTvxJf8ip7VgjZjyVPrjw1te5otM7RmP7xm+sK2Gv9I8Gi++BRbEkR9EBw8zRUcKxwp73xkaLiqQb+kGduJTNHG72zcW9LoJgqQxpP3/Tj//c3yB0tqzaml05/+orHLksVO+95kX7/7qgJvnjlrfr2Ggsyx0eoy9uPzN5SPd86aXggOsEKW2Prz7du3VID3/tzs/sSRs2w7ovVHKtjrX2pd7ZMlTxAYfBAL9jiDwfLkq55Tm7ifhMlTGPyCAs7RFRhn47JnlcB9RM5T97ASuZXIcVNuUDIndpDbdsfrqsOppeXl5Y+XVKdjFCTh+zGaVuj0d9zy05PPK3QzBamxdwtTCrzyg/2Rvf2EstUjordGwa/kx9mSJLr8mLLtCW8HHGJc2R5hS219IiF6PnTusOqcMl57gm0Z8kanKMAQg0qSyuZfn7zItsbGyO9QlnxY0eCuD1XL2ys/MsrQhltE7Ug0uFOzufJFE2PxBo/YAx8XPPdDwWN0MrDRYIZF0mSMKCNHgaIVFoBbNoLJ7tEQDKxGF0kcLQimojCZopv0OkNOyWCCg9XMVAi7ARJzQdM2QUh0gmBozjc3Skg6dSBRqDGYSUOu66Zg+I2fNZs/M3/f/Grl/XnyF1Gw3VKCez0PN5IUfFLqvgUN4C0qNqYs5YhPL+aVZYDE4IpUk57oSFnJm4FyCqqOE0jhY2SMyLFoo56zyo6becOS5UVDdj7Vih0zp+tcMhwRpBeLyqtIjlJKAIZSbI8SGSF3k0pA3mR5tHuwPFoa7N7reoq2bqCsAk1HqCu5uvI1n6JuRXI+S1Mco54YmYTwcn6Aeic+kssXi8XpXC4V3t7/ADuTNKaQJdScAAAAAElFTkSuQmCC
250257 :target: https://mybinder.org/v2/gh/xflr6/graphviz/stable
251258 :alt: Binder (stable)
252
253
3636 Installation
3737 ------------
3838
39 This package runs under Python 3.6+, use pip_ to install:
39 This package runs under Python 3.7+, use pip_ to install:
4040
4141 .. code:: bash
4242
123123 :align: center
124124 :alt: round-table.svg
125125
126 **Caveat:**
127 Backslash-escapes and strings of the form ``<...>``
128 have a special meaning in the DOT language.
129 If you need to render arbitrary strings (e.g. from user input),
130 check the details in the `user guide`_.
131
126132
127133 See also
128134 --------
172178 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
173179 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
174180 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
181
182 .. _user guide: https://graphviz.readthedocs.io/en/stable/manual.html
175183
176184 .. _pygraphviz: https://pypi.org/project/pygraphviz/
177185 .. _graphviz-python: https://pypi.org/project/graphviz-python/
0 """pytest command line options and doctest namespace."""
0 """pytest command line options and doctest flag definition/setup."""
11
2 import pytest
2 import doctest
3 import unittest.mock
4
5 NO_EXE = doctest.register_optionflag('NO_EXE')
6
7 class NoExeChecker(doctest.OutputChecker): # noqa: E302
8
9 def check_output(self, want, got, optionflags, *args, **kwargs) -> bool:
10 if optionflags & NO_EXE:
11 return True
12 return super().check_output(want, got, optionflags, *args, **kwargs)
13
14 unittest.mock.patch.object(doctest, 'OutputChecker', new=NoExeChecker).start() # noqa: E305
15
16 import pytest # noqa: E402
317
418 SKIP_EXE = '--skip-exe'
519
3232 .. _DOT command: https://graphviz.org/doc/info/command.html
3333 .. _DOT layouts: https://graphviz.org/docs/layouts/
3434 .. _DOT outputs: https://graphviz.org/docs/outputs/
35 .. _DOT neato: https://graphviz.org/docs/layouts/neato/
36 .. _neato no-op: https://www.graphviz.org/doc/info/command.html#-n
3537 .. _DOT attrs: https://www.graphviz.org/doc/info/attrs.html
38 .. _DOT pos: https://graphviz.org/docs/attrs/pos/
39 .. _DOT overlap: https://graphviz.org/docs/attrs/overlap/
40 .. _DOT splines: https://graphviz.org/docs/attrs/splines/
3641 .. _DOT escString: https://www.graphviz.org/docs/attr-types/escString/
3742 .. _DOT shapes: https://graphviz.org/doc/info/shapes.html
3843 .. _DOT shapes HTML: https://graphviz.org/doc/info/shapes.html#html
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.49.3 (20211023.0002)
4 -->
5 <!-- Title: splines Pages: 1 -->
6 <svg width="112pt" height="76pt"
7 viewBox="0.00 0.00 111.60 75.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 71.8)">
9 <title>splines</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-71.8 107.6,-71.8 107.6,4 -4,4"/>
11 <!-- a -->
12 <g id="node1" class="node">
13 <title>a</title>
14 <ellipse fill="blue" stroke="blue" cx="1.8" cy="-1.8" rx="1.8" ry="1.8"/>
15 </g>
16 <!-- b -->
17 <g id="node2" class="node">
18 <title>b</title>
19 <ellipse fill="green" stroke="green" cx="101.8" cy="-1.8" rx="1.8" ry="1.8"/>
20 </g>
21 <!-- a&#45;&gt;b -->
22 <g id="edge1" class="edge">
23 <title>a&#45;&gt;b</title>
24 <path fill="none" stroke="black" d="M1.8,-1.8C31.8,-67.8 71.8,-61.8 101.8,-1.8"/>
25 </g>
26 <!-- c -->
27 <g id="node3" class="node">
28 <title>c</title>
29 <ellipse fill="red" stroke="red" cx="51.8" cy="-51.8" rx="1.8" ry="1.8"/>
30 </g>
31 </g>
32 </svg>
88 graphviz.Source
99 graphviz.escape
1010 graphviz.nohtml
11 graphviz.RequiredArgumentError
1211 graphviz.ExecutableNotFound
1312 graphviz.CalledProcessError
13 graphviz.RequiredArgumentError
1414 graphviz.render
1515 graphviz.pipe
1616 graphviz.pipe_string
9191 Exceptions
9292 ----------
9393
94 .. autoexception:: graphviz.ExecutableNotFound
95
96 .. autoexception:: graphviz.CalledProcessError
97
9498 .. autoexception:: graphviz.RequiredArgumentError
95
96 .. autoexception:: graphviz.ExecutableNotFound
97
98 .. autoexception:: graphviz.CalledProcessError
9999
100100 .. autoexception:: graphviz.FileExistsError
101101
106106 .. autoexception:: graphviz.UnknownSuffixWarning
107107
108108 .. autoexception:: graphviz.FormatSuffixMismatchWarning
109
110 .. autoexception:: graphviz.DotSyntaxWarning
109111
110112
111113 Low-level functions
267269 | graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
268270 | node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
269271 | edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
270 | body: Iterable of verbatim lines to add to the graph ``body``.
272 | body: Iterable of verbatim lines (including their final newline)
273 | to add to the graph ``body``.
271274 | strict (bool): Rendering should merge multi-edges.
272275 |
273276 | Note:
362365 | (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
363366 | attrs: Attributes to be set (must be strings, may be empty).
364367 |
365 | See the `usage examples in the User Guide <attributes>`.
368 | See the :ref:`usage examples in the User Guide <attributes>`.
366369 |
367370 | clear(self, keep_attrs: bool = False) -> None
368371 | Reset content to an empty body, clear graph/node/egde_attr mappings.
389392 | The ``tail_name`` and ``head_name`` strings are separated
390393 | by (optional) colon(s) into ``node`` name, ``port`` name,
391394 | and ``compass`` (e.g. ``sw``).
392 | See `details in the User Guide <ports>`.
395 | See :ref:`details in the User Guide <node-ports-compass>`.
393396 |
394397 | edges(self, tail_head_iter) -> None
395398 | Create a bunch of edges.
403406 | The ``tail_name`` and ``head_name`` strings are separated
404407 | by (optional) colon(s) into ``node`` name, ``port`` name,
405408 | and ``compass`` (e.g. ``sw``).
406 | See `details in the User Guide <ports>`.
409 | See :ref:`details in the User Guide <node-ports-compass>`.
407410 |
408411 | node(self,
409412 name: str,
446449 | body: Verbatim lines to add to the subgraph ``body``
447450 | (``with``-block use).
448451 |
449 | See the `usage examples in the User Guide <subgraphs>`.
452 | See the :ref:`usage examples in the User Guide <subgraphs-clusters>`.
450453 |
451454 | When used as a context manager, the returned new graph instance
452455 | uses ``strict=None`` and the parent graph's values
468471 format: Optional[str] = None,
469472 renderer: Optional[str] = None,
470473 formatter: Optional[str] = None,
474 neato_no_op: Union[bool, int, NoneType] = None,
471475 quiet: bool = False,
472476 quiet_view: bool = False, *,
473477 outfile: Union[os.PathLike, str, NoneType] = None,
490494 | (``'cairo'``, ``'gd'``, ...).
491495 | formatter: The output formatter used for rendering
492496 | (``'cairo'``, ``'gd'``, ...).
497 | neato_no_op: Neato layout engine no-op flag.
493498 | quiet (bool): Suppress ``stderr`` output
494499 | from the layout subprocess.
495500 | quiet_view (bool): Suppress ``stderr`` output
603608 format: Optional[str] = None,
604609 renderer: Optional[str] = None,
605610 formatter: Optional[str] = None,
611 neato_no_op: Union[bool, int, NoneType] = None,
606612 quiet: bool = False, *,
607613 engine: Optional[str] = None,
608614 encoding: Optional[str] = None) -> Union[bytes, str]
615621 | (``'cairo'``, ``'gd'``, ...).
616622 | formatter: The output formatter used for rendering
617623 | (``'cairo'``, ``'gd'``, ...).
624 | neato_no_op: Neato layout engine no-op flag.
618625 | quiet (bool): Suppress ``stderr`` output
619626 | from the layout subprocess.
620627 | engine: Layout engine for rendering
774781 | graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
775782 | node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
776783 | edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
777 | body: Iterable of verbatim lines to add to the graph ``body``.
784 | body: Iterable of verbatim lines (including their final newline)
785 | to add to the graph ``body``.
778786 | strict (bool): Rendering should merge multi-edges.
779787 |
780788 | Note:
869877 | (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
870878 | attrs: Attributes to be set (must be strings, may be empty).
871879 |
872 | See the `usage examples in the User Guide <attributes>`.
880 | See the :ref:`usage examples in the User Guide <attributes>`.
873881 |
874882 | clear(self, keep_attrs: bool = False) -> None
875883 | Reset content to an empty body, clear graph/node/egde_attr mappings.
896904 | The ``tail_name`` and ``head_name`` strings are separated
897905 | by (optional) colon(s) into ``node`` name, ``port`` name,
898906 | and ``compass`` (e.g. ``sw``).
899 | See `details in the User Guide <ports>`.
907 | See :ref:`details in the User Guide <node-ports-compass>`.
900908 |
901909 | edges(self, tail_head_iter) -> None
902910 | Create a bunch of edges.
910918 | The ``tail_name`` and ``head_name`` strings are separated
911919 | by (optional) colon(s) into ``node`` name, ``port`` name,
912920 | and ``compass`` (e.g. ``sw``).
913 | See `details in the User Guide <ports>`.
921 | See :ref:`details in the User Guide <node-ports-compass>`.
914922 |
915923 | node(self,
916924 name: str,
953961 | body: Verbatim lines to add to the subgraph ``body``
954962 | (``with``-block use).
955963 |
956 | See the `usage examples in the User Guide <subgraphs>`.
964 | See the :ref:`usage examples in the User Guide <subgraphs-clusters>`.
957965 |
958966 | When used as a context manager, the returned new graph instance
959967 | uses ``strict=None`` and the parent graph's values
975983 format: Optional[str] = None,
976984 renderer: Optional[str] = None,
977985 formatter: Optional[str] = None,
986 neato_no_op: Union[bool, int, NoneType] = None,
978987 quiet: bool = False,
979988 quiet_view: bool = False, *,
980989 outfile: Union[os.PathLike, str, NoneType] = None,
9971006 | (``'cairo'``, ``'gd'``, ...).
9981007 | formatter: The output formatter used for rendering
9991008 | (``'cairo'``, ``'gd'``, ...).
1009 | neato_no_op: Neato layout engine no-op flag.
10001010 | quiet (bool): Suppress ``stderr`` output
10011011 | from the layout subprocess.
10021012 | quiet_view (bool): Suppress ``stderr`` output
11101120 format: Optional[str] = None,
11111121 renderer: Optional[str] = None,
11121122 formatter: Optional[str] = None,
1123 neato_no_op: Union[bool, int, NoneType] = None,
11131124 quiet: bool = False, *,
11141125 engine: Optional[str] = None,
11151126 encoding: Optional[str] = None) -> Union[bytes, str]
11221133 | (``'cairo'``, ``'gd'``, ...).
11231134 | formatter: The output formatter used for rendering
11241135 | (``'cairo'``, ``'gd'``, ...).
1136 | neato_no_op: Neato layout engine no-op flag.
11251137 | quiet (bool): Suppress ``stderr`` output
11261138 | from the layout subprocess.
11271139 | engine: Layout engine for rendering
13801392 format: Optional[str] = None,
13811393 renderer: Optional[str] = None,
13821394 formatter: Optional[str] = None,
1395 neato_no_op: Union[bool, int, NoneType] = None,
13831396 quiet: bool = False,
13841397 quiet_view: bool = False, *,
13851398 outfile: Union[os.PathLike, str, NoneType] = None,
14021415 | (``'cairo'``, ``'gd'``, ...).
14031416 | formatter: The output formatter used for rendering
14041417 | (``'cairo'``, ``'gd'``, ...).
1418 | neato_no_op: Neato layout engine no-op flag.
14051419 | quiet (bool): Suppress ``stderr`` output
14061420 | from the layout subprocess.
14071421 | quiet_view (bool): Suppress ``stderr`` output
14981512 format: Optional[str] = None,
14991513 renderer: Optional[str] = None,
15001514 formatter: Optional[str] = None,
1515 neato_no_op: Union[bool, int, NoneType] = None,
15011516 quiet: bool = False, *,
15021517 engine: Optional[str] = None,
15031518 encoding: Optional[str] = None) -> Union[bytes, str]
15101525 | (``'cairo'``, ``'gd'``, ...).
15111526 | formatter: The output formatter used for rendering
15121527 | (``'cairo'``, ``'gd'``, ...).
1528 | neato_no_op: Neato layout engine no-op flag.
15131529 | quiet (bool): Suppress ``stderr`` output
15141530 | from the layout subprocess.
15151531 | engine: Layout engine for rendering
6262
6363 Use the :meth:`~.Graph.render` method to save the DOT source code
6464 and render it with the default ``dot`` `layout engine <DOT layouts_>`_
65 (see :ref:`below <Engines>` for using other layout engines).
65 (see :ref:`below <engines>` for using other layout engines).
6666
6767 .. doctest::
6868
8787
8888
8989 .. include:: _links.rst
90
91 .. attention::
92
93 Backslash-escapes and strings of the form ``<...>``
94 have a special meaning in the DOT_ language
95 and are currently passed on as is by this library.
96 If you need to render arbitrary strings literally (e.g. from user input),
97 consider wrapping them with the :func:`graphviz.escape` function first.
98 See the sections on :ref:`backslash-escapes`
99 and :ref:`quoting-and-html-like-labels` below for details.
0 # -*- coding: utf-8 -*-
1 #
20 # Configuration file for the Sphinx documentation builder.
31 #
4 # This file does only contain a selection of the most common options. For a
5 # full list see the documentation:
2 # This file only contains a selection of the most common options. For a full
3 # list see the documentation:
64 # https://www.sphinx-doc.org/en/master/usage/configuration.html
75
86 # -- Path setup --------------------------------------------------------------
2018 # -- Project information -----------------------------------------------------
2119
2220 project = 'graphviz'
23 copyright = '2013-2021, Sebastian Bank'
21 copyright = '2013-2022, Sebastian Bank'
2422 author = 'Sebastian Bank'
2523
26 # The short X.Y version
27 version = '0.19.1'
2824 # The full version, including alpha/beta/rc tags
29 release = version
25 release = '0.20.1'
3026
3127
3228 # -- General configuration ---------------------------------------------------
33
34 # If your documentation needs a minimal Sphinx version, state it here.
35 #
36 # needs_sphinx = '1.0'
3729
3830 # Add any Sphinx extension module names here, as strings. They can be
3931 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
6052 # Add any paths that contain templates here, relative to this directory.
6153 templates_path = ['_templates']
6254
63 # The suffix(es) of source filenames.
64 # You can specify multiple suffix as a list of string:
65 #
66 # source_suffix = ['.rst', '.md']
67 source_suffix = '.rst'
68
69 # The master toctree document.
70 master_doc = 'index'
71
72 # The language for content autogenerated by Sphinx. Refer to documentation
73 # for a list of supported languages.
74 #
75 # This is also used if you do content translation via gettext catalogs.
76 # Usually you set "language" from the command line for these cases.
77 language = None
78
7955 # List of patterns, relative to source directory, that match files and
8056 # directories to ignore when looking for source files.
81 # This pattern also affects html_static_path and html_extra_path .
57 # This pattern also affects html_static_path and html_extra_path.
8258 exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
8359
8460 # The name of the Pygments (syntax highlighting) style to use.
9672 html_theme = 'sphinx_rtd_theme'
9773 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
9874
99 # Theme options are theme-specific and customize the look and feel of a theme
100 # further. For a list of options available for each theme, see the
101 # documentation.
102 #
103 # html_theme_options = {}
104
10575 # Add any paths that contain custom static files (such as style sheets) here,
10676 # relative to this directory. They are copied after the builtin static files,
10777 # so a file named "default.css" will overwrite the builtin "default.css".
10878 html_static_path = ['_static']
109
110 # Custom sidebar templates, must be a dictionary that maps document names
111 # to template names.
112 #
113 # The default sidebars (for documents that don't match any pattern) are
114 # defined by theme itself. Builtin themes are using these templates by
115 # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
116 # 'searchbox.html']``.
117 #
118 # html_sidebars = {}
119
120
121 # -- Options for HTMLHelp output ---------------------------------------------
122
123 # Output file base name for HTML help builder.
124 htmlhelp_basename = 'graphvizdoc'
125
126
127 # -- Options for LaTeX output ------------------------------------------------
128
129 latex_elements = {
130 # The paper size ('letterpaper' or 'a4paper').
131 #
132 # 'papersize': 'letterpaper',
133
134 # The font size ('10pt', '11pt' or '12pt').
135 #
136 # 'pointsize': '10pt',
137
138 # Additional stuff for the LaTeX preamble.
139 #
140 # 'preamble': '',
141
142 # Latex figure (float) alignment
143 #
144 # 'figure_align': 'htbp',
145 }
146
147 # Grouping the document tree into LaTeX files. List of tuples
148 # (source start file, target name, title,
149 # author, documentclass [howto, manual, or own class]).
150 latex_documents = [
151 (master_doc, 'graphviz.tex', 'graphviz Documentation',
152 'Sebastian Bank', 'manual'),
153 ]
154
155
156 # -- Options for manual page output ------------------------------------------
157
158 # One entry per manual page. List of tuples
159 # (source start file, name, description, authors, manual section).
160 man_pages = [
161 (master_doc, 'graphviz', 'graphviz Documentation',
162 [author], 1)
163 ]
164
165
166 # -- Options for Texinfo output ----------------------------------------------
167
168 # Grouping the document tree into Texinfo files. List of tuples
169 # (source start file, target name, title, author,
170 # dir menu entry, description, category)
171 texinfo_documents = [
172 (master_doc, 'graphviz', 'graphviz Documentation',
173 author, 'graphviz', 'One line description of project.',
174 'Miscellaneous'),
175 ]
17679
17780
17881 # -- Extension configuration -------------------------------------------------
18487 'py': ('https://docs.python.org/3', None),
18588 }
18689
187 # monkey patch, see https://github.com/sphinx-doc/sphinx/issues/2044
188 from sphinx.ext.autodoc import ClassLevelDocumenter, InstanceAttributeDocumenter
189
190 def add_directive_header(self, sig):
191 ClassLevelDocumenter.add_directive_header(self, sig)
192
193 InstanceAttributeDocumenter.add_directive_header = add_directive_header
4747
4848 - GitHub Actions
4949 `Build workflow <https://github.com/xflr6/graphviz/actions/workflows/build.yaml>`_
50 (Python 3.6 to 3.10, experimental: PyPy 3.6 to 3.8)
50 (Python 3.7 to 3.10, experimental: PyPy 3.7 to 3.8)
5151 - Codecov
5252 `test coverage <https://app.codecov.io/gh/xflr6/graphviz>`_
5353 (`main branch <https://app.codecov.io/gh/xflr6/graphviz/branch/master>`_)
8282 (`nbviewer <nbviewer graphviz-escapes.ipynb_>`_).
8383
8484
85
8685 .. include:: _links.rst
11 ------------
22
33 :doc:`graphviz <api>` provides a simple pure-Python interface for the Graphviz_
4 graph-drawing software. It runs under Python 3.6+. To install it with pip_, run
4 graph-drawing software. It runs under Python 3.7+. To install it with pip_, run
55 the following:
66
77 .. code:: bash
4141 in repeated add/render/view cycles)
4242
4343
44 .. include:: _links.rst
44 .. include:: _links.rst
55
66 .. include:: installation.rst
77
8
98 .. include:: basic_usage.rst
10
119
1210 .. include:: formats.rst
1311
14
1512 .. include:: piped_output.rst
16
1713
1814 .. include:: jupyter_notebooks.rst
1915
20
2116 .. include:: styling.rst
2217
23
18 .. _attributes:
2419 .. include:: attributes.rst
2520
26
21 .. _node-ports-compass:
2722 .. include:: node_ports.rst
2823
29
24 .. _backslash-escapes:
3025 .. include:: escapes.rst
3126
32
27 .. _quoting-and-html-like-labels:
3328 .. include:: quoting.rst
3429
35
30 .. _subgraphs-clusters:
3631 .. include:: subgraphs_and_clusters.rst
3732
38
39 .. _Engines:
40
33 .. _engines:
4134 .. include:: engines.rst
4235
36 .. include:: neato_no_op.rst
4337
4438 .. include:: unflatten.rst
4539
46
4740 .. include:: custom_dot.rst
4841
49
50 .. _Sources:
51
42 .. _using-raw-dot:
5243 .. include:: raw_dot.rst
53
5444
5545 .. include:: existing_files.rst
5646
57
5847 .. include:: integration_with_viewers.rst
0 ``neato`` no-op flag
1 --------------------
2
3 The `neato <DOT neato_>`_ layout engine
4 supports an additional `rendering flag <neato no-op_>`_
5 that allows more control over the node positioning and the edge layout
6 via the `pos <DOT pos_>`_,
7 `overlap <DOT overlap_>`_,
8 and `splines <DOT splines_>`_ attributes.
9
10 Use the ``neato_no_op`` keyword argument of
11 :meth:`~.Graph.render` or :meth:`~.Graph.pipe`
12 to pass it to the layout command:
13
14 .. doctest::
15
16 >>> doctest_mark_exe()
17
18 >>> import graphviz
19
20 >>> n = graphviz.Digraph(name='splines', engine='neato',
21 ... graph_attr={'splines': 'true'},
22 ... node_attr={'shape': 'point'})
23 >>> n.node('a', pos='0,0!', color='blue')
24 >>> n.node('b', pos='100,0!', color='green')
25 >>> n.node('c', pos='50,50!', color='red')
26 >>> n.edge('a', 'b', pos='0,0 30,66 70,60 100,0')
27 >>> n.render(neato_no_op=2, directory='doctest-output').replace('\\', '/')
28 'doctest-output/splines.gv.pdf'
29
30 .. image:: _static/splines.svg
31 :align: center
32
33
34 .. include:: _links.rst
55 - Render `graphviz.org gallery`_ examples with logging:
66 `examples/graphviz-notebook.ipynb <nbviewer graphviz-notebook.ipynb_>`_
77 (`source <GitHub graphviz-notebook.ipynb_>`_)
8 - `Laypout engine <DOT layouts_>`_ comparison:
8 - `Layout engine <DOT layouts_>`_ comparison:
99 `examples/graphviz-engines.ipynb <nbviewer graphviz-engines.ipynb_>`_
1010 (`source <GitHub graphviz-engines.ipynb_>`_)
1111 - Example for :meth:`graphviz.set_jupyter_format`:
4444 See :class:`API docs <.Source>`).
4545
4646
47 .. include:: _links.rst
47 .. include:: _links.rst
6666 .. code:: bash
6767
6868 $ python setup.py sdist bdist_wheel
69 $ python -m twine check --strict dist/*
6970
7071 - ``dist/graphviz-$MAJOR.$MINOR[.$BUGFIX].zip``
7172 - ``dist/graphviz-$MAJOR.$MINOR[.$BUGFIX]-py3-none-any.whl``
4343 The method returns a :class:`.Source` object
4444 that you can :meth:`~.Source.render`, :meth:`~.Source.view`, etc.
4545 with the same basic API as :class:`.Graph` or :class:`.Digraph` objects
46 (minus modification, see details :ref:`below <Sources>`).
46 (minus modification, see details :ref:`below <using-raw-dot>`).
4747
4848 .. doctest::
4949
77 {
88 "data": {
99 "text/plain": [
10 "('0.19', (2, 40, 1))"
10 "('0.20.dev0', (2, 40, 1))"
1111 ]
1212 },
1313 "execution_count": 1,
1616 }
1717 ],
1818 "source": [
19 "#%cd -q ..\n",
19 "%cd -q ..\n",
2020 "\n",
2121 "import graphviz\n",
2222 "\n",
8989 "</svg>\n"
9090 ],
9191 "text/plain": [
92 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
92 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
9393 ]
9494 },
9595 "metadata": {},
157157 "</svg>\n"
158158 ],
159159 "text/plain": [
160 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
160 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
161161 ]
162162 },
163163 "metadata": {},
225225 "</svg>\n"
226226 ],
227227 "text/plain": [
228 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
228 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
229229 ]
230230 },
231231 "metadata": {},
293293 "</svg>\n"
294294 ],
295295 "text/plain": [
296 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
296 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
297297 ]
298298 },
299299 "metadata": {},
361361 "</svg>\n"
362362 ],
363363 "text/plain": [
364 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
364 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
365365 ]
366366 },
367367 "metadata": {},
411411 "</svg>\n"
412412 ],
413413 "text/plain": [
414 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
414 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
415415 ]
416416 },
417417 "metadata": {},
479479 "</svg>\n"
480480 ],
481481 "text/plain": [
482 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
482 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
483483 ]
484484 },
485485 "metadata": {},
547547 "</svg>\n"
548548 ],
549549 "text/plain": [
550 "<graphviz.graphs.Digraph at 0x7fa255779c10>"
550 "<graphviz.graphs.Digraph at 0x7fc7701f6390>"
551551 ]
552552 },
553553 "metadata": {},
77 {
88 "data": {
99 "text/plain": [
10 "('0.19', (2, 49, 3))"
10 "('0.20.dev0', (2, 40, 1))"
1111 ]
1212 },
1313 "execution_count": 1,
1616 }
1717 ],
1818 "source": [
19 "#%cd -q ..\n",
19 "%cd -q ..\n",
2020 "\n",
2121 "import graphviz\n",
2222 "\n",
5757 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
5858 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
5959 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
60 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
61 " -->\n",
62 "<!-- Pages: 1 -->\n",
60 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
61 " -->\n",
62 "<!-- Title: %3 Pages: 1 -->\n",
6363 "<svg width=\"62pt\" height=\"44pt\"\n",
6464 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
6565 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
66 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
67 "<!-- A -->\n",
68 "<g id=\"node1\" class=\"node\">\n",
69 "<title>A</title>\n",
70 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
71 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">&quot;</text>\n",
72 "</g>\n",
73 "</g>\n",
74 "</svg>\n"
75 ],
76 "text/plain": [
77 "<graphviz.graphs.Digraph at 0x28003e87460>"
66 "<title>%3</title>\n",
67 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
68 "<!-- A -->\n",
69 "<g id=\"node1\" class=\"node\">\n",
70 "<title>A</title>\n",
71 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
72 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">&quot;</text>\n",
73 "</g>\n",
74 "</g>\n",
75 "</svg>\n"
76 ],
77 "text/plain": [
78 "<graphviz.graphs.Digraph at 0x7f1e5c1cb490>"
7879 ]
7980 },
8081 "execution_count": 3,
107108 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
108109 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
109110 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
110 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
111 " -->\n",
112 "<!-- Pages: 1 -->\n",
111 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
112 " -->\n",
113 "<!-- Title: %3 Pages: 1 -->\n",
113114 "<svg width=\"62pt\" height=\"44pt\"\n",
114115 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
115116 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
116 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
117 "<!-- A -->\n",
118 "<g id=\"node1\" class=\"node\">\n",
119 "<title>A</title>\n",
120 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
121 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">&quot;</text>\n",
122 "</g>\n",
123 "</g>\n",
124 "</svg>\n"
125 ],
126 "text/plain": [
127 "<graphviz.graphs.Digraph at 0x28003e879d0>"
117 "<title>%3</title>\n",
118 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
119 "<!-- A -->\n",
120 "<g id=\"node1\" class=\"node\">\n",
121 "<title>A</title>\n",
122 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
123 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">&quot;</text>\n",
124 "</g>\n",
125 "</g>\n",
126 "</svg>\n"
127 ],
128 "text/plain": [
129 "<graphviz.graphs.Digraph at 0x7f1e5c1dd310>"
128130 ]
129131 },
130132 "execution_count": 4,
145147 "name": "stderr",
146148 "output_type": "stream",
147149 "text": [
148 "Error: <stdin>: syntax error in line 4 scanning a quoted string (missing endquote? longer than 16384?)\n",
150 "/home/jovyan/graphviz/quoting.py:88: DotSyntaxWarning: expect syntax error scanning invalid quoted string: '\\\\'\n",
151 " category=exceptions.DotSyntaxWarning)\n",
152 "Error: <stdin>: syntax error in line 2 scanning a quoted string (missing endquote? longer than 16384?)\n",
149153 "String starting:\"\"]\n",
150154 "}\n",
151155 "\n"
190194 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
191195 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
192196 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
193 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
194 " -->\n",
195 "<!-- Pages: 1 -->\n",
197 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
198 " -->\n",
199 "<!-- Title: %3 Pages: 1 -->\n",
196200 "<svg width=\"62pt\" height=\"44pt\"\n",
197201 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
198202 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
199 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
200 "<!-- A -->\n",
201 "<g id=\"node1\" class=\"node\">\n",
202 "<title>A</title>\n",
203 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
204 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\</text>\n",
205 "</g>\n",
206 "</g>\n",
207 "</svg>\n"
208 ],
209 "text/plain": [
210 "<graphviz.graphs.Digraph at 0x28003e87bb0>"
203 "<title>%3</title>\n",
204 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
205 "<!-- A -->\n",
206 "<g id=\"node1\" class=\"node\">\n",
207 "<title>A</title>\n",
208 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
209 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">\\</text>\n",
210 "</g>\n",
211 "</g>\n",
212 "</svg>\n"
213 ],
214 "text/plain": [
215 "<graphviz.graphs.Digraph at 0x7f1e5c1e2d50>"
211216 ]
212217 },
213218 "execution_count": 6,
240245 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
241246 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
242247 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
243 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
244 " -->\n",
245 "<!-- Pages: 1 -->\n",
248 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
249 " -->\n",
250 "<!-- Title: %3 Pages: 1 -->\n",
246251 "<svg width=\"62pt\" height=\"44pt\"\n",
247252 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
248253 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
249 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
250 "<!-- A -->\n",
251 "<g id=\"node1\" class=\"node\">\n",
252 "<title>A</title>\n",
253 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
254 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\&quot;</text>\n",
255 "</g>\n",
256 "</g>\n",
257 "</svg>\n"
258 ],
259 "text/plain": [
260 "<graphviz.graphs.Digraph at 0x28003e86e00>"
254 "<title>%3</title>\n",
255 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\n",
256 "<!-- A -->\n",
257 "<g id=\"node1\" class=\"node\">\n",
258 "<title>A</title>\n",
259 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
260 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">\\&quot;</text>\n",
261 "</g>\n",
262 "</g>\n",
263 "</svg>\n"
264 ],
265 "text/plain": [
266 "<graphviz.graphs.Digraph at 0x7f1e5c1b9ed0>"
261267 ]
262268 },
263269 "execution_count": 7,
297303 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
298304 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
299305 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
300 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
301 " -->\n",
302 "<!-- Pages: 1 -->\n",
303 "<svg width=\"87pt\" height=\"44pt\"\n",
304 " viewBox=\"0.00 0.00 87.29 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
305 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
306 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 83.29,-40 83.29,4 -4,4\"/>\n",
307 "<!-- A -->\n",
308 "<g id=\"node1\" class=\"node\">\n",
309 "<title>A</title>\n",
310 "<ellipse fill=\"none\" stroke=\"black\" cx=\"39.65\" cy=\"-18\" rx=\"39.79\" ry=\"18\"/>\n",
311 "<text text-anchor=\"middle\" x=\"39.65\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">node: A</text>\n",
312 "</g>\n",
313 "</g>\n",
314 "</svg>\n"
315 ],
316 "text/plain": [
317 "<graphviz.graphs.Digraph at 0x28003e87d30>"
306 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
307 " -->\n",
308 "<!-- Title: %3 Pages: 1 -->\n",
309 "<svg width=\"100pt\" height=\"44pt\"\n",
310 " viewBox=\"0.00 0.00 100.29 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
311 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
312 "<title>%3</title>\n",
313 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 96.2918,-40 96.2918,4 -4,4\"/>\n",
314 "<!-- A -->\n",
315 "<g id=\"node1\" class=\"node\">\n",
316 "<title>A</title>\n",
317 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"46.1459\" cy=\"-18\" rx=\"46.2923\" ry=\"18\"/>\n",
318 "<text text-anchor=\"middle\" x=\"46.1459\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">node: A</text>\n",
319 "</g>\n",
320 "</g>\n",
321 "</svg>\n"
322 ],
323 "text/plain": [
324 "<graphviz.graphs.Digraph at 0x7f1e5c267f50>"
318325 ]
319326 },
320327 "execution_count": 8,
347354 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
348355 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
349356 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
350 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
357 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
351358 " -->\n",
352359 "<!-- Title: spam Pages: 1 -->\n",
353 "<svg width=\"118pt\" height=\"44pt\"\n",
354 " viewBox=\"0.00 0.00 118.49 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
360 "<svg width=\"146pt\" height=\"44pt\"\n",
361 " viewBox=\"0.00 0.00 145.79 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
355362 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
356363 "<title>spam</title>\n",
357 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 114.49,-40 114.49,4 -4,4\"/>\n",
358 "<!-- A -->\n",
359 "<g id=\"node1\" class=\"node\">\n",
360 "<title>A</title>\n",
361 "<ellipse fill=\"none\" stroke=\"black\" cx=\"55.25\" cy=\"-18\" rx=\"55.49\" ry=\"18\"/>\n",
362 "<text text-anchor=\"middle\" x=\"55.25\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">graph: spam</text>\n",
363 "</g>\n",
364 "</g>\n",
365 "</svg>\n"
366 ],
367 "text/plain": [
368 "<graphviz.graphs.Digraph at 0x28003ed0340>"
364 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 141.7878,-40 141.7878,4 -4,4\"/>\n",
365 "<!-- A -->\n",
366 "<g id=\"node1\" class=\"node\">\n",
367 "<title>A</title>\n",
368 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"68.8939\" cy=\"-18\" rx=\"68.7879\" ry=\"18\"/>\n",
369 "<text text-anchor=\"middle\" x=\"68.8939\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">graph: spam</text>\n",
370 "</g>\n",
371 "</g>\n",
372 "</svg>\n"
373 ],
374 "text/plain": [
375 "<graphviz.graphs.Digraph at 0x7f1e5c1e2890>"
369376 ]
370377 },
371378 "execution_count": 9,
398405 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
399406 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
400407 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
401 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
402 " -->\n",
403 "<!-- Pages: 1 -->\n",
404 "<svg width=\"69pt\" height=\"44pt\"\n",
405 " viewBox=\"0.00 0.00 69.09 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
406 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
407 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 65.09,-40 65.09,4 -4,4\"/>\n",
408 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
409 " -->\n",
410 "<!-- Title: %3 Pages: 1 -->\n",
411 "<svg width=\"79pt\" height=\"44pt\"\n",
412 " viewBox=\"0.00 0.00 79.49 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
413 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
414 "<title>%3</title>\n",
415 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 75.4937,-40 75.4937,4 -4,4\"/>\n",
408416 "<!-- A -->\n",
409417 "<g id=\"node1\" class=\"node\">\n",
410418 "<title>A</title>\n",
411419 "<g id=\"a_node1\"><a xlink:href=\"https://example.org/spam\" xlink:title=\"spam\">\n",
412 "<ellipse fill=\"none\" stroke=\"black\" cx=\"30.55\" cy=\"-18\" rx=\"30.59\" ry=\"18\"/>\n",
413 "<text text-anchor=\"middle\" x=\"30.55\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">spam</text>\n",
420 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"35.7468\" cy=\"-18\" rx=\"35.9954\" ry=\"18\"/>\n",
421 "<text text-anchor=\"middle\" x=\"35.7468\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">spam</text>\n",
414422 "</a>\n",
415423 "</g>\n",
416424 "</g>\n",
418426 "</svg>\n"
419427 ],
420428 "text/plain": [
421 "<graphviz.graphs.Digraph at 0x28003e874c0>"
429 "<graphviz.graphs.Digraph at 0x7f1e5c16c310>"
422430 ]
423431 },
424432 "execution_count": 10,
451459 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
452460 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
453461 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
454 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
455 " -->\n",
456 "<!-- Pages: 1 -->\n",
457 "<svg width=\"99pt\" height=\"83pt\"\n",
458 " viewBox=\"0.00 0.00 98.51 82.95\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
459 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 78.95)\">\n",
460 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-78.95 94.51,-78.95 94.51,4 -4,4\"/>\n",
461 "<!-- A -->\n",
462 "<g id=\"node1\" class=\"node\">\n",
463 "<title>A</title>\n",
464 "<ellipse fill=\"none\" stroke=\"black\" cx=\"45.25\" cy=\"-37.48\" rx=\"45.01\" ry=\"37.45\"/>\n",
465 "<text text-anchor=\"middle\" x=\"45.25\" y=\"-48.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">centered</text>\n",
466 "<text text-anchor=\"start\" x=\"21.25\" y=\"-33.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">left</text>\n",
467 "<text text-anchor=\"end\" x=\"69.25\" y=\"-18.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">right</text>\n",
468 "</g>\n",
469 "</g>\n",
470 "</svg>\n"
471 ],
472 "text/plain": [
473 "<graphviz.graphs.Digraph at 0x28003e1bfa0>"
462 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
463 " -->\n",
464 "<!-- Title: %3 Pages: 1 -->\n",
465 "<svg width=\"121pt\" height=\"83pt\"\n",
466 " viewBox=\"0.00 0.00 121.14 82.95\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
467 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 78.9533)\">\n",
468 "<title>%3</title>\n",
469 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-78.9533 117.1371,-78.9533 117.1371,4 -4,4\"/>\n",
470 "<!-- A -->\n",
471 "<g id=\"node1\" class=\"node\">\n",
472 "<title>A</title>\n",
473 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"56.5685\" cy=\"-37.4767\" rx=\"56.6372\" ry=\"37.4533\"/>\n",
474 "<text text-anchor=\"middle\" x=\"56.5685\" y=\"-48.7767\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">centered</text>\n",
475 "<text text-anchor=\"start\" x=\"24.5685\" y=\"-33.7767\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">left</text>\n",
476 "<text text-anchor=\"end\" x=\"88.5685\" y=\"-18.7767\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">right</text>\n",
477 "</g>\n",
478 "</g>\n",
479 "</svg>\n"
480 ],
481 "text/plain": [
482 "<graphviz.graphs.Digraph at 0x7f1e5c16cb10>"
474483 ]
475484 },
476485 "execution_count": 11,
499508 "name": "python",
500509 "nbconvert_exporter": "python",
501510 "pygments_lexer": "ipython3",
502 "version": "3.10.0"
511 "version": "3.7.12"
503512 }
504513 },
505514 "nbformat": 4,
506 "nbformat_minor": 2
515 "nbformat_minor": 4
507516 }
88 {
99 "data": {
1010 "text/plain": [
11 "('0.19', (2, 49, 3))"
11 "('0.20.dev0', (2, 40, 1))"
1212 ]
1313 },
1414 "execution_count": 1,
5353 "outputs": [
5454 {
5555 "data": {
56 "image/png": "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\n",
56 "image/png": "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\n",
5757 "text/plain": [
58 "<graphviz.graphs.Digraph at 0x13e013ef460>"
58 "<graphviz.graphs.Digraph at 0x7fb0306b1210>"
5959 ]
6060 },
6161 "execution_count": 3,
8888 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
8989 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
9090 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
91 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
91 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
9292 " -->\n",
93 "<!-- Pages: 1 -->\n",
94 "<svg width=\"390pt\" height=\"116pt\"\n",
95 " viewBox=\"0.00 0.00 389.98 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
93 "<!-- Title: %3 Pages: 1 -->\n",
94 "<svg width=\"488pt\" height=\"116pt\"\n",
95 " viewBox=\"0.00 0.00 488.38 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
9696 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\n",
97 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 385.98,-112 385.98,4 -4,4\"/>\n",
97 "<title>%3</title>\n",
98 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-112 484.3795,-112 484.3795,4 -4,4\"/>\n",
9899 "<!-- A -->\n",
99100 "<g id=\"node1\" class=\"node\">\n",
100101 "<title>A</title>\n",
101 "<ellipse fill=\"none\" stroke=\"black\" cx=\"190.99\" cy=\"-90\" rx=\"53.89\" ry=\"18\"/>\n",
102 "<text text-anchor=\"middle\" x=\"190.99\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">King Arthur</text>\n",
102 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"239.0398\" cy=\"-90\" rx=\"66.0889\" ry=\"18\"/>\n",
103 "<text text-anchor=\"middle\" x=\"239.0398\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">King Arthur</text>\n",
103104 "</g>\n",
104105 "<!-- B -->\n",
105106 "<g id=\"node2\" class=\"node\">\n",
106107 "<title>B</title>\n",
107 "<ellipse fill=\"none\" stroke=\"black\" cx=\"90.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\n",
108 "<text text-anchor=\"middle\" x=\"90.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Bedevere the Wise</text>\n",
108 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"115.0398\" cy=\"-18\" rx=\"115.0796\" ry=\"18\"/>\n",
109 "<text text-anchor=\"middle\" x=\"115.0398\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Sir Bedevere the Wise</text>\n",
109110 "</g>\n",
110111 "<!-- A&#45;&gt;B -->\n",
111112 "<g id=\"edge1\" class=\"edge\">\n",
112113 "<title>A&#45;&gt;B</title>\n",
113 "<path fill=\"none\" stroke=\"black\" d=\"M168.8,-73.46C155.33,-64.04 137.92,-51.85 122.98,-41.39\"/>\n",
114 "<polygon fill=\"black\" stroke=\"black\" points=\"124.72,-38.33 114.52,-35.47 120.7,-44.07 124.72,-38.33\"/>\n",
114 "<path fill=\"none\" stroke=\"#000000\" d=\"M210.9023,-73.6621C194.0767,-63.8924 172.4517,-51.3359 154.0004,-40.6223\"/>\n",
115 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"155.6378,-37.5258 145.2324,-35.5312 152.1228,-43.5793 155.6378,-37.5258\"/>\n",
115116 "</g>\n",
116117 "<!-- L -->\n",
117118 "<g id=\"node3\" class=\"node\">\n",
118119 "<title>L</title>\n",
119 "<ellipse fill=\"none\" stroke=\"black\" cx=\"290.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\n",
120 "<text text-anchor=\"middle\" x=\"290.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Lancelot the Brave</text>\n",
120 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"364.0398\" cy=\"-18\" rx=\"116.1796\" ry=\"18\"/>\n",
121 "<text text-anchor=\"middle\" x=\"364.0398\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Sir Lancelot the Brave</text>\n",
121122 "</g>\n",
122123 "<!-- A&#45;&gt;L -->\n",
123124 "<g id=\"edge2\" class=\"edge\">\n",
124125 "<title>A&#45;&gt;L</title>\n",
125 "<path fill=\"none\" stroke=\"black\" d=\"M213.19,-73.46C226.65,-64.04 244.07,-51.85 259.01,-41.39\"/>\n",
126 "<polygon fill=\"black\" stroke=\"black\" points=\"261.28,-44.07 267.47,-35.47 257.27,-38.33 261.28,-44.07\"/>\n",
126 "<path fill=\"none\" stroke=\"#000000\" d=\"M267.4042,-73.6621C284.3654,-63.8924 306.1649,-51.3359 324.765,-40.6223\"/>\n",
127 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"326.6853,-43.5553 333.6037,-35.5312 323.1914,-37.4896 326.6853,-43.5553\"/>\n",
127128 "</g>\n",
128129 "<!-- B&#45;&gt;L -->\n",
129130 "<g id=\"edge3\" class=\"edge\">\n",
130131 "<title>B&#45;&gt;L</title>\n",
131 "<path fill=\"none\" stroke=\"black\" d=\"M182.01,-18C184.62,-18 187.22,-18 189.83,-18\"/>\n",
132 "<polygon fill=\"black\" stroke=\"black\" points=\"189.89,-21.5 199.89,-18 189.89,-14.5 189.89,-21.5\"/>\n",
132 "<path fill=\"none\" stroke=\"#000000\" d=\"M230.2996,-18C232.6341,-18 234.9687,-18 237.3033,-18\"/>\n",
133 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"237.5395,-21.5001 247.5395,-18 237.5395,-14.5001 237.5395,-21.5001\"/>\n",
133134 "</g>\n",
134135 "</g>\n",
135136 "</svg>\n"
162163 "name": "python",
163164 "nbconvert_exporter": "python",
164165 "pygments_lexer": "ipython3",
165 "version": "3.10.0"
166 "version": "3.7.12"
166167 }
167168 },
168169 "nbformat": 4,
88 "name": "stderr",
99 "output_type": "stream",
1010 "text": [
11 "[DEBUG@graphviz.backend.execute] run [WindowsPath('dot'), '-V']\n"
11 "[DEBUG@graphviz.backend.execute] run [PosixPath('dot'), '-V']\n"
1212 ]
1313 },
1414 {
1515 "data": {
1616 "text/plain": [
17 "('0.19', (2, 49, 3))"
17 "('0.20.dev0', (2, 40, 1))"
1818 ]
1919 },
2020 "execution_count": 1,
4343 "name": "stderr",
4444 "output_type": "stream",
4545 "text": [
46 "[DEBUG@graphviz.backend.execute] run [WindowsPath('dot'), '-Kdot', '-Tsvg']\n"
46 "[DEBUG@graphviz.backend.execute] run [PosixPath('dot'), '-Kdot', '-Tsvg']\n"
4747 ]
4848 },
4949 {
5252 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
5353 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
5454 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
55 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
55 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
5656 " -->\n",
57 "<!-- Pages: 1 -->\n",
58 "<svg width=\"390pt\" height=\"116pt\"\n",
59 " viewBox=\"0.00 0.00 389.98 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
57 "<!-- Title: %3 Pages: 1 -->\n",
58 "<svg width=\"488pt\" height=\"116pt\"\n",
59 " viewBox=\"0.00 0.00 488.38 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
6060 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\n",
61 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 385.98,-112 385.98,4 -4,4\"/>\n",
61 "<title>%3</title>\n",
62 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-112 484.3795,-112 484.3795,4 -4,4\"/>\n",
6263 "<!-- A -->\n",
6364 "<g id=\"node1\" class=\"node\">\n",
6465 "<title>A</title>\n",
65 "<ellipse fill=\"none\" stroke=\"black\" cx=\"190.99\" cy=\"-90\" rx=\"53.89\" ry=\"18\"/>\n",
66 "<text text-anchor=\"middle\" x=\"190.99\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">King Arthur</text>\n",
66 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"239.0398\" cy=\"-90\" rx=\"66.0889\" ry=\"18\"/>\n",
67 "<text text-anchor=\"middle\" x=\"239.0398\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">King Arthur</text>\n",
6768 "</g>\n",
6869 "<!-- B -->\n",
6970 "<g id=\"node2\" class=\"node\">\n",
7071 "<title>B</title>\n",
71 "<ellipse fill=\"none\" stroke=\"black\" cx=\"90.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\n",
72 "<text text-anchor=\"middle\" x=\"90.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Bedevere the Wise</text>\n",
72 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"115.0398\" cy=\"-18\" rx=\"115.0796\" ry=\"18\"/>\n",
73 "<text text-anchor=\"middle\" x=\"115.0398\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Sir Bedevere the Wise</text>\n",
7374 "</g>\n",
7475 "<!-- A&#45;&gt;B -->\n",
7576 "<g id=\"edge1\" class=\"edge\">\n",
7677 "<title>A&#45;&gt;B</title>\n",
77 "<path fill=\"none\" stroke=\"black\" d=\"M168.8,-73.46C155.33,-64.04 137.92,-51.85 122.98,-41.39\"/>\n",
78 "<polygon fill=\"black\" stroke=\"black\" points=\"124.72,-38.33 114.52,-35.47 120.7,-44.07 124.72,-38.33\"/>\n",
78 "<path fill=\"none\" stroke=\"#000000\" d=\"M210.9023,-73.6621C194.0767,-63.8924 172.4517,-51.3359 154.0004,-40.6223\"/>\n",
79 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"155.6378,-37.5258 145.2324,-35.5312 152.1228,-43.5793 155.6378,-37.5258\"/>\n",
7980 "</g>\n",
8081 "<!-- L -->\n",
8182 "<g id=\"node3\" class=\"node\">\n",
8283 "<title>L</title>\n",
83 "<ellipse fill=\"none\" stroke=\"black\" cx=\"290.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\n",
84 "<text text-anchor=\"middle\" x=\"290.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Lancelot the Brave</text>\n",
84 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"364.0398\" cy=\"-18\" rx=\"116.1796\" ry=\"18\"/>\n",
85 "<text text-anchor=\"middle\" x=\"364.0398\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Sir Lancelot the Brave</text>\n",
8586 "</g>\n",
8687 "<!-- A&#45;&gt;L -->\n",
8788 "<g id=\"edge2\" class=\"edge\">\n",
8889 "<title>A&#45;&gt;L</title>\n",
89 "<path fill=\"none\" stroke=\"black\" d=\"M213.19,-73.46C226.65,-64.04 244.07,-51.85 259.01,-41.39\"/>\n",
90 "<polygon fill=\"black\" stroke=\"black\" points=\"261.28,-44.07 267.47,-35.47 257.27,-38.33 261.28,-44.07\"/>\n",
90 "<path fill=\"none\" stroke=\"#000000\" d=\"M267.4042,-73.6621C284.3654,-63.8924 306.1649,-51.3359 324.765,-40.6223\"/>\n",
91 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"326.6853,-43.5553 333.6037,-35.5312 323.1914,-37.4896 326.6853,-43.5553\"/>\n",
9192 "</g>\n",
9293 "<!-- B&#45;&gt;L -->\n",
9394 "<g id=\"edge3\" class=\"edge\">\n",
9495 "<title>B&#45;&gt;L</title>\n",
95 "<path fill=\"none\" stroke=\"black\" d=\"M182.01,-18C184.62,-18 187.22,-18 189.83,-18\"/>\n",
96 "<polygon fill=\"black\" stroke=\"black\" points=\"189.89,-21.5 199.89,-18 189.89,-14.5 189.89,-21.5\"/>\n",
96 "<path fill=\"none\" stroke=\"#000000\" d=\"M230.2996,-18C232.6341,-18 234.9687,-18 237.3033,-18\"/>\n",
97 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"237.5395,-21.5001 247.5395,-18 237.5395,-14.5001 237.5395,-21.5001\"/>\n",
9798 "</g>\n",
9899 "</g>\n",
99100 "</svg>\n"
100101 ],
101102 "text/plain": [
102 "<graphviz.graphs.Digraph at 0x203f26fb670>"
103 "<graphviz.graphs.Digraph at 0x7fe7ac3fc910>"
103104 ]
104105 },
105106 "execution_count": 2,
129130 "name": "stderr",
130131 "output_type": "stream",
131132 "text": [
132 "[DEBUG@graphviz.backend.execute] run [WindowsPath('dot'), '-Kdot', '-Tsvg']\n"
133 "[DEBUG@graphviz.backend.execute] run [PosixPath('dot'), '-Kdot', '-Tsvg']\n"
133134 ]
134135 },
135136 {
138139 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
139140 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
140141 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
141 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
142 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
142143 " -->\n",
143144 "<!-- Title: the holy hand grenade Pages: 1 -->\n",
144145 "<svg width=\"332pt\" height=\"44pt\"\n",
145146 " viewBox=\"0.00 0.00 332.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
146147 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
147148 "<title>the holy hand grenade</title>\n",
148 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 328,-40 328,4 -4,4\"/>\n",
149 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-40 328,-40 328,4 -4,4\"/>\n",
149150 "<!-- 1 -->\n",
150151 "<g id=\"node1\" class=\"node\">\n",
151152 "<title>1</title>\n",
152 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
153 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">1</text>\n",
153 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
154 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
154155 "</g>\n",
155156 "<!-- 2 -->\n",
156157 "<g id=\"node2\" class=\"node\">\n",
157158 "<title>2</title>\n",
158 "<ellipse fill=\"none\" stroke=\"black\" cx=\"117\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
159 "<text text-anchor=\"middle\" x=\"117\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">2</text>\n",
159 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"117\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
160 "<text text-anchor=\"middle\" x=\"117\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
160161 "</g>\n",
161162 "<!-- 1&#45;&gt;2 -->\n",
162163 "<g id=\"edge1\" class=\"edge\">\n",
163164 "<title>1&#45;&gt;2</title>\n",
164 "<path fill=\"none\" stroke=\"black\" d=\"M54.4,-18C62.39,-18 71.31,-18 79.82,-18\"/>\n",
165 "<polygon fill=\"black\" stroke=\"black\" points=\"79.92,-21.5 89.92,-18 79.92,-14.5 79.92,-21.5\"/>\n",
165 "<path fill=\"none\" stroke=\"#000000\" d=\"M54.003,-18C62.0277,-18 70.9665,-18 79.5309,-18\"/>\n",
166 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"79.7051,-21.5001 89.705,-18 79.705,-14.5001 79.7051,-21.5001\"/>\n",
166167 "</g>\n",
167168 "<!-- 3 -->\n",
168169 "<g id=\"node3\" class=\"node\">\n",
169170 "<title>3</title>\n",
170 "<ellipse fill=\"none\" stroke=\"black\" cx=\"207\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
171 "<text text-anchor=\"middle\" x=\"207\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">3</text>\n",
171 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"207\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
172 "<text text-anchor=\"middle\" x=\"207\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
172173 "</g>\n",
173174 "<!-- 2&#45;&gt;3 -->\n",
174175 "<g id=\"edge2\" class=\"edge\">\n",
175176 "<title>2&#45;&gt;3</title>\n",
176 "<path fill=\"none\" stroke=\"black\" d=\"M144.4,-18C152.39,-18 161.31,-18 169.82,-18\"/>\n",
177 "<polygon fill=\"black\" stroke=\"black\" points=\"169.92,-21.5 179.92,-18 169.92,-14.5 169.92,-21.5\"/>\n",
177 "<path fill=\"none\" stroke=\"#000000\" d=\"M144.003,-18C152.0277,-18 160.9665,-18 169.5309,-18\"/>\n",
178 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"169.7051,-21.5001 179.705,-18 169.705,-14.5001 169.7051,-21.5001\"/>\n",
178179 "</g>\n",
179180 "<!-- lob -->\n",
180181 "<g id=\"node4\" class=\"node\">\n",
181182 "<title>lob</title>\n",
182 "<ellipse fill=\"none\" stroke=\"black\" cx=\"297\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
183 "<text text-anchor=\"middle\" x=\"297\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">lob</text>\n",
183 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"297\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
184 "<text text-anchor=\"middle\" x=\"297\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">lob</text>\n",
184185 "</g>\n",
185186 "<!-- 3&#45;&gt;lob -->\n",
186187 "<g id=\"edge3\" class=\"edge\">\n",
187188 "<title>3&#45;&gt;lob</title>\n",
188 "<path fill=\"none\" stroke=\"black\" d=\"M234.4,-18C242.39,-18 251.31,-18 259.82,-18\"/>\n",
189 "<polygon fill=\"black\" stroke=\"black\" points=\"259.92,-21.5 269.92,-18 259.92,-14.5 259.92,-21.5\"/>\n",
189 "<path fill=\"none\" stroke=\"#000000\" d=\"M234.003,-18C242.0277,-18 250.9665,-18 259.5309,-18\"/>\n",
190 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"259.7051,-21.5001 269.705,-18 259.705,-14.5001 259.7051,-21.5001\"/>\n",
190191 "</g>\n",
191192 "</g>\n",
192193 "</svg>\n"
193194 ],
194195 "text/plain": [
195 "<graphviz.sources.Source at 0x203f26fa8c0>"
196 "<graphviz.sources.Source at 0x7fe7ac3fc390>"
196197 ]
197198 },
198199 "execution_count": 3,
214215 "name": "stderr",
215216 "output_type": "stream",
216217 "text": [
217 "[DEBUG@graphviz.backend.execute] run [WindowsPath('dot'), '-Kdot', '-Tsvg']\n"
218 "[DEBUG@graphviz.backend.execute] run [PosixPath('dot'), '-Kdot', '-Tsvg']\n"
218219 ]
219220 },
220221 {
223224 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
224225 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
225226 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
226 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
227 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
227228 " -->\n",
228229 "<!-- Title: finite_state_machine Pages: 1 -->\n",
229 "<svg width=\"576pt\" height=\"258pt\"\n",
230 " viewBox=\"0.00 0.00 576.00 258.45\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
231 "<g id=\"graph0\" class=\"graph\" transform=\"scale(0.77 0.77) rotate(0) translate(4 331.69)\">\n",
230 "<svg width=\"576pt\" height=\"248pt\"\n",
231 " viewBox=\"0.00 0.00 576.00 248.40\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
232 "<g id=\"graph0\" class=\"graph\" transform=\"scale(.7099 .7099) rotate(0) translate(4 345.8939)\">\n",
232233 "<title>finite_state_machine</title>\n",
233 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-331.69 744.17,-331.69 744.17,4 -4,4\"/>\n",
234 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-345.8939 807.3633,-345.8939 807.3633,4 -4,4\"/>\n",
234235 "<!-- LR_0 -->\n",
235236 "<g id=\"node1\" class=\"node\">\n",
236237 "<title>LR_0</title>\n",
237 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"31.71\" ry=\"31.71\"/>\n",
238 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"35.69\" ry=\"35.69\"/>\n",
239 "<text text-anchor=\"middle\" x=\"35.85\" y=\"-80.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_0</text>\n",
238 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"38.4469\" cy=\"-88.4469\" rx=\"34.3995\" ry=\"34.3995\"/>\n",
239 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"38.4469\" cy=\"-88.4469\" rx=\"38.394\" ry=\"38.394\"/>\n",
240 "<text text-anchor=\"middle\" x=\"38.4469\" y=\"-84.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_0</text>\n",
240241 "</g>\n",
241242 "<!-- LR_2 -->\n",
242243 "<g id=\"node5\" class=\"node\">\n",
243244 "<title>LR_2</title>\n",
244 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-151.85\" rx=\"31.7\" ry=\"31.7\"/>\n",
245 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-148.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_2</text>\n",
245 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"188.3408\" cy=\"-159.4469\" rx=\"34.394\" ry=\"34.394\"/>\n",
246 "<text text-anchor=\"middle\" x=\"188.3408\" y=\"-155.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_2</text>\n",
246247 "</g>\n",
247248 "<!-- LR_0&#45;&gt;LR_2 -->\n",
248249 "<g id=\"edge1\" class=\"edge\">\n",
249250 "<title>LR_0&#45;&gt;LR_2</title>\n",
250 "<path fill=\"none\" stroke=\"black\" d=\"M68.21,-99.45C88.53,-109.56 115.1,-122.77 136.47,-133.4\"/>\n",
251 "<polygon fill=\"black\" stroke=\"black\" points=\"135.06,-136.61 145.58,-137.94 138.18,-130.35 135.06,-136.61\"/>\n",
252 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-129.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(B)</text>\n",
251 "<path fill=\"none\" stroke=\"#000000\" d=\"M73.2124,-104.9142C95.4839,-115.4635 124.4765,-129.1964 147.795,-140.2417\"/>\n",
252 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"146.5421,-143.5209 157.0778,-144.6386 149.5387,-137.1947 146.5421,-143.5209\"/>\n",
253 "<text text-anchor=\"middle\" x=\"115.3939\" y=\"-138.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">SS(B)</text>\n",
253254 "</g>\n",
254255 "<!-- LR_1 -->\n",
255256 "<g id=\"node6\" class=\"node\">\n",
256257 "<title>LR_1</title>\n",
257 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-42.85\" rx=\"31.7\" ry=\"31.7\"/>\n",
258 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-39.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_1</text>\n",
258 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"188.3408\" cy=\"-45.4469\" rx=\"34.394\" ry=\"34.394\"/>\n",
259 "<text text-anchor=\"middle\" x=\"188.3408\" y=\"-41.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_1</text>\n",
259260 "</g>\n",
260261 "<!-- LR_0&#45;&gt;LR_1 -->\n",
261262 "<g id=\"edge2\" class=\"edge\">\n",
262263 "<title>LR_0&#45;&gt;LR_1</title>\n",
263 "<path fill=\"none\" stroke=\"black\" d=\"M70.29,-73.82C89.49,-68.06 113.72,-60.79 133.88,-54.74\"/>\n",
264 "<polygon fill=\"black\" stroke=\"black\" points=\"135.13,-58.02 143.7,-51.8 133.12,-51.32 135.13,-58.02\"/>\n",
265 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-71.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(S)</text>\n",
264 "<path fill=\"none\" stroke=\"#000000\" d=\"M75.4994,-77.8177C96.6252,-71.7574 123.2023,-64.1332 145.2564,-57.8066\"/>\n",
265 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"146.3881,-61.1232 155.0353,-55.0013 144.4578,-54.3945 146.3881,-61.1232\"/>\n",
266 "<text text-anchor=\"middle\" x=\"115.3939\" y=\"-76.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">SS(S)</text>\n",
266267 "</g>\n",
267268 "<!-- LR_3 -->\n",
268269 "<g id=\"node2\" class=\"node\">\n",
269270 "<title>LR_3</title>\n",
270 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"31.71\" ry=\"31.71\"/>\n",
271 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"35.69\" ry=\"35.69\"/>\n",
272 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-32.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_3</text>\n",
271 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"353.2347\" cy=\"-38.4469\" rx=\"34.3995\" ry=\"34.3995\"/>\n",
272 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"353.2347\" cy=\"-38.4469\" rx=\"38.394\" ry=\"38.394\"/>\n",
273 "<text text-anchor=\"middle\" x=\"353.2347\" y=\"-34.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_3</text>\n",
273274 "</g>\n",
274275 "<!-- LR_4 -->\n",
275276 "<g id=\"node3\" class=\"node\">\n",
276277 "<title>LR_4</title>\n",
277 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"31.71\" ry=\"31.71\"/>\n",
278 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"35.69\" ry=\"35.69\"/>\n",
279 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-288.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_4</text>\n",
278 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"353.2347\" cy=\"-303.4469\" rx=\"34.3995\" ry=\"34.3995\"/>\n",
279 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"353.2347\" cy=\"-303.4469\" rx=\"38.394\" ry=\"38.394\"/>\n",
280 "<text text-anchor=\"middle\" x=\"353.2347\" y=\"-299.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_4</text>\n",
280281 "</g>\n",
281282 "<!-- LR_8 -->\n",
282283 "<g id=\"node4\" class=\"node\">\n",
283284 "<title>LR_8</title>\n",
284 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"31.71\" ry=\"31.71\"/>\n",
285 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"35.69\" ry=\"35.69\"/>\n",
286 "<text text-anchor=\"middle\" x=\"704.32\" y=\"-149.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_8</text>\n",
285 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"764.9164\" cy=\"-159.4469\" rx=\"34.3995\" ry=\"34.3995\"/>\n",
286 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"764.9164\" cy=\"-159.4469\" rx=\"38.394\" ry=\"38.394\"/>\n",
287 "<text text-anchor=\"middle\" x=\"764.9164\" y=\"-155.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_8</text>\n",
287288 "</g>\n",
288289 "<!-- LR_6 -->\n",
289290 "<g id=\"node7\" class=\"node\">\n",
290291 "<title>LR_6</title>\n",
291 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-172.85\" rx=\"31.7\" ry=\"31.7\"/>\n",
292 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-169.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_6</text>\n",
292 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"353.2347\" cy=\"-179.4469\" rx=\"34.394\" ry=\"34.394\"/>\n",
293 "<text text-anchor=\"middle\" x=\"353.2347\" y=\"-175.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_6</text>\n",
293294 "</g>\n",
294295 "<!-- LR_8&#45;&gt;LR_6 -->\n",
295296 "<g id=\"edge13\" class=\"edge\">\n",
296297 "<title>LR_8&#45;&gt;LR_6</title>\n",
297 "<path fill=\"none\" stroke=\"black\" d=\"M668.7,-158.83C625.38,-165.98 548.87,-177.52 482.78,-181.85 454.53,-183.7 447.36,-183.19 419.08,-181.85 401.3,-181.01 381.7,-179.28 364.95,-177.56\"/>\n",
298 "<polygon fill=\"black\" stroke=\"black\" points=\"365.25,-174.07 354.94,-176.5 364.51,-181.04 365.25,-174.07\"/>\n",
299 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-183.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\n",
298 "<path fill=\"none\" stroke=\"#000000\" d=\"M726.9091,-165.4889C679.8084,-172.6439 597.0195,-184.1344 525.5755,-188.4469 495.0117,-190.2918 487.2723,-189.7751 456.6817,-188.4469 437.3205,-187.6063 415.9784,-185.8847 397.7331,-184.1702\"/>\n",
299 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"397.9588,-180.6757 387.6682,-183.1962 397.2846,-187.6432 397.9588,-180.6757\"/>\n",
300 "<text text-anchor=\"middle\" x=\"558.5755\" y=\"-190.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(b)</text>\n",
300301 "</g>\n",
301302 "<!-- LR_5 -->\n",
302303 "<g id=\"node8\" class=\"node\">\n",
303304 "<title>LR_5</title>\n",
304 "<ellipse fill=\"none\" stroke=\"black\" cx=\"450.93\" cy=\"-107.85\" rx=\"31.7\" ry=\"31.7\"/>\n",
305 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-104.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_5</text>\n",
305 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"491.1286\" cy=\"-112.4469\" rx=\"34.394\" ry=\"34.394\"/>\n",
306 "<text text-anchor=\"middle\" x=\"491.1286\" y=\"-108.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_5</text>\n",
306307 "</g>\n",
307308 "<!-- LR_8&#45;&gt;LR_5 -->\n",
308309 "<g id=\"edge14\" class=\"edge\">\n",
309310 "<title>LR_8&#45;&gt;LR_5</title>\n",
310 "<path fill=\"none\" stroke=\"black\" d=\"M668.83,-147.36C628.46,-140.82 559.62,-129.34 500.78,-117.85 497.99,-117.3 495.11,-116.73 492.22,-116.15\"/>\n",
311 "<polygon fill=\"black\" stroke=\"black\" points=\"492.89,-112.72 482.4,-114.17 491.51,-119.58 492.89,-112.72\"/>\n",
312 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-139.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\n",
311 "<path fill=\"none\" stroke=\"#000000\" d=\"M726.6271,-153.9547C691.452,-148.7973 637.9082,-140.6643 591.5755,-132.4469 572.9886,-129.1504 552.543,-125.1485 534.9769,-121.5931\"/>\n",
312 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"535.5004,-118.128 525.0029,-119.5601 534.1023,-124.9869 535.5004,-118.128\"/>\n",
313 "<text text-anchor=\"middle\" x=\"626.0225\" y=\"-147.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(a)</text>\n",
313314 "</g>\n",
314315 "<!-- LR_2&#45;&gt;LR_4 -->\n",
315316 "<g id=\"edge6\" class=\"edge\">\n",
316317 "<title>LR_2&#45;&gt;LR_4</title>\n",
317 "<path fill=\"none\" stroke=\"black\" d=\"M198.14,-173.42C222.46,-196.62 261.37,-233.76 289.13,-260.26\"/>\n",
318 "<polygon fill=\"black\" stroke=\"black\" points=\"287,-263.06 296.65,-267.43 291.83,-257.99 287,-263.06\"/>\n",
319 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-241.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(A)</text>\n",
318 "<path fill=\"none\" stroke=\"#000000\" d=\"M214.4688,-182.2642C242.0117,-206.3171 285.6174,-244.3975 316.5904,-271.4459\"/>\n",
319 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"314.3408,-274.1281 324.1752,-278.0696 318.9453,-268.8556 314.3408,-274.1281\"/>\n",
320 "<text text-anchor=\"middle\" x=\"268.7878\" y=\"-256.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(A)</text>\n",
320321 "</g>\n",
321322 "<!-- LR_2&#45;&gt;LR_6 -->\n",
322323 "<g id=\"edge4\" class=\"edge\">\n",
323324 "<title>LR_2&#45;&gt;LR_6</title>\n",
324 "<path fill=\"none\" stroke=\"black\" d=\"M206.29,-156.25C228.1,-159.37 257.6,-163.59 281.38,-167\"/>\n",
325 "<polygon fill=\"black\" stroke=\"black\" points=\"281.13,-170.5 291.52,-168.45 282.12,-163.57 281.13,-170.5\"/>\n",
326 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-167.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(b)</text>\n",
325 "<path fill=\"none\" stroke=\"#000000\" d=\"M222.908,-163.6396C247.9462,-166.6765 282.0002,-170.8069 309.0187,-174.084\"/>\n",
326 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"308.6472,-177.5645 318.9959,-175.2941 309.4901,-170.6154 308.6472,-177.5645\"/>\n",
327 "<text text-anchor=\"middle\" x=\"268.7878\" y=\"-175.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">SS(b)</text>\n",
327328 "</g>\n",
328329 "<!-- LR_2&#45;&gt;LR_5 -->\n",
329330 "<g id=\"edge5\" class=\"edge\">\n",
330331 "<title>LR_2&#45;&gt;LR_5</title>\n",
331 "<path fill=\"none\" stroke=\"black\" d=\"M204.48,-140.61C226.77,-132.49 258.56,-122.07 287.39,-116.85 328.17,-109.46 375.56,-107.58 408.61,-107.32\"/>\n",
332 "<polygon fill=\"black\" stroke=\"black\" points=\"408.82,-110.82 418.81,-107.29 408.8,-103.82 408.82,-110.82\"/>\n",
333 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-120.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(a)</text>\n",
332 "<path fill=\"none\" stroke=\"#000000\" d=\"M220.8332,-147.3168C246.0707,-138.4771 282.1505,-127.0986 314.7878,-121.4469 359.0488,-113.7825 410.4168,-111.9436 446.2537,-111.7723\"/>\n",
333 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"446.3926,-115.2723 456.3905,-111.7663 446.3885,-108.2723 446.3926,-115.2723\"/>\n",
334 "<text text-anchor=\"middle\" x=\"353.2347\" y=\"-125.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">SS(a)</text>\n",
334335 "</g>\n",
335336 "<!-- LR_1&#45;&gt;LR_3 -->\n",
336337 "<g id=\"edge3\" class=\"edge\">\n",
337338 "<title>LR_1&#45;&gt;LR_3</title>\n",
338 "<path fill=\"none\" stroke=\"black\" d=\"M206.65,-41.36C227.15,-40.38 254.31,-39.09 277.16,-38\"/>\n",
339 "<polygon fill=\"black\" stroke=\"black\" points=\"277.49,-41.49 287.31,-37.51 277.16,-34.49 277.49,-41.49\"/>\n",
340 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-44.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S($end)</text>\n",
339 "<path fill=\"none\" stroke=\"#000000\" d=\"M222.908,-43.9795C246.5853,-42.9744 278.325,-41.627 304.5534,-40.5135\"/>\n",
340 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"304.8328,-44.0049 314.6753,-40.0839 304.5358,-37.0112 304.8328,-44.0049\"/>\n",
341 "<text text-anchor=\"middle\" x=\"268.7878\" y=\"-47.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S($end)</text>\n",
341342 "</g>\n",
342343 "<!-- LR_6&#45;&gt;LR_6 -->\n",
343344 "<g id=\"edge9\" class=\"edge\">\n",
344345 "<title>LR_6&#45;&gt;LR_6</title>\n",
345 "<path fill=\"none\" stroke=\"black\" d=\"M311.26,-202.53C310.87,-213.59 314.86,-222.69 323.24,-222.69 328.86,-222.69 332.51,-218.58 334.18,-212.53\"/>\n",
346 "<polygon fill=\"black\" stroke=\"black\" points=\"337.67,-212.83 335.21,-202.53 330.7,-212.12 337.67,-212.83\"/>\n",
347 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-226.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\n",
346 "<path fill=\"none\" stroke=\"#000000\" d=\"M340.1169,-211.4545C339.907,-222.7382 344.2796,-231.8939 353.2347,-231.8939 359.2514,-231.8939 363.1995,-227.7609 365.079,-221.6263\"/>\n",
347 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"368.583,-221.8119 366.3525,-211.4545 361.6372,-220.9422 368.583,-221.8119\"/>\n",
348 "<text text-anchor=\"middle\" x=\"353.2347\" y=\"-235.6939\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(b)</text>\n",
348349 "</g>\n",
349350 "<!-- LR_6&#45;&gt;LR_5 -->\n",
350351 "<g id=\"edge10\" class=\"edge\">\n",
351352 "<title>LR_6&#45;&gt;LR_5</title>\n",
352 "<path fill=\"none\" stroke=\"black\" d=\"M351.82,-158.58C369.91,-149.23 393.77,-136.89 413.43,-126.72\"/>\n",
353 "<polygon fill=\"black\" stroke=\"black\" points=\"415.14,-129.78 422.41,-122.08 411.92,-123.56 415.14,-129.78\"/>\n",
354 "<text text-anchor=\"middle\" x=\"389.08\" y=\"-147.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\n",
353 "<path fill=\"none\" stroke=\"#000000\" d=\"M384.525,-164.2436C404.1831,-154.6921 429.7327,-142.278 450.8909,-131.9977\"/>\n",
354 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"452.4973,-135.1085 459.9622,-127.5901 449.4381,-128.8123 452.4973,-135.1085\"/>\n",
355 "<text text-anchor=\"middle\" x=\"424.1817\" y=\"-155.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(a)</text>\n",
355356 "</g>\n",
356357 "<!-- LR_5&#45;&gt;LR_5 -->\n",
357358 "<g id=\"edge8\" class=\"edge\">\n",
358359 "<title>LR_5&#45;&gt;LR_5</title>\n",
359 "<path fill=\"none\" stroke=\"black\" d=\"M439.69,-138.02C439.45,-148.86 443.2,-157.69 450.93,-157.69 456.01,-157.69 459.36,-153.89 461,-148.21\"/>\n",
360 "<polygon fill=\"black\" stroke=\"black\" points=\"464.51,-148.35 462.17,-138.02 457.56,-147.56 464.51,-148.35\"/>\n",
361 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-161.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\n",
360 "<path fill=\"none\" stroke=\"#000000\" d=\"M478.7566,-144.7125C478.6257,-155.8774 482.7497,-164.8939 491.1286,-164.8939 496.7582,-164.8939 500.467,-160.8237 502.2551,-154.7664\"/>\n",
361 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"505.7446,-155.067 503.5006,-144.7125 498.7977,-154.2064 505.7446,-155.067\"/>\n",
362 "<text text-anchor=\"middle\" x=\"491.1286\" y=\"-168.6939\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(a)</text>\n",
362363 "</g>\n",
363364 "<!-- LR_7 -->\n",
364365 "<g id=\"node9\" class=\"node\">\n",
365366 "<title>LR_7</title>\n",
366 "<ellipse fill=\"none\" stroke=\"black\" cx=\"575.62\" cy=\"-84.85\" rx=\"31.7\" ry=\"31.7\"/>\n",
367 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-81.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_7</text>\n",
367 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"626.0225\" cy=\"-89.4469\" rx=\"34.394\" ry=\"34.394\"/>\n",
368 "<text text-anchor=\"middle\" x=\"626.0225\" y=\"-85.7469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">LR_7</text>\n",
368369 "</g>\n",
369370 "<!-- LR_5&#45;&gt;LR_7 -->\n",
370371 "<g id=\"edge7\" class=\"edge\">\n",
371372 "<title>LR_5&#45;&gt;LR_7</title>\n",
372 "<path fill=\"none\" stroke=\"black\" d=\"M482.57,-102.1C498.09,-99.19 517.14,-95.62 533.88,-92.49\"/>\n",
373 "<polygon fill=\"black\" stroke=\"black\" points=\"534.76,-95.88 543.95,-90.6 533.47,-89 534.76,-95.88\"/>\n",
374 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-102.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\n",
373 "<path fill=\"none\" stroke=\"#000000\" d=\"M525.168,-106.6431C542.4218,-103.7012 563.5777,-100.0941 582.0497,-96.9445\"/>\n",
374 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"582.7245,-100.38 591.994,-95.249 581.5479,-93.4796 582.7245,-100.38\"/>\n",
375 "<text text-anchor=\"middle\" x=\"558.5755\" y=\"-107.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(b)</text>\n",
375376 "</g>\n",
376377 "<!-- LR_7&#45;&gt;LR_8 -->\n",
377378 "<g id=\"edge11\" class=\"edge\">\n",
378379 "<title>LR_7&#45;&gt;LR_8</title>\n",
379 "<path fill=\"none\" stroke=\"black\" d=\"M604.38,-99.37C618.26,-106.67 635.28,-115.67 650.47,-123.85 654.74,-126.14 659.19,-128.56 663.62,-130.98\"/>\n",
380 "<polygon fill=\"black\" stroke=\"black\" points=\"662.17,-134.17 672.62,-135.9 665.53,-128.03 662.17,-134.17\"/>\n",
381 "<text text-anchor=\"middle\" x=\"637.97\" y=\"-127.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\n",
380 "<path fill=\"none\" stroke=\"#000000\" d=\"M657,-104.732C672.4832,-112.4022 691.492,-121.8649 708.4694,-130.4469 712.7313,-132.6013 717.1681,-134.8574 721.5984,-137.1192\"/>\n",
381 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"720.1286,-140.2987 730.6252,-141.7387 723.3177,-134.0672 720.1286,-140.2987\"/>\n",
382 "<text text-anchor=\"middle\" x=\"693.4694\" y=\"-134.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(b)</text>\n",
382383 "</g>\n",
383384 "<!-- LR_7&#45;&gt;LR_5 -->\n",
384385 "<g id=\"edge12\" class=\"edge\">\n",
385386 "<title>LR_7&#45;&gt;LR_5</title>\n",
386 "<path fill=\"none\" stroke=\"black\" d=\"M545.05,-75.8C531.36,-72.99 515.01,-71.6 500.78,-75.85 495.43,-77.44 490.13,-79.83 485.1,-82.59\"/>\n",
387 "<polygon fill=\"black\" stroke=\"black\" points=\"483.11,-79.7 476.38,-87.89 486.75,-85.69 483.11,-79.7\"/>\n",
388 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-79.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\n",
387 "<path fill=\"none\" stroke=\"#000000\" d=\"M592.6491,-80.1131C577.456,-77.3057 559.3781,-76.0067 543.5755,-80.4469 538.2486,-81.9437 532.927,-84.1479 527.8273,-86.7112\"/>\n",
388 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"525.9854,-83.7304 518.9342,-91.6381 529.3777,-89.8535 525.9854,-83.7304\"/>\n",
389 "<text text-anchor=\"middle\" x=\"558.5755\" y=\"-84.2469\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">S(a)</text>\n",
389390 "</g>\n",
390391 "</g>\n",
391392 "</svg>\n"
392393 ],
393394 "text/plain": [
394 "<graphviz.graphs.Digraph at 0x203f27271f0>"
395 "<graphviz.graphs.Digraph at 0x7fe7ac39d890>"
395396 ]
396397 },
397398 "execution_count": 4,
440441 "name": "stderr",
441442 "output_type": "stream",
442443 "text": [
443 "[DEBUG@graphviz.backend.execute] run [WindowsPath('dot'), '-Kdot', '-Tsvg']\n"
444 "[DEBUG@graphviz.backend.execute] run [PosixPath('dot'), '-Kdot', '-Tsvg']\n"
444445 ]
445446 },
446447 {
449450 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
450451 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
451452 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
452 "<!-- Generated by graphviz version 2.49.3 (20211023.0002)\n",
453 "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
453454 " -->\n",
454455 "<!-- Title: G Pages: 1 -->\n",
455456 "<svg width=\"222pt\" height=\"364pt\"\n",
456457 " viewBox=\"0.00 0.00 222.00 364.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
457458 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 360)\">\n",
458459 "<title>G</title>\n",
459 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-360 218,-360 218,4 -4,4\"/>\n",
460 "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-360 218,-360 218,4 -4,4\"/>\n",
460461 "<g id=\"clust1\" class=\"cluster\">\n",
461462 "<title>cluster0</title>\n",
462 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-152 64,-348 206,-348 206,-152 64,-152\"/>\n",
463 "<polygon fill=\"none\" stroke=\"#000000\" points=\"64,-152 64,-348 206,-348 206,-152 64,-152\"/>\n",
463464 "</g>\n",
464465 "<g id=\"clust2\" class=\"cluster\">\n",
465466 "<title>cluster1</title>\n",
466 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-8 64,-132 206,-132 206,-8 64,-8\"/>\n",
467 "<polygon fill=\"none\" stroke=\"#000000\" points=\"64,-8 64,-132 206,-132 206,-8 64,-8\"/>\n",
467468 "</g>\n",
468469 "<!-- a -->\n",
469470 "<g id=\"node1\" class=\"node\">\n",
470471 "<title>a</title>\n",
471 "<ellipse fill=\"none\" stroke=\"black\" cx=\"135\" cy=\"-322\" rx=\"27\" ry=\"18\"/>\n",
472 "<text text-anchor=\"middle\" x=\"135\" y=\"-318.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">a</text>\n",
472 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"135\" cy=\"-322\" rx=\"27\" ry=\"18\"/>\n",
473 "<text text-anchor=\"middle\" x=\"135\" y=\"-318.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
473474 "</g>\n",
474475 "<!-- b -->\n",
475476 "<g id=\"node2\" class=\"node\">\n",
476477 "<title>b</title>\n",
477 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\n",
478 "<text text-anchor=\"middle\" x=\"99\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">b</text>\n",
478 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"99\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\n",
479 "<text text-anchor=\"middle\" x=\"99\" y=\"-246.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">b</text>\n",
479480 "</g>\n",
480481 "<!-- a&#45;&gt;b -->\n",
481482 "<g id=\"edge1\" class=\"edge\">\n",
482483 "<title>a&#45;&gt;b</title>\n",
483 "<path fill=\"none\" stroke=\"black\" d=\"M126.65,-304.76C122.29,-296.28 116.85,-285.71 111.96,-276.2\"/>\n",
484 "<polygon fill=\"black\" stroke=\"black\" points=\"114.99,-274.44 107.3,-267.15 108.77,-277.64 114.99,-274.44\"/>\n",
484 "<path fill=\"none\" stroke=\"#000000\" d=\"M126.2854,-304.5708C122.0403,-296.0807 116.8464,-285.6929 112.1337,-276.2674\"/>\n",
485 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"115.237,-274.6477 107.6343,-267.2687 108.976,-277.7782 115.237,-274.6477\"/>\n",
485486 "</g>\n",
486487 "<!-- c -->\n",
487488 "<g id=\"node3\" class=\"node\">\n",
488489 "<title>c</title>\n",
489 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\n",
490 "<text text-anchor=\"middle\" x=\"171\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">c</text>\n",
490 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"171\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\n",
491 "<text text-anchor=\"middle\" x=\"171\" y=\"-246.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">c</text>\n",
491492 "</g>\n",
492493 "<!-- a&#45;&gt;c -->\n",
493494 "<g id=\"edge2\" class=\"edge\">\n",
494495 "<title>a&#45;&gt;c</title>\n",
495 "<path fill=\"none\" stroke=\"black\" d=\"M143.35,-304.76C147.71,-296.28 153.15,-285.71 158.04,-276.2\"/>\n",
496 "<polygon fill=\"black\" stroke=\"black\" points=\"161.23,-277.64 162.7,-267.15 155.01,-274.44 161.23,-277.64\"/>\n",
496 "<path fill=\"none\" stroke=\"#000000\" d=\"M143.7146,-304.5708C147.9597,-296.0807 153.1536,-285.6929 157.8663,-276.2674\"/>\n",
497 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"161.024,-277.7782 162.3657,-267.2687 154.763,-274.6477 161.024,-277.7782\"/>\n",
497498 "</g>\n",
498499 "<!-- d -->\n",
499500 "<g id=\"node4\" class=\"node\">\n",
500501 "<title>d</title>\n",
501 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-178\" rx=\"27\" ry=\"18\"/>\n",
502 "<text text-anchor=\"middle\" x=\"99\" y=\"-174.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">d</text>\n",
502 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"99\" cy=\"-178\" rx=\"27\" ry=\"18\"/>\n",
503 "<text text-anchor=\"middle\" x=\"99\" y=\"-174.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">d</text>\n",
503504 "</g>\n",
504505 "<!-- b&#45;&gt;d -->\n",
505506 "<g id=\"edge3\" class=\"edge\">\n",
506507 "<title>b&#45;&gt;d</title>\n",
507 "<path fill=\"none\" stroke=\"black\" d=\"M99,-231.7C99,-223.98 99,-214.71 99,-206.11\"/>\n",
508 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-206.1 99,-196.1 95.5,-206.1 102.5,-206.1\"/>\n",
508 "<path fill=\"none\" stroke=\"#000000\" d=\"M99,-231.8314C99,-224.131 99,-214.9743 99,-206.4166\"/>\n",
509 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"102.5001,-206.4132 99,-196.4133 95.5001,-206.4133 102.5001,-206.4132\"/>\n",
509510 "</g>\n",
510511 "<!-- f -->\n",
511512 "<g id=\"node7\" class=\"node\">\n",
512513 "<title>f</title>\n",
513 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\n",
514 "<text text-anchor=\"middle\" x=\"99\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">f</text>\n",
514 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"99\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\n",
515 "<text text-anchor=\"middle\" x=\"99\" y=\"-30.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">f</text>\n",
515516 "</g>\n",
516517 "<!-- b&#45;&gt;f -->\n",
517518 "<g id=\"edge7\" class=\"edge\">\n",
518519 "<title>b&#45;&gt;f</title>\n",
519 "<path fill=\"none\" stroke=\"black\" d=\"M112.75,-234.07C120.96,-224.1 130.62,-210.25 135,-196 142.02,-173.17 145.55,-157.68 145.58,-142.23\"/>\n",
520 "<polygon fill=\"black\" stroke=\"black\" points=\"149.07,-141.82 145.1,-132 142.07,-142.15 149.07,-141.82\"/>\n",
520 "<path fill=\"none\" stroke=\"#000000\" d=\"M113.1229,-234.2844C121.2535,-224.1468 130.6901,-210.2347 135,-196 141.9225,-173.1366 145.3998,-157.6593 145.432,-142.2164\"/>\n",
521 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"148.9176,-141.8227 144.9572,-131.9959 141.9251,-142.1476 148.9176,-141.8227\"/>\n",
521522 "</g>\n",
522523 "<!-- c&#45;&gt;d -->\n",
523524 "<g id=\"edge4\" class=\"edge\">\n",
524525 "<title>c&#45;&gt;d</title>\n",
525 "<path fill=\"none\" stroke=\"black\" d=\"M156.43,-234.83C146.25,-224.94 132.48,-211.55 120.97,-200.36\"/>\n",
526 "<polygon fill=\"black\" stroke=\"black\" points=\"123.41,-197.85 113.8,-193.38 118.53,-202.87 123.41,-197.85\"/>\n",
526 "<path fill=\"none\" stroke=\"#000000\" d=\"M155.7307,-234.7307C145.803,-224.803 132.6847,-211.6847 121.5637,-200.5637\"/>\n",
527 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"123.7933,-197.8436 114.2473,-193.2473 118.8436,-202.7933 123.7933,-197.8436\"/>\n",
527528 "</g>\n",
528529 "<!-- e -->\n",
529530 "<g id=\"node5\" class=\"node\">\n",
530531 "<title>e</title>\n",
531 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\n",
532 "<text text-anchor=\"middle\" x=\"99\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">e</text>\n",
532 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"99\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\n",
533 "<text text-anchor=\"middle\" x=\"99\" y=\"-102.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">e</text>\n",
533534 "</g>\n",
534535 "<!-- c&#45;&gt;e -->\n",
535536 "<g id=\"edge10\" class=\"edge\">\n",
536537 "<title>c&#45;&gt;e</title>\n",
537 "<path fill=\"none\" stroke=\"black\" d=\"M135,-152C130.7,-144.41 125.16,-136.77 119.71,-129.99\"/>\n",
538 "<polygon fill=\"black\" stroke=\"black\" points=\"122.07,-127.36 112.97,-121.94 116.71,-131.86 122.07,-127.36\"/>\n",
538 "<path fill=\"none\" stroke=\"#000000\" d=\"M135,-152C130.7681,-144.3996 125.3302,-136.7278 119.9697,-129.8859\"/>\n",
539 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"122.3507,-127.2677 113.3176,-121.7311 116.9265,-131.6924 122.3507,-127.2677\"/>\n",
539540 "</g>\n",
540541 "<!-- g -->\n",
541542 "<g id=\"node6\" class=\"node\">\n",
542543 "<title>g</title>\n",
543 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\n",
544 "<text text-anchor=\"middle\" x=\"171\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">g</text>\n",
544 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"171\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\n",
545 "<text text-anchor=\"middle\" x=\"171\" y=\"-30.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">g</text>\n",
545546 "</g>\n",
546547 "<!-- c&#45;&gt;g -->\n",
547548 "<g id=\"edge9\" class=\"edge\">\n",
548549 "<title>c&#45;&gt;g</title>\n",
549 "<path fill=\"none\" stroke=\"black\" d=\"M171,-152C171,-148.77 171,-145.53 171,-142.29\"/>\n",
550 "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-141.99 171,-132 167.5,-142 174.5,-141.99\"/>\n",
550 "<path fill=\"none\" stroke=\"#000000\" d=\"M171,-152.004C171,-148.766 171,-145.516 171,-142.2656\"/>\n",
551 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"174.5001,-141.9975 171,-131.9976 167.5001,-141.9976 174.5001,-141.9975\"/>\n",
551552 "</g>\n",
552553 "<!-- d&#45;&gt;e -->\n",
553554 "<g id=\"edge8\" class=\"edge\">\n",
554555 "<title>d&#45;&gt;e</title>\n",
555 "<path fill=\"none\" stroke=\"black\" d=\"M99,-159.7C99,-151.98 99,-142.71 99,-134.11\"/>\n",
556 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-134.1 99,-124.1 95.5,-134.1 102.5,-134.1\"/>\n",
556 "<path fill=\"none\" stroke=\"#000000\" d=\"M99,-159.8314C99,-152.131 99,-142.9743 99,-134.4166\"/>\n",
557 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"102.5001,-134.4132 99,-124.4133 95.5001,-134.4133 102.5001,-134.4132\"/>\n",
557558 "</g>\n",
558559 "<!-- h -->\n",
559560 "<g id=\"node8\" class=\"node\">\n",
560561 "<title>h</title>\n",
561 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\n",
562 "<text text-anchor=\"middle\" x=\"27\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">h</text>\n",
562 "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\n",
563 "<text text-anchor=\"middle\" x=\"27\" y=\"-102.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">h</text>\n",
563564 "</g>\n",
564565 "<!-- d&#45;&gt;h -->\n",
565566 "<g id=\"edge11\" class=\"edge\">\n",
566567 "<title>d&#45;&gt;h</title>\n",
567 "<path fill=\"none\" stroke=\"black\" d=\"M84.43,-162.83C74.25,-152.94 60.48,-139.55 48.97,-128.36\"/>\n",
568 "<polygon fill=\"black\" stroke=\"black\" points=\"51.41,-125.85 41.8,-121.38 46.53,-130.87 51.41,-125.85\"/>\n",
568 "<path fill=\"none\" stroke=\"#000000\" d=\"M83.7307,-162.7307C73.803,-152.803 60.6847,-139.6847 49.5637,-128.5637\"/>\n",
569 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"51.7933,-125.8436 42.2473,-121.2473 46.8436,-130.7933 51.7933,-125.8436\"/>\n",
569570 "</g>\n",
570571 "<!-- e&#45;&gt;g -->\n",
571572 "<g id=\"edge5\" class=\"edge\">\n",
572573 "<title>e&#45;&gt;g</title>\n",
573 "<path fill=\"none\" stroke=\"black\" d=\"M113.57,-90.83C123.75,-80.94 137.52,-67.55 149.03,-56.36\"/>\n",
574 "<polygon fill=\"black\" stroke=\"black\" points=\"151.47,-58.87 156.2,-49.38 146.59,-53.85 151.47,-58.87\"/>\n",
574 "<path fill=\"none\" stroke=\"#000000\" d=\"M114.2693,-90.7307C124.197,-80.803 137.3153,-67.6847 148.4363,-56.5637\"/>\n",
575 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"151.1564,-58.7933 155.7527,-49.2473 146.2067,-53.8436 151.1564,-58.7933\"/>\n",
575576 "</g>\n",
576577 "<!-- e&#45;&gt;f -->\n",
577578 "<g id=\"edge6\" class=\"edge\">\n",
578579 "<title>e&#45;&gt;f</title>\n",
579 "<path fill=\"none\" stroke=\"black\" d=\"M99,-87.7C99,-79.98 99,-70.71 99,-62.11\"/>\n",
580 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-62.1 99,-52.1 95.5,-62.1 102.5,-62.1\"/>\n",
580 "<path fill=\"none\" stroke=\"#000000\" d=\"M99,-87.8314C99,-80.131 99,-70.9743 99,-62.4166\"/>\n",
581 "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"102.5001,-62.4132 99,-52.4133 95.5001,-62.4133 102.5001,-62.4132\"/>\n",
581582 "</g>\n",
582583 "</g>\n",
583584 "</svg>\n"
584585 ],
585586 "text/plain": [
586 "<graphviz.graphs.Digraph at 0x203f2726cb0>"
587 "<graphviz.graphs.Digraph at 0x7fe7ac4083d0>"
587588 ]
588589 },
589590 "execution_count": 5,
630631 "name": "python",
631632 "nbconvert_exporter": "python",
632633 "pygments_lexer": "ipython3",
633 "version": "3.10.0"
634 "version": "3.7.12"
634635 }
635636 },
636637 "nbformat": 4,
637 "nbformat_minor": 1
638 "nbformat_minor": 4
638639 }
3030 from .backend import (DOT_BINARY, UNFLATTEN_BINARY,
3131 render, pipe, pipe_string, pipe_lines, pipe_lines_string,
3232 unflatten, version, view)
33 from .exceptions import (RequiredArgumentError, FileExistsError,
33 from .exceptions import (ExecutableNotFound, CalledProcessError,
34 RequiredArgumentError, FileExistsError,
3435 UnknownSuffixWarning, FormatSuffixMismatchWarning,
35 ExecutableNotFound, CalledProcessError)
36 DotSyntaxWarning)
3637 from .graphs import Graph, Digraph
3738 from .jupyter_integration import SUPPORTED_JUPYTER_FORMATS
3839 from .parameters import ENGINES, FORMATS, RENDERERS, FORMATTERS
4748 'escape', 'nohtml',
4849 'render', 'pipe', 'pipe_string', 'pipe_lines', 'pipe_lines_string',
4950 'unflatten', 'version', 'view',
51 'ExecutableNotFound', 'CalledProcessError',
5052 'RequiredArgumentError', 'FileExistsError',
5153 'UnknownSuffixWarning', 'FormatSuffixMismatchWarning',
52 'ExecutableNotFound, CalledProcessError',
54 'DotSyntaxWarning',
5355 'set_default_engine', 'set_default_format', 'set_jupyter_format']
5456
5557 __title__ = 'graphviz'
56 __version__ = '0.19.1'
58 __version__ = '0.20.1'
5759 __author__ = 'Sebastian Bank <sebastian.bank@uni-leipzig.de>'
5860 __license__ = 'MIT, see LICENSE.txt'
59 __copyright__ = 'Copyright (c) 2013-2021 Sebastian Bank'
61 __copyright__ = 'Copyright (c) 2013-2022 Sebastian Bank'
6062
6163 ENGINES = ENGINES
6264 """:class:`set` of known layout commands used for rendering
8587 """:class:`pathlib.Path` of unflatten command (``Path('unflatten')``)."""
8688
8789
90 ExecutableNotFound = ExecutableNotFound
91
92
93 CalledProcessError = CalledProcessError
94
95
8896 RequiredArgumentError = RequiredArgumentError
8997
9098
91 ExecutableNotFound = ExecutableNotFound
99 FileExistsError = FileExistsError
92100
93101
94102 UnknownSuffixWarning = UnknownSuffixWarning
97105 FormatSuffixMismatchWarning = FormatSuffixMismatchWarning
98106
99107
100 CalledProcessError = CalledProcessError
101
102
103 FileExistsError = FileExistsError
108 DotSyntaxWarning = DotSyntaxWarning
0 """Python 3.6 to 3.8 compatibility and platform compatibility."""
0 """Python 3.7 to 3.8 compatibility and platform compatibility."""
11
2 import pathlib
2 import os
33 import platform
44 import sys
55 import typing
4040 return startupinfo
4141
4242
43 def make_subprocess_arg(arg: typing.Union[str, pathlib.Path]):
43 def make_subprocess_arg(arg: typing.Union[str, os.PathLike]) -> typing.Union[str, os.PathLike]:
4444 """Return subprocess argument as is (default no-op)."""
4545 return arg
4646
4747
4848 if platform.system() == 'Windows' and sys.version_info < (3, 8): # pragma: no cover
49 def make_subprocess_arg(arg: typing.Union[str, pathlib.Path]) -> str: # noqa: F811
49 def make_subprocess_arg(arg: typing.Union[str, os.PathLike]) -> str: # noqa: F811
5050 """Workaround https://bugs.python.org/issue41649 (not backported)."""
51 return str(arg)
51 return os.fspath(arg)
3838 return decorator
3939
4040
41 def mkdirs(filename, *, mode: int = 0o777) -> None:
41 def mkdirs(filename: typing.Union[os.PathLike, str], *, mode: int = 0o777) -> None:
4242 """Recursively create directories up to the path of ``filename``
4343 as needed."""
4444 dirname = os.path.dirname(filename)
6666
6767
6868 @typing.overload
69 def promote_pathlike(filepath: typing.Union[os.PathLike, str]
70 ) -> pathlib.Path:
69 def promote_pathlike(filepath: typing.Union[os.PathLike, str]) -> pathlib.Path:
7170 """Return path object for path-like-object."""
7271
7372
1313
1414 def command(engine: str, format_: str, *,
1515 renderer: typing.Optional[str] = None,
16 formatter: typing.Optional[str] = None
16 formatter: typing.Optional[str] = None,
17 neato_no_op: typing.Union[bool, int, None] = None
1718 ) -> typing.List[typing.Union[os.PathLike, str]]:
1819 """Return ``subprocess.Popen`` argument list for rendering.
1920
2122 Upstream documentation:
2223 - https://www.graphviz.org/doc/info/command.html#-K
2324 - https://www.graphviz.org/doc/info/command.html#-T
25 - https://www.graphviz.org/doc/info/command.html#-n
2426 """
2527 if formatter is not None and renderer is None:
2628 raise exceptions.RequiredArgumentError('formatter given without renderer')
3335 output_format = [f for f in (format_, renderer, formatter) if f is not None]
3436 output_format_flag = ':'.join(output_format)
3537
36 return [DOT_BINARY, f'-K{engine}', f'-T{output_format_flag}']
38 cmd = [DOT_BINARY, f'-K{engine}', f'-T{output_format_flag}']
39
40 if neato_no_op:
41 cmd.append(f'-n{neato_no_op:d}')
42
43 return cmd
2222 def run_check(cmd: typing.Sequence[typing.Union[os.PathLike, str]], *,
2323 input_lines: typing.Optional[typing.Iterator[bytes]] = ...,
2424 encoding: None = ...,
25 capture_output: bool = ...,
2625 quiet: bool = ...,
2726 **kwargs) -> subprocess.CompletedProcess:
2827 """Accept bytes input_lines with default ``encoding=None```."""
3231 def run_check(cmd: typing.Sequence[typing.Union[os.PathLike, str]], *,
3332 input_lines: typing.Optional[typing.Iterator[str]] = ...,
3433 encoding: str,
35 capture_output: bool = ...,
3634 quiet: bool = ...,
3735 **kwargs) -> subprocess.CompletedProcess:
3836 """Accept string input_lines when given ``encoding``."""
5149 def run_check(cmd: typing.Sequence[typing.Union[os.PathLike, str]], *,
5250 input_lines: typing.Optional[BytesOrStrIterator] = None,
5351 encoding: typing.Optional[str] = None,
54 capture_output: bool = False,
5552 quiet: bool = False,
5653 **kwargs) -> subprocess.CompletedProcess:
5754 """Run the command described by ``cmd``
6764 if not kwargs.pop('check', True): # pragma: no cover
6865 raise NotImplementedError('check must be True or omited')
6966
70 if capture_output: # Python 3.6 compat
71 kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
72
7367 if encoding is not None:
7468 kwargs['encoding'] = encoding
7569
7973 if input_lines is not None:
8074 assert kwargs.get('input') is None
8175 assert iter(input_lines) is input_lines
76 if kwargs.pop('capture_output'):
77 kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
8278 proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
8379 else:
8480 proc = subprocess.run(cmd, **kwargs)
122118
123119
124120 class ExecutableNotFound(RuntimeError):
125 """:class:`RuntimeError` raised if the Graphviz executable is not found."""
121 """:exc:`RuntimeError` raised if the Graphviz executable is not found."""
126122
127123 _msg = ('failed to execute {!r}, '
128124 'make sure the Graphviz executables are on your systems\' PATH')
132128
133129
134130 class CalledProcessError(subprocess.CalledProcessError):
135 """:class:`~subprocess.CalledProcessError` raised if a subprocess ``returncode`` is not ``0``.""" # noqa: E501
131 """:exc:`~subprocess.CalledProcessError` raised if a subprocess ``returncode`` is not ``0``.""" # noqa: E501
136132
137133 def __str__(self) -> 'str':
138134 return f'{super().__str__()} [stderr: {self.stderr!r}]'
1414 def pipe(engine: str, format: str, data: bytes,
1515 renderer: typing.Optional[str] = None,
1616 formatter: typing.Optional[str] = None,
17 neato_no_op: typing.Union[bool, int, None] = None,
1718 quiet: bool = False) -> bytes:
1819 """Return ``data`` (``bytes``) piped through ``engine`` into ``format`` as ``bytes``.
1920
2324 data: Binary (encoded) DOT source bytes to render.
2425 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
2526 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
27 neato_no_op: Neato layout engine no-op flag.
2628 quiet: Suppress ``stderr`` output from the layout subprocess.
2729
2830 Returns:
4850 The layout command is started from the current directory.
4951 """
5052 cmd = dot_command.command(engine, format,
51 renderer=renderer, formatter=formatter)
53 renderer=renderer,
54 formatter=formatter,
55 neato_no_op=neato_no_op)
5256 kwargs = {'input': data}
5357
5458 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
5963 encoding: str,
6064 renderer: typing.Optional[str] = None,
6165 formatter: typing.Optional[str] = None,
66 neato_no_op: typing.Union[bool, int, None] = None,
6267 quiet: bool = False) -> str:
6368 """Return ``input_string`` piped through ``engine`` into ``format`` as string.
6469
6974 encoding: Encoding to en/decode subprocess stdin and stdout (required).
7075 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
7176 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
77 neato_no_op: Neato layout engine no-op flag.
7278 quiet: Suppress ``stderr`` output from the layout subprocess.
7379
7480 Returns:
95101 The layout command is started from the current directory.
96102 """
97103 cmd = dot_command.command(engine, format,
98 renderer=renderer, formatter=formatter)
104 renderer=renderer,
105 formatter=formatter,
106 neato_no_op=neato_no_op)
99107 kwargs = {'input': input_string, 'encoding': encoding}
100108
101109 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
106114 input_encoding: str,
107115 renderer: typing.Optional[str] = None,
108116 formatter: typing.Optional[str] = None,
117 neato_no_op: typing.Union[bool, int, None] = None,
109118 quiet: bool = False) -> bytes:
110119 r"""Return ``input_lines`` piped through ``engine`` into ``format`` as ``bytes``.
111120
116125 input_encoding: Encode input_lines for subprocess stdin (required).
117126 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
118127 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
128 neato_no_op: Neato layout engine no-op flag.
119129 quiet: Suppress ``stderr`` output from the layout subprocess.
120130
121131 Returns:
142152 The layout command is started from the current directory.
143153 """
144154 cmd = dot_command.command(engine, format,
145 renderer=renderer, formatter=formatter)
155 renderer=renderer,
156 formatter=formatter,
157 neato_no_op=neato_no_op)
146158 kwargs = {'input_lines': (line.encode(input_encoding) for line in input_lines)}
147159
148160 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
153165 encoding: str,
154166 renderer: typing.Optional[str] = None,
155167 formatter: typing.Optional[str] = None,
168 neato_no_op: typing.Union[bool, int, None] = None,
156169 quiet: bool = False) -> str:
157170 r"""Return ``input_lines`` piped through ``engine`` into ``format`` as string.
158171
163176 encoding: Encoding to en/decode subprocess stdin and stdout (required).
164177 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
165178 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
179 neato_no_op: Neato layout engine no-op flag.
166180 quiet: Suppress ``stderr`` output from the layout subprocess.
167181
168182 Returns:
189203 The layout command is started from the current directory.
190204 """
191205 cmd = dot_command.command(engine, format,
192 renderer=renderer, formatter=formatter)
206 renderer=renderer,
207 formatter=formatter,
208 neato_no_op=neato_no_op)
193209 kwargs = {'input_lines': input_lines, 'encoding': encoding}
194210
195211 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
159159 filepath: typing.Union[os.PathLike, str],
160160 renderer: typing.Optional[str] = ...,
161161 formatter: typing.Optional[str] = ...,
162 neato_no_op: typing.Union[bool, int, None] = ...,
162163 quiet: bool = ..., *,
163164 outfile: typing.Union[os.PathLike, str, None] = ...,
164165 raise_if_result_exists: bool = ...,
172173 filepath: typing.Union[os.PathLike, str, None] = ...,
173174 renderer: typing.Optional[str] = ...,
174175 formatter: typing.Optional[str] = ...,
176 neato_no_op: typing.Union[bool, int, None] = ...,
175177 quiet: bool = False, *,
176178 outfile: typing.Union[os.PathLike, str, None] = ...,
177179 raise_if_result_exists: bool = ...,
185187 filepath: typing.Union[os.PathLike, str, None] = ...,
186188 renderer: typing.Optional[str] = ...,
187189 formatter: typing.Optional[str] = ...,
190 neato_no_op: typing.Union[bool, int, None] = ...,
188191 quiet: bool = False, *,
189192 outfile: typing.Union[os.PathLike, str, None] = ...,
190193 raise_if_result_exists: bool = ...,
198201 filepath: typing.Union[os.PathLike, str, None] = None,
199202 renderer: typing.Optional[str] = None,
200203 formatter: typing.Optional[str] = None,
204 neato_no_op: typing.Union[bool, int, None] = None,
201205 quiet: bool = False, *,
202206 outfile: typing.Union[os.PathLike, str, None] = None,
203207 raise_if_result_exists: bool = False,
214218 in which case it defaults to ``outfile.with_suffix('.gv')``.
215219 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
216220 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
221 neato_no_op: Neato layout engine no-op flag.
217222 quiet: Suppress ``stderr`` output from the layout subprocess.
218223 outfile: Path for the rendered output file.
219224 raise_if_result_exits: Raise :exc:`graphviz.FileExistsError`
306311 args = ['-O', filepath.name]
307312
308313 cmd = dot_command.command(engine, format,
309 renderer=renderer, formatter=formatter)
314 renderer=renderer,
315 formatter=formatter,
316 neato_no_op=neato_no_op)
310317
311318 if raise_if_result_exists and os.path.exists(outfile):
312319 raise exceptions.FileExistsError(f'output file exists: {os.fspath(outfile)!r}')
99 __all__ = ['GraphSyntax', 'DigraphSyntax', 'Dot']
1010
1111
12 def comment(line: str):
12 def comment(line: str) -> str:
1313 """Return comment header line."""
1414 return f'// {line}\n'
1515
214214 The ``tail_name`` and ``head_name`` strings are separated
215215 by (optional) colon(s) into ``node`` name, ``port`` name,
216216 and ``compass`` (e.g. ``sw``).
217 See `details in the User Guide <ports>`.
217 See :ref:`details in the User Guide <node-ports-compass>`.
218218 """
219219 tail_name = self._quote_edge(tail_name)
220220 head_name = self._quote_edge(head_name)
234234 The ``tail_name`` and ``head_name`` strings are separated
235235 by (optional) colon(s) into ``node`` name, ``port`` name,
236236 and ``compass`` (e.g. ``sw``).
237 See `details in the User Guide <ports>`.
237 See :ref:`details in the User Guide <node-ports-compass>`.
238238 """
239239 edge = self._edge_plain
240240 quote = self._quote_edge
251251 (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
252252 attrs: Attributes to be set (must be strings, may be empty).
253253
254 See the `usage examples in the User Guide <attributes>`.
254 See the :ref:`usage examples in the User Guide <attributes>`.
255255 """
256256 if kw is not None and kw.lower() not in ('graph', 'node', 'edge'):
257257 raise ValueError('attr statement must target graph, node, or edge:'
293293 body: Verbatim lines to add to the subgraph ``body``
294294 (``with``-block use).
295295
296 See the `usage examples in the User Guide <subgraphs>`.
296 See the :ref:`usage examples in the User Guide <subgraphs-clusters>`.
297297
298298 When used as a context manager, the returned new graph instance
299299 uses ``strict=None`` and the parent graph's values
11
22 from .backend.execute import ExecutableNotFound, CalledProcessError
33
4 __all__ = ['RequiredArgumentError', 'FileExistsError',
4 __all__ = ['ExecutableNotFound', 'CalledProcessError',
5 'RequiredArgumentError', 'FileExistsError',
56 'UnknownSuffixWarning', 'FormatSuffixMismatchWarning',
6 'ExecutableNotFound', 'CalledProcessError']
7 'DotSyntaxWarning']
78
89
910 class RequiredArgumentError(TypeError):
10 """:class:`TypeError` raised if a required argument is missing."""
11 """:exc:`TypeError` raised if a required argument is missing."""
1112
1213
1314 class FileExistsError(FileExistsError):
14 """:class:`FileNotFoundError` raised with ``raise_if_exists=True``."""
15 """:exc:`FileExistsError` raised with ``raise_if_exists=True``."""
1516
1617
1718 class UnknownSuffixWarning(RuntimeWarning):
18 """:class:`RuntimeWarning` raised if the suffix of ``outfile`` is unknown
19 """:exc:`RuntimeWarning` raised if the suffix of ``outfile`` is unknown
1920 and the given ``format`` is used instead."""
2021
2122
2223 class FormatSuffixMismatchWarning(UserWarning):
23 """:class:`UserWarning` raised if the suffix ``outfile``
24 """:exc:`UserWarning` raised if the suffix ``outfile``
2425 does not match the given ``format``."""
26
27
28 class DotSyntaxWarning(RuntimeWarning):
29 """:exc:`RuntimeWarning` raised if a quoted string
30 is expected to cause a ``CalledProcessError`` from rendering."""
9595 graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
9696 node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
9797 edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
98 body: Iterable of verbatim lines to add to the graph ``body``.
98 body: Iterable of verbatim lines (including their final newline)
99 to add to the graph ``body``.
99100 strict (bool): Rendering should merge multi-edges.
100101
101102 Note:
4040 'vrml',
4141 'wbmp',
4242 'webp',
43 'xlib',
44 'x11'}
43 'xlib', 'x11'}
4544
4645 DEFAULT_FORMAT = 'pdf'
4746
2323 format: typing.Optional[str] = ...,
2424 renderer: typing.Optional[str] = ...,
2525 formatter: typing.Optional[str] = ...,
26 neato_no_op: typing.Union[bool, int, None] = ...,
2627 quiet: bool = ..., *,
2728 engine: typing.Optional[str] = ...,
2829 encoding: None = ...) -> bytes:
3334 format: typing.Optional[str] = ...,
3435 renderer: typing.Optional[str] = ...,
3536 formatter: typing.Optional[str] = ...,
37 neato_no_op: typing.Union[bool, int, None] = ...,
3638 quiet: bool = ..., *,
3739 engine: typing.Optional[str] = ...,
3840 encoding: str) -> str:
4345 format: typing.Optional[str] = ...,
4446 renderer: typing.Optional[str] = ...,
4547 formatter: typing.Optional[str] = ...,
48 neato_no_op: typing.Union[bool, int, None] = ...,
4649 quiet: bool = ..., *,
4750 engine: typing.Optional[str] = ...,
4851 encoding: typing.Optional[str]) -> typing.Union[bytes, str]:
5255 format: typing.Optional[str] = None,
5356 renderer: typing.Optional[str] = None,
5457 formatter: typing.Optional[str] = None,
58 neato_no_op: typing.Union[bool, int, None] = None,
5559 quiet: bool = False, *,
5660 engine: typing.Optional[str] = None,
5761 encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
6468 (``'cairo'``, ``'gd'``, ...).
6569 formatter: The output formatter used for rendering
6670 (``'cairo'``, ``'gd'``, ...).
71 neato_no_op: Neato layout engine no-op flag.
6772 quiet (bool): Suppress ``stderr`` output
6873 from the layout subprocess.
6974 engine: Layout engine for rendering
98103 return self._pipe_legacy(format,
99104 renderer=renderer,
100105 formatter=formatter,
106 neato_no_op=neato_no_op,
101107 quiet=quiet,
102108 engine=engine,
103109 encoding=encoding)
107113 format: typing.Optional[str] = None,
108114 renderer: typing.Optional[str] = None,
109115 formatter: typing.Optional[str] = None,
116 neato_no_op: typing.Union[bool, int, None] = None,
110117 quiet: bool = False, *,
111118 engine: typing.Optional[str] = None,
112119 encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
113120 return self._pipe_future(format,
114121 renderer=renderer,
115122 formatter=formatter,
123 neato_no_op=neato_no_op,
116124 quiet=quiet,
117125 engine=engine,
118126 encoding=encoding)
120128 def _pipe_future(self, format: typing.Optional[str] = None, *,
121129 renderer: typing.Optional[str] = None,
122130 formatter: typing.Optional[str] = None,
131 neato_no_op: typing.Union[bool, int, None] = None,
123132 quiet: bool = False,
124133 engine: typing.Optional[str] = None,
125134 encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
127136 format=format,
128137 renderer=renderer,
129138 formatter=formatter,
139 neato_no_op=neato_no_op,
130140 quiet=quiet,
131141 verify=True)
132142
22 import functools
33 import re
44 import typing
5 import warnings
56
67 from . import _tools
8 from . import exceptions
79
810 __all__ = ['quote', 'quote_edge',
911 'a_list', 'attr_list',
2022
2123 COMPASS = {'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'c', '_'} # TODO
2224
23 QUOTE_OPTIONAL_BACKSLASHES = re.compile(r'(?P<bs>(?:\\\\)*)'
24 r'\\?(?P<quote>")')
25
26 ESCAPE_UNESCAPED_QUOTES = functools.partial(QUOTE_OPTIONAL_BACKSLASHES.sub,
27 r'\g<bs>\\\g<quote>')
25 FINAL_ODD_BACKSLASHES = re.compile(r'(?<!\\)(?:\\{2})*\\$')
26
27 QUOTE_WITH_OPTIONAL_BACKSLASHES = re.compile(r'''
28 (?P<escaped_backslashes>(?:\\{2})*)
29 \\? # treat \" same as "
30 (?P<literal_quote>")
31 ''', flags=re.VERBOSE)
32
33 ESCAPE_UNESCAPED_QUOTES = functools.partial(QUOTE_WITH_OPTIONAL_BACKSLASHES.sub,
34 r'\g<escaped_backslashes>'
35 r'\\'
36 r'\g<literal_quote>')
2837
2938
3039 @_tools.deprecate_positional_args(supported_number=1)
3241 is_html_string=HTML_STRING.match,
3342 is_valid_id=ID.match,
3443 dot_keywords=KEYWORDS,
44 endswith_odd_number_of_backslashes=FINAL_ODD_BACKSLASHES.search,
3545 escape_unescaped_quotes=ESCAPE_UNESCAPED_QUOTES) -> str:
3646 r"""Return DOT identifier from string, quote if needed.
3747
7181 if is_html_string(identifier) and not isinstance(identifier, NoHtml):
7282 pass
7383 elif not is_valid_id(identifier) or identifier.lower() in dot_keywords:
84 if endswith_odd_number_of_backslashes(identifier):
85 warnings.warn('expect syntax error scanning invalid quoted string:'
86 f' {identifier!r}',
87 category=exceptions.DotSyntaxWarning)
7488 return f'"{escape_unescaped_quotes(identifier)}"'
7589 return identifier
7690
2626 format: typing.Optional[str] = None,
2727 renderer: typing.Optional[str] = None,
2828 formatter: typing.Optional[str] = None,
29 neato_no_op: typing.Union[bool, int, None] = None,
2930 quiet: bool = False,
3031 quiet_view: bool = False, *,
3132 outfile: typing.Union[os.PathLike, str, None] = None,
4849 (``'cairo'``, ``'gd'``, ...).
4950 formatter: The output formatter used for rendering
5051 (``'cairo'``, ``'gd'``, ...).
52 neato_no_op: Neato layout engine no-op flag.
5153 quiet (bool): Suppress ``stderr`` output
5254 from the layout subprocess.
5355 quiet_view (bool): Suppress ``stderr`` output
102104 format=format,
103105 renderer=renderer,
104106 formatter=formatter,
107 neato_no_op=neato_no_op,
105108 quiet=quiet,
106109 outfile=outfile,
107110 raise_if_result_exists=raise_if_result_exists,
00 Metadata-Version: 2.1
11 Name: graphviz
2 Version: 0.19.1
2 Version: 0.20.1
33 Summary: Simple Python interface for Graphviz
44 Home-page: https://github.com/xflr6/graphviz
55 Author: Sebastian Bank
1818 Classifier: License :: OSI Approved :: MIT License
1919 Classifier: Operating System :: OS Independent
2020 Classifier: Programming Language :: Python :: 3
21 Classifier: Programming Language :: Python :: 3.6
2221 Classifier: Programming Language :: Python :: 3.7
2322 Classifier: Programming Language :: Python :: 3.8
2423 Classifier: Programming Language :: Python :: 3.9
2524 Classifier: Programming Language :: Python :: 3.10
2625 Classifier: Topic :: Scientific/Engineering :: Visualization
27 Requires-Python: >=3.6
26 Requires-Python: >=3.7
2827 Provides-Extra: dev
2928 Provides-Extra: test
3029 Provides-Extra: docs
6968 Installation
7069 ------------
7170
72 This package runs under Python 3.6+, use pip_ to install:
71 This package runs under Python 3.7+, use pip_ to install:
7372
7473 .. code:: bash
7574
156155 :align: center
157156 :alt: round-table.svg
158157
158 **Caveat:**
159 Backslash-escapes and strings of the form ``<...>``
160 have a special meaning in the DOT language.
161 If you need to render arbitrary strings (e.g. from user input),
162 check the details in the `user guide`_.
163
159164
160165 See also
161166 --------
205210 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
206211 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
207212 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
213
214 .. _user guide: https://graphviz.readthedocs.io/en/stable/manual.html
208215
209216 .. _pygraphviz: https://pypi.org/project/pygraphviz/
210217 .. _graphviz-python: https://pypi.org/project/graphviz-python/
249256 .. |Binder-stable| image:: https://img.shields.io/badge/launch-binder%20(stable)-579ACA.svg?logo=data:image/png;base64,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
250257 :target: https://mybinder.org/v2/gh/xflr6/graphviz/stable
251258 :alt: Binder (stable)
252
253
3030 docs/jupyter_notebooks.rst
3131 docs/license.rst
3232 docs/manual.rst
33 docs/neato_no_op.rst
3334 docs/node_ports.rst
3435 docs/notebooks.rst
3536 docs/piped_output.rst
6263 docs/_static/qtconsole.png
6364 docs/_static/rank_same.svg
6465 docs/_static/round-table.svg
66 docs/_static/splines.svg
6567 docs/_static/structs.svg
6668 docs/_static/structs_revisited.svg
6769 docs/_static/traffic_lights.svg
66 twine
77
88 [docs]
9 sphinx>=1.8
9 sphinx>=5
1010 sphinx-autodoc-typehints
1111 sphinx-rtd-theme
1212
1313 [test]
14 pytest>=6
14 pytest>=7
1515 pytest-mock>=3
1616 mock>=4
1717 pytest-cov
22
33 """Run the tests with https://pytest.org."""
44
5 import doctest
65 import pathlib
76 import platform
87 import sys
9 from unittest import mock
8
9 import pytest
1010
1111 SELF = pathlib.Path(__file__)
12
13 NO_EXE = doctest.register_optionflag('NO_EXE')
1412
1513 ARGS = [#'--skip-exe',
1614 #'--only-exe',
2624 ARGS += ['--capture=sys', '--color=no']
2725
2826
29 class NoExeChecker(doctest.OutputChecker):
30
31 def check_output(self, want, got, optionflags, *args, **kwargs) -> bool:
32 if optionflags & NO_EXE:
33 return True
34 return super().check_output(want, got, optionflags, *args, **kwargs)
35
36
37 mock.patch.object(doctest, 'OutputChecker', new=NoExeChecker).start()
38 import pytest # noqa: E402
39
40
4127 print('run', [SELF.name] + sys.argv[1:])
4228 args = ARGS + sys.argv[1:]
4329
22
33 setup(
44 name='graphviz',
5 version='0.19.1',
5 version='0.20.1',
66 author='Sebastian Bank',
77 author_email='sebastian.bank@uni-leipzig.de',
88 description='Simple Python interface for Graphviz',
1818 },
1919 packages=find_packages(),
2020 platforms='any',
21 python_requires='>=3.6',
21 python_requires='>=3.7',
2222 extras_require={
2323 'dev': ['tox>=3', 'flake8', 'pep8-naming', 'wheel', 'twine'],
24 'test': ['pytest>=6',
24 'test': ['pytest>=7',
2525 'pytest-mock>=3', 'mock>=4',
2626 'pytest-cov', 'coverage'],
27 'docs': ['sphinx>=1.8', 'sphinx-autodoc-typehints', 'sphinx-rtd-theme'],
27 'docs': ['sphinx>=5', 'sphinx-autodoc-typehints', 'sphinx-rtd-theme'],
2828 },
2929 long_description=pathlib.Path('README.rst').read_text(encoding='utf-8'),
3030 classifiers=[
3434 'License :: OSI Approved :: MIT License',
3535 'Operating System :: OS Independent',
3636 'Programming Language :: Python :: 3',
37 'Programming Language :: Python :: 3.6',
3837 'Programming Language :: Python :: 3.7',
3938 'Programming Language :: Python :: 3.8',
4039 'Programming Language :: Python :: 3.9',
5353 mock_run.assert_called_once_with([_common.EXPECTED_DOT_BINARY,
5454 '-Kdot', '-Tpng'],
5555 input=b'nongraph',
56 stdout=subprocess.PIPE,
57 stderr=subprocess.PIPE,
56 capture_output=True,
5857 startupinfo=_common.StartupinfoMatcher())
5958 if not quiet:
6059 mock_out.decode.assert_not_called()
9695 mock_run.assert_called_once_with([_common.EXPECTED_DOT_BINARY,
9796 '-Kdot', '-Tpng'],
9897 input=b'nongraph',
99 stdout=subprocess.PIPE,
100 stderr=subprocess.PIPE,
98 capture_output=True,
10199 startupinfo=_common.StartupinfoMatcher())
102100 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
103101
115113 mock_run.assert_called_once_with([_common.EXPECTED_DOT_BINARY, '-Kdot', '-Tpng'],
116114 input='nongraph',
117115 encoding=encoding,
118 stdout=subprocess.PIPE,
119 stderr=subprocess.PIPE,
116 capture_output=True,
120117 startupinfo=_common.StartupinfoMatcher())
121118 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
122119
118118 if directory is not None:
119119 filepath = os.path.join(directory, filepath)
120120
121 result = graphviz.render('dot', 'pdf', filepath, quiet=quiet)
121 result = graphviz.render('dot', 'pdf', filepath,
122 neato_no_op=True,
123 quiet=quiet)
122124
123125 assert result == f'{filepath}.pdf'
124126
125127 mock_run.assert_called_once_with([_common.EXPECTED_DOT_BINARY,
126 '-Kdot', '-Tpdf', '-O', 'nonfilepath'],
127 stdout=subprocess.PIPE,
128 stderr=subprocess.PIPE,
128 '-Kdot', '-Tpdf',
129 '-n1',
130 '-O', 'nonfilepath'],
131 capture_output=True,
129132 cwd=_tools.promote_pathlike(directory),
130133 startupinfo=_common.StartupinfoMatcher())
131134 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
3838 mock_run.assert_called_once_with([_common.EXPECTED_UNFLATTEN_BINARY,
3939 '-l', '10', '-f', '-c', '23'],
4040 input='nonsource',
41 stdout=subprocess.PIPE,
42 stderr=subprocess.PIPE,
41 capture_output=True,
4342 startupinfo=_common.StartupinfoMatcher(),
4443 encoding='utf-8')
4544 assert capsys.readouterr() == ('', '')
2929 return cls('graph { spam -- \\ }')
3030 else:
3131 invalid_dot = cls()
32 invalid_dot.edge('spam', '\\')
32 with pytest.warns(graphviz.DotSyntaxWarning, match=r'syntax error'):
33 invalid_dot.edge('spam', '\\')
3334 return invalid_dot
3435
3536
115116 mock_render.assert_called_once_with(dot.engine, dot.format,
116117 mock_save.return_value,
117118 renderer=None, formatter=None,
119 neato_no_op=None,
118120 outfile=None,
119121 raise_if_result_exists=False,
120122 overwrite_filepath=False,
142144 mock_render.assert_called_once_with(dot.engine, dot.format,
143145 mock_save.return_value,
144146 renderer=None, formatter=None,
147 neato_no_op=None,
145148 outfile=pathlib.Path(outfile),
146149 raise_if_result_exists=True,
147150 overwrite_filepath=True,
155158 quiet, cls,
156159 filename='format.gv', format='jpg',
157160 renderer='cairo', formatter='core'):
158 args = [''] if cls.__name__ == 'Source' else []
159 dot = cls(*args, filename=filename, format=format,
161 dot = cls(*[''] if cls.__name__ == 'Source' else [],
162 filename=filename, format=format,
160163 renderer=renderer, formatter=formatter)
161164
162165 assert dot.format == format
170173 mock_save.assert_called_once_with(None, None, skip_existing=None)
171174 mock_render.assert_called_once_with('dot', format, mock_save.return_value,
172175 renderer=renderer, formatter=formatter,
176 neato_no_op=None,
177 outfile=None,
178 raise_if_result_exists=False,
179 overwrite_filepath=False,
180 quiet=quiet)
181
182
183 @pytest.mark.parametrize(
184 'neato_no_op', [None, False, True, 0, 1, 2])
185 def test_neato_no_op_mocked(mocker, mock_render,
186 quiet, cls, neato_no_op,
187 engine='neato',
188 filename='neato_no_op.gv', format='svg'):
189 dot = cls(*[''] if cls.__name__ == 'Source' else [],
190 engine=engine,
191 filename=filename, format=format)
192
193 mock_save = mocker.patch.object(dot, 'save', autospec=True)
194
195 assert dot.render(neato_no_op=neato_no_op,
196 quiet=quiet) is mock_render.return_value
197
198 mock_save.assert_called_once_with(None, None, skip_existing=None)
199 mock_render.assert_called_once_with(engine, format, mock_save.return_value,
200 renderer=None, formatter=None,
201 neato_no_op=neato_no_op,
173202 outfile=None,
174203 raise_if_result_exists=False,
175204 overwrite_filepath=False,
205234 expected_args = ['dot', 'pdf', mocker.ANY]
206235 expected_kwargs = {'quiet': quiet,
207236 'renderer': None,
208 'formatter': None}
237 'formatter': None,
238 'neato_no_op': None}
209239
210240 if encoding == input_encoding:
211241 assert result is mock_pipe_lines_string.return_value
231261
232262 mock_pipe_lines.assert_called_once_with(dot.engine, format_, mocker.ANY,
233263 renderer=None, formatter=None,
264 neato_no_op=None,
234265 input_encoding='utf-8',
235266 quiet=False)
236267 _, _, data = mock_pipe_lines.call_args.args
291322 input_encoding=input_encoding,
292323 quiet=False,
293324 renderer=None,
294 formatter=None)
325 formatter=None,
326 neato_no_op=None)
295327
296328
297329 def test_repr_mimebundle_image_svg_xml_mocked(mocker, dot):
2121 assert cls().filename == f'{cls.__name__}.gv'
2222 assert type('Subcls', (cls,), {})().filename == 'Subcls.gv'
2323 assert cls('spam').filename == 'spam.gv'
24
25
26 @pytest.mark.parametrize(
27 'cls, body_lines, expected',
28 [(graphviz.Graph, ['\tspam -- {\n', '\t\teggs, ham\n', '\t}\n'],
29 'graph {\n\tspam -- {\n\t\teggs, ham\n\t}\n}\n'),
30 (graphviz.Digraph, ['\tspam -> {\n', '\t\teggs, ham\n', '\t}\n'],
31 'digraph {\n\tspam -> {\n\t\teggs, ham\n\t}\n}\n')],
32 ids=lambda p: getattr(p, '__name__', '...'))
33 def test_init_body(cls, body_lines, expected):
34 dot = cls(body=iter(body_lines))
35 assert dot.source == expected
2436
2537
2638 @pytest.mark.exe
00 import functools
11 import os
2 import warnings
23
34 import pytest
45
4344 def func(first, second, third=None, **kwargs):
4445 pass
4546
46 with pytest.warns(None) as captured:
47 with warnings.catch_warnings():
48 warnings.simplefilter('error')
4749 func('first', 'second', third='third', extra='extra')
4850
49 assert not captured
50
51 with pytest.warns(category, match=match) as captured:
52 func('first', 'second', 'third', extra='extra')
53
54 assert bool(captured) == bool(category is not None)
51 if category is not None:
52 with pytest.warns(category, match=match):
53 func('first', 'second', 'third', extra='extra')
54 else:
55 with warnings.catch_warnings():
56 warnings.simplefilter('error')
57 func('first', 'second', 'third', extra='extra')
00 [tox]
1 envlist = py{310,39,38,37,36}
1 envlist = py{310,39,38,37}
22 skip_missing_interpreters = true
33
44 [testenv]