graphviz-0.8.4/0000755000000000000000000000000013316607326012062 5ustar rootrootgraphviz-0.8.4/CHANGES.txt0000666000000000000000000001461313316254132013675 0ustar rootrootChangelog ========= Version 0.8.4 ------------- Tag Python 3.7 support (work around subprocess close_fds issue on Windows). Version 0.8.3 ------------- Fix compatibility with ``python -OO``. Version 0.8.2 ------------- Add ``nohtml()`` to support labels of the form ``'<...>'`` (disabling their default treatment as HTML strings). Make default ``'utf-8'`` ``encoding`` more visible. Set ``encoding = locale.getpreferredencoding()`` when ``encoding`` argument/property is set to ``None`` explicitly (follow stdlib ``io.open()`` behaviour). Version 0.8.1 ------------- Add ``Source.from_file()``-classmethod (simpler in-line SVG display of ready-made .gv files within Jupyter). Drop Python 3.3 support. Version 0.8 ----------- Add ``clear()``-method for ``Graph`` and ``Digraph``. Add ``grapviz.version()`` function. Drop dot source extra indent for edge statements following dotguide examples. Include LICENSE file in wheel. Version 0.7.1 ------------- Fix ``TypeError`` in ``graphviz.pipe()`` with invalid dot code under Python 3. Add ``copy()``-method for ``Graph``, ``Digraph``, and ``Source``. Add ``graphviz.render(..., quiet=True)``. Fix ``graphivz.view()`` exception on unsupported platform. Raise a dedicated ``RuntimeError`` subclass ``graphviz.ExecutableNotFound`` when the Graphviz executables are not found. Port tests from ``nose/unittest`` to ``pytest``, extend, use mocks. Version 0.7 ----------- Support setting top-level attrs with ``g.attr(key=value)``. Add context manager usage of ``subgraph()`` for adding a subgraph in a with-block. Add json-based output formats to known ``FORMATS`` (Graphviz 2.40+). Drop extra indent level for DOT source with nonempty ``graph/node/edge_attr``. Add a final newline to a saved DOT source file if it does not end with one. Raise ``subprocess.CalledProcessError`` on non-zero exit status from rendering. Raise early when adding a ``subgraph()`` with ``strict=True`` (avoid DOT syntax error). Make undocumented ``quote()``, ``quote_edge()``, and ``attributes()`` methods private. Version 0.6 ----------- Drop Python 2.6 support (use ``graphviz<0.6`` there). Improve tests for ``mkdirs()``. Better document adding custom DOT using the ``body`` attribute. Add ``view()``-support for FreeBSD (pull request Julien Gamba). Version 0.5.2 ------------- Add ``ENGINES`` and ``FORMATS`` to the documented public API. Version 0.5.1 ------------- Fixed PY3 compatibility. Version 0.5 ----------- Add low-level functions ``render()``, ``pipe()``, and ``view()`` for directly working with existing files and strings. Support all ``render()``-arguments in the ``view()``-short-cut-method. Version 0.4.10 -------------- Added ``'patchwork'`` engine. Version 0.4.9 ------------- Add support for ``strict`` graphs and digraphs. Hide ``render/pipe()`` subrocess console window on Windows when invoked from non-console process (e.g. from IDLE). Improve documentation markup/wording. Make ``TestNoent`` more robust. Version 0.4.8 ------------- Make ``_repr_svg_()`` available on ``Source`` (pull request RafalSkolasinski). Version 0.4.7 ------------- Fixed ``view()``-method on Linux under Python 3 (pull request Antony Lee). Version 0.4.6 ------------- Fixed ``view()``-method on Linux and Darwin (pull request Eric L. Frederich). Version 0.4.5 ------------- Added example for HTML-like labels (``structs.py``). Added ``Source`` class for rendering verbatim DOT source code. Added Python 2.6 support (pull request Jim Crist). Version 0.4.4 ------------- Added the ``pipe()``-method directly returning the ``stdout`` of rendering. Added ``_repr_svg_()`` for inline rendering in IPython notebooks. Version 0.4.3 ------------- Added examples generating some of the graphs from the Graphviz Gallery. Added sphinx-based API documentation. Version 0.4.2 ------------- Added support for HTML-like labels. Version 0.4.1 ------------- Added support for less common output formats. Removed dropped formats (``'dia'``, ``'pcl'``). Added ``'osage'`` layout engine. Documented ``format`` and ``engine`` options in the README. The ``view()`` convenience method now returns the result file name (like render()). Version 0.4 ----------- Added ``attr()`` method for inline switching of node/edge attributes. Added ``subgraph()`` method (obsoletes separate ``Subgraph`` class). Add ``cleanup`` option to ``render()``. Replaced ``dry`` option on ``render()`` with separate ``save()`` method. Removed undocumented ``append()`` and ``extend()`` methods (if needed, the ``body`` attribute can be edited directly). Version 0.3.5 ------------- Skip empty ``comment`` when creating DOT source. Document ``graph_attr``, ``node_attr``, and ``edge_attr`` in the README. More informative exception when Graphviz excutables cannot be called. Version 0.3.4 ------------- Fixed missing identifier quoting for DOT keywords (thanks to Paulo Urio). Version 0.3.3 ------------- Made ``format`` and ``engine`` case-insensitive. Version 0.3.2 ------------- Indent ``graph_attr``, ``node_attr``, and ``edge_attr`` lines, adapt nodes and edges. Version 0.3.1 ------------- Fixed ``view()`` failing on paths with forward slashes on Windows. Version 0.3 ----------- Added Python 3.3+ support. Made attributes order stable (sorting plain dicts). Fixed edgeop in undirected graphs. Version 0.2.2 ------------- Support pdf opening on Linux. Fixed rendering filenames w/spaces. Version 0.2.1 ------------- Fixed rendering on Mac OS X. Version 0.2 ----------- Added format selection, use ``'PDF``' as default. Added engines selection, use ``'dot'`` as default. Added source encoding, use ``'UTF-8'`` as default. Changed constructor arguments order, removed ``compile()`` and ``save()``-method, reimplemented compilation in ``render()`` method, make interface more similar to gv.3python (backwards incompatible change). Double-quote-sign escaping, attribute list quoting. ``mkdirs()`` now correctly supports current directory filenames. Version 0.1.1 ------------- Removed automatic ``'-'`` to ``'−'`` replacement from labels. Fixed documentation typos. Version 0.1 ----------- First public release. graphviz-0.8.4/LICENSE.txt0000666000000000000000000000212313316251122013674 0ustar rootrootThe MIT License (MIT) Copyright (c) 2013-2018 Sebastian Bank Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. graphviz-0.8.4/MANIFEST.in0000666000000000000000000000040313316251124013610 0ustar rootrootinclude README.rst LICENSE.txt CHANGES.txt include requirements.txt include run-tests.py try-examples.py tox.ini recursive-include tests *.py recursive-include examples *.py *.ipynb recursive-include docs *.rst *.txt *.py *.png *.svg prune docs/_build graphviz-0.8.4/PKG-INFO0000666000000000000000000001573313316254574013177 0ustar rootrootMetadata-Version: 2.1 Name: graphviz Version: 0.8.4 Summary: Simple Python interface for Graphviz Home-page: https://github.com/xflr6/graphviz Author: Sebastian Bank Author-email: sebastian.bank@uni-leipzig.de License: MIT Description: Graphviz ======== |PyPI version| |License| |Supported Python| |Format| |Docs| |Travis| |Codecov| This package facilitates the creation and rendering of graph descriptions in the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from Python. Create a graph object, assemble the graph by adding nodes and edges, and retrieve its DOT source code string. Save the source code to a file and render it with the Graphviz installation of your system. Use the ``view`` option/method to directly inspect the resulting (PDF, PNG, SVG, etc.) file with its default application. Graphs can also be rendered and displayed within `Jupyter notebooks`_ (formerly known as `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_. Links ----- - GitHub: https://github.com/xflr6/graphviz - PyPI: https://pypi.org/project/graphviz/ - Documentation: https://graphviz.readthedocs.io - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html - Issue Tracker: https://github.com/xflr6/graphviz/issues - Download: https://pypi.org/project/graphviz/#files Installation ------------ This package runs under Python 2.7, and 3.4+, use pip_ to install: .. code:: bash $ pip install graphviz To render the generated DOT source code, you also need to install Graphviz (`download page`_). Make sure that the directory containing the ``dot`` executable is on your systems' path. Quickstart ---------- Create a graph object: .. code:: python >>> from graphviz import Digraph >>> dot = Digraph(comment='The Round Table') >>> dot #doctest: +ELLIPSIS Add nodes and edges: .. code:: python >>> dot.node('A', 'King Arthur') >>> dot.node('B', 'Sir Bedevere the Wise') >>> dot.node('L', 'Sir Lancelot the Brave') >>> dot.edges(['AB', 'AL']) >>> dot.edge('B', 'L', constraint='false') Check the generated source code: .. code:: python >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { A [label="King Arthur"] B [label="Sir Bedevere the Wise"] L [label="Sir Lancelot the Brave"] A -> B A -> L B -> L [constraint=false] } Save and render the source code, optionally view the result: .. code:: python >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP 'test-output/round-table.gv.pdf' .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png :align: center See also -------- - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG - graphviz-python_ |--| official Python bindings (documentation_) - pydot_ |--| stable pure-Python approach, requires pyparsing License ------- This package is distributed under the `MIT license`_. .. _pip: https://pip.readthedocs.io .. _Graphviz: https://www.graphviz.org .. _master repo: https://gitlab.com/graphviz/graphviz/ .. _download page: https://www.graphviz.org/download/ .. _DOT: https://www.graphviz.org/doc/info/lang.html .. _Jupyter notebooks: https://jupyter.org .. _IPython notebooks: https://ipython.org/notebook.html .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb .. _Jupyter Qt Console: https://qtconsole.readthedocs.io .. _pygraphviz: https://pypi.org/project/pygraphviz/ .. _graphviz-python: https://pypi.org/project/graphviz-python/ .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf .. _pydot: https://pypi.org/project/pydot/ .. _MIT license: https://opensource.org/licenses/MIT .. |--| unicode:: U+2013 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Latest PyPI Version .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: License .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Supported Python Versions .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Format .. |Docs| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable :target: https://graphviz.readthedocs.io/en/stable/ :alt: Readthedocs .. |Travis| image:: https://img.shields.io/travis/xflr6/graphviz.svg :target: https://travis-ci.org/xflr6/graphviz :alt: Travis .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg :target: https://codecov.io/gh/xflr6/graphviz :alt: Codecov Keywords: graph visualization dot render Platform: any Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Scientific/Engineering :: Visualization Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* Provides-Extra: test Provides-Extra: docs Provides-Extra: dev graphviz-0.8.4/README.rst0000666000000000000000000001131413316251124013544 0ustar rootrootGraphviz ======== |PyPI version| |License| |Supported Python| |Format| |Docs| |Travis| |Codecov| This package facilitates the creation and rendering of graph descriptions in the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from Python. Create a graph object, assemble the graph by adding nodes and edges, and retrieve its DOT source code string. Save the source code to a file and render it with the Graphviz installation of your system. Use the ``view`` option/method to directly inspect the resulting (PDF, PNG, SVG, etc.) file with its default application. Graphs can also be rendered and displayed within `Jupyter notebooks`_ (formerly known as `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_. Links ----- - GitHub: https://github.com/xflr6/graphviz - PyPI: https://pypi.org/project/graphviz/ - Documentation: https://graphviz.readthedocs.io - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html - Issue Tracker: https://github.com/xflr6/graphviz/issues - Download: https://pypi.org/project/graphviz/#files Installation ------------ This package runs under Python 2.7, and 3.4+, use pip_ to install: .. code:: bash $ pip install graphviz To render the generated DOT source code, you also need to install Graphviz (`download page`_). Make sure that the directory containing the ``dot`` executable is on your systems' path. Quickstart ---------- Create a graph object: .. code:: python >>> from graphviz import Digraph >>> dot = Digraph(comment='The Round Table') >>> dot #doctest: +ELLIPSIS Add nodes and edges: .. code:: python >>> dot.node('A', 'King Arthur') >>> dot.node('B', 'Sir Bedevere the Wise') >>> dot.node('L', 'Sir Lancelot the Brave') >>> dot.edges(['AB', 'AL']) >>> dot.edge('B', 'L', constraint='false') Check the generated source code: .. code:: python >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { A [label="King Arthur"] B [label="Sir Bedevere the Wise"] L [label="Sir Lancelot the Brave"] A -> B A -> L B -> L [constraint=false] } Save and render the source code, optionally view the result: .. code:: python >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP 'test-output/round-table.gv.pdf' .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png :align: center See also -------- - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG - graphviz-python_ |--| official Python bindings (documentation_) - pydot_ |--| stable pure-Python approach, requires pyparsing License ------- This package is distributed under the `MIT license`_. .. _pip: https://pip.readthedocs.io .. _Graphviz: https://www.graphviz.org .. _master repo: https://gitlab.com/graphviz/graphviz/ .. _download page: https://www.graphviz.org/download/ .. _DOT: https://www.graphviz.org/doc/info/lang.html .. _Jupyter notebooks: https://jupyter.org .. _IPython notebooks: https://ipython.org/notebook.html .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb .. _Jupyter Qt Console: https://qtconsole.readthedocs.io .. _pygraphviz: https://pypi.org/project/pygraphviz/ .. _graphviz-python: https://pypi.org/project/graphviz-python/ .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf .. _pydot: https://pypi.org/project/pydot/ .. _MIT license: https://opensource.org/licenses/MIT .. |--| unicode:: U+2013 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Latest PyPI Version .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: License .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Supported Python Versions .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Format .. |Docs| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable :target: https://graphviz.readthedocs.io/en/stable/ :alt: Readthedocs .. |Travis| image:: https://img.shields.io/travis/xflr6/graphviz.svg :target: https://travis-ci.org/xflr6/graphviz :alt: Travis .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg :target: https://codecov.io/gh/xflr6/graphviz :alt: Codecov graphviz-0.8.4/requirements.txt0000666000000000000000000000011513316251122015334 0ustar rootroot# development environment: install in development mode -e .[dev,test,docs] graphviz-0.8.4/run-tests.py0000666000000000000000000000057013316251122014373 0ustar rootroot#!/usr/bin/env python # run-tests.py import sys import pytest ARGS = [ #'--exitfirst', #'--pdb', ] if 'idlelib' in sys.modules or 'thonny' in sys.modules: ARGS.extend(['--capture=sys', '--color=no']) elif sys.version_info.major == 2 and 'win_unicode_console' in sys.modules: ARGS.append('--capture=sys') pytest.main(ARGS + sys.argv[1:]) graphviz-0.8.4/setup.cfg0000666000000000000000000000077313316254574013721 0ustar rootroot[metadata] license_file = LICENSE.txt [sdist] formats = zip [bdist_wheel] universal = 1 [tool:pytest] minversion = 3.4 testpaths = README.rst docs graphviz tests addopts = --doctest-modules --doctest-glob='*.rst' --ignore=docs/conf.py --cov --cov-report=term --cov-report=html mock_use_standalone_module = true [coverage:run] source = graphviz branch = false [flake8] ignore = E126,E128 max-line-length = 100 exclude = docs, .tox [egg_info] tag_build = tag_date = 0 graphviz-0.8.4/setup.py0000666000000000000000000000267513316254110013577 0ustar rootroot# setup.py import io from setuptools import setup, find_packages setup( name='graphviz', version='0.8.4', author='Sebastian Bank', author_email='sebastian.bank@uni-leipzig.de', description='Simple Python interface for Graphviz', keywords='graph visualization dot render', license='MIT', url='https://github.com/xflr6/graphviz', packages=find_packages(), platforms='any', python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', extras_require={ 'dev': ['tox>=3.0', 'flake8', 'pep8-naming', 'wheel', 'twine'], 'test': ['mock>=2', 'pytest>=3.4', 'pytest-mock>=1.8', 'pytest-cov'], 'docs': ['sphinx>=1.3', 'sphinx-rtd-theme'], }, long_description=io.open('README.rst', encoding='utf-8').read(), classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Topic :: Scientific/Engineering :: Visualization', ], ) graphviz-0.8.4/tox.ini0000666000000000000000000000020013316251122013356 0ustar rootroot[tox] envlist = py{27,34,35,36,37} skip_missing_interpreters = true [testenv] extras = test commands = pytest {posargs} graphviz-0.8.4/try-examples.py0000666000000000000000000000051213316251124015057 0ustar rootroot#!/usr/bin/env python # try-examples.py - import graphviz here and run all scripts in the example dir import os import io import glob import graphviz # noqa: F401 os.chdir('examples') for filename in glob.iglob('*.py'): with io.open(filename, encoding='utf-8') as fd: code = fd.read() exec(code) graphviz-0.8.4/docs/0000755000000000000000000000000013316607326013012 5ustar rootrootgraphviz-0.8.4/docs/api.rst0000666000000000000000000000317613316251122014315 0ustar rootroot.. _api: API Reference ============= .. autosummary:: :nosignatures: ~graphviz.Graph ~graphviz.Digraph ~graphviz.Source graphviz.render graphviz.pipe graphviz.view .. note:: The two main classes :class:`.Graph` and :class:`.Digraph` (for creating `undirected` vs. `directed` graphs) have exactly the same API. Their division reflects the fact that both graph types cannot be mixed. Graph ----- .. autoclass:: graphviz.Graph :members: source, node, edge, edges, attr, subgraph, format, engine, encoding, clear, copy, pipe, save, render, view, directed Digraph ------- .. autoclass:: graphviz.Digraph :members: source, node, edge, edges, attr, subgraph, format, engine, encoding, clear, copy, pipe, save, render, view, directed Source ------ .. autoclass:: graphviz.Source :members: format, engine, encoding, copy, pipe, save, render, view, from_file, source Low-level functions ------------------- The functions in this section are provided to work directly with existing files and strings instead of using the object-oriented DOT creation methods documented above. .. autofunction:: graphviz.render .. autofunction:: graphviz.pipe .. autofunction:: graphviz.view Other ----- .. autodata:: graphviz.ENGINES :annotation: .. autodata:: graphviz.FORMATS :annotation: .. autodata:: graphviz.ExecutableNotFound :annotation: .. autofunction:: graphviz.version .. autofunction:: graphviz.nohtml graphviz-0.8.4/docs/changelog.rst0000666000000000000000000000005713316251122015466 0ustar rootroot.. _changelog: .. include:: ../CHANGES.txt graphviz-0.8.4/docs/conf.py0000666000000000000000000001355013316254216014315 0ustar rootroot# -*- coding: utf-8 -*- # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import sys sys.path.insert(0, os.path.abspath(os.pardir)) import graphviz # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'graphviz' copyright = u'2013-2018, Sebastian Bank' author = u'Sebastian Bank' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = u'0.8.4' # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars #html_sidebars = { # '**': [ # 'relations.html', # needs 'show_related': True theme option to display # 'searchbox.html', # ] #} # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'graphvizdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'graphviz.tex', u'graphviz Documentation', u'Sebastian Bank', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'graphviz', u'graphviz Documentation', [author], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'graphviz', u'graphviz Documentation', author, 'graphviz', 'One line description of project.', 'Miscellaneous'), ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'py': ('https://docs.python.org/2', None), 'py3': ('https://docs.python.org/3', None), } # monkey patch, see https://github.com/sphinx-doc/sphinx/issues/2044 from sphinx.ext.autodoc import ClassLevelDocumenter, InstanceAttributeDocumenter def add_directive_header(self, sig): ClassLevelDocumenter.add_directive_header(self, sig) InstanceAttributeDocumenter.add_directive_header = add_directive_header graphviz-0.8.4/docs/examples.rst0000666000000000000000000000463113316251122015357 0ustar rootroot.. _examples: Examples ======== The following code examples are included in the ``examples/`` directory of the `source repository/distribution`__. Most of them recreate examples from the `graphviz.org gallery`__ or the `graphviz.org documentation`__. .. __: https://github.com/xflr6/graphviz/tree/master/examples/ .. __: http://www.graphviz.org/gallery/ .. __: http://www.graphviz.org/documentation/ hello.py -------- .. literalinclude:: ../examples/hello.py :lines: 2- .. image:: _static/hello.svg :align: center process.py ---------- .. literalinclude:: ../examples/process.py :lines: 2- .. image:: _static/process.svg :align: center fsm.py ------ .. literalinclude:: ../examples/fsm.py :lines: 2- .. image:: _static/fsm.svg :align: center .. _cluster.py: cluster.py ---------- .. literalinclude:: ../examples/cluster.py :lines: 2- .. image:: _static/cluster.svg :align: center er.py ----- .. literalinclude:: ../examples/er.py :lines: 2- .. image:: _static/er.svg :align: center unix.py ------- .. literalinclude:: ../examples/unix.py :lines: 2- .. image:: _static/unix.svg :align: center structs.py ---------- .. literalinclude:: ../examples/structs.py :lines: 2- .. image:: _static/structs.svg :align: center structs_revisited.py -------------------- .. literalinclude:: ../examples/structs_revisited.py :lines: 2- .. image:: _static/structs_revisited.svg :align: center btree.py -------- .. literalinclude:: ../examples/btree.py :lines: 2- .. image:: _static/btree.svg :align: center traffic_lights.py ----------------- .. literalinclude:: ../examples/traffic_lights.py :lines: 2- .. image:: _static/traffic_lights.svg :align: center fdpclust.py ----------- .. literalinclude:: ../examples/fdpclust.py :lines: 2- .. image:: _static/fdpclust.svg :align: center cluster_edge.py --------------- .. literalinclude:: ../examples/cluster_edge.py :lines: 2- .. image:: _static/cluster_edge.svg :align: center g_c_n.py -------- .. literalinclude:: ../examples/g_c_n.py :lines: 2- .. image:: _static/g_c_n.svg :align: center angles.py --------- .. literalinclude:: ../examples/angles.py :lines: 2- .. image:: _static/angles.svg :align: center graphviz-0.8.4/docs/index.rst0000666000000000000000000000061213316251122014643 0ustar rootroot.. graphviz documentation master file .. include:: ../README.rst User Guide ========== .. toctree:: :maxdepth: 2 manual Examples ======== .. toctree:: :maxdepth: 2 examples API Reference ============= .. toctree:: :maxdepth: 2 api Project Info ============ .. toctree:: :maxdepth: 2 changelog license graphviz-0.8.4/docs/license.rst0000666000000000000000000000010113316251122015147 0ustar rootroot.. _license: License ======= .. include:: ../LICENSE.txt graphviz-0.8.4/docs/manual.rst0000666000000000000000000003733313316251122015023 0ustar rootroot.. _manual: User Guide ========== Installation ------------ :mod:`graphviz` provides a simple pure-Python interface for the Graphviz_ graph-drawing software. It runs under Python 2.7 and 3.4+. To install it with pip_ run the following: .. code:: bash $ pip install graphviz For a system-wide install, this typically requires administrator access. For an isolated install, you can run the same inside a virtualenv_ or a :mod:`py3:venv` (Python 3 only). The only dependency is a working installation of Graphviz (`download page`_). After installing Graphviz, make sure that its ``bin/`` subdirectory containing the layout commands for rendering graph descriptions (``dot``, ``circo``, ``neato``, etc.) is on your systems' path: On the command-line, ``dot -V`` should print the version of your Graphiz installation. Basic usage ----------- The :mod:`graphviz` module provides two classes: :class:`.Graph` and :class:`.Digraph`. They create graph descriptions in the DOT_ language for undirected and directed graphs respectively. They have the same :ref:`API `. Create a graph by instantiating a new :class:`.Graph` or :class:`.Digraph` object: .. code:: python >>> from graphviz import Digraph >>> dot = Digraph(comment='The Round Table') >>> dot #doctest: +ELLIPSIS Their constructors allow to set the graph's :attr:`~.Graph.name`, the :attr:`~.Graph.filename` for the DOT source and the rendered graph, a :attr:`~.Graph.comment` for the first source code line, etc. Add nodes and edges to the graph object using its :meth:`~.Graph.node` and :meth:`~.Graph.edge` or :meth:`~.Graph.edges` methods: .. code:: python >>> dot.node('A', 'King Arthur') >>> dot.node('B', 'Sir Bedevere the Wise') >>> dot.node('L', 'Sir Lancelot the Brave') >>> dot.edges(['AB', 'AL']) >>> dot.edge('B', 'L', constraint='false') The :meth:`~.Graph.node`-method takes a ``name`` identifier as first argument and an optional ``label``. The :meth:`~.Graph.edge`-method takes the names of start- and end-node, while :meth:`~.Graph.edges` takes iterable of name-pairs. Keyword arguments are turned into (node and edge) attributes (see `Graphviz docs `_). Check the generated source code: .. code:: python >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { A [label="King Arthur"] B [label="Sir Bedevere the Wise"] L [label="Sir Lancelot the Brave"] A -> B A -> L B -> L [constraint=false] } Use the :meth:`~.Graph.render`-method to save the source code and render it with the default layout program (``dot``, see below for using `other layout commands `_). .. code:: python >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP 'test-output/round-table.gv.pdf' .. image:: _static/round-table.svg :align: center Passing ``view=True`` will automatically open the resulting (PDF, PNG, SVG, etc.) file with your system's default viewer application for the file type. Formats ------- To use a different `output file format`_ than the default PDF, use the :attr:`~.Graph.format` argument when creating your :class:`.Graph` or :class:`.Digraph` object: .. code:: python >>> from graphviz import Graph >>> g = Graph(format='png') You can also change the :attr:`~.Graph.format` attribute on an existing graph object: .. code:: python >>> dot.format = 'svg' >>> dot.render() # doctest: +SKIP 'test-output/round-table.gv.svg' Piped output ------------ To directly access the results from the Graphviz rendering command (e.g. ``dot``) as binary data string from within Python instead of writing to a file, use the :meth:`~.Graph.pipe`-method of your :class:`.Graph` or :class:`.Digraph` object: .. code:: python >>> h = Graph('hello', format='svg') >>> h.edge('Hello', 'World') >>> print(h.pipe().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS Note that :meth:`~.Graph.pipe` returns the raw ``stdout`` from the rendering command (``str`` on Python 2, ``bytes`` on Python 3): When piping into plain-text formats like ``'svg'`` or ``'plain'``, you usually want to decode the return value as shown above. .. note:: The output for :meth:`~.Graph.pipe` is buffered in memory, so do not use this method if the data size is large. Jupyter notebooks ----------------- :class:`.Graph` and :class:`.Digraph` objects have a :meth:`~.Graph._repr_svg_`-method so they can be rendered and displayed directly inside a `Jupyter notebook`_. For an example, check the ``examples/notebook.ipynb`` file in the `source repository/distribution `_ (or the same within nbviewer_). This also allows direct displaying within the `Jupyter Qt Console`_ (e.g. `the one `_ inside `Spyder IDE`_): .. image:: _static/qtconsole.png :align: center Styling ------- Use the :attr:`~.Graph.graph_attr`, :attr:`~.Graph.node_attr`, and :attr:`~.Graph.edge_attr` arguments to change the default appearance_ of your graph, nodes, and edges. .. code:: python >>> ps = Digraph(name='pet-shop', node_attr={'shape': 'plaintext'}) >>> ps.node('parrot') >>> ps.node('dead') >>> ps.edge('parrot', 'dead') After creation, they can be edited on the graph object: .. code:: python >>> ps.graph_attr['rankdir'] = 'LR' >>> ps.edge_attr.update(arrowhead='vee', arrowsize='2') >>> print(ps.source) # doctest: +NORMALIZE_WHITESPACE digraph "pet-shop" { graph [rankdir=LR] node [shape=plaintext] edge [arrowhead=vee arrowsize=2] parrot dead parrot -> dead } .. image:: _static/pet-shop.svg :align: center .. _attributes: Attributes ---------- To directly add attitbute statements (affecting all following graph, node, or edge items within the same (sub-)graph), use the :meth:`~.Graph.attr`-method with the target as first argument: .. code:: python >>> ni = Graph('ni') >>> ni.attr('node', shape='rarrow') >>> ni.node('1', 'Ni!') >>> ni.node('2', 'Ni!') >>> ni.node('3', 'Ni!', shape='egg') >>> ni.attr('node', shape='star') >>> ni.node('4', 'Ni!') >>> ni.node('5', 'Ni!') By omitting its first argument, you can use it to set arbitrary attributes as key-value pairs targeting the current (sub-)graph (e.g. for ``rankdir``, ``label``, or setting ``rank='same'`` within a subgraph context): .. code:: python >>> ni.attr(rankdir='LR') >>> ni.edges(['12', '23', '34', '45']) >>> print(ni.source) # doctest: +NORMALIZE_WHITESPACE graph ni { node [shape=rarrow] 1 [label="Ni!"] 2 [label="Ni!"] 3 [label="Ni!" shape=egg] node [shape=star] 4 [label="Ni!"] 5 [label="Ni!"] rankdir=LR 1 -- 2 2 -- 3 3 -- 4 4 -- 5 } .. image:: _static/ni.svg :align: center Quoting and HTML-like labels ---------------------------- The graph-building methods of :class:`.Graph` and :class:`.Digraph` objects automatically take care of quoting/escaping strings `where required `_ (whitespace, keywords, double quotes, etc.): .. code:: python >>> q = Digraph() >>> q.edge('spam', 'eggs eggs') >>> q.edge('node', '"here\'s a quote"') >>> print(q.source) # doctest: +NORMALIZE_WHITESPACE digraph { spam -> "eggs eggs" "node" -> "\"here's a quote\"" } If a string starts with ``'<'`` and ends with ``'>'``, it is passed on as is, without quoting/escaping: The content between the angle brackets is treated by the engine as special **HTML string** that can be used for `HTML-like labels`_: .. code:: python >>> h = Graph('html_table') >>> h.node('tab', label='''< ... ... ... ... ...
leftright
>''') .. image:: _static/html_table.svg :align: center For strings that should literally begin with ``'<'`` and end with ``'>'``, use the :func:`.nohtml` function to disable the special meaning of angled parenthesis and apply normal quoting/escaping (before ``0.8.2``, the only workaround was to add leading or trailing space, e.g. ``label=' <>'``): .. code:: python >>> from graphviz import nohtml >>> d = Digraph(format='svg') >>> d.node('diamond', label=nohtml('<>')) >>> print(d.source) # doctest: +NORMALIZE_WHITESPACE digraph { diamond [label="<>"] } .. image:: _static/diamond.svg :align: center .. _subgraphs: Subgraphs & clusters -------------------- :class:`.Graph` and :class:`.Digraph` objects have a :meth:`~.Graph.subgraph`-method for adding a subgraph to an instance. There are two ways to use it: Either with a ready-made graph object of the same kind as the only argument (whose content is added as a subgraph) or omitting the ``graph`` argument (returning a context manager for defining the subgraph content more elegantly within a ``with``-block). First usage option, with ``graph`` as the only argument: .. code:: python >>> p = Graph(name='parent') >>> p.edge('spam', 'eggs') >>> c = Graph(name='child', node_attr={'shape': 'box'}) >>> c.edge('foo', 'bar') >>> p.subgraph(c) Second usage, with a ``with``-block (omitting the ``graph`` argument): .. code:: python >>> p = Graph(name='parent') >>> p.edge('spam', 'eggs') >>> with p.subgraph(name='child', node_attr={'shape': 'box'}) as c: ... c.edge('foo', 'bar') Both produce the same result: .. code:: python >>> print(p.source) # doctest: +NORMALIZE_WHITESPACE graph parent { spam -- eggs subgraph child { node [shape=box] foo -- bar } } .. note:: If the ``name`` of a subgraph begins with ``'cluster'`` (all lowercase) the layout engine will treat it as a special cluster subgraph (:ref:`example `). Also see the `Subgraphs and Clusters` section of `the DOT language documentation `_. Engines ------- To use a different layout command than the default ``dot`` when rendering your graph, use the :attr:`~.Graph.engine` argument when creating your graph. .. code:: python >>> g = Graph(engine='neato') You can also change the :attr:`~.Graph.engine` attribute of an existing instance: .. code:: python >>> dot.engine = 'circo' Custom DOT statements --------------------- To add arbitrary statements to the created DOT_ source, use the :attr:`~.Graph.body` attribute of the :class:`.Graph` or :class:`.Digraph` object. It holds the verbatim list of lines to be written to the source file. Use its ``append()`` or ``extend()`` method: .. code:: python >>> rt = Digraph(comment='The Round Table') >>> rt.body.append('\t"King Arthur" -> {\n\t\t"Sir Bedevere", "Sir Lancelot"\n\t}') >>> rt.edge('Sir Bedevere', 'Sir Lancelot', constraint='false') >>> print(rt.source) # doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { "King Arthur" -> { "Sir Bedevere", "Sir Lancelot" } "Sir Bedevere" -> "Sir Lancelot" [constraint=false] } Note that you might need to correctly quote/escape identifiers and strings containing whitespace or other special characters when using this method. Using raw DOT ------------- To render a ready-made DOT source code string (instead of assembling one with the higher-level interface of :class:`.Graph` or :class:`.Digraph`), create a :class:`.Source` object holding your DOT string: .. code:: python >>> from graphviz import Source >>> src = Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }') >>> src #doctest: +ELLIPSIS Use the :meth:`~.Source.render`-method to save and render it: .. code:: python >>> src.render('test-output/holy-grenade.gv', view=True) # doctest: +SKIP 'test-output/holy-grenade.gv.pdf' .. image:: _static/holy-grenade.svg :align: center Apart from the missing editing methods, :class:`.Source` objects are the same as the higher-level graph objects (:meth:`~.Source.pipe`-method, :attr:`~.Source.format`, :attr:`~.Source.engine`, Jupyter notebook repr, etc.), see above. Existing files -------------- To directly render an existing DOT source file (e.g. created with other tools), you can use the :func:`graphviz.render` function. .. code:: python >>> from graphviz import render >>> render('dot', 'png', 'test-output/holy-grenade.gv') # doctest: +SKIP 'test-output/holy-grenade.gv.png' To directly display the graph of an existing DOT source file inside a Jupyter `notebook `_ or `Qt Console `_, you can use the :meth:`.Source.from_file`-classmethod (alternate constructor): .. image:: _static/qtconsole-source.png :align: center Note that if you call :meth:`~.Source.render` or :meth:`~.Source.view` on the returned :class:`.Source` object, it will still :meth:`~.Source.save` as usual (i.e. write the content read into :attr:`~.Source.source` back into the file). You can use :func:`graphviz.render` and :func:`graphiz.view` to directly work on files in case you need to avoid this round-trip. Integration with viewers ------------------------ On platforms such as Windows, viewer programs opened by rendering with ``view=True`` or the :meth:`~.Graph.view`-method might lock the (PDF, PNG, etc.) file for as long as the viewer is open (blocking re-rendering it with a ``Permission denied`` error). You can use the :func:`~tempfile.mktemp` function from the stdlib :mod:`tempfile` module to render to a different file for each invocation to avoid needing to close the viewer window each time within such an incremental workflow (and also preserve its intermediate steps): .. code:: python >>> import tempfile >>> g = Graph() >>> g.node('spam') >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP 'C:\\Users\\User\\AppData\\Local\\Temp\\tmp3aoie8d0.gv.pdf' >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP 'C:\\Users\\User\\AppData\\Local\\Temp\\tmphh4ig7a_.gv.pdf' Other options are viewers that `support live updates`_ or using the Jupyter `notebook `_ or `Qt Console `_ to display the current version of the rendered graph in repeated add/render/view cycles. .. _pip: https://pip.readthedocs.io .. _virtualenv: https://virtualenv.pypa.io .. _Graphviz: https://www.graphviz.org .. _download page: https://www.graphviz.org/download/ .. _DOT: https://www.graphviz.org/doc/info/lang.html .. _output file format: https://www.graphviz.org/doc/info/output.html .. _appearance: https://www.graphviz.org/doc/info/attrs.html .. _HTML-like labels: https://graphviz.gitlab.io/_pages/doc/info/shapes.html#html .. _Jupyter notebook: https://jupyter.org .. _notebook.ipynb: https://github.com/xflr6/graphviz/blob/master/examples/notebook.ipynb .. _nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb .. _Jupyter Qt Console: https://qtconsole.readthedocs.io .. _spyderconsole: https://pythonhosted.org/spyder/ipythonconsole.html .. _Spyder IDE: https://github.com/spyder-ide/spyder .. _support live updates: https://superuser.com/questions/599442/pdf-viewer-that-handles-live-updating-of-pdf-doesnt-lock-the-file graphviz-0.8.4/docs/pet-shop.png0000666000000000000000000000346113316251122015254 0ustar rootrootPNG  IHDR;i~*bKGDIDATxMh[w23 ]ⲕv!(TЅ"T7FK5.JpU "(.. j]hBI|wq;Id=3s9ofU!"cl%0*8,I0&˜$ c8,I0&˜$ c8,I0&˜$ c8,I0&$be 8,Mׯ_Dgg'.\/_]+033ĶmpI{ʘV<$W(ؿ?B6 fcy4 Dϟcxx}}}w.s4.|wif>ԩSغu+nܸE+-oaaя֙T*Ec/--ѡCHUU4'K-b[5h4a!"f IQ ]IQ:x xr4j72,6,N~!MUUܼyׯ_/pd@Dx ݋~<|us(ADDe2Md޶T> 8NqR~TH=eY1pѻs{. %2HUURoN۷w0(L_qhbb.|:m@^`D8d۶*""0H$4ͲadY{b pUXc+1ޗ(*m޼^J?k]ai8{߰q>"b1@D*χj?*>Hpp`'NJbF=Ak%^4b`Ku4N8Ao߾y=F(Q,&<ds5PR[\<T j~Wʳmm((#`ΝB8|04Og=wJUmd2nPCCCx^~#GpPaǷbS8pKKKE41\t ===>W6ñv=ѣGݐtttŋ8{,ls_uww7B?6+cibnno>\r###T4KX^^vDZk.+bpX y?+fl-8,I0&˜$ c8,I0&˜$ c8,I0&˜$ c8,I0&IE0WJv&IENDB`graphviz-0.8.4/docs/requirements.txt0000666000000000000000000000000013316251122016255 0ustar rootrootgraphviz-0.8.4/docs/round-table.png0000666000000000000000000003546013316251122015735 0ustar rootrootPNG  IHDRcbKGD IDATx{Two \pQ** T"jEe{9=}g=}}nZ[[]iXE[PV$@-&!pH2gg&"!B; BB!P@!nB@Zh4h4hiiA[[Z[[u:48nnn\\\WWWH$H$xzz2B :UUUDUUP[[ BRZBVCv6X7xyy&M”)S0ydbDԋ܌7o ***PQQ\*tuu?\]]OOO~G H$~~vvv0AR05477ojPThnnFASS_Bb1 "$$9s&܆%X BPXX\᧟~O?*+MP J>>>D/EcP(娬DEEnOwHR̜9fœ9s0888MT 2 c駟(,,D{{;Ə9s`֬Y AXXfΜ@/Jף%%%(..[NR쌈DEE!::9sa2&P@`.\@ff&233T*#::L>]pmc ?3rssǵkנh%K ..K,YQ BISS;ٳP*%Kxb,]f͂.^"ddd 33/^D]]|}}j*d2\ BHQ@TWW8q.\H8d2a٣4PcqΟ?SNŋC\\z!իWcڵXr%]/Z'NӧԄ+WGEbb"ƍ't(T bWѣG ɰi&^18s >S9sx#""B@ zNݻq%DEEa֭xG0a#VhhhÇ~cٲex嗱zj:CHj)BHNNFhh(֭[###غu+#Ȅ s!//Ν3d2_1 BLddd ::6mߏb8qqqqBF(>>| nܸh<裸{qEC#P@sd2-[___O?EhhСA6{l|ͅD"%Ka(JC#fP@̛77oqi b8wN>ɓ'@t:abb"tR"lժU(((໫رQ,B*@,V#++ ă>(tH?~?8.]/BD IGffMv®]cJ% ]VP$!!U"tH 2&Gmm-~̛7oH!>ϟ8j۶m?Z636n8"GEEŋ(//s='t8N11>k+W jJn不#**=TVV"00p=y$֮]kt_`i&//{/b˖-BCȰ2ܾ}>a`7->c~PW_}T+WOVc߾}C`"##/jjjaESx ؼy`1(J۷7ovnzɓ'!vZTVV{y]">j* 2 uVs-j۶mî]{nTC\۶mc3=b5K.[lAdd$za'!62FT*6n8_|0nS+))aw8L&3yVVc1\$~Ta̓Y~~>c{2sseee|>s2(vBm v#\vmPbjkk-t 3pSLZ}uV $$7}ɓXxqmۆ6;.{XgO)իW1|Ab dQ 3bbb JW_ oBDȘсy!66:ASZZ gggHn[ۂw(**B^^b2lS#G[ V/jtxS,Tx2DFF֭[!SO Ҁ>|XrQPZZLZ7}^y|gjA cO?z [lo-t8rAoq]믿RqOo&oߎݻw:BA 1mxgqF6D رcRRR~AԋQ@ƼO=駟bٲeBDpY<> ˗/8"BEȘrJ{+3Ν;BEIee%x Z /ש8 T ѣGqa!$$;wF:42DT*?b̙p>|Ǐ:4Blb Dkk+}v؁m۶K P*@$_?GGGC#ĦP@uuu{6m/PC#P\\wy$K:4Bl}}]aѢExꩧn:`j5K:t=f͚_|?8F!V8{,:cǎ裏bprr8BmmmHKKqI㡇“O>˗ IZ_ҥKpqqU ɰzj^aԩS8y$Ξ=6,Y7o#<D"t8T 2@JN©SSLL /_%K`…pqq:QE˸p.\`ʕ|-thT 2ڐg"##7n܀,XKbС(ոz*pE\r]]];w. ..N2@ dŋDFF1ydDEE!::QQQ 3kc c rEEEz*rssqUTWWsA\\.]ŋ= BT 24 ]f+--c nnn9s&f͚3g",, 3f@PPШ;EjQQQR㧟~͛7qMhZ!$$| WWWC'd̠555᧟~BQQpQARA!J?Wz֢uuusJ%*** QYY ֯_XapsstY@ 0ưw^˘5k< ܺu rrJ]]]4oooA"nnnpuuD"X̏{{{@gg't:iZ F?j\Qb>>> \iӦ֭[شi~g;Մ*B3<3g^o^c@Th4PhjjVFASS;zycc#H$2 w|OOOoooרUصkv L{Ǫq !C Bt lݺ8x >Cŋ㏣ ǚ5k1~͑h4lݺ Xf |q/FAA~@&!)) ---BEȘD- llڴ j}~aCIGEX`!2P !äӟh"̘1T`Æ (,,T*}݇7|BEȘA- Rl޼ׯ_`wI)c?_8tO.tXzԂ@baϞ=DWW^;vPq"/"rssֆ۷O@ d( d2ر/"0k,۷#)) P*BEȨE}qhQwHB 2 /^/;+;$!CZ$\EJ={PaB! Ԃ@uvv3}T 6C2Ȩ0oS1{RwHBZىW瞣@@"VDDD?:,BF,*#BkbǎxMmHXX}vW:$BZy!PUU=V[bڵ}ج8 >>>o߆H$[o%@ZM|2_l ">>>8x R#...]pw2TBP * 6l=ʹ?"ѸSL1/_chjj8ZBZo:sEqq1u_$#awy!//h]wpp[( *M8pznbԩS 2BW^^|A(J7V:t{1"#b +++;ى;w 99y"dh:t lq uV !ƨ111(**2jn5eggcɒ%!+==+V@OiʂX,1F-DPӟp۸8444 Sd .J^to1 QbD0ϟostt䏸چ#4BRputtqخ.EffpFYtfBCCCA,C׃1pd2<X` W\ӧBD"wkE0~x"&c#Z^FNC[[Z[[M>Q7fsvvƸqydo! 0qDP*P*sjjjT*QWW:hhh7W;::B"nnnF+F:3vrr2@ Ϝ*ã S|,sE תaZ[[%3V_H$tjioooL~~~,}u (JTWWCP`/WruuZ[[1eL<|H$pvvV@Spww7^O-2\>hooGKKKMMMh4/JFAGGG7(7p{yyaĉ1>>>:b ]+** !qΝ;P*Fï≠jð2P(%*n L2RȀ( TVVB.ۨsDMM  qwwٜ`?Cswwk,@SSSuuuP*hooL4 U% c@h4(--5*Gee%a'Nȯ,N[5 ը2jQ(;w#q!((/R)R)N` TDH555(++sW TVVod ???">'TWWwk Q{yy剠 bԩ1c$K47p"44SNH1 ^[n~: QQQ.D"Hn_Zpp0Rsю_sܹs1o<̛7aaa{a|q?'''̘1è 򆿿[\oc bAAA|;w.1mڴCs6] ڵk "h4b_FN .TVVIƍΆ[1w\DDD <<sufr \QVV.cΜ9|q/%Z[[ \~D"9sy!22χС[dSBYYrrrpdgg#??:s̡"nݺettrz̘1111#22IGG򐓓dgg֭[ôia3uwFF6Caa! PWW̟? ,@ll,bbb0}tC V z!-- .]BNN#&&E@@!gEVV_ QQQXp!xbm%FK.!-- ?jIDAT???<e!|WވŋpZ@矑4dddSNŋ }ܹ fdT˗q5B||͠HKKCJJ RSSЀ$$$`Ŋ 1pmoӧD$$$KRǑ 8::bXf "!z=]4;v 8q"˗uyV ?_ V?0֭[ɓ',ZZZѣo҂8lٲ#v=z1.]WWW$%%aƍ'ZK/16n8OLb*0{{{vZ?Vrrrؚ5k2e {뭷؝;wQ~`7ofNNNlW^a555V fo2777v5cBHt:~Z]vM谺)--eׯg"w}㬳S3jkko&M\\\ث4 ^;{뭷Xsssn;wd;w:  KNNf2LPHX&[_/q9ۙZ:$ob1={6;~!Ym4b ya4jiia.b^^^O?z^ rJ&ً/jkkbIII KJJbLR1ӳ&X|޽ݻwP[~ P-1v=\nqBavNOO6 'e{8r>wn&J%$$0GG>! }1X֯_oS*jЦ;ޭnpҥK,((M>ݼya-~Seeeۛ-_VxK;!Nͽ>XMe#@PTfP.SRR^.3[ ^goczZ-Z%''3Vۧ~ΎokCrOwkh8rhQ__-Z&O~ÙXXXgCdq+^~~~ Ws^ 2LT*KJJI od,==}JŒKJJNt!s͘܎R,}-;wH")))>}^pCjjM&fy;űw^d wa &H$bƍc7ndNb=?2{{{k0Bt+LT*w^~;wۅiܶ#ɺ[oMΚ4 YKۻ)!򂵹w3Xזe˖c}7әFR /yVV7qJg#R(L&s[I&$>fÍњpKV;w4zYk>#3BtGyNtsN ;w`zݍ۸U*#V!lٲ2^\`ppp`;{gم XWWx]]],""m߾}cl!WZ5 Mtnl=d|HÝ=}=}7{mJbSLxۧμؾ}<())1%99opϭ=mb8 +Kip;{ oz2?Sv>3kϒk6jnc>_4^Ř $V!TUU1X222z\`pttd/{WngΜaLT pploihfee#3v0 kRܽϚ\mkk}6i$ݾen e{5_O P(Ν;L&3ژ +ScχΣpGEmzzzasmciI_s؆P{f0r)--eO[ħOfF}8\lFaVّ7FcZV,o"Fc VM=RRRba6nI||;>"""^>\a޽{-^4XN_s`'kc ӷf~=W06kkvܹnu[7o26ϗp~\rO+`nmz}otN0++rGCy[3$$nrvzzū--?w>ҴHhB bovv{pR)۵k{Yhh0,IJ`Mܶ]ҟ/MDZ6p4`@Ϳw[O6wc8LsaXyyy~gPo\^Oaћp;/nx΋}ӍtM{\xoӰ\ۚȚ3/C͟!tĴ@cn/^df7zS=)ooo?7WJKKM- Zp)L,m;kmc>w1}?2ŝ'4mGC6h\A6XJbsa=UÛL$1777OtwEܺu+w]7/n{Fئ5ܶcz;))|di Oי=a[2y/盛Psb… f߷?3ۛݸqcȂ/-))gp1%qn۸{5r~IJJ6\Õ0\KMY`ͼ]`y<;/s6wb~~ū-gw܆?XFa˖-c3f`MMMVcX 8::׳:nCC2e [f kiihN\av\ wikn\sñ&Ns2wl%Õ{n{n kK򘷷7{-#b1L+Wȑ#Xb!6_EBBp%̘1êt:z)Z H$}oYY-Z ?~~~~ 2Llܸ˗/ѣGaooov8;Kpttɓ'n:Z *Z[[,`BH9rtɱ8:t6msq|2j5Νcǎyڊ2 =+3'a8pswwgR8p!(**bVb"رCk֭[o_5!DGaR?>|تq, z'pM\[lADDN>=H5 !3 << x"XL{Aff&4 裏_~,&Bƺo˗7nj\ ޽{QXX3f`X`8@&.\~;"33Gnn.,Y"thŋ~ѣGq5̞=>(.]$th ---ؿ?j*xyyʕ+Oo\{1&L^zscBFJ{=6k,w}СC͖t:石X>~BѠ ӓ9;;^ ֪ŁG-#'|'Nд\ pz=Ν;/hllDll,~a$&&"((h0fCȨ܌SN!%%ONҥKalذnnnB8(p|嗸pzjb„ 8q"&L@MC hhh@MM  P(PSS_]] Vˏd6sO2b[Q\۷oɓ'󃿿????>WЍc hhh@}}=J%QSS;w𹣪 J:wfs;;*V#j(J9rԠ۸\`X4>wssD"!H wwwxxx+ۛjhZ FF tttMŅO\B5Wč =`pGvF;qtt#La~0dQ^Z&Rjd6Go 3:3c$POP*JYWWgvf_tqqw=pH$ppp3ƍX 777Dn}c-},u:4q4QjсvkjjBWWqk4j-i#12"477םsn|!?ۿ;'''8:: 1}n7n7}܌Nj|!JBss34M9ͭe/ì?z掦ۙjZ~2Z[[m#q+28EiIK$0yzz-(GEt9!ݵmmh4Z ^ommmF;_nmΞSQftG\K7H$Fyg|ZY|!HL+B!P9F!n@ BH7T B!1B!&pi5IENDB`graphviz-0.8.4/docs/_static/0000755000000000000000000000000013316607326014440 5ustar rootrootgraphviz-0.8.4/docs/_static/angles.svg0000666000000000000000000002540113316251122016425 0ustar rootroot G cluster_1 Linear Angle Variations (white to black gradient) cluster_2 Radial Angle Variations (white to black gradient) n9 n9:360 n8 n8:315 n7 n7:270 n6 n6:225 n5 n5:180 n14 n14:180 n5->n14 n4 n4:135 n3 n3:90 n2 n2:45 n1 n1:0 n18 n18:360 n17 n17:315 n16 n16:270 n15 n15:225 n13 n13:135 n12 n12:90 n11 n11:45 n10 n10:0 graphviz-0.8.4/docs/_static/btree.svg0000666000000000000000000002110213316251122016247 0ustar rootroot g node0 G node1 E node0:f0->node1:f1 node4 R node0:f2->node4:f1 node2 B node1:f0->node2:f1 node3 F node1:f2->node3:f1 node7 A node2:f0->node7:f1 node8 C node2:f2->node8:f1 node5 H node4:f0->node5:f1 node6 Y node4:f2->node6:f1 graphviz-0.8.4/docs/_static/cluster.svg0000666000000000000000000002031213316251122016631 0ustar rootroot G cluster_0 process #1 cluster_1 process #2 a0 a0 a1 a1 a0->a1 a2 a2 a1->a2 b3 b3 a1->b3 a3 a3 a2->a3 a3->a0 end end a3->end b0 b0 b1 b1 b0->b1 b2 b2 b1->b2 b2->a3 b2->b3 b3->end start start start->a0 start->b0 graphviz-0.8.4/docs/_static/cluster_edge.svg0000666000000000000000000001401613316251122017621 0ustar rootroot G cluster0 cluster1 a a b b a->b c c a->c d d b->d f f b->f c->d e e c->e g g c->g d->e h h d->h e->g e->f graphviz-0.8.4/docs/_static/diamond.svg0000666000000000000000000000152213316251122016565 0ustar rootroot %3 diamond <> graphviz-0.8.4/docs/_static/er.svg0000666000000000000000000001730313316251122015564 0ustar rootroot ER Entity Relation Diagram drawn by NEATO course course C-I C-I course--C-I n institute institute name1 name institute--name1 S-I S-I institute--S-I 1 student student name2 name student--name2 grade grade student--grade number number student--number S-C S-C student--S-C m name0 name name0--course code code code--course C-I--institute 1 S-C--course n S-I--student n graphviz-0.8.4/docs/_static/fdpclust.svg0000666000000000000000000001031013316251122016771 0ustar rootroot G clusterA clusterC clusterB e e e--__0:clusterB a a b b a--b C C D D C--D d d d--D f f d--f __1:clusterC--__2:clusterB graphviz-0.8.4/docs/_static/fsm.svg0000666000000000000000000002354413316251122015747 0ustar rootroot finite_state_machine LR_0 LR_0 LR_2 LR_2 LR_0->LR_2 SS(B) LR_1 LR_1 LR_0->LR_1 SS(S) LR_3 LR_3 LR_4 LR_4 LR_8 LR_8 LR_6 LR_6 LR_8->LR_6 S(b) LR_5 LR_5 LR_8->LR_5 S(a) LR_2->LR_4 S(A) LR_2->LR_6 SS(b) LR_2->LR_5 SS(a) LR_1->LR_3 S($end) LR_6->LR_6 S(b) LR_6->LR_5 S(a) LR_5->LR_5 S(a) LR_7 LR_7 LR_5->LR_7 S(b) LR_7->LR_8 S(b) LR_7->LR_5 S(a) graphviz-0.8.4/docs/_static/g_c_n.svg0000666000000000000000000000375113316251122016225 0ustar rootroot G agraph cluster1 acluster anode anode graphviz-0.8.4/docs/_static/hello.svg0000666000000000000000000000266513316251122016266 0ustar rootroot G Hello Hello World World Hello->World graphviz-0.8.4/docs/_static/holy-grenade.svg0000666000000000000000000000464213316251122017536 0ustar rootroot the holy hand grenade 1 1 2 2 1->2 3 3 2->3 lob lob 3->lob graphviz-0.8.4/docs/_static/html_table.svg0000666000000000000000000000261513316251122017271 0ustar rootroot html_table tab left right graphviz-0.8.4/docs/_static/ni.svg0000666000000000000000000001200113316251122015552 0ustar rootroot ni 1 Ni! 2 Ni! 1--2 3 Ni! 2--3 4 Ni! 3--4 5 Ni! 4--5 graphviz-0.8.4/docs/_static/pet-shop.svg0000666000000000000000000000250513316251122016713 0ustar rootroot pet-shop parrot parrot dead dead parrot->dead graphviz-0.8.4/docs/_static/process.svg0000666000000000000000000001371413316251122016636 0ustar rootroot G run run intr intr run--intr kernel kernel run--kernel runbl runbl intr--runbl runbl--run zombie zombie kernel--zombie sleep sleep kernel--sleep runmem runmem kernel--runmem sleep--runmem swap swap sleep--swap runswap runswap swap--runswap runswap--runmem new new runswap--new new--runmem graphviz-0.8.4/docs/_static/qtconsole-source.png0000666000000000000000000007140713316251122020455 0ustar rootrootPNG  IHDR B,5bKGD pHYs  tIME  44I+iTXtCommentCreated with GIMPd.e IDATxy[u$i;i+V\B-I܂t@ K.UnâM.e"P*\Ԁ/ E$U| T$t_Z-Lq|ٲҾi'g~^gcw88`Wfhݰ{0>k]v^x$ֿauT$ sEHRIX,sVQT߫#^猇.3'f_Vq&N֓.Q| V&ݪI[iBv>5_Y=9Gn{Tw5ǣ='^77~ύ{>~Sqx^0z+4o_1h]]]xG}v8jTlkkߏ+uǮnikkoYK^x0?S15FLpx\CB=p.JZe()縤>qF;w |? Yehc9b&S3Qh7 *;r7Ǎ851;!7 RIP,Q,(z(Jx<EfŦnh5^mFÉ&zXGGci% d5Q'R౏c0Vս9m=W`'~kul='c7(%Iŋ+,bCCCqq?lXࠩ|owcfy_L.{!H"Ceaa*ϧH/"D&,_oݍo?@w47D Ґj j*HKf |MVtW=֍B3t|Eu '.ŭ1Bʿय़DqK~K,n.ZtMmo/އ3_LUF!n,y3U $)D-BGUD;G5 z&`d}p*LfSr}0Ɠfllr`JȆl?w Nwp V<ߏ\n= oΞ!_[z3Ok8Vaժy^T]c}a[g.]%'TxpGaUtn#؆'.ªUZ_[s!|kF~8%ࡳe 7+;8 EJi{NFkgBY 7Zfk(ͼonҒq>o4Qn67P|SivڣFÅq '7RD)'y V~bn/^&}Z :<^<^/gu8b^/|ЪLd5*SQӫȾ3pK5߮_v:?ڎ݊[} _vNuE**3-p%Q^yx8i[q%m)Z^5e{VGuSU[&,z_p͉Ӏ}X^}"r:ߝ{>Ӱ jvýՉ4D8 mxzOc4UQJYgGn.G l7ǜ?ʹ2b_mWTD,UpUyӷ= ^__{~!A_Fq#x$6O%W_[?Pma-JPسZUEīqS\mc꺷Ykh~EH 5?f7k1VK@9 5p /#Τ7TvFLMfjiie\L\ŹU2kㅇy*ާR,q܉QO>8SZ|8OyWQlrIZt#wW[8eZ*c:è]倇{RX]`-)er,B-%ZRTB5K$}!}'Ni8ˁ{v v8 _Y b}.r_8Txޮ8{\Ξa?O5lO"s-L8Nc%g߀LW/7n#9t,*mpq܃X3?Wb\j8'-Z4r"^ċ׾(l5V`v+-YcWd)[(QԍiUj-"z5~Znv~-Lʃ('MS&CɌƵG _vU1҂ &cVcӏi4{/yڐYZ|Z0nqUVsK,cZ7i,6|i<+)AR{5||^F 8,&"\ Opb)@Qp |JAjVO|{kpIW1]S51ypU9ß{pn;Tr ^ 61{8*n.Ts[ &K$I#0 XL3e >M•S>ío^/;$Iӭ oˏRI9bhh{,7ƅ]jYבՂѵt7":V(u7NZOe}F֢aQwZ-N2۱ɬ^g6L$4`'*YNp2Ɵhu] ƍVL:|𡥕X6ʪ>_ |p ˷fmiik_x<L|G)T{3՚/0slqd< Ift{ɘ2@]Zye|e| kF>>p ?6黂.}8ig7=ދ; Y͒Izyt%pLҔq^W7]}r])rDˋNM*VY8W #$%'ۺB|g'yG(V1:DRaދ7[0y8i͸w[-qҩ1Yԭ>%Mq5s@:_0O+T!w |LI?xt-|?3%E3ͺ&:Yo7i.Eqڂڏ{}CdiCSmZӨ*fyj/{377ֹVE&V}~UÇe7|Gy$2kquC&`h77~|1{s=Z ϧ'ޯ/P׹߸xZ[:q2Z&MFĉ7qZ'NBI7yZ'MF˄Ih8 -uL ߤ7q"Z\|'7i2Z'MoLh(7yOI?u*&wc?}.U!0uD<۱CLf]S_#kGü݌} .tˡ_y^5? hHԶ;b?Ò9GhogŒzy Pu8[Y$\wOKB1(&&o?^[, 8$,7q?{'b3H{ 8G v른(.ҜdJ iI**H/(|?x9b\@Ι%I%&/}p27R\y W ZEZD*Bލ`}b#>҇ jS-4[1n6ؠZ2v֬jY56Zm3jWW3/".r,[ |!&L!W;7ko#?\s8`\+&j:>5de׬ڄ&Ӻū@$%s <_!S+w˻<4^W^4 %bCEe,@$K2(~7?30gv* ZZ|`̋C:?2͊ī^E8K,t1;pxb ]UĂ ǷqLe$Y Ή]^ TPUϙYIƍ:YD1EVk9u7SNVA_>|DNAtsV; myim%y}Nf{; -*VcdkPpc0t2IH(ZWgPgkec23*Z1{θMUlP=d%P5ή7Z,ִ݀}8Q'!JV&47Rcw-Ew%+u#nv+ 7X]Jc גʵٖf똺hgvzJ_mwX S_5XI?VMpUܵQ7Fv&2[*YI&m%Rű:INb׼h5Ϊ7KZZ Ϫ3%k>INK^7Cu>fўGvmոq+Dn,VSƏQ(cNmFq٘X/ګVy.9Nf8rNUjxf̓,(FZU 7vcZajev]ffRURQxŨ+!jw΍;uXV5VZ&Fjzݤ<GPKcq[mnqyqqr١O FlvԸթq(<9' ]< a$F J򸛏hڑu}DvuzV4+Al箓p6 A2(}lMSSkū(oQYu&2NfXY;vs\o(3sd JjV8dӤ",6a&HVԉJV|V;yƃdmgu"8A]= IDAThxiUQZ?H1`ϼw[WA+V [ N73Lm-$F`^W3ŵ(-%  i|! i+&5IIAA4 _P1ihD1EAA4r r R  9-3U!HK%'  Yy K^ q.__s9/<̧[³lVp*q/>Š3SX<{ՁWGO>-9o}i>tyq֏8/{Cb:]wG/n8AAeoCZ,'?.|J&ώo(I$q4o?'eǧp?D!rj+ro%سqIf,;m]<{qx.ҽq;3ŭx|5*77s:}8o~q PN&Bkπ3CD csO}} G;'?53j ɳp/w.|eqqv*\+0]w:Ph  ?)/R7!Ľ4760u&θUl{CG.ZSYU_۸fvzÛfByܬ <G:蠃:p]c]8RW{b.tm1oP x䌃pzŋu|M‰7_pm2f_ \_=Rv1> `3o.Ɠwn!u '\\b<ճw۬I~G a# ߧ-Ba ΍) .jNuQ_xjˠ<`b!%  fwً>AAİ R}E  b)uAA#AE= R  b{BJAA4 IP*C=^^)AAQ=餓xz] R9{AZH" W#${Bɺ/$+$B3cQjz⿹# Sz^{?~<"(eiԣYW=,##a l20r7B\ 8]!g|G<7j2R{,ks0$.d@Lj hĜ9spgN@2: iUcӬ}FKT2XdT Z>YIze-uX#!2Hw(=l&bbe72٘fM#b+p-hee?eK[XF7;*=S,7t8=3@HT941,VLg9)~4ZB &pM(LAAT*}\tEXp!N9̝;z*$Ir&5"ڀнêD_Y{N(7tx$ҹe ^G<6Uٟȗ-m1$ҝA3 WZ?M kѹ -"pks@*$?G.a,g=XP %thhCCCػwzXͶW5EB`TH2hVd7̭}:O;3}QؔS&gX G곖{2lzA,41A]ą$S|=J!ޥHkҝXԩ Jji FqA,nŬ=e[ B} 1,핯 ^ ífKYskh)5|.' bt R u]6lmmm|KV$|D2CDD^y#xMG&Ϙy G x$ '_'s{kvg;\إ3w ~4ڻAA|;w]tݻcϞ=;vi;okk}}}wg===͛ '_F*l"пtTNX)$RMDЅ.5AA bΝ|hmm3ݒ^/:00 s>g} NMC\c1Q[4>B.1j(@"yt;ݏs%  t"deZDzONIJN+H{8x(\ <AAomۆw}TdYHNv|SݫPmnOAAVl۶ 't: 000I89זڽ{^=.N$AAAرsNMʢS%p㣏P*P$%|<1:e2z-;JWl)%AJAATj$Iw EXDI*ɂH%tq|˞15'  ;Q*I\bbQ=JRyc#j=YH  Az|>m@ysh=d_IcS9⨺ԥ;7yc`5d6]>ġ^($ЕF6^exO^U;M'ͬ܆UaU,$h@^,A.QD  B20߬zSw_S[?pF0(hy,uM_k:r#DT iKK e3 y8UI#=E>Q1eH đ BȀg" PBmE//c MAcD@ IUd4;{'GeA&異Wo;~}ޯ]wH-ʍxDd@?2O|8m2\qߜꯪg[?{6_e y>?LgZE._{ LD_gApKH0ZZZd4si, u Z[B K!$*"_l)gn:,ڭs^ǹDW:\he{#A)DM[΁dARZMc#6{;߇ȲtZ@Vp>$V /MouӴ{`E$Dj9 Itc–-VZɂ`Iq_ *zNXV֤)ec}C=_Cpi}ɑv)$э.~cYp&˺NSwP?WԟuV}^&e1w"PWCD˂mjji-cHפ?Jk5DzH-߂XR4y!$A[<¬ZXSr˦fH4 4rCæ\by -"/)##Gd : c!ٍTna58@QλgPHgar{a; T ]Zt' ]GgE0Ʋ<A.Qdս0}-o|;#8ٻ= ?ՖOmm7C,tM7{,p\(7)K:CVS|8oϾT>H]\\ap4)߸mrBzev Ե0Er"^ZUɔoi";c0L{}!9G3^UnT HkZ#~Y|:Iv!48¯`^z/abɺл}BcMcêD_Y)jw ԗ;-m+1O`Oz! ˚4T-׽0d b]>rOGTb; fsP ..AzfW g>}lj#5fUTС*׷0j\mczw.]GrhjT-.Ƙ;_mEs h0Yx:#Kp1"ZE&c2nhmXB2Q{M?KȰ>]inA+ #͵#^?ZsQ-j:D]P>lҷH= 3 TZvTY G6dRJji67[=p_p u2S !UQ PDzH@lb՘Zi:m*Yt'M[c#_Mn[TK0fO\~sA-B$ea >ݕ=r VB?B\j,QO:o~UZ`->t̆ Fkæ\YG/!~EtV&nVoO_9zGoןQ8~_6Qg^VP^_7lwHDp 3T7~|$ϯ(~~Pu#'lH>l~p&7{WBx.4yƋGdJ<ۖ!&:KWY99.2$U!oX??_WwS}> wM40+NCnUSX|kYv(Woc[ ׫9aˆ]i^?Uģjt9\_uǯUQ~,w}7|y.;_//߰~s=_zi;;C;  8ֆNX=M3s>Iol'F>*[>fŰzq}9 Ҁk mʕ+dmRԴ{wj Lq-ϡo%oQז3H /$*8cB\dL˦!⯻f# AױX"ùA}bL.8xB,Hؗh!)(}6™,xkuK^!c$$la-|< 88(AA֭[ҍ7s;b  ylذA^T*sI(f  aA/JPtAA#&H0>AAA@H@'HfmZmKk(;]c6qz=~fhIkNXOsowA56 +J]wypΑ5+0^ǓҚ%}D>NZ7E(_7.<19GoeM Q,]H"`j@ɀr-jn0؃ݤuH"Az+G;_t;,֦;-P>zPs)X,aԐ>N ׍a?Vyʟc-&h2_MRC{ #\.n@zo5.Iߦů,0ܔ+1-o!XUDzH#dce9q |AuΗr>I;L?!dtij=;!<A.ށtX{^wd dwS'8'ЭV|1d9`]FQk8ş}ECB!Z]_!Lg94.~7}XlOHO]Ŀ{8x>_ecO\?Y%Q뭟mZXWia7Bsn7C(EWW_d 'y[[_߹x$c~-LFOk~\>G!W'/oL E-J7+'}FKQC8şS1{$N-Uex)y]t]?m}jzD8wz?nꯦůSYānW ~w?|Ϟ{.߸ /n?6;ﺓر?7{.?n؅ Z- þ~Xgӯ$==Cl*}V'5FU^N? ыOK˨G`& ^(᥆*x&݉Ac3هfc2rK۰b8* IDAT@/VQ֔vwz>1֏wNP ZjqT >5=/^^ q.Z8@ʟQ~uoЏ>V!xq/QL^z)Kxoom}>w]^K<ѻQ٥.5..7;unG#M$ďZ6 `Ò>N"HDvӟpk?O]C*l]ٖ?8t3Өmh]MM?HF"śհ:Om۠u_[`F7wm;A.ۿ_x1g\r K.e]|w#@ҊY@X->)$ªa]BDxO˖A V\%K([J(J$ {bb! bʔIȭ2R^x<K(\C՚ 0s9;noFC]#^aXH"4u\,AA$ר Mc~-刍r?F{ YN  jPL  ^/^/8 II.>K| Y  xjO˞(AAQ sA iӴs'NĤI,$H  Z$ ?IB裏+P5 AA v٫띚eCXH\H=G!skOQw+bꝎ8%nxhnIuE bڏFU&>Ge#~S9KdQ\t0rTN#Mĸ;v#ʜ9sp)`߯:pgu,`Oy_"/;S3 2 sˎ XBˠڵJ{H 4>P>2Q!- R峞7Zp`5e"@$#y9~V6ϻ/FXV_ˆeޗN;s瞄~8r(c fβ_60W ]RٵUw̭z+EBnD!t*j biwuʫ&зztɇš4:\܉Be XXa]oto:G _fp"&~υ,8dA5N鳿bŬ*;9_wdںeVAgx.wc#;!q,_n?uį#i<~qn&$?ܑį{^~ǏwJBZ kȋg"'Vi[oDzH#dcʢ\mzLUKPnk>3@H)Tj 1*[7;tn m=+[}*SIwbq@p1:k*Zsit] { !dtECB!l!gy ([2@dv`OrC6i")|}W_ ,ˑ O0eԨ gwj\>ϛ`(=HZ .ܕ/glO&} __Ņ cft][pB $^Z1)%>S׺Kwf`OEq$SnwceC.|>X$,,= c<+ZN]\o;㿐DZݺU:5rtsr2@G?b^KeTw55DO>Fw5;V{ʢ6~!h:'݇`_뿺q~haUO\ KC:M2lWk~>$Ikpƙgⳟ=vf4?L<Ͷ˾BڸYƖAk%1E'aj!J0Vu4WكHYqh =:BZJFFO?Ga4rTl Wor,Kdoeeذ:a.?:ѷ?АI?bT*ahhCyv{|h!ƐےOj+:ЇRuik!mXn%D_/6ji4_(wY}.M9@8:9X ZouldkfwҲD*i)wj=_NWge@wRo5f?!nq҆ W(~Iqj~j~Ô1$IE`0_6楿s32ppD2_<q 3T7~|$ϯ(~Tz1q!|&~y8d@65xnhLX9M~IdʼHDC]δ)Es\.~Ɵo|oYvlӧ9V?Ǿ;'6W#~76|Mj/-ƿ'~w?|Ϟ{.߸ /n?6;ﺓر?i~ꩧN;`09F+p/#taM4E_:"KAlg~^Y?؄obpp+WĒ%K9G$vfڽg{((AL2 /S[q9w܁;cH!et(\kpAivOꤚQFROISO4`'bcr(Y(FS^AAp"I<~  BEԟAAHRI됒(%  Sxh(AA1Tա>U(%  FBzDuJAA)He'AAHRI)AAA XD)AA1ܢT$JAA1bh]d!%  ݲO=AA1CB   1 1˞  94 )R  b$(AA#cLҤ&  b$ )AA1bs^eO   |@\JAAÅ[1] GՆ{Gq$ FOw#X-2pZףJ#$J ƾT $.A⒣(K$s֕>Qur>5˽ܥ~rVF dfG{l"EB?qbAciӦa` x}:y<xLG~GMg~gy k}{n-w(qsYrQwD=Ǣ,273470#8> |d7={]r寶W'  Gvsc[tݾD -g6x%! tH,lqL;-XJϩy c7CL~ ئr~$fE_HdK&@>  gL]Ac*keQ; C`f1erËz9S¯<Cj.(x2D׵u-wǵ~$rc`Uu "$B0ѡ?G6GqX$5Ku?kndJJ1ԧ>3f1ιnz1S7٬Y87pZ؈ecY@o bN uDtys oΝ;jOm|?яp7@cf7\NmeK~ayP 4B* ['|y'bYM͖{" e|@{ X-O3ۅƌccZ  $Jce 1  mAAhB[(AA1HAA#JC%  ) Q  bD)@3  G$IuAA#&JBJAA1yR  ).{  n.{  )|=AA1*)AAAeOAA(eOAAAJAA#0> S  b8Ѷ   FJ4  aQJ{On bTnhot93WB{,WA2`WU4%Ɣ#E42GoT#c-F䫀Bά+3gs~J̈o4fQ8}zL>̙xzL6D` b_iFp~#67_X(FD3,I X(kdp^SrD!F9zcl9hDz#7B#޹ 9:|wvݺOC &_Y׻'Xys6BYuG] !]U3}L>ƕؔ"DrWQK`ttTޡZP:@ X:ꬃJWH"׫X #\.n_W z7j|=ZE%=3`veڵS ]ue\`3F SERCv봀븣]wWDcBimE\B+rZAHIH3s9|* _3 l2![A\jn>?m^R"W,F@@@B._4' n}_Qf}Xۢ :G +?HGrڢ > ]0DY{ ELҍ߯)K -t(Y2Z3#,߈o({.e2NsHVn}~e"]&4f_kJ&nDdDQXdf[Ҕhg Yai;Gn_(3x]S$ ?QaR-Mk8}5E:vtv(3Xg?cSnq{-򈳢6pgEmgicm&ʷ75zzzDKKhmmq^ܽ{WܺuKErMٳg ^?7;/wD==|`󐁁J@i#^FE*/Dىf/ap:eUD]DU!jTK4ZyYj'#@fK~<̤ռl<u'1O]9 ']RvDno߆7|}}e|zI LI$IAys/ 77:$Ir1ՙ!eQаنC `W Tn2$aQ*mW[b&v\ضvGIDAT]ZQ㸬콴9'as;qD0*W+H*7=nAOd eUC o<_e?W ~e\Ս#b4L/H?\ȳRoFAjU"""E) R""""b R""""߂cHh܊Q ҆ $#F吅Th4&`qJ!U#2V JPB`xi1Қ 4X񾀂lUX>װ 'Q!(oK\DDDDnTZW6PUWSVamT&N{5OWFI>.B4y4Hh?v65Y׋j]aLDDDDgIM>tT7OYj[3p^\%6 %jb2_UpsӠBFj j'< u-(K6ߔx ;$];=E̛yqJҎ%Rw R5WL3;U1(+o :) ƌ&P:t!3l90N5(FcYm/h9ȕX}>P`m}l߳phm93g̜<S˗Z ̙3ĢE#2g̜3'SAxbnZg?]z93sf̙25^|E8pqooȜ3s6ÇV. (g""w3^p؂=|?RK/tttqt}}}ؽ{7V\ 6ʕ+z qsk׮᷿-,_|&g""wC5݋;v8t?˗Ǝ;w^om3r~-[Μ?Dhh(5OyFdظq#Z[[>g""Ogs.\G.ʕ+O8%R;e^BHH3n kĉxΝ;ǜl͚5xl2dgg;Wm">>ܞ޽{HLLDZZ^}U̚5 Fg򗔔 -- SNŪU9y*o[ z̛7よQUUyNws/ƍP(۷EEE#`˗c…HLLDSSfΜɜ?D@@'zFii)֮] xWh̚5 NXވ\zVބhtu$p SOaA&Oŋ'O%˗/{ʓ&MBXX ,@WWH1 CiiDžrUر=ͨ1znԩO> }?8f̘F< KN سgJJJVL<qqqFE(\r&Mš5k2g""Z={6ŋ L,_a3u~i;wظq̹G}W^avv XjfϞ8҂uuuBEErrrp!PZZ !P\\۷L&Cii]wfDDJ?xp̗Hx,hoݺ3f@VVGw^tuuaϞ=Ç2g̜3+۷ __!$h$ͽJZz 999/Ho߾ ֭[0m4Z.̜3s&"n:}t<8t{<.Sa̙93g"@1cBC~cIӦM?ɜ3sfDDa=cYK.aѢEnEp%_N̜3s&"DFUΝ;3ϸ]WƮ]S̙93gLD|lÆ 3gP^^E~~>/^6+93g̜<$Iueː@ܼye| #;;-w*̙93gLD䉼u5kʕ+s4448vĜ3sfDDh L>hmm̙34^>sǜ3sfDD˰:}… ())A\\>7x駡Vq%ݻVsf̙9;!5gƌ8z(z-jH=̙3HMM$I}pr]̙93gLD4d2|}} p6oviӅmu>|>>>ҥK[߼yϟ?d2>|TlܸqBo̙93gLD.님ܻwO_ 22/!Ûo9p!}g:F;cŊiӦO?nBgg'BCCg혖,Yn)̙93gLDĂT&A&aӦM*3sf̙h R4''K,9s#>4{мW(|1>F[th־W4}״0&cGga?Ra> wݙZZai8R9w?~-;muZSLkjmak+kjHᮜ?Bʖ^[W#& ;s;)[ok?_8#[hcn&Žn?F+lBbuiN{>0{l#wmpzv5g$I[izLIENDB`graphviz-0.8.4/docs/_static/qtconsole.png0000666000000000000000000007641713316251122017165 0ustar rootrootPNG  IHDReؑbKGD pHYs  tIME .\%iTXtCommentCreated with GIMPd.e IDATxy[e?'LY@L2(KԲ.#ܛpK* nadM!T.h(KQ" RY89'y%š<>r%0ԁ(U+bx( <q=c}Xߌ1ӡ*@UUo;v~ʞ$1RdSUwT2*ƃ. ?Dd.Vy$K#[v|}NWW(|:%3A4Th'2&c[|/d:^] =YldYſea/ou__xb{Z[7g?ƿP(.OzbJ( @1:ͷQGo^D+D8ㅣ(0E("eb\y=!}zT*UYyEXkk{dX,b||ce(>x/[\CGJX,1"c#0亂T1>,RKe16xC޹-σJ* SYMQX,BH͢Ԫ+@!bDw ZK D&ΗY&ܪ'ut|U,X,Z~/{FT_u+ɿv5@o5S&tO۝sXzW5uȺ~ǫT+a*YιoucEw{NDik=h0n|0A4N$.{2&VjL$v͋y%lh X cj`dd+1ZX?###5kTӼR>ű1.< RG kVfXX N]Io]; (&.ˢ23U70mtEr-{_}4Rq >8tK.LeJˊ:Vډ5;$ƞVX^Qq[QZYZ_mV}#b1Vh;AF]큝jsE*{ S+!)kyec'Z6aAbw콪? E1%TVU˒??y_=,;Ja+k J]YBeBʝbVSKPǡ"Ϩ32q]a%@ekE`Ro\."Zm-k/HNMV&EǗsY{C)S[(e3LfY6eBesp8u/emwӄl^(!{رcGE{xښOۊRTBnd=&R}>Q P}8Oï1^:_(UQw뫼(eZƔW%J?}uU5%χ(OO;j( aoVr'.< lX0nzB;w-?Gp"_~bWa*]=ox$rط/R 7z75 XNfmǩʄ%JNK QopkmX܍ow%{HBHirʷvx,neduW;K6S6Yɪ+J"_&R܊R=a>1lڴ ?9MLMʼQ1coi&{6###Ư=>'|Rx6lͭӺ˓к} |J庯|c6F>v(0c) 0Kxe@I Pdڡ2JPPT(ŌYmN=ax|*< %򕓰{?_`wj$2PTVfXJy9.\{"Zrh.}y[qY/`qg^ Nv+aWG<suɟ|t[yޣE1wuX ' l~+qi?nǔ: K]nDW3(nVGմ&>ɖYDi-_6nLh 끬e+X;Z .ŪLH[= I_%rY|Iyk|d5@NSXyT-T8TzNjBZ)s3"~5&]e7*NxY('5Lz1(e `n]`tP(z/T}_D-t[ i !5++͏-|^|3< `˯/JR#5A/XQñ$/(9uyʾenQZj%H,.vƒjh׮"dqv< /P[% *_ϳVK8YC+ ^E:'gd2V;*'&Ij5#5WꝚweCN|oRY \y#Ch *Bxuv<7s|+o6¸+ʛE <0uj痗h:M`O-'$1O ,Y_M׫zw -c o}f/ •Xr4`!+V UW3@/f( ,pQ|xKQwQ|`Eew˦U[xxОڗk{[?,b߼ pw!pM _' ̰hn5κJfw ~mŃJs=ܣ];Fmً-ҟj?si,Ňp5?u2u' Ko|3U7VC/kN\q۪-FKOq+VɺN%kċ)}vۍg;8Oz 'O~Y7V2KZ*iyϻe@</^$ɍw/];ugOU*yT0)c ͜/7v[q/bɕ77_ފ-D)KbOY<2]^;K[N+oGЖes_tmTx슿ڻol)\XS'6?ꊣ~,~$hx(r* _Ǵ*7I>x=^xqʯi uGu@tk}|m̨2[ .;leS{'c"}C2<x@^BcWMz;JuۡR5 oiZ.p-{ਲ਼/b8@M~x {0ܷo#Y ]3ӁK{EH|I[{`@ep'@UG6c5Oν)O2wO}|p6>7O1[vl#;\;=y1*w꾗sԓl2T;'B $2-&pb!ASBӮ#[*c*sK&Nns5)?WB&Hq2n5T_ hݦ喉S%얰4 uCG4i5m t:1M+{M>BĪ֝ϴkDf8s:u|Q}'[>Pd NM(eT,V|jQ*]+[H}q:LUND61ͶeV[bND aN{v"pn3 k5oJ8p\Xi;>zSly.8f~nE>IVƊ5t,qBUfu\qg=|MSԟ㭯=#"nV^B_X4o?:!5.|b7,1 h3>ݎ0Zl!u/IF,Gv;lD>ꭣ壜ꁕҩNZY5ĩYQeVP;o/4^6Ɣ1iӦs4̞=)%Dpi:u`]wm P2 tLsL94^W6 _*ֵYαpK?yT@UJOy߻tĬc1EǴ1:5Qsx!<FFGV ]ILrnƛ7#ܐŘ ƀ &UEZ\؃ u֑8,]gYgtΚ,h, E&E?ן~Ջ]~, _v"4UUq Anf̜čoߌͿgOej<@J16CϏclxVRyFX|$߸ØȋM_B_Ηm辕ؒ- %+S2A+kUFEݶVOȉvcٷh(Lki3>e+6*?p&oO-3,~ڽ=!D|ɞcGz9 {v}wLeӱˮs4Le_~6@gG'>_5M<61itvsLt̘ӱˌ>3g`1gs t̜>30mttG9͘31 g7}ߌ6sv)el>aF7q!LUGQOwDxQ KlvEy \?nO>]%w/_p8^4a\zfyPi_Hs{.o9ȯ.ŅYh9]nY=~mI'>`v0r陨Tz>nUL .J#@,}㬻gÕoBIn9\q1/{#~r [eڠch$*?p6I_oYu!E+n3}~_?}tpS?ǍzDkհYtjkfm /a7]uO6mғgⓘ"&Zuت=s8fiU׼Uط˲rq>1"X,VAkVdz,VV mdvZZ2A#ݚegmۜZ'Uٍ eLd/[ΪGܵQ خd񭖓o޼y8b lݺkVvmL7`{wG4ǣ-TVڤ(Yi T1A\fv4lje!c+<@wɷaF]~YFEb|l{>oe'!1~UL-Kdxpw`R Eˑ`p'+'?*|ߺSrɺ@bvJM]P]pTsbtZZ|!D!Zde]v Bs*.kVV k~ڵ|"۴jٲj(>2ۢ0[lAgg'."ޮg=z5bTx>ضm6oIXwdU| /TURͨV@(+I_S_=ӥ)I\fw,qA 9v3yAW,`u3aOo]Ey˪uo'<,$ L|MU4ݞV)Nq K &թZUjQci/^ՖXuZl_&E*/n=᮸?/^Emx0<<*k۪WJRmeiY,nU9-%+;n&YfUn-癈vBֽ(;z^;/^6n'*cU8f NABeT2DK)o-l|^bTuϏ%uM+kl=ZŸ]ZS./{p~1*춸na/22a$<hվ8 gvĞmuM&0 +)SZJxZ UQ7Yv:-諵YŦˋR9qQ]7 ܌i-8YԳݸPQh(s*R+Lƥfx͎ղ䑓Нbb׫ZZڎpݲתD;DSY[ȍIؽ;czhe)ߎɶ,e8IJ& +V~"sOnVI`2+,ιyX61pz'ݴNڕ)_T|iЅhbV ;F^nSMVxQh1:@wcywjZ) '}$vƅM%U;4kߍt3̥bS^ωۑÊKE*+z[* a;䟵UVmw޺X{+|62+8^]'B7fӗlQw?`E)۩ HQ]5Il5^nl]coiQZ>qn& 5vKEH%a:SNiiN*Nm׈8ubVcNߢUwK&u$ IDAToK*n]X%UVᔗn>TܖZڽzzvks}(e+Sl=1.NnpZ`)vc)Lj*-LxF[bEƌ:MNr;L~Ti=L&qيPuOt%RjNfQY ےnbLY#vH1dbOx *f.X⮅V)/wc wn2M6>;3g!EhfL"Lܘħ(XujLQZ9入lmQk2 ]ZnWfuLEaU魾řZl1(&v#m/zk,OTݷ몗'^fl TDN6I:YʝĞXc+eKz3N&Qh"L>)*f<ݸQ٭ho7 ʋDv=[3TֲcRy7~ i&D[P'KvW$L[W˙VFv Zܬeƿ=vrijΎw'04U^{k֬-ºuZ  wy8S ajw?O˯P*AA-P]"  ZlāOW)  VҪ%%AAD됭[%JK%'  ZYY%{L)~}8"|,ftQlUt?OW csC襻o.>rKo rp=|+CwOis&ӽѰ dAApk^R1&NR_^t%|zJ*  ?.,a\+]B< OJjűGw4d .1ˣx/ErtN?Ea< (}lo1ݱҽѰ dAApo(w883Q#ؾ{ŭV59{#~<9<~ ieԟf~s>"ەW.yh#68{qA}'lƯ/[W;oa,  j穞T=JZ,'[$׶$qn1t_˃ܻ* Z,*qC5ks",:j]W.{9 $=~wǰlEZnIfQ?̗de5r|pݛۗa~u[./t_ 0om.3b*<ӽu|<7/|tAta:,J[N=ڱ췕#Xv N]+V6p|+F ͿA[Ʊr[x&@|>t, [=*}I\XㄓGj֬ڶnJׁK߸sM׬  ]?sݍVo1qioF%M ЋpN!;_=Д0AtAGM6:բ^8W=yƪ( (=q~N԰W7}A`p 7y { a WvL^TNGǩŃkn. zAM cqՊ^6c-i8t1ѵbFT8c:˸y$ ѥ=}˸;ۿmDf~?k.&áXa!pFx0|xk#NCQ So;HVp[k嫊Ev]}s;'7AD7{|VW0w㎻7rCy]p:w/GJ.x/tU0OVО}ȟ7b Un5%;ǚk7"|xQ'1,FCǼE*W!|u? 7yP&e*38-_lw| 3.]:蠃:h!xdR>|Spc7A(|lW8 wr sWENM (8 " Ny )[eʭҬ.|?:*rj.1w |c/p Nˤ$ܖeFS|/ޏc ÏvY# W&LiEtA<4׿ugu! #XyAIJN,8x?}A|4( q b5 *LibA19"D)A|Y^ZD@AL x@ EAAPr$JAAD{mHBAAW.=Osl}eAAT; {rL)LO.9R  btt:|>:;;b2xrElrG  `Z<   MU=AAA cL S  ݂JAADS(%qJAA4な(JE7AAD㎃u8RH ݯdvDx ?_H$WHV""a'MG2rADš]vpص0jvEe 1~ %lSd`zRU.|cISY#_[! Nү&񜉘O#ҥA\AӃ; 'tva8nݺ]xA S<OCTh~H,CܟC,˖*C,ȦW!Uq3#ڸ?\y^tS3%NѬ\b1KtI~#:{ڇyQ0Ƴ, w`~ +|'Kn>\BH#gp}RW4icnV  @Twߍks-ZN8{,>CUUgM@]4ŪPEK- շЀB\%;r+`$l-jmNH-D'O?Cɹ=n#f!r:Ʈ4Dwc_ Eall ƿa5 ׎,; ] uG?^GsƻvlWKw@juCEc mus8Ƭd=5i: {S+BALXtCÕ@(-6թMJCZZI{LDo+-g]Q,ٲWH VuE*|ZWt$] nKVO]t5~WHL$*Qi|pI2c RK@AE^}lҥ,Ͳ9s_fV`v|_x<0<_~a<D:̀0KsWÇ|O!^x3oJ?|o>SI_;o>~ =2w0y!f>AA1FFF؋/^~eo۷~?vyk{|͙3r9vײk)^{-cSOřg|#mNe.A`xIXZ@!0qXXU2AA`tt:|>:;;f+XUO;?225Gq`ppk֬c bDqbݓo Bc@;+ٳfW_1PնOAAanUUtX,4QԒ*]@}ߎ1AAGS*3iX*XԏZ@GA K)R  (׫- z]m3(~EQO!( E^ʑLK25=ڼt3c1ERGa3坥iU[9E_OfmELڷ濓Ng+?oCoZaU? P+a˻oH!<$PHj|8[#uY&aA1YwQ~u_8#dT7J4#}ޗZ\I "O DtR5gN!F/$! 7#2,E-K~o&P܈_Z6MFD$dpUiZΞ 8!0hW/_/~濓N쿹kv{qUkC@<럛ö~bn`Lߨ]/$\aHcBTe0ͩ}*-|f6VD$ǑIqE"4DgCX8Lǔ=>`cT.K @JaA+F t!ũDW4 l I AVijzo{' C/rFOj% !{~ICKK{jd7D8Рn}__z $ E}3,X"4~'h\Vqu{CӚ_CpIC)v)$Џ)}Y0Ⱥi-NSwlߚە?WشV~5YB(=H.4TL"BEP5-_Mz%JW0?zf~s R.C/EKPBցWO ÄݝmFgĉ.sau&Ծ`R]{0UBUf q4 WҭRvK q^tsj)П( +2x8Tuk^ĺW7궕 i0Y{^H -6juHo:3}%/ߘ|tǐ1v}]{ؕË(mxkwo#qkڱf?s߯ZDܡ>}[\{!rK@t˺w+iE&WIKJb锌4c ,;&Ie_Kj3{גg'*i8RۚEDJٟVXIo4$j!S随.BkQqíJۏ oʿ\DuKcֶ>k׾9&m1V~zB@bv_t!#X{D, [K-C0Ae"( VL$Ji=+EQ!~WsZihџ~O79~kek .>SLdѯQ-C*&0*$_ֈ5a *$ɓ8*ahE[mhoFXн.,n_wj?ܶs- "p0|.OkZKf矹}s.֏Zڱo?Qp|{.*cH˟-Uƭ7'}PH&,Lgy͙3^2g<3 Җt7*~|8mϯ{3?0u#imF8t708Jzq*ĿMe40𛮋kaqpo[LK_wu7gM紴V-Bٰ_7a?PwS?[ƻq:T?mcâ_g珩wUeۡ~R] ou\*sª9 S>Uh*+_p*.ۯE?6;c;vzk;{7٫^. ۰a=d=8[~^{lΜ9ga?яC?d~'|2ziطO4L)GL`of}-ʟf`Dk3::+W3/JƎNo؁xeG1b֬=8>l<8k׮œO>YLi GXQ(5L"^5܁HSz6a~uLuO'_b҆s]}i6$KRy,DYJ]Qd%G8p& $Z[VΘH z>  h'  % Q+U  hnN&QJR    pxK }lnw$ld"J{2\Nɒ?'?::||`>M~KZcԮ:Q[K=>^RC: m-jA,O &Y ?wE*OUkuM "ט7˧u}Y=#~+X>&yiv ։Rn|N*R4[g@@@@Z"bme5PjvWv D-Qi`@Y*~8[}a1;̧!@ `~MqJ?#\n.T~pkU>]O^/8[RmM=eӿg" r-?=^@eL֏o}+ne62탛a~ (z5kؚ5kؖ-[؜9s/;C+:=\gj__VWo6g~{ ~O{|+~s;ߴn:\V{#s*<5_7ϾYXWVK?tzzש|-_wsqJKCfo_=u7t\hfV)[.ҏӦojkh_wJh####;`>{؎ﰷxMꫯ 6lbO==c=֯n^c<"3g۲e [f {}QvZm۶DX)&F/7 :+W- 58K"Ee]FK^ʦɓqJ?#{W(5nˮ|5zDP˷Mnl IDAT}qM?t~vԩjY:E4M!)*Jm}Q裏2~D安D?}Xm5>`>zBڑ2d~Wo.]{?ʏMwM wS/lJ/T&/DSW➏\D'{~, L/L%BCl%:ՃޠB퉵pV}mf$+~a% PѕvwF^ Q!e?PCC.cjjWyr/zbcԖǐkbhs2㔿ou2a'8&:} snX5} #H^/fY6e/m6E 7&ܵgٍvCg܄:bע]_2.JF|=izg[)\SsJ]CڗOw q~& ݔo7l<8ׯ֭[u)r/bݦnD@A,C{j.l&vof8%AS}RpKAsmx<铜$KʯE )`novetEeTy h.b)  %> R  ([JIAA)N  01xHAA+Ju ѧ;a,yܺGrEѬ@ ׻}W#EyG$=-LDd~MSKz֐Nsg!Q&d硝sjLdI\LS{tf>m&^Ĕf>ᅬbh@0Yk{'+iFiF/F)hvR5\Hű3tI#T[#-x>?tOjR&K-=ClM܄/d١tO }nj1$u3OW4k/l">|;KN0Y g]LzqN5Vm29b\/TpjV ]}`CreePI2v~9c[~H_7GvkX~=6l8Ơj6*I,'%5Y]{L_yk=F+VNnMC zhSeTagײuWzzDoOSwHۼ۬r@n)|N[F?w^P:P]6A q/l d>fw:r7 &+6}ү)h)zb'?`Yۿq>|bU|H]M;Vtm[2>? =ӗXyKa|%1Q+qꊢU 1UG]h` d4j`Y-R| Qw fjy[mj4-N_u`DYZM˟x c~;MI_#ԣji _˖V! /V(P_--Y[2}X8*2c ZX4}~([F->4ؤڲYa ,$Xf*)|Z^j!^O\Ѫ5~ F^ 'Vv)Y?1Ԯ)j}jm*_Ĕ1Nc`lΜ9lt pڸ,g!YF|ouq§H(q'SΧ]}us\*䔿npo*e ᰖiS?]~s.}ݦu␏-mT6jg7~wigR&چF&:Bnnۼr|ɿF1awq{{vxvoW_}0\`=a{ '{q~vngٜ9sB;ә c H_|1ziطFK&d T?'`UZP|bʕ8CT*AUUJ*ޱ""0::Yf 8f(.;yvvjR<:4\h" O $L9AJG4C}VL2$%꾷ס>}p)AAAJ#xfvuWnJAADK/{AADÔJ%}wQ/X,X,all6QJ”  h'}OAALaJ  vLdE8"7=`ĝeD >G@%[e +LL-.̔+(iܭT b* RƘxKi0yXRqѽZ@o S"ɮÒĝXܲnZdf d' )'LE,vH>Βzg u`:Í[Sk[w(୑o$X@YA>ʝ sD/ qgٍe! 5BO/(]= ِ<JbwA@L| 0S@ @ ?n$YEH󀿞(T+1.2kU0A11ގ``H3M<㯡esY҇z9l_p(Cz .1,=ui [c/B$*' vv=O ݆p,5z6u @+n3i78vli vit9|>Ėkg'tY-Viq ĉZ@s[ ?$u*sC F3cW..l<&@V%4KO KP>MlVEq}>/_.resy6QLÚN.AAB6U὘P-F Pz/ j?Ƅ($HAĤDѮLi3HqH_ث~ڋ0ƀf a{oI)&tR@i?Wn/eQՅ^Fn)qHޛR`` ں ;V A1ᨪ;wC& Pb}`CQH܉ث}PY7M/ξOA_|smAdYZ{l0 `7}\g Ƅn(t*h,_Gsw}n)˴9q?"ul^WcIӚo2Am,gH1ec?,x^/$*nEB - iϧ%ETSa<@u  &JOOc+%Kp׃O#tľFjǒU Z1$#BC l b3::+Wc RUUQ*x{Nj((K(f͚ƚͣc|rr-[bϷE,7-)RPan -;JI]AAZ7iWbh=Oj3듓-"{]tKS]  >RC@AAL4$AA1a)%  CVR  b"f?IAA톺"@ $v(HrDj[MP(CVKM% vHA|0)%+idiwvE6' hWl: Zg, $´%;}3z(Ě@AmLW5+D W*:(PbKny3Y 3%jV4 |TDwyֻJJl~9?W$?poX%q ZT,naw }PA2mt|Ry2tX7S}pP6HVDЗ6u4rOn0UҀ|$C>'-Ym〮hE0l/?jlӁ=m̻2X7 J#\ ltAA+uP|Fwi|C=J\77z9 B)đՅHW)ȼJ\ѯE`(L:]Q<e5Pt)zD57Cr]ѬBY} o%+H !ḷ AD{񑕴`sݴ-rUmXz] `YnaAw#! bI_Y"KA]&6Nc>[}Jo'Lfy v%KW}0w&?_Ɛ" ,!<quGMl̥@B.QW "UcJ]" <փnI߲ZFM7HASZʝ*E2 ,!ڶ,TtURSHDQuWObU_2ɦ;!~–បiNo Ь~ݱ\LEEDyI@)c8NZ)WD^4if2 YA9p<{}^c꾽2v No? ]~vY+& д4-E-nob%I ssX:GmT܀zm9jӫ-zk.w~IO- ^a*MJRPlMWp)"mjkzA[2 #X12 4+W)I}~>=Q\3[YeT\0*krU5JWrk롦/[IbF^ծ{Yq:"Bi3U1~j^`4†%R#W/?>xHJAq\~erˤR{C˙%+r]+FN,,=]A#75Q]%JG(49k\Gj}6+,q*ydꒉ]"b'JQQ:co$M6S/%)LAGTB%k~Z''+J UROz),H͸um˯/uTҘjvmiܪY枸Q>ޗÍ~yAFU~NTZ_YRZFuOBUO{|(VBuaNh6(;ex۶ХSL]s/mҊkcm;RzЗ| x|{( (NIIv,2@:pGꞍQ7!vOх]wT~C_F 5 c0Jl}yy!7tr0HU>ڗu@q z5%xW*~SFVe5nv&ʊߤCVp_zO^_| ڪ/ۏ_GOiRlaWVttYʈSǃ ίGkZf+ wmؚڽ $)1]}4[;ޗ>ѥnKuav,8ݕTnڥ/|*^zu].ď'W]n[ڰJRfEؿ)Mr-yW9W(y+=1]}B^^UOvq~tvjۃv\G"+\F@1LI7o̙7҈~L3_lKg126qSY|uCƘɚFEEE?=2MSVjԪΟWT***Rǎ=2}Q꥗^ŋ%q} UeC>{HPo>9ZC ~^<G 48}߂&[YI7W*j$tR49B)Rܜ'VxN"`nSeLӔjjiZe-?ZKe50 f)J1BƇyxWoZT --Dgv⥟ҒeOWU1~j^`4bVQ1&tmモaHE9::U+GkVκIn]T\\[;ZmNRlΤt4M%P85|u={(\n׹ruuv9ה&~nZKa_'za2]˫1F_֗+6 `\SZT-҈ 7:P3,4׻泡הKdWPP = RJB)yI(@`1M<^Oje4\|mkoU \ZS|L[򾭉OPZxY-OIDAThiji6ӽ1J:ǥj!eϤioe#VհV2M=QhALӬe(MW8L(SlFLWz77o`+XkahO*ոۺjHҥ0<:>o7vVK^ߘhOSؤJ=~ fn}c5454(Z/4M=xsK4+)`oЀ RJB)RP B)`)ohLs'{4QB)<J+##C~N>sΩP6mڨM6rqq<==VZqTZ:rvޭ$9rD'O.///yxxSNj۶$IϟWAArssu}7̔.+$$D}B0 ڱc>CmڴInnn ј1cs^bJJJG={V#Gرc*:@s i0F3gb YF={Tdd.\(zݺuk[{ք $I|6oެ^zIo~)SՕL4yӧOkԩ0`JKKK;vPTT]iu]v կ_?M>]YYYJrb-[L RRRxbqf}||d}Wruuw߭˗ŋ LSRR#Gzgt-4ر}Y߿_TppRSSi MJ5oc4J}jȑ:uꔦNJhɡ4>>^gvm-"|}}gUVoZ@+ ʮtÆ z׵{H˸h Q׮]Rݮ)OS.]ZliQff&-)OO>6gZeZm^iii_~լYh%.=:r7YF~~~ڷo_(EDDHN8_W?~]+fڴiڿO+h ^SllZnmz>N>m:?ObIR뫒VN_V> qFM8[,jӦk׮_J|Ay@p, ۧ^zn{ŢB͙3Gւ $I{ァ4yzzj޼yjժ5{s)11Qٳgk׮6[N?\C Y!SzQׯ^;i&=iӦ:ϟ5k4MOij…5URR#FwUnokС:r:vhO_|uܹ^e<#޽uII||իem޼Y֭$i„ *..[oU}suuٳgi) 4+khptt,a)##C})Y3,9rDWR"eddp)i ;w[ObkC;w 6T>))exyy)55U/^,j߿Nݢ')Bi@@:T/^X>j-qtI3F۷oku*ՊǍk͚5|;wN/yBJ[@``RRRgt}i޽'|PmݺU^^^ھ}OӤILyyyi޽:srssu뭷?WǎsNmڴIsՒ%KC6_nnN8Re giD?w 4ilN]\\ ^ HgϞZn-rajQ0d QFfŋT~>x ǫ膪?Nh eהJ=ܣW_a*(..NC wMkh`et2dշo])}駴dמRIڵV\GyDYYY-bN>H%&&ӓYȑ#u)\\\ZTe={V3gxZ@x.7:U4tPJ9v옆)S跿-Ş̴iӴdz}e {h U1ctwjĉڰa^~eyxx477h֬Y,Z@#3MҌN [*I~~~JJJw߭AiѢEi…նm[Sׇ֭`l|}}[^4c " nE4! 45B)T8@SRR4R4)NIhB)<JP &G(A-iC$L䡔` fJB)R1UўP &G(@)-%ɃcsɜM0A...2 Cǎ$;vLVUΝӻᆱN:qDZfJ]\\sk?x` -[?}o,X ''k999iѢEEJ[œ&MRu9qD"@K-a'twT7GF-4**Jڵ+ܶm[pnPL0AKKK 6۷ 6ho^۷=i?W~~snreff*33SYYY:w~bAԾ}{U ^^^~:tH_~kyxxCҥ䤇~XE999***҅ tYeggoٳg={j u뭷rXV%''kӦM裏G ҠA4ydۻ$PԦM*)##C))):p-[W1b" ٗ_~7xCk׮O~5J߿M۫ e/3Fҥ>3رCcG9-[hٲe:uꔢnݺ5tppP``5o;wꩧRϞ=+ݝH,z-),,LӰaZ)q0+((Hև~Hh$v)xbcco>O M:UTRR.]ʸ 3:V^^Zl W:u&NbZ @s /^Ըq奷~ڱE[6mhڵrvv֤IdZi-1Ξ=[Zb, W9JHHЏ? ZH)ݶm6nܨÇ7k.KKKeX4MYVQk׮U߾}`Z թ{XO\/^sܹ6nHht՚:uj{35.o׮]ʏʕ+i5vf5ϟׁV fggW_i:u=͛7G'OVAAVXP?աCuVrvv̙3պuk_RbbfΜkԩѣGm7xCyyyU^^^*+,,LoTXX6mz/BuU=z_+44Tu-MBBBt1M6Mfŋɓ'Hyyyzg{rt6_:ufΜ3f̙3[nEꫯh9 NUyy>}Za߿|M8p {Qa駟ֺu딙@IҤI4sLQ\\^>$sիW+CYYY{R [F۶m_z7uy(33S_;VtСJ7[tqQ!T}wر7kT lյާ%< ///EGG+''G+VPնm[IS6u/)%%آikO>-ZuTt+**JӟC&66V[lQZZ$iϞ=^P__6Siiug+;;[*,,>JMM՝wIhP@ر^6 CSLѴi$I}Qll Pgz뭷4}tJNNիuEm޼YGֺuTPPڵKG{'4E!!!Z|Qu>HZ WeC777S-Zm4_72_^+V?񏛪BBBOjpS***ٳg֭[_sώa2Ma*,,GE1j^x͛7OR;vΜ9SҖd۶mոqhvVPUV)&&זL+VT MJ%?Ə_*--a+DǏׄ МB$-^XNNN!iII~ߪCZh9RŢwyG/~Q硖EFFoi{JK3<;ڵJ9v옆 "]VZ4P*IZ|ϟPǫUFII^yӲe!hPZ9kcرڷoݫ@m߾z64m6 4H~>S;XkڵzWh"hƍFmذAzuݝءԞe^޽[ ,PBBNMҴh"jʕz{wp0pj͚5 SN4rHiРArtlPIIۧ;vhƍĉsN nPZ/^_|Qז-[4c ;vL 5p@SݻwW۶m봝8qB)))t}<+Wj ; fJ@gi߾}Zn;'NSN𐫫tImڴ$H:{uiG{V5{lcǎmBi:v_sVU|Μ9leee… ***RaaVծ];uA...rss<== 988ԘVVkUX,ڵvQh488X.\(ܹsg[=zД)SZf(@QZZ$M«qM:ݎ}_Skkj5=ɺmZef%3gu|n/K*{XkNҞvRv?Geݡ|[ 5E6/V>4-ixC}ZڬlU}4d/bUa{DW 5`k۬IU@ShWͿ./#눙IENDB`graphviz-0.8.4/docs/_static/round-table.svg0000666000000000000000000000443313316251122017372 0ustar rootroot %3 A King Arthur B Sir Bedevere the Wise A->B L Sir Lancelot the Brave A->L B->L graphviz-0.8.4/docs/_static/structs.svg0000666000000000000000000001045313316251122016664 0ustar rootroot structs struct1 left middle right struct2 one two struct1:f1->struct2:f0 struct3 hello world b g h c d e f struct1:f2->struct3:here graphviz-0.8.4/docs/_static/structs_revisited.svg0000666000000000000000000000765313316251122020752 0ustar rootroot structs struct1 left middle right struct2 one two struct1:f1->struct2:f0 struct3 hello world b c d e f g h struct1:f2->struct3:here graphviz-0.8.4/docs/_static/traffic_lights.svg0000666000000000000000000002402413316251122020144 0ustar rootroot TrafficLights PetriNet Model TrafficLights Extracted from ConceptBase and layed out by Graphviz gy2 gy2 yellow2 yellow2 gy2->yellow2 yr2 yr2 red2 red2 yr2->red2 safe1 safe1 yr2->safe1 rg2 rg2 green2 green2 rg2->green2 gy1 gy1 yellow1 yellow1 gy1->yellow1 yr1 yr1 safe2 safe2 yr1->safe2 red1 red1 yr1->red1 rg1 rg1 green1 green1 rg1->green1 green2->gy2 yellow2->yr2 red2->rg2 safe2->rg2 green1->gy1 yellow1->yr1 red1->rg1 safe1->rg1 graphviz-0.8.4/docs/_static/unix.svg0000666000000000000000000007167713316251122016157 0ustar rootroot unix 5th Edition 5th Edition 6th Edition 6th Edition 5th Edition->6th Edition PWB 1.0 PWB 1.0 5th Edition->PWB 1.0 LSX LSX 6th Edition->LSX 1 BSD 1 BSD 6th Edition->1 BSD Mini Unix Mini Unix 6th Edition->Mini Unix Wollongong Wollongong 6th Edition->Wollongong Interdata Interdata 6th Edition->Interdata PWB 1.2 PWB 1.2 PWB 1.0->PWB 1.2 USG 1.0 USG 1.0 PWB 1.0->USG 1.0 2 BSD 2 BSD 1 BSD->2 BSD Unix/TS 3.0 Unix/TS 3.0 Interdata->Unix/TS 3.0 PWB 2.0 PWB 2.0 Interdata->PWB 2.0 7th Edition 7th Edition Interdata->7th Edition TS 4.0 TS 4.0 Unix/TS 3.0->TS 4.0 PWB 2.0->Unix/TS 3.0 8th Edition 8th Edition 7th Edition->8th Edition 32V 32V 7th Edition->32V V7M V7M 7th Edition->V7M Ultrix-11 Ultrix-11 7th Edition->Ultrix-11 Xenix Xenix 7th Edition->Xenix UniPlus+ UniPlus+ 7th Edition->UniPlus+ 9th Edition 9th Edition 8th Edition->9th Edition 3 BSD 3 BSD 32V->3 BSD V7M->Ultrix-11 2.8 BSD 2.8 BSD 2 BSD->2.8 BSD 2.8 BSD->Ultrix-11 2.9 BSD 2.9 BSD 2.8 BSD->2.9 BSD 4 BSD 4 BSD 3 BSD->4 BSD 4.1 BSD 4.1 BSD 4 BSD->4.1 BSD 4.1 BSD->8th Edition 4.1 BSD->2.8 BSD 4.2 BSD 4.2 BSD 4.1 BSD->4.2 BSD 4.3 BSD 4.3 BSD 4.2 BSD->4.3 BSD Ultrix-32 Ultrix-32 4.2 BSD->Ultrix-32 PWB 1.2->PWB 2.0 CB Unix 1 CB Unix 1 USG 1.0->CB Unix 1 USG 2.0 USG 2.0 USG 1.0->USG 2.0 CB Unix 2 CB Unix 2 CB Unix 1->CB Unix 2 USG 3.0 USG 3.0 USG 2.0->USG 3.0 CB Unix 3 CB Unix 3 CB Unix 2->CB Unix 3 Unix/TS++ Unix/TS++ CB Unix 3->Unix/TS++ PDP-11 Sys V PDP-11 Sys V CB Unix 3->PDP-11 Sys V CB Unix 3->TS 4.0 Unix/TS++->TS 4.0 USG 3.0->Unix/TS 3.0 Unix/TS 1.0 Unix/TS 1.0 Unix/TS 1.0->Unix/TS 3.0 System V.0 System V.0 TS 4.0->System V.0 System V.2 System V.2 System V.0->System V.2 System V.3 System V.3 System V.2->System V.3 graphviz-0.8.4/examples/0000755000000000000000000000000013316607326013700 5ustar rootrootgraphviz-0.8.4/examples/angles.py0000666000000000000000000000222513316251124015517 0ustar rootroot#!/usr/bin/env python # angles.py - http://www.graphviz.org/Gallery/gradient/angles.html from graphviz import Digraph g = Digraph('G', filename='angles.gv') g.attr(bgcolor='blue') with g.subgraph(name='cluster_1') as c: c.attr(fontcolor='white') c.attr('node', shape='circle', style='filled', fillcolor='white:black', gradientangle='360', label='n9:360', fontcolor='black') c.node('n9') for i, a in zip(range(8, 0, -1), range(360 - 45, -1, -45)): c.attr('node', gradientangle='%d' % a, label='n%d:%d' % (i, a)) c.node('n%d' % i) c.attr(label='Linear Angle Variations (white to black gradient)') with g.subgraph(name='cluster_2') as c: c.attr(fontcolor='white') c.attr('node', shape='circle', style='radial', fillcolor='white:black', gradientangle='360', label='n18:360', fontcolor='black') c.node('n18') for i, a in zip(range(17, 9, -1), range(360 - 45, -1, -45)): c.attr('node', gradientangle='%d' % a, label='n%d:%d' % (i, a)) c.node('n%d' % i) c.attr(label='Radial Angle Variations (white to black gradient)') g.edge('n5', 'n14') g.view() graphviz-0.8.4/examples/btree.py0000666000000000000000000000160613316251124015351 0ustar rootroot#!/usr/bin/env python # btree.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 13 from graphviz import Digraph, nohtml g = Digraph('g', filename='btree.gv', node_attr={'shape': 'record', 'height': '.1'}) g.node('node0', nohtml(' | G|')) g.node('node1', nohtml(' | E|')) g.node('node2', nohtml(' | B|')) g.node('node3', nohtml(' | F|')) g.node('node4', nohtml(' | R|')) g.node('node5', nohtml(' | H|')) g.node('node6', nohtml(' | Y|')) g.node('node7', nohtml(' | A|')) g.node('node8', nohtml(' | C|')) g.edge('node0:f2', 'node4:f1') g.edge('node0:f0', 'node1:f1') g.edge('node1:f0', 'node2:f1') g.edge('node1:f2', 'node3:f1') g.edge('node2:f2', 'node8:f1') g.edge('node2:f0', 'node7:f1') g.edge('node4:f2', 'node6:f1') g.edge('node4:f0', 'node5:f1') g.view() graphviz-0.8.4/examples/cluster.py0000666000000000000000000000171613316251124015733 0ustar rootroot#!/usr/bin/env python # cluster.py - http://www.graphviz.org/content/cluster from graphviz import Digraph g = Digraph('G', filename='cluster.gv') # NOTE: the subgraph name needs to begin with 'cluster' (all lowercase) # so that Graphviz recognizes it as a special cluster subgraph with g.subgraph(name='cluster_0') as c: c.attr(style='filled') c.attr(color='lightgrey') c.node_attr.update(style='filled', color='white') c.edges([('a0', 'a1'), ('a1', 'a2'), ('a2', 'a3')]) c.attr(label='process #1') with g.subgraph(name='cluster_1') as c: c.node_attr.update(style='filled') c.edges([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3')]) c.attr(label='process #2') c.attr(color='blue') g.edge('start', 'a0') g.edge('start', 'b0') g.edge('a1', 'b3') g.edge('b2', 'a3') g.edge('a3', 'a0') g.edge('a3', 'end') g.edge('b3', 'end') g.node('start', shape='Mdiamond') g.node('end', shape='Msquare') g.view() graphviz-0.8.4/examples/cluster_edge.py0000666000000000000000000000101613316251124016710 0ustar rootroot#!/usr/bin/env python # cluster_edge.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 20 from graphviz import Digraph g = Digraph('G', filename='cluster_edge.gv') g.attr(compound='true') with g.subgraph(name='cluster0') as c: c.edges(['ab', 'ac', 'bd', 'cd']) with g.subgraph(name='cluster1') as c: c.edges(['eg', 'ef']) g.edge('b', 'f', lhead='cluster1') g.edge('d', 'e') g.edge('c', 'g', ltail='cluster0', lhead='cluster1') g.edge('c', 'e', ltail='cluster0') g.edge('d', 'h') g.view() graphviz-0.8.4/examples/er.py0000666000000000000000000000211413316251124014651 0ustar rootroot#!/usr/bin/env python # er.py - http://www.graphviz.org/content/ER from graphviz import Graph e = Graph('ER', filename='er.gv', engine='neato') e.attr('node', shape='box') e.node('course') e.node('institute') e.node('student') e.attr('node', shape='ellipse') e.node('name0', label='name') e.node('name1', label='name') e.node('name2', label='name') e.node('code') e.node('grade') e.node('number') e.attr('node', shape='diamond', style='filled', color='lightgrey') e.node('C-I') e.node('S-C') e.node('S-I') e.edge('name0', 'course') e.edge('code', 'course') e.edge('course', 'C-I', label='n', len='1.00') e.edge('C-I', 'institute', label='1', len='1.00') e.edge('institute', 'name1') e.edge('institute', 'S-I', label='1', len='1.00') e.edge('S-I', 'student', label='n', len='1.00') e.edge('student', 'grade') e.edge('student', 'name2') e.edge('student', 'number') e.edge('student', 'S-C', label='m', len='1.00') e.edge('S-C', 'course', label='n', len='1.00') e.attr(label=r'\n\nEntity Relation Diagram\ndrawn by NEATO') e.attr(fontsize='20') e.view() graphviz-0.8.4/examples/fdpclust.py0000666000000000000000000000072513316251124016075 0ustar rootroot#!/usr/bin/env python # fdpclust.py - http://www.graphviz.org/content/fdpclust from graphviz import Graph g = Graph('G', filename='fdpclust.gv', engine='fdp') g.node('e') with g.subgraph(name='clusterA') as a: a.edge('a', 'b') with a.subgraph(name='clusterC') as c: c.edge('C', 'D') with g.subgraph(name='clusterB') as b: b.edge('d', 'f') g.edge('d', 'D') g.edge('e', 'clusterB') g.edge('clusterC', 'clusterB') g.view() graphviz-0.8.4/examples/fsm.py0000666000000000000000000000156413316251124015040 0ustar rootroot#!/usr/bin/env python # fsm.py - http://www.graphviz.org/content/fsm from graphviz import Digraph f = Digraph('finite_state_machine', filename='fsm.gv') f.attr(rankdir='LR', size='8,5') f.attr('node', shape='doublecircle') f.node('LR_0') f.node('LR_3') f.node('LR_4') f.node('LR_8') f.attr('node', shape='circle') f.edge('LR_0', 'LR_2', label='SS(B)') f.edge('LR_0', 'LR_1', label='SS(S)') f.edge('LR_1', 'LR_3', label='S($end)') f.edge('LR_2', 'LR_6', label='SS(b)') f.edge('LR_2', 'LR_5', label='SS(a)') f.edge('LR_2', 'LR_4', label='S(A)') f.edge('LR_5', 'LR_7', label='S(b)') f.edge('LR_5', 'LR_5', label='S(a)') f.edge('LR_6', 'LR_6', label='S(b)') f.edge('LR_6', 'LR_5', label='S(a)') f.edge('LR_7', 'LR_8', label='S(b)') f.edge('LR_7', 'LR_5', label='S(a)') f.edge('LR_8', 'LR_6', label='S(b)') f.edge('LR_8', 'LR_5', label='S(a)') f.view() graphviz-0.8.4/examples/g_c_n.py0000666000000000000000000000100213316251124015303 0ustar rootroot#!/usr/bin/env python # http://www.graphviz.org/Gallery/gradient/g_c_n.html from graphviz import Graph g = Graph('G', filename='g_c_n.gv') g.attr(bgcolor='purple:pink', label='agraph', fontcolor='white') with g.subgraph(name='cluster1') as c: c.attr(fillcolor='blue:cyan', label='acluster', fontcolor='white', style='filled', gradientangle='270') c.attr('node', shape='box', fillcolor='red:yellow', style='filled', gradientangle='90') c.node('anode') g.view() graphviz-0.8.4/examples/hello.py0000666000000000000000000000027413316251124015353 0ustar rootroot#!/usr/bin/env python # hello.py - http://www.graphviz.org/content/hello from graphviz import Digraph g = Digraph('G', filename='hello.gv') g.edge('Hello', 'World') g.view() graphviz-0.8.4/examples/notebook.ipynb0000666000000000000000000007460613316251124016573 0ustar rootroot{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "%3\r\n", "\r\n", "\r\n", "A\r\n", "\r\n", "King Arthur\r\n", "\r\n", "\r\n", "B\r\n", "\r\n", "Sir Bedevere the Wise\r\n", "\r\n", "\r\n", "A->B\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "L\r\n", "\r\n", "Sir Lancelot the Brave\r\n", "\r\n", "\r\n", "A->L\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "B->L\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from graphviz import Digraph\n", "\n", "dot = Digraph(comment='The Round Table')\n", "\n", "dot.node('A', 'King Arthur')\n", "dot.node('B', 'Sir Bedevere the Wise')\n", "dot.node('L', 'Sir Lancelot the Brave')\n", "\n", "dot.edges(['AB', 'AL'])\n", "dot.edge('B', 'L', constraint='false')\n", "\n", "dot" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "the holy hand grenade\r\n", "\r\n", "\r\n", "1\r\n", "\r\n", "1\r\n", "\r\n", "\r\n", "2\r\n", "\r\n", "2\r\n", "\r\n", "\r\n", "1->2\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "3\r\n", "\r\n", "3\r\n", "\r\n", "\r\n", "2->3\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "lob\r\n", "\r\n", "lob\r\n", "\r\n", "\r\n", "3->lob\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from graphviz import Source\n", "\n", "src = Source('digraph \"the holy hand grenade\" { rankdir=LR; 1 -> 2 -> 3 -> lob }')\n", "src" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "finite_state_machine\r\n", "\r\n", "\r\n", "LR_0\r\n", "\r\n", "\r\n", "LR_0\r\n", "\r\n", "\r\n", "LR_2\r\n", "\r\n", "LR_2\r\n", "\r\n", "\r\n", "LR_0->LR_2\r\n", "\r\n", "\r\n", "SS(B)\r\n", "\r\n", "\r\n", "LR_1\r\n", "\r\n", "LR_1\r\n", "\r\n", "\r\n", "LR_0->LR_1\r\n", "\r\n", "\r\n", "SS(S)\r\n", "\r\n", "\r\n", "LR_3\r\n", "\r\n", "\r\n", "LR_3\r\n", "\r\n", "\r\n", "LR_4\r\n", "\r\n", "\r\n", "LR_4\r\n", "\r\n", "\r\n", "LR_8\r\n", "\r\n", "\r\n", "LR_8\r\n", "\r\n", "\r\n", "LR_6\r\n", "\r\n", "LR_6\r\n", "\r\n", "\r\n", "LR_8->LR_6\r\n", "\r\n", "\r\n", "S(b)\r\n", "\r\n", "\r\n", "LR_5\r\n", "\r\n", "LR_5\r\n", "\r\n", "\r\n", "LR_8->LR_5\r\n", "\r\n", "\r\n", "S(a)\r\n", "\r\n", "\r\n", "LR_2->LR_4\r\n", "\r\n", "\r\n", "S(A)\r\n", "\r\n", "\r\n", "LR_2->LR_6\r\n", "\r\n", "\r\n", "SS(b)\r\n", "\r\n", "\r\n", "LR_2->LR_5\r\n", "\r\n", "\r\n", "SS(a)\r\n", "\r\n", "\r\n", "LR_1->LR_3\r\n", "\r\n", "\r\n", "S($end)\r\n", "\r\n", "\r\n", "LR_6->LR_6\r\n", "\r\n", "\r\n", "S(b)\r\n", "\r\n", "\r\n", "LR_6->LR_5\r\n", "\r\n", "\r\n", "S(a)\r\n", "\r\n", "\r\n", "LR_5->LR_5\r\n", "\r\n", "\r\n", "S(a)\r\n", "\r\n", "\r\n", "LR_7\r\n", "\r\n", "LR_7\r\n", "\r\n", "\r\n", "LR_5->LR_7\r\n", "\r\n", "\r\n", "S(b)\r\n", "\r\n", "\r\n", "LR_7->LR_8\r\n", "\r\n", "\r\n", "S(b)\r\n", "\r\n", "\r\n", "LR_7->LR_5\r\n", "\r\n", "\r\n", "S(a)\r\n", "\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# http://www.graphviz.org/content/fsm\n", "\n", "from graphviz import Digraph\n", "\n", "f = Digraph('finite_state_machine', filename='fsm.gv')\n", "f.attr(rankdir='LR', size='8,5')\n", "\n", "f.attr('node', shape='doublecircle')\n", "f.node('LR_0')\n", "f.node('LR_3')\n", "f.node('LR_4')\n", "f.node('LR_8')\n", "\n", "f.attr('node', shape='circle')\n", "f.edge('LR_0', 'LR_2', label='SS(B)')\n", "f.edge('LR_0', 'LR_1', label='SS(S)')\n", "f.edge('LR_1', 'LR_3', label='S($end)')\n", "f.edge('LR_2', 'LR_6', label='SS(b)')\n", "f.edge('LR_2', 'LR_5', label='SS(a)')\n", "f.edge('LR_2', 'LR_4', label='S(A)')\n", "f.edge('LR_5', 'LR_7', label='S(b)')\n", "f.edge('LR_5', 'LR_5', label='S(a)')\n", "f.edge('LR_6', 'LR_6', label='S(b)')\n", "f.edge('LR_6', 'LR_5', label='S(a)')\n", "f.edge('LR_7', 'LR_8', label='S(b)')\n", "f.edge('LR_7', 'LR_5', label='S(a)')\n", "f.edge('LR_8', 'LR_6', label='S(b)')\n", "f.edge('LR_8', 'LR_5', label='S(a)')\n", "\n", "f" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "G\r\n", "\r\n", "cluster0\r\n", "\r\n", "\r\n", "cluster1\r\n", "\r\n", "\r\n", "\r\n", "a\r\n", "\r\n", "a\r\n", "\r\n", "\r\n", "b\r\n", "\r\n", "b\r\n", "\r\n", "\r\n", "a->b\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "c\r\n", "\r\n", "c\r\n", "\r\n", "\r\n", "a->c\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "d\r\n", "\r\n", "d\r\n", "\r\n", "\r\n", "b->d\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "f\r\n", "\r\n", "f\r\n", "\r\n", "\r\n", "b->f\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "c->d\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "e\r\n", "\r\n", "e\r\n", "\r\n", "\r\n", "c->e\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "g\r\n", "\r\n", "g\r\n", "\r\n", "\r\n", "c->g\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "d->e\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "h\r\n", "\r\n", "h\r\n", "\r\n", "\r\n", "d->h\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "e->g\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "e->f\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# http://www.graphviz.org/pdf/dotguide.pdf Figure 20\n", "\n", "from graphviz import Digraph\n", "\n", "g = Digraph('G', filename='cluster_edge.gv')\n", "g.attr(compound='true')\n", "\n", "with g.subgraph(name='cluster0') as c:\n", " c.edges(['ab', 'ac', 'bd', 'cd'])\n", "\n", "with g.subgraph(name='cluster1') as c:\n", " c.edges(['eg', 'ef'])\n", "\n", "g.edge('b', 'f', lhead='cluster1')\n", "g.edge('d', 'e')\n", "g.edge('c', 'g', ltail='cluster0', lhead='cluster1')\n", "g.edge('c', 'e', ltail='cluster0')\n", "g.edge('d', 'h')\n", "\n", "g" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 1 } graphviz-0.8.4/examples/process.py0000666000000000000000000000100613316251124015720 0ustar rootroot#!/usr/bin/env python # process.py - http://www.graphviz.org/content/process from graphviz import Graph g = Graph('G', filename='process.gv', engine='sfdp') g.edge('run', 'intr') g.edge('intr', 'runbl') g.edge('runbl', 'run') g.edge('run', 'kernel') g.edge('kernel', 'zombie') g.edge('kernel', 'sleep') g.edge('kernel', 'runmem') g.edge('sleep', 'swap') g.edge('swap', 'runswap') g.edge('runswap', 'new') g.edge('runswap', 'runmem') g.edge('new', 'runmem') g.edge('sleep', 'runmem') g.view() graphviz-0.8.4/examples/structs.py0000666000000000000000000000172513316251124015761 0ustar rootroot#!/usr/bin/env python # structs.py - http://www.graphviz.org/doc/info/shapes.html#html from graphviz import Digraph s = Digraph('structs', node_attr={'shape': 'plaintext'}) s.node('struct1', '''<
left middle right
>''') s.node('struct2', '''<
one two
>''') s.node('struct3', '''<
hello
world
b g h
c d e
f
>''') s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')]) s.view() graphviz-0.8.4/examples/structs_revisited.py0000666000000000000000000000073213316251124020034 0ustar rootroot#!/usr/bin/env python # structs_revisited.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 12 from graphviz import Digraph s = Digraph('structs', filename='structs_revisited.gv', node_attr={'shape': 'record'}) s.node('struct1', ' left| middle| right') s.node('struct2', ' one| two') s.node('struct3', r'hello\nworld |{ b |{c| d|e}| f}| g | h') s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')]) s.view() graphviz-0.8.4/examples/traffic_lights.py0000666000000000000000000000201313316251124017231 0ustar rootroot#!/usr/bin/env python # traffic_lights.py - http://www.graphviz.org/content/traffic_lights from graphviz import Digraph t = Digraph('TrafficLights', filename='traffic_lights.gv', engine='neato') t.attr('node', shape='box') for i in (2, 1): t.node('gy%d' % i) t.node('yr%d' % i) t.node('rg%d' % i) t.attr('node', shape='circle', fixedsize='true', width='0.9') for i in (2, 1): t.node('green%d' % i) t.node('yellow%d' % i) t.node('red%d' % i) t.node('safe%d' % i) for i, j in [(2, 1), (1, 2)]: t.edge('gy%d' % i, 'yellow%d' % i) t.edge('rg%d' % i, 'green%d' % i) t.edge('yr%d' % i, 'safe%d' % j) t.edge('yr%d' % i, 'red%d' % i) t.edge('safe%d' % i, 'rg%d' % i) t.edge('green%d' % i, 'gy%d' % i) t.edge('yellow%d' % i, 'yr%d' % i) t.edge('red%d' % i, 'rg%d' % i) t.attr(overlap='false') t.attr(label=r'PetriNet Model TrafficLights\n' r'Extracted from ConceptBase and layed out by Graphviz') t.attr(fontsize='12') t.view() graphviz-0.8.4/examples/unix.py0000666000000000000000000000344413316251124015235 0ustar rootroot#!/usr/bin/env python # unix.py - http://www.graphviz.org/content/unix from graphviz import Digraph u = Digraph('unix', filename='unix.gv') u.attr(size='6,6') u.node_attr.update(color='lightblue2', style='filled') u.edge('5th Edition', '6th Edition') u.edge('5th Edition', 'PWB 1.0') u.edge('6th Edition', 'LSX') u.edge('6th Edition', '1 BSD') u.edge('6th Edition', 'Mini Unix') u.edge('6th Edition', 'Wollongong') u.edge('6th Edition', 'Interdata') u.edge('Interdata', 'Unix/TS 3.0') u.edge('Interdata', 'PWB 2.0') u.edge('Interdata', '7th Edition') u.edge('7th Edition', '8th Edition') u.edge('7th Edition', '32V') u.edge('7th Edition', 'V7M') u.edge('7th Edition', 'Ultrix-11') u.edge('7th Edition', 'Xenix') u.edge('7th Edition', 'UniPlus+') u.edge('V7M', 'Ultrix-11') u.edge('8th Edition', '9th Edition') u.edge('1 BSD', '2 BSD') u.edge('2 BSD', '2.8 BSD') u.edge('2.8 BSD', 'Ultrix-11') u.edge('2.8 BSD', '2.9 BSD') u.edge('32V', '3 BSD') u.edge('3 BSD', '4 BSD') u.edge('4 BSD', '4.1 BSD') u.edge('4.1 BSD', '4.2 BSD') u.edge('4.1 BSD', '2.8 BSD') u.edge('4.1 BSD', '8th Edition') u.edge('4.2 BSD', '4.3 BSD') u.edge('4.2 BSD', 'Ultrix-32') u.edge('PWB 1.0', 'PWB 1.2') u.edge('PWB 1.0', 'USG 1.0') u.edge('PWB 1.2', 'PWB 2.0') u.edge('USG 1.0', 'CB Unix 1') u.edge('USG 1.0', 'USG 2.0') u.edge('CB Unix 1', 'CB Unix 2') u.edge('CB Unix 2', 'CB Unix 3') u.edge('CB Unix 3', 'Unix/TS++') u.edge('CB Unix 3', 'PDP-11 Sys V') u.edge('USG 2.0', 'USG 3.0') u.edge('USG 3.0', 'Unix/TS 3.0') u.edge('PWB 2.0', 'Unix/TS 3.0') u.edge('Unix/TS 1.0', 'Unix/TS 3.0') u.edge('Unix/TS 3.0', 'TS 4.0') u.edge('Unix/TS++', 'TS 4.0') u.edge('CB Unix 3', 'TS 4.0') u.edge('TS 4.0', 'System V.0') u.edge('System V.0', 'System V.2') u.edge('System V.2', 'System V.3') u.view() graphviz-0.8.4/graphviz/0000755000000000000000000000000013316607326013714 5ustar rootrootgraphviz-0.8.4/graphviz/backend.py0000666000000000000000000001621413316254076015665 0ustar rootroot# backend.py - execute rendering, open files in viewer import os import io import re import sys import errno import platform import subprocess import contextlib from ._compat import stderr_write_binary from . import tools __all__ = ['render', 'pipe', 'version', 'view'] ENGINES = { # http://www.graphviz.org/pdf/dot.1.pdf 'dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage', } FORMATS = { # http://www.graphviz.org/doc/info/output.html 'bmp', 'canon', 'dot', 'gv', 'xdot', 'xdot1.2', 'xdot1.4', 'cgimage', 'cmap', 'eps', 'exr', 'fig', 'gd', 'gd2', 'gif', 'gtk', 'ico', 'imap', 'cmapx', 'imap_np', 'cmapx_np', 'ismap', 'jp2', 'jpg', 'jpeg', 'jpe', 'json', 'json0', 'dot_json', 'xdot_json', # Graphviz 2.40 'pct', 'pict', 'pdf', 'pic', 'plain', 'plain-ext', 'png', 'pov', 'ps', 'ps2', 'psd', 'sgi', 'svg', 'svgz', 'tga', 'tif', 'tiff', 'tk', 'vml', 'vmlz', 'vrml', 'wbmp', 'webp', 'xlib', 'x11', } PLATFORM = platform.system().lower() POPEN_KWARGS = {} if PLATFORM == 'windows': # pragma: no cover POPEN_KWARGS['startupinfo'] = subprocess.STARTUPINFO() POPEN_KWARGS['startupinfo'].dwFlags |= subprocess.STARTF_USESHOWWINDOW POPEN_KWARGS['startupinfo'].wShowWindow = subprocess.SW_HIDE # work around WinError 87 from https://bugs.python.org/issue19764 # https://github.com/python/cpython/commit/b2a6083eb0384f38839d3f1ed32262a3852026fa # TODO: consider not reusing the instance instead (adapt test code for this) if sys.version_info >= (3, 7): POPEN_KWARGS['close_fds'] = False class ExecutableNotFound(RuntimeError): """Exception raised if the Graphviz executable is not found.""" _msg = ('failed to execute %r, ' 'make sure the Graphviz executables are on your systems\' PATH') def __init__(self, args): super(ExecutableNotFound, self).__init__(self._msg % args) def command(engine, format, filepath=None): """Return args list for ``subprocess.Popen`` and name of the rendered file.""" if engine not in ENGINES: raise ValueError('unknown engine: %r' % engine) if format not in FORMATS: raise ValueError('unknown format: %r' % format) args, rendered = [engine, '-T%s' % format], None if filepath is not None: args.extend(['-O', filepath]) rendered = '%s.%s' % (filepath, format) return args, rendered def render(engine, format, filepath, quiet=False): """Render file with Graphviz ``engine`` into ``format``, return result filename. Args: engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...). format: The output format used for rendering (``'pdf'``, ``'png'``, ...). filepath: Path to the DOT source file to render. quiet (bool): Suppress ``stderr`` output on non-zero exit status. Returns: The (possibly relative) path of the rendered file. Raises: ValueError: If ``engine`` or ``format`` are not known. graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. """ args, rendered = command(engine, format, filepath) if quiet: open = io.open else: @contextlib.contextmanager def open(name, mode): assert name == os.devnull and mode == 'w' yield None with open(os.devnull, 'w') as stderr: try: subprocess.check_call(args, stderr=stderr, **POPEN_KWARGS) except OSError as e: if e.errno == errno.ENOENT: raise ExecutableNotFound(args) else: # pragma: no cover raise return rendered def pipe(engine, format, data, quiet=False): """Return ``data`` piped through Graphviz ``engine`` into ``format``. Args: engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...). format: The output format used for rendering (``'pdf'``, ``'png'``, ...). data: The binary (encoded) DOT source string to render. quiet (bool): Suppress ``stderr`` output on non-zero exit status. Returns: Binary (encoded) stdout of the layout command. Raises: ValueError: If ``engine`` or ``format`` are not known. graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. """ args, _ = command(engine, format) try: proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **POPEN_KWARGS) except OSError as e: if e.errno == errno.ENOENT: raise ExecutableNotFound(args) else: # pragma: no cover raise outs, errs = proc.communicate(data) if proc.returncode: if not quiet: stderr_write_binary(errs) sys.stderr.flush() raise subprocess.CalledProcessError(proc.returncode, args, output=outs) return outs def version(): """Return the version number tuple from the ``stderr`` output of ``dot -V``. Returns: Two or three ``int`` version ``tuple``. Raises: graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. RuntimmeError: If the output cannot be parsed into a version number. """ args = ['dot', '-V'] try: outs = subprocess.check_output(args, stderr=subprocess.STDOUT, **POPEN_KWARGS) except OSError as e: if e.errno == errno.ENOENT: raise ExecutableNotFound(args) else: # pragma: no cover raise info = outs.decode('ascii') ma = re.search(r'graphviz version (\d+\.\d+(?:\.\d+)?) ', info) if ma is None: raise RuntimeError return tuple(int(d) for d in ma.group(1).split('.')) def view(filepath): """Open filepath with its default viewing application (platform-specific). Args: filepath: Path to the file to open in viewer. Raises: RuntimeError: If the current platform is not supported. """ try: view_func = getattr(view, PLATFORM) except AttributeError: raise RuntimeError('platform %r not supported' % PLATFORM) view_func(filepath) @tools.attach(view, 'darwin') def view_darwin(filepath): """Open filepath with its default application (mac).""" subprocess.Popen(['open', filepath]) @tools.attach(view, 'linux') @tools.attach(view, 'freebsd') def view_unixoid(filepath): """Open filepath in the user's preferred application (linux, freebsd).""" subprocess.Popen(['xdg-open', filepath]) @tools.attach(view, 'windows') def view_windows(filepath): """Start filepath with its associated application (windows).""" os.startfile(os.path.normpath(filepath)) graphviz-0.8.4/graphviz/dot.py0000666000000000000000000002437113316251122015054 0ustar rootroot# dot.py - create dot code r"""Assemble DOT source code objects. >>> dot = Graph(comment=u'M\xf8nti Pyth\xf8n ik den H\xf8lie Grailen') >>> dot.node(u'M\xf8\xf8se') >>> dot.node('trained_by', u'trained by') >>> dot.node('tutte', u'TUTTE HERMSGERVORDENBROTBORDA') >>> dot.edge(u'M\xf8\xf8se', 'trained_by') >>> dot.edge('trained_by', 'tutte') >>> dot.node_attr['shape'] = 'rectangle' >>> print(dot.source.replace(u'\xf8', '0')) #doctest: +NORMALIZE_WHITESPACE // M0nti Pyth0n ik den H0lie Grailen graph { node [shape=rectangle] "M00se" trained_by [label="trained by"] tutte [label="TUTTE HERMSGERVORDENBROTBORDA"] "M00se" -- trained_by trained_by -- tutte } >>> dot.view('test-output/m00se.gv') # doctest: +SKIP 'test-output/m00se.gv.pdf' """ from . import lang, files __all__ = ['Graph', 'Digraph'] class Dot(files.File): """Assemble, save, and render DOT source code, open result in viewer.""" _comment = '// %s' _subgraph = 'subgraph %s{' _subgraph_plain = '%s{' _node = _attr = '\t%s%s' _attr_plain = _attr % ('%s', '') _tail = '}' _quote = staticmethod(lang.quote) _quote_edge = staticmethod(lang.quote_edge) _a_list = staticmethod(lang.a_list) _attr_list = staticmethod(lang.attr_list) def __init__(self, name=None, comment=None, filename=None, directory=None, format=None, engine=None, encoding=files.File._encoding, graph_attr=None, node_attr=None, edge_attr=None, body=None, strict=False): self.name = name self.comment = comment super(Dot, self).__init__(filename, directory, format, engine, encoding) self.graph_attr = dict(graph_attr) if graph_attr is not None else {} self.node_attr = dict(node_attr) if node_attr is not None else {} self.edge_attr = dict(edge_attr) if edge_attr is not None else {} self.body = list(body) if body is not None else [] self.strict = strict def _kwargs(self): result = super(Dot, self)._kwargs() result.update({ 'name': self.name, 'comment': self.comment, 'graph_attr': dict(self.graph_attr), 'node_attr': dict(self.node_attr), 'edge_attr': dict(self.edge_attr), 'body': list(self.body), 'strict': self.strict, }) return result def clear(self, keep_attrs=False): """Reset content to an empty body, clear graph/node/egde_attr mappings. Args: keep_attrs (bool): preserve graph/node/egde_attr mappings """ if not keep_attrs: for a in (self.graph_attr, self.node_attr, self.edge_attr): a.clear() del self.body[:] def __iter__(self, subgraph=False): """Yield the DOT source code line by line (as graph or subgraph).""" if self.comment: yield self._comment % self.comment if subgraph: if self.strict: raise ValueError('subgraphs cannot be strict') head = self._subgraph if self.name else self._subgraph_plain else: head = self._head_strict if self.strict else self._head yield head % (self._quote(self.name) + ' ' if self.name else '') for kw in ('graph', 'node', 'edge'): attrs = getattr(self, '%s_attr' % kw) if attrs: yield self._attr % (kw, self._attr_list(None, attrs)) for line in self.body: yield line yield self._tail def __str__(self): """The DOT source code as string.""" return '\n'.join(self) source = property(__str__, doc=__str__.__doc__) def node(self, name, label=None, _attributes=None, **attrs): """Create a node. Args: name: Unique identifier for the node inside the source. label: Caption to be displayed (defaults to the node ``name``). attrs: Any additional node attributes (must be strings). """ name = self._quote(name) attr_list = self._attr_list(label, attrs, _attributes) line = self._node % (name, attr_list) self.body.append(line) def edge(self, tail_name, head_name, label=None, _attributes=None, **attrs): """Create an edge between two nodes. Args: tail_name: Start node identifier. head_name: End node identifier. label: Caption to be displayed near the edge. attrs: Any additional edge attributes (must be strings). """ tail_name = self._quote_edge(tail_name) head_name = self._quote_edge(head_name) attr_list = self._attr_list(label, attrs, _attributes) line = self._edge % (tail_name, head_name, attr_list) self.body.append(line) def edges(self, tail_head_iter): """Create a bunch of edges. Args: tail_head_iter: Iterable of ``(tail_name, head_name)`` pairs. """ edge = self._edge_plain quote = self._quote_edge lines = (edge % (quote(t), quote(h)) for t, h in tail_head_iter) self.body.extend(lines) def attr(self, kw=None, _attributes=None, **attrs): """Add a general or graph/node/edge attribute statement. Args: kw: Attributes target (``None`` or ``'graph'``, ``'node'``, ``'edge'``). attrs: Attributes to be set (must be strings, may be empty). See the :ref:`usage examples in the User Guide `. """ if kw is not None and kw.lower() not in ('graph', 'node', 'edge'): raise ValueError('attr statement must target graph, node, or edge: ' '%r' % kw) if attrs or _attributes: if kw is None: a_list = self._a_list(None, attrs, _attributes) line = self._attr_plain % a_list else: attr_list = self._attr_list(None, attrs, _attributes) line = self._attr % (kw, attr_list) self.body.append(line) def subgraph(self, graph=None, name=None, comment=None, graph_attr=None, node_attr=None, edge_attr=None, body=None): """Add the current content of the given sole ``graph`` argument as subgraph \ or return a context manager returning a new graph instance created \ with the given (``name``, ``comment``, etc.) arguments whose content is \ added as subgraph when leaving the context manager's ``with``-block. Args: graph: An instance of the same kind (:class:`.Graph`, :class:`.Digraph`) as the current graph (sole argument in non-with-block use). name: Subgraph name (``with``-block use). comment: Subgraph comment (``with``-block use). graph_attr: Subgraph-level attribute-value mapping (``with``-block use). node_attr: Node-level attribute-value mapping (``with``-block use). edge_attr: Edge-level attribute-value mapping (``with``-block use). body: Verbatim lines to add to the subgraph ``body`` (``with``-block use). See the :ref:`usage examples in the User Guide `. .. note:: If the ``name`` of the subgraph begins with ``'cluster'`` (all lowercase) the layout engine will treat it as a special cluster subgraph. """ if graph is None: kwargs = {'name': name, 'comment': comment, 'graph_attr': graph_attr, 'node_attr': node_attr, 'edge_attr': edge_attr, 'body': body} return SubgraphContext(self, kwargs) args = [name, comment, graph_attr, node_attr, edge_attr, body] if not all(a is None for a in args): raise ValueError('graph must be sole argument of subgraph()') if graph.directed != self.directed: raise ValueError('%r cannot add subgraph of different kind: %r ' % (self, graph)) lines = ['\t' + line for line in graph.__iter__(subgraph=True)] self.body.extend(lines) class SubgraphContext(object): """Return a blank instance of the parent and add as subgraph on exit.""" def __init__(self, parent, kwargs): self.parent = parent self.graph = parent.__class__(**kwargs) def __enter__(self): return self.graph def __exit__(self, type_, value, traceback): if type_ is None: self.parent.subgraph(self.graph) class Graph(Dot): """Graph source code in the DOT language. Args: name: Graph name used in the source code. comment: Comment added to the first line of the source. filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``). directory: (Sub)directory for source saving and rendering. format: Rendering output format (``'pdf'``, ``'png'``, ...). engine: Layout command used (``'dot'``, ``'neato'``, ...). encoding: Encoding for saving the source. graph_attr: Mapping of ``(attribute, value)`` pairs for the graph. node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes. edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges. body: Iterable of verbatim lines to add to the graph ``body``. strict (bool): Rendering should merge multi-edges. Note: All parameters are optional and can be changed under their corresponding attribute name after instance creation. """ _head = 'graph %s{' _head_strict = 'strict %s' % _head _edge = '\t%s -- %s%s' _edge_plain = _edge % ('%s', '%s', '') @property def directed(self): """``False``""" return False class Digraph(Dot): """Directed graph source code in the DOT language.""" if Graph.__doc__ is not None: __doc__ += Graph.__doc__.partition('.')[2] _head = 'digraph %s{' _head_strict = 'strict %s' % _head _edge = '\t%s -> %s%s' _edge_plain = _edge % ('%s', '%s', '') @property def directed(self): """``True``""" return True graphviz-0.8.4/graphviz/files.py0000666000000000000000000002233013316251122015361 0ustar rootroot# files.py - save, render, view """Save DOT code objects, render with Graphviz dot, and open in viewer.""" import os import io import codecs import locale from ._compat import text_type from . import backend, tools __all__ = ['File', 'Source'] class Base(object): _format = 'pdf' _engine = 'dot' _encoding = 'utf-8' @property def format(self): """The output format used for rendering (``'pdf'``, ``'png'``, ...).""" return self._format @format.setter def format(self, format): format = format.lower() if format not in backend.FORMATS: raise ValueError('unknown format: %r' % format) self._format = format @property def engine(self): """The layout commmand used for rendering (``'dot'``, ``'neato'``, ...).""" return self._engine @engine.setter def engine(self, engine): engine = engine.lower() if engine not in backend.ENGINES: raise ValueError('unknown engine: %r' % engine) self._engine = engine @property def encoding(self): """The encoding for the saved source file.""" return self._encoding @encoding.setter def encoding(self, encoding): if encoding is None: encoding = locale.getpreferredencoding() codecs.lookup(encoding) # raise early self._encoding = encoding def copy(self): """Return a copied instance of the object. Returns: An independent copy of the current object. """ kwargs = self._kwargs() return self.__class__(**kwargs) def _kwargs(self): ns = self.__dict__ attrs = ('_format', '_engine', '_encoding') return {a[1:]: ns[a] for a in attrs if a in ns} class File(Base): directory = '' _default_extension = 'gv' def __init__(self, filename=None, directory=None, format=None, engine=None, encoding=Base._encoding): if filename is None: name = getattr(self, 'name', None) or self.__class__.__name__ filename = '%s.%s' % (name, self._default_extension) self.filename = filename if directory is not None: self.directory = directory if format is not None: self.format = format if engine is not None: self.engine = engine self.encoding = encoding def _kwargs(self): result = super(File, self)._kwargs() result['filename'] = self.filename if 'directory' in self.__dict__: result['directory'] = self.directory return result def _repr_svg_(self): return self.pipe(format='svg').decode(self._encoding) def pipe(self, format=None): """Return the source piped through the Graphviz layout command. Args: format: The output format used for rendering (``'pdf'``, ``'png'``, etc.). Returns: Binary (encoded) stdout of the layout command. Raises: ValueError: If ``format`` is not known. graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. """ if format is None: format = self._format data = text_type(self.source).encode(self._encoding) outs = backend.pipe(self._engine, format, data) return outs @property def filepath(self): return os.path.join(self.directory, self.filename) def save(self, filename=None, directory=None): """Save the DOT source to file. Ensure the file ends with a newline. Args: filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``) directory: (Sub)directory for source saving and rendering. Returns: The (possibly relative) path of the saved source file. """ if filename is not None: self.filename = filename if directory is not None: self.directory = directory filepath = self.filepath tools.mkdirs(filepath) data = text_type(self.source) with io.open(filepath, 'w', encoding=self.encoding) as fd: fd.write(data) if not data.endswith(u'\n'): fd.write(u'\n') return filepath def render(self, filename=None, directory=None, view=False, cleanup=False): """Save the source to file and render with the Graphviz engine. Args: filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``) directory: (Sub)directory for source saving and rendering. view (bool): Open the rendered result with the default application. cleanup (bool): Delete the source file after rendering. Returns: The (possibly relative) path of the rendered file. Raises: graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. RuntimeError: If viewer opening is requested but not supported. """ filepath = self.save(filename, directory) rendered = backend.render(self._engine, self._format, filepath) if cleanup: os.remove(filepath) if view: self._view(rendered, self._format) return rendered def view(self, filename=None, directory=None, cleanup=False): """Save the source to file, open the rendered result in a viewer. Args: filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``) directory: (Sub)directory for source saving and rendering. cleanup (bool): Delete the source file after rendering. Returns: The (possibly relative) path of the rendered file. Raises: graphviz.ExecutableNotFound: If the Graphviz executable is not found. subprocess.CalledProcessError: If the exit status is non-zero. RuntimeError: If opening the viewer is not supported. Short-cut method for calling :meth:`.render` with ``view=True``. """ return self.render(filename=filename, directory=directory, view=True, cleanup=cleanup) def _view(self, filepath, format): """Start the right viewer based on file format and platform.""" methodnames = [ '_view_%s_%s' % (format, backend.PLATFORM), '_view_%s' % backend.PLATFORM, ] for name in methodnames: view_method = getattr(self, name, None) if view_method is not None: break else: raise RuntimeError('%r has no built-in viewer support for %r ' 'on %r platform' % (self.__class__, format, backend.PLATFORM)) view_method(filepath) _view_darwin = staticmethod(backend.view.darwin) _view_freebsd = staticmethod(backend.view.freebsd) _view_linux = staticmethod(backend.view.linux) _view_windows = staticmethod(backend.view.windows) class Source(File): """Verbatim DOT source code string to be rendered by Graphviz. Args: source: The verbatim DOT source code string. filename: Filename for saving the source (defaults to ``'Source.gv'``). directory: (Sub)directory for source saving and rendering. format: Rendering output format (``'pdf'``, ``'png'``, ...). engine: Layout command used (``'dot'``, ``'neato'``, ...). encoding: Encoding for saving the source. Note: All parameters except ``source`` are optional. All of them can be changed under their corresponding attribute name after instance creation. """ @classmethod def from_file(cls, filename, directory=None, format=None, engine=None, encoding=File._encoding): """Return an instance with the source string read from the given file. Args: filename: Filename for loading/saving the source. directory: (Sub)directory for source loading/saving and rendering. format: Rendering output format (``'pdf'``, ``'png'``, ...). engine: Layout command used (``'dot'``, ``'neato'``, ...). encoding: Encoding for loading/saving the source. """ filepath = os.path.join(directory or '', filename) if encoding is None: encoding = locale.getpreferredencoding() with io.open(filepath, encoding=encoding) as fd: source = fd.read() return cls(source, filename, directory, format, engine, encoding) def __init__(self, source, filename=None, directory=None, format=None, engine=None, encoding=File._encoding): super(Source, self).__init__(filename, directory, format, engine, encoding) self.source = source #: The verbatim DOT source code string. def _kwargs(self): result = super(Source, self)._kwargs() result['source'] = self.source return result graphviz-0.8.4/graphviz/lang.py0000666000000000000000000001036313316251122015203 0ustar rootroot# lang.py - dot language creation helpers """Quote strings to be valid DOT identifiers, assemble attribute lists.""" import re import collections from . import _compat, tools __all__ = ['quote', 'quote_edge', 'a_list', 'attr_list'] # http://www.graphviz.org/doc/info/lang.html HTML_STRING = re.compile(r'<.*>$', re.DOTALL) ID = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*|-?(\.\d+|\d+(\.\d*)?))$') KEYWORDS = {'node', 'edge', 'graph', 'digraph', 'subgraph', 'strict'} COMPASS = {'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'c', '_'} # TODO def quote(identifier, html=HTML_STRING.match, valid_id=ID.match, dot_keywords=KEYWORDS): """Return DOT identifier from string, quote if needed. >>> quote('') '""' >>> quote('spam') 'spam' >>> quote('spam spam') '"spam spam"' >>> quote('-4.2') '-4.2' >>> quote('.42') '.42' >>> quote('<spam>') '<spam>' >>> quote(nohtml('<>')) '"<>"' """ if html(identifier) and not isinstance(identifier, NoHtml): pass elif not valid_id(identifier) or identifier.lower() in dot_keywords: return '"%s"' % identifier.replace('"', '\\"') return identifier def quote_edge(identifier): """Return DOT edge statement node_id from string, quote if needed. >>> quote_edge('spam') 'spam' >>> quote_edge('spam spam:eggs eggs') '"spam spam":"eggs eggs"' >>> quote_edge('spam:eggs:s') 'spam:eggs:s' """ node, _, rest = identifier.partition(':') parts = [quote(node)] if rest: port, _, compass = rest.partition(':') parts.append(quote(port)) if compass: parts.append(compass) return ':'.join(parts) def a_list(label=None, kwargs=None, attributes=None): """Return assembled DOT a_list string. >>> a_list('spam', {'spam': None, 'ham': 'ham ham', 'eggs': ''}) 'label=spam eggs="" ham="ham ham"' """ result = ['label=%s' % quote(label)] if label is not None else [] if kwargs: items = ['%s=%s' % (quote(k), quote(v)) for k, v in tools.mapping_items(kwargs) if v is not None] result.extend(items) if attributes: if hasattr(attributes, 'items'): attributes = tools.mapping_items(attributes) items = ['%s=%s' % (quote(k), quote(v)) for k, v in attributes if v is not None] result.extend(items) return ' '.join(result) def attr_list(label=None, kwargs=None, attributes=None): """Return assembled DOT attribute list string. Sorts ``kwargs`` and ``attributes`` if they are plain dicts (to avoid unpredictable order from hash randomization in Python 3 versions). >>> attr_list() '' >>> attr_list('spam spam', kwargs={'eggs': 'eggs', 'ham': 'ham ham'}) ' [label="spam spam" eggs=eggs ham="ham ham"]' >>> attr_list(kwargs={'spam': None, 'eggs': ''}) ' [eggs=""]' """ content = a_list(label, kwargs, attributes) if not content: return '' return ' [%s]' % content class NoHtml(object): """Mixin for string subclasses disabling fall-through of ``'<...>'``.""" __slots__ = () _doc = "%s subclass that does not treat ``'<...>'`` as DOT HTML string." @classmethod def _subcls(cls, other): name = '%s_%s' % (cls.__name__, other.__name__) bases = (other, cls) ns = {'__doc__': cls._doc % other.__name__} return type(name, bases, ns) NOHTML = collections.OrderedDict((c, NoHtml._subcls(c)) for c in _compat.string_classes) def nohtml(s): """Return copy of ``s`` that will not treat ``'<...>'`` as DOT HTML string in quoting. Args: s: String in which leading ``'<'`` and trailing ``'>'`` should be treated as literal. Raises: TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2. >>> quote('<>-*-<>') '<>-*-<>' >>> quote(nohtml('<>-*-<>')) '"<>-*-<>"' """ try: subcls = NOHTML[type(s)] except KeyError: raise TypeError('%r does not have one of the required types: %r' % (s, list(NOHTML))) return subcls(s) graphviz-0.8.4/graphviz/tools.py0000666000000000000000000000244513316251122015424 0ustar rootroot# tools.py import os from . import _compat __all__ = ['attach', 'mkdirs', 'mapping_items'] def attach(object, name): """Return a decorator doing ``setattr(object, name)`` with its argument. >>> spam = type('Spam', (object,), {})() >>> @attach(spam, 'eggs') ... def func(): ... pass >>> spam.eggs # doctest: +ELLIPSIS """ def decorator(func): setattr(object, name, func) return func return decorator def mkdirs(filename, mode=0o777): """Recursively create directories up to the path of ``filename`` as needed.""" dirname = os.path.dirname(filename) if not dirname: return _compat.makedirs(dirname, mode=mode, exist_ok=True) def mapping_items(mapping, _iteritems=_compat.iteritems): """Return an iterator over the ``mapping`` items, sort if it's a plain dict. >>> list(mapping_items({'spam': 0, 'ham': 1, 'eggs': 2})) [('eggs', 2), ('ham', 1), ('spam', 0)] >>> from collections import OrderedDict >>> list(mapping_items(OrderedDict(enumerate(['spam', 'ham', 'eggs'])))) [(0, 'spam'), (1, 'ham'), (2, 'eggs')] """ if type(mapping) is dict: return iter(sorted(_iteritems(mapping))) return _iteritems(mapping) graphviz-0.8.4/graphviz/_compat.py0000666000000000000000000000171013316251122015700 0ustar rootroot# _compat.py - Python 2/3 compatibility import os import sys PY2 = sys.version_info.major == 2 if PY2: string_classes = (str, unicode) # needed individually for sublassing text_type = unicode def iteritems(d): return d.iteritems() def makedirs(name, mode=0o777, exist_ok=False): try: os.makedirs(name, mode) except OSError: if not exist_ok or not os.path.isdir(name): raise def stderr_write_binary(data): sys.stderr.write(data) else: string_classes = (str,) text_type = str def iteritems(d): return iter(d.items()) def makedirs(name, mode=0o777, exist_ok=False): # allow os.makedirs mocking return os.makedirs(name, mode, exist_ok=exist_ok) def stderr_write_binary(data): encoding = sys.stderr.encoding or sys.getdefaultencoding() sys.stderr.write(data.decode(encoding)) graphviz-0.8.4/graphviz/__init__.py0000666000000000000000000000257213316254170016032 0ustar rootroot# graphviz - create dot, save, render, view """Assemble DOT source code and render it with Graphviz. >>> dot = Digraph(comment='The Round Table') >>> dot.node('A', 'King Arthur') >>> dot.node('B', 'Sir Bedevere the Wise') >>> dot.node('L', 'Sir Lancelot the Brave') >>> dot.edges(['AB', 'AL']) >>> dot.edge('B', 'L', constraint='false') >>> print(dot) #doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { A [label="King Arthur"] B [label="Sir Bedevere the Wise"] L [label="Sir Lancelot the Brave"] A -> B A -> L B -> L [constraint=false] } """ from .dot import Graph, Digraph from .files import Source from .lang import nohtml from .backend import render, pipe, version, view, ENGINES, FORMATS, ExecutableNotFound __all__ = [ 'Graph', 'Digraph', 'Source', 'nohtml', 'render', 'pipe', 'version', 'view', 'ENGINES', 'FORMATS', 'ExecutableNotFound', ] __title__ = 'graphviz' __version__ = '0.8.4' __author__ = 'Sebastian Bank ' __license__ = 'MIT, see LICENSE.txt' __copyright__ = 'Copyright (c) 2013-2018 Sebastian Bank' #: Set of known layout commands used for rendering (``'dot'``, ``'neato'``, ...) ENGINES = ENGINES #: Set of known output formats for rendering (``'pdf'``, ``'png'``, ...) FORMATS = FORMATS ExecutableNotFound = ExecutableNotFound graphviz-0.8.4/graphviz.egg-info/0000755000000000000000000000000013316607326015406 5ustar rootrootgraphviz-0.8.4/graphviz.egg-info/dependency_links.txt0000666000000000000000000000000113316254574021463 0ustar rootroot graphviz-0.8.4/graphviz.egg-info/PKG-INFO0000666000000000000000000001573313316254574016523 0ustar rootrootMetadata-Version: 2.1 Name: graphviz Version: 0.8.4 Summary: Simple Python interface for Graphviz Home-page: https://github.com/xflr6/graphviz Author: Sebastian Bank Author-email: sebastian.bank@uni-leipzig.de License: MIT Description: Graphviz ======== |PyPI version| |License| |Supported Python| |Format| |Docs| |Travis| |Codecov| This package facilitates the creation and rendering of graph descriptions in the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from Python. Create a graph object, assemble the graph by adding nodes and edges, and retrieve its DOT source code string. Save the source code to a file and render it with the Graphviz installation of your system. Use the ``view`` option/method to directly inspect the resulting (PDF, PNG, SVG, etc.) file with its default application. Graphs can also be rendered and displayed within `Jupyter notebooks`_ (formerly known as `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_. Links ----- - GitHub: https://github.com/xflr6/graphviz - PyPI: https://pypi.org/project/graphviz/ - Documentation: https://graphviz.readthedocs.io - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html - Issue Tracker: https://github.com/xflr6/graphviz/issues - Download: https://pypi.org/project/graphviz/#files Installation ------------ This package runs under Python 2.7, and 3.4+, use pip_ to install: .. code:: bash $ pip install graphviz To render the generated DOT source code, you also need to install Graphviz (`download page`_). Make sure that the directory containing the ``dot`` executable is on your systems' path. Quickstart ---------- Create a graph object: .. code:: python >>> from graphviz import Digraph >>> dot = Digraph(comment='The Round Table') >>> dot #doctest: +ELLIPSIS Add nodes and edges: .. code:: python >>> dot.node('A', 'King Arthur') >>> dot.node('B', 'Sir Bedevere the Wise') >>> dot.node('L', 'Sir Lancelot the Brave') >>> dot.edges(['AB', 'AL']) >>> dot.edge('B', 'L', constraint='false') Check the generated source code: .. code:: python >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE // The Round Table digraph { A [label="King Arthur"] B [label="Sir Bedevere the Wise"] L [label="Sir Lancelot the Brave"] A -> B A -> L B -> L [constraint=false] } Save and render the source code, optionally view the result: .. code:: python >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP 'test-output/round-table.gv.pdf' .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png :align: center See also -------- - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG - graphviz-python_ |--| official Python bindings (documentation_) - pydot_ |--| stable pure-Python approach, requires pyparsing License ------- This package is distributed under the `MIT license`_. .. _pip: https://pip.readthedocs.io .. _Graphviz: https://www.graphviz.org .. _master repo: https://gitlab.com/graphviz/graphviz/ .. _download page: https://www.graphviz.org/download/ .. _DOT: https://www.graphviz.org/doc/info/lang.html .. _Jupyter notebooks: https://jupyter.org .. _IPython notebooks: https://ipython.org/notebook.html .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb .. _Jupyter Qt Console: https://qtconsole.readthedocs.io .. _pygraphviz: https://pypi.org/project/pygraphviz/ .. _graphviz-python: https://pypi.org/project/graphviz-python/ .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf .. _pydot: https://pypi.org/project/pydot/ .. _MIT license: https://opensource.org/licenses/MIT .. |--| unicode:: U+2013 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Latest PyPI Version .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: License .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Supported Python Versions .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg :target: https://pypi.org/project/graphviz/ :alt: Format .. |Docs| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable :target: https://graphviz.readthedocs.io/en/stable/ :alt: Readthedocs .. |Travis| image:: https://img.shields.io/travis/xflr6/graphviz.svg :target: https://travis-ci.org/xflr6/graphviz :alt: Travis .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg :target: https://codecov.io/gh/xflr6/graphviz :alt: Codecov Keywords: graph visualization dot render Platform: any Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Scientific/Engineering :: Visualization Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* Provides-Extra: test Provides-Extra: docs Provides-Extra: dev graphviz-0.8.4/graphviz.egg-info/requires.txt0000666000000000000000000000021413316254574020012 0ustar rootroot [dev] tox>=3.0 flake8 pep8-naming wheel twine [docs] sphinx>=1.3 sphinx-rtd-theme [test] mock>=2 pytest>=3.4 pytest-mock>=1.8 pytest-cov graphviz-0.8.4/graphviz.egg-info/SOURCES.txt0000666000000000000000000000305213316254574017301 0ustar rootrootCHANGES.txt LICENSE.txt MANIFEST.in README.rst requirements.txt run-tests.py setup.cfg setup.py tox.ini try-examples.py docs/api.rst docs/changelog.rst docs/conf.py docs/examples.rst docs/index.rst docs/license.rst docs/manual.rst docs/pet-shop.png docs/requirements.txt docs/round-table.png docs/_static/angles.svg docs/_static/btree.svg docs/_static/cluster.svg docs/_static/cluster_edge.svg docs/_static/diamond.svg docs/_static/er.svg docs/_static/fdpclust.svg docs/_static/fsm.svg docs/_static/g_c_n.svg docs/_static/hello.svg docs/_static/holy-grenade.svg docs/_static/html_table.svg docs/_static/ni.svg docs/_static/pet-shop.svg docs/_static/process.svg docs/_static/qtconsole-source.png docs/_static/qtconsole.png docs/_static/round-table.svg docs/_static/structs.svg docs/_static/structs_revisited.svg docs/_static/traffic_lights.svg docs/_static/unix.svg examples/angles.py examples/btree.py examples/cluster.py examples/cluster_edge.py examples/er.py examples/fdpclust.py examples/fsm.py examples/g_c_n.py examples/hello.py examples/notebook.ipynb examples/process.py examples/structs.py examples/structs_revisited.py examples/traffic_lights.py examples/unix.py graphviz/__init__.py graphviz/_compat.py graphviz/backend.py graphviz/dot.py graphviz/files.py graphviz/lang.py graphviz/tools.py graphviz.egg-info/PKG-INFO graphviz.egg-info/SOURCES.txt graphviz.egg-info/dependency_links.txt graphviz.egg-info/requires.txt graphviz.egg-info/top_level.txt tests/conftest.py tests/test_backend.py tests/test_dot.py tests/test_files.py tests/test_lang.py tests/test_tools.pygraphviz-0.8.4/graphviz.egg-info/top_level.txt0000666000000000000000000000001113316254574020137 0ustar rootrootgraphviz graphviz-0.8.4/tests/0000755000000000000000000000000013316607326013224 5ustar rootrootgraphviz-0.8.4/tests/conftest.py0000666000000000000000000000335513316251124015424 0ustar rootroot# conftest.py import re import sys import platform as _platform import pytest def pytest_addoption(parser): parser.addoption('--skipexe', action='store_true', help='skip tests that run Graphviz executables') def pytest_configure(config): pytest.exe = pytest.mark.skipif(config.getoption('--skipexe'), reason='skipped by --skipexe option') @pytest.fixture(scope='session') def svg_pattern(): return re.compile(r'(?s)^<\?xml .+\s*$') @pytest.fixture(scope='session') def py2(): return sys.version_info.major == 2 @pytest.fixture(scope='session') def test_platform(): return _platform.system().lower() @pytest.fixture(params=['nonplatform', 'darwin', 'freebsd', 'linux', 'windows'], ids=lambda p: 'platform=%r' % p) def platform(monkeypatch, request): monkeypatch.setattr('graphviz.backend.PLATFORM', request.param) yield request.param @pytest.fixture def check_call(mocker): yield mocker.patch('subprocess.check_call') @pytest.fixture def check_output(mocker): yield mocker.patch('subprocess.check_output') @pytest.fixture def Popen(mocker): # noqa: N802 yield mocker.patch('subprocess.Popen') @pytest.fixture def startfile(mocker): yield mocker.patch('os.startfile', create=True) @pytest.fixture def empty_path(monkeypatch): monkeypatch.setenv('PATH', '') @pytest.fixture(params=[False, True], ids=lambda q: 'quiet=%r' % q) def quiet(request): return request.param @pytest.fixture def pipe(mocker): yield mocker.patch('graphviz.backend.pipe') @pytest.fixture def render(mocker): yield mocker.patch('graphviz.backend.render') graphviz-0.8.4/tests/test_backend.py0000666000000000000000000001404113316254202016217 0ustar rootroot# test_backend.py import subprocess import pytest from graphviz.backend import (render, pipe, version, view, ExecutableNotFound, POPEN_KWARGS) def test_render_engine_unknown(): with pytest.raises(ValueError, match=r'engine'): render('', 'pdf', 'nonfilepath') def test_render_format_unknown(): with pytest.raises(ValueError, match=r'format'): render('dot', '', 'nonfilepath') @pytest.mark.usefixtures('empty_path') def test_render_missing_executable(): with pytest.raises(ExecutableNotFound, match=r'execute'): render('dot', 'pdf', 'nonfilepath') @pytest.exe def test_render_missing_file(quiet, engine='dot', format_='pdf'): with pytest.raises(subprocess.CalledProcessError) as e: render(engine, format_, '', quiet=quiet) assert e.value.returncode == 2 @pytest.exe def test_render(capsys, tmpdir, engine='dot', format_='pdf', filename='hello.gv', data=b'digraph { hello -> world }'): lpath = tmpdir / filename lpath.write_binary(data) rendered = lpath.new(ext='%s.%s' % (lpath.ext, format_)) assert render(engine, format_, str(lpath)) == str(rendered) assert rendered.size() assert capsys.readouterr() == ('', '') def test_render_mocked(mocker, check_call, quiet): open_ = mocker.patch('io.open', mocker.mock_open()) mocker.patch('os.devnull', mocker.sentinel.devnull) assert render('dot', 'pdf', 'nonfilepath', quiet=quiet) == 'nonfilepath.pdf' if quiet: open_.assert_called_once_with(mocker.sentinel.devnull, 'w') stderr = open_.return_value else: stderr = None check_call.assert_called_once_with(['dot', '-Tpdf', '-O', 'nonfilepath'], stderr=stderr, **POPEN_KWARGS) @pytest.mark.usefixtures('empty_path') def test_pipe_missing_executable(): with pytest.raises(ExecutableNotFound, match=r'execute'): pipe('dot', 'pdf', b'nongraph') @pytest.exe @pytest.mark.xfail('version() == (2, 36, 0)', reason='https://bugs.launchpad.net/ubuntu/+source/graphviz/+bug/1694108') def test_pipe_invalid_data(capsys, quiet, engine='dot', format_='svg'): with pytest.raises(subprocess.CalledProcessError) as e: pipe(engine, format_, b'nongraph', quiet=quiet) assert e.value.returncode == 1 out, err = capsys.readouterr() assert out == '' if quiet: assert err == '' else: assert 'syntax error' in err @pytest.exe def test_pipe(capsys, svg_pattern, engine='dot', format_='svg', data=b'graph { spam }'): src = pipe(engine, format_, data).decode('ascii') assert svg_pattern.match(src) assert capsys.readouterr() == ('', '') def test_pipe_pipe_invalid_data_mocked(mocker, py2, Popen, quiet): # noqa: N803 stderr = mocker.patch('sys.stderr', new_callable=mocker.NonCallableMock) proc = Popen.return_value proc.returncode = mocker.sentinel.returncode errs = mocker.Mock() proc.communicate.return_value = mocker.sentinel.outs, errs with pytest.raises(subprocess.CalledProcessError) as e: pipe('dot', 'png', b'nongraph', quiet=quiet) assert e.value.returncode is mocker.sentinel.returncode Popen.assert_called_once_with(['dot', '-Tpng'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **POPEN_KWARGS) proc.communicate.assert_called_once_with(b'nongraph') if not quiet: if py2: stderr.write.assert_called_once_with(errs) else: errs.decode.assert_called_once_with(stderr.encoding) stderr.write.assert_called_once_with(errs.decode.return_value) stderr.flush.assert_called_once_with() def test_pipe_mocked(mocker, Popen): # noqa: N803 proc = Popen.return_value proc.returncode = 0 proc.communicate.return_value = mocker.sentinel.outs, mocker.sentinel.errs assert pipe('dot', 'png', b'nongraph') is mocker.sentinel.outs Popen.assert_called_once_with(['dot', '-Tpng'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **POPEN_KWARGS) proc.communicate.assert_called_once_with(b'nongraph') @pytest.mark.usefixtures('empty_path') def test_version_missing_executable(): with pytest.raises(ExecutableNotFound, match=r'execute'): version() @pytest.exe def test_version(capsys): assert version() is not None assert capsys.readouterr() == ('', '') def test_version_parsefail_mocked(check_output): check_output.return_value = b'nonversioninfo' with pytest.raises(RuntimeError): version() check_output.assert_called_once_with(['dot', '-V'], stderr=subprocess.STDOUT, **POPEN_KWARGS) def test_version_mocked(check_output): check_output.return_value = b'dot - graphviz version 1.2.3 (mocked)' assert version() == (1, 2, 3) check_output.assert_called_once_with(['dot', '-V'], stderr=subprocess.STDOUT, **POPEN_KWARGS) def test_view(platform, Popen, startfile): # noqa: N803 if platform == 'nonplatform': with pytest.raises(RuntimeError, match=r'platform'): view('nonfilepath') else: view('nonfilepath') if platform == 'darwin': Popen.assert_called_once_with(['open', 'nonfilepath']) elif platform in ('linux', 'freebsd'): Popen.assert_called_once_with(['xdg-open', 'nonfilepath']) elif platform == 'windows': startfile.assert_called_once_with('nonfilepath') else: raise RuntimeError graphviz-0.8.4/tests/test_dot.py0000666000000000000000000001222013316251124015413 0ustar rootroot# test_dot.py import itertools import pytest from graphviz.dot import Graph, Digraph @pytest.fixture(params=[Graph, Digraph]) def cls(request): return request.param @pytest.fixture(params=list(itertools.permutations([Graph, Digraph], 2)), ids=lambda c: '%s, %s' % (c[0].__name__, c[1].__name__)) def classes(request): return request.param def test_copy(cls): c = cls() assert c.__class__ is cls assert c.copy() is not c assert c.copy() is not c.copy() assert c.copy().__class__ is c.__class__ assert c.copy().__dict__ == c.__dict__ def test__repr_svg_(mocker, cls): c = cls() kwargs = {'return_value.decode.return_value': mocker.sentinel.decoded} pipe = mocker.patch.object(c, 'pipe', new_callable=mocker.Mock, **kwargs) assert c._repr_svg_() is mocker.sentinel.decoded pipe.assert_called_once_with(format='svg') pipe.return_value.decode.assert_called_once_with(c.encoding) @pytest.mark.parametrize('keep_attrs', [False, True]) def test_clear(cls, keep_attrs): kwargs = {'%s_attr' % a: {a: a} for a in ('graph', 'node', 'edge')} c = cls(**kwargs) assert all(getattr(c, k) == v for k, v in kwargs.items()) c.node('spam') assert len(c.body) == 1 body = c.body c.clear(keep_attrs) assert c.body == [] assert c.body is body if keep_attrs: assert all(getattr(c, k) == v for k, v in kwargs.items()) else: assert all(getattr(c, k) == {} for k in kwargs) def test_iter_subgraph_strict(cls): with pytest.raises(ValueError, match=r'strict'): cls().subgraph(cls(strict=True)) def test_iter_strict(): assert Graph(strict=True).source == 'strict graph {\n}' assert Digraph(strict=True).source == 'strict digraph {\n}' def test_attr_invalid_kw(cls): with pytest.raises(ValueError, match=r'attr'): cls().attr('spam') def test_attr_kw_none(): dot = Graph() dot.attr(spam='eggs') assert dot.source == 'graph {\n\tspam=eggs\n}' def test_subgraph_graph_none(): dot = Graph() with dot.subgraph(name='name', comment='comment'): pass assert dot.source == 'graph {\n\t// comment\n\tsubgraph name {\n\t}\n}' def test_subgraph_graph_notsole(cls): with pytest.raises(ValueError, match=r'sole'): cls().subgraph(cls(), name='spam') def test_subgraph_mixed(classes): cls1, cls2 = classes with pytest.raises(ValueError, match=r'kind'): cls1().subgraph(cls2()) def test_subgraph_reflexive(): # guard against potential infinite loop dot = Graph() dot.subgraph(dot) assert dot.source == 'graph {\n\t{\n\t}\n}' def test_subgraph(): s1 = Graph() s1.node('A') s1.node('B') s1.node('C') s1.edge('A', 'B', constraint='false') s1.edges(['AC', 'BC']) s2 = Graph() s2.node('D') s2.node('E') s2.node('F') s2.edge('D', 'E', constraint='false') s2.edges(['DF', 'EF']) dot = Graph() dot.subgraph(s1) dot.subgraph(s2) dot.attr('edge', style='dashed') dot.edges(['AD', 'BE', 'CF']) assert dot.source == '''graph { \t{ \t\tA \t\tB \t\tC \t\tA -- B [constraint=false] \t\tA -- C \t\tB -- C \t} \t{ \t\tD \t\tE \t\tF \t\tD -- E [constraint=false] \t\tD -- F \t\tE -- F \t} \tedge [style=dashed] \tA -- D \tB -- E \tC -- F }''' def test_label_html(): """http://www.graphviz.org/doc/info/shapes.html#html""" dot = Digraph('structs', node_attr={'shape': 'plaintext'}) dot.node('struct1', '''<
left middle right
>''') dot.node('struct2', '''<
one two
>''') dot.node('struct3', '''<
hello
world
b g h
c d e
f
>''') dot.edge('struct1:f1', 'struct2:f0') dot.edge('struct1:f2', 'struct3:here') assert dot.source == '''digraph structs { \tnode [shape=plaintext] \tstruct1 [label=<
left middle right
>] \tstruct2 [label=<
one two
>] \tstruct3 [label=<
hello
world
b g h
c d e
f
>] \tstruct1:f1 -> struct2:f0 \tstruct1:f2 -> struct3:here }''' graphviz-0.8.4/tests/test_files.py0000666000000000000000000001267713316251124015747 0ustar rootroot# test_files.py import locale import pytest from graphviz.files import Source SOURCE = { 'source': 'digraph { hello -> world }', 'filename': 'hello.gv', 'directory': 'test-output', 'format': 'PNG', 'engine': 'NEATO', 'encoding': 'utf-8', } @pytest.fixture(scope='module') def source(): return Source(**SOURCE) def test_format(source): assert not SOURCE['format'].islower() assert source.format == SOURCE['format'].lower() with pytest.raises(ValueError, match=r'format'): source.format = '' def test_engine(source): assert not SOURCE['engine'].islower() assert source.engine == SOURCE['engine'].lower() with pytest.raises(ValueError, match=r'engine'): source.engine = '' def test_encoding(source): assert source.encoding == SOURCE['encoding'] with pytest.raises(LookupError, match=r'encoding'): source.encoding = '' def test_encoding_none(source): source_copy = source.copy() source_copy.encoding = None assert source_copy.encoding == locale.getpreferredencoding() def test_init(source): assert source.source == SOURCE['source'] assert source.filename == SOURCE['filename'] assert source.directory == SOURCE['directory'] def test_init_filename(): assert Source('').filename == 'Source.gv' assert type('Named', (Source,), {'name': 'name'})('').filename == 'name.gv' def test__repr_svg_(mocker, source): kwargs = {'return_value.decode.return_value': mocker.sentinel.decoded} pipe = mocker.patch.object(source, 'pipe', new_callable=mocker.Mock, **kwargs) assert source._repr_svg_() is mocker.sentinel.decoded pipe.assert_called_once_with(format='svg') pipe.return_value.decode.assert_called_once_with(source.encoding) def test_pipe_format(pipe, source, format_='svg'): assert source.format != format_ assert source.pipe(format=format_) is pipe.return_value data = source.source.encode(source.encoding) pipe.assert_called_once_with(source.engine, format_, data) def test_pipe(pipe, source): assert source.pipe() is pipe.return_value data = source.source.encode(source.encoding) pipe.assert_called_once_with(source.engine, source.format, data) def test_filepath(test_platform, source): if test_platform == 'windows': assert source.filepath == 'test-output\\hello.gv' else: assert source.filepath == 'test-output/hello.gv' def test_save(mocker, py2, filename='filename', directory='directory'): source = Source(**SOURCE) makedirs = mocker.patch('os.makedirs', new_callable=mocker.Mock) open_ = mocker.patch('io.open', mocker.mock_open()) assert source.save(filename, directory) == source.filepath assert source.filename == filename and source.directory == directory if py2: makedirs.assert_called_once_with(source.directory, 0o777) else: makedirs.assert_called_once_with(source.directory, 0o777, exist_ok=True) open_.assert_called_once_with(source.filepath, 'w', encoding=source.encoding) assert open_.return_value.write.call_args_list == [((source.source,),), ((u'\n',),)] def test_render(mocker, render, source): save = mocker.patch.object(source, 'save', new_callable=mocker.Mock) _view = mocker.patch.object(source, '_view', new_callable=mocker.Mock) remove = mocker.patch('os.remove', new_callable=mocker.Mock) assert source.render(cleanup=True, view=True) is render.return_value save.assert_called_once_with(None, None) render.assert_called_once_with(source.engine, source.format, save.return_value) remove.assert_called_once_with(save.return_value) _view.assert_called_once_with(render.return_value, source.format) def test_view(mocker, source): render = mocker.patch.object(source, 'render', new_callable=mocker.Mock) kwargs = {'filename': 'filename', 'directory': 'directory', 'cleanup': True} assert source.view(**kwargs) is render.return_value render.assert_called_once_with(view=True, **kwargs) def test__view(mocker, platform, source): if platform == 'nonplatform': with pytest.raises(RuntimeError, match=r'support'): source._view('name', 'png') else: _view_platform = mocker.patch.object(source, '_view_%s' % platform, new_callable=mocker.Mock) assert source._view(mocker.sentinel.name, 'png') is None _view_platform.assert_called_once_with(mocker.sentinel.name) def test_copy(source): assert source.copy() is not source assert source.copy() is not source.copy() assert source.copy().__class__ is source.__class__ assert source.copy().__dict__ == source.__dict__ def test_from_file(tmpdir, filename='hello.gv', directory='source_hello', data=u'digraph { hello -> world }', encoding='utf-8'): lpath = tmpdir.mkdir(directory) (lpath / filename).write_text(data, encoding=encoding) source = Source.from_file(filename, str(lpath)) assert source.encoding == 'utf-8' source = Source.from_file(filename, str(lpath), encoding=None) assert source.encoding == locale.getpreferredencoding() source = Source.from_file(filename, str(lpath), encoding=encoding) assert source.source == data assert source.filename == filename assert source.directory == str(lpath) assert source.encoding == encoding graphviz-0.8.4/tests/test_lang.py0000666000000000000000000000162313316251124015553 0ustar rootroot# test_lang.py import pytest from graphviz.lang import quote, attr_list, nohtml def test_quote_quotes(): assert quote('"spam"') == r'"\"spam\""' def test_quote_keyword(): assert quote('node') == '"node"' assert quote('EDGE') == '"EDGE"' assert quote('Graph') == '"Graph"' def test_attr_list_pairs(): assert attr_list(attributes=[('spam', 'eggs')]) == ' [spam=eggs]' def test_attr_list_map(): assert attr_list(attributes={'spam': 'eggs'}) == ' [spam=eggs]' def test_nohtml(py2): assert nohtml('spam') == 'spam' assert isinstance(nohtml('spam'), str) assert nohtml(u'spam') == u'spam' assert isinstance(nohtml(u'spam'), unicode if py2 else str) def test_nohtml_invalid(py2): match = r"required types.+'str'" if py2: match += r".+'unicode'" with pytest.raises(TypeError, match=match): nohtml(True) graphviz-0.8.4/tests/test_tools.py0000666000000000000000000000165513316251124015777 0ustar rootroot# test_tools.py import os import functools import pytest from graphviz.tools import mkdirs def itertree(root): for path, dirs, files in os.walk(root): base = os.path.relpath(path, root) rel_path = functools.partial(os.path.join, base if base != '.' else '') for is_file, names in [(False, dirs), (True, files)]: for n in names: yield is_file, rel_path(n).replace('\\', '/') def test_mkdirs_invalid(tmpdir): with tmpdir.as_cwd(): (tmpdir / 'spam.eggs').write_binary(b'') with pytest.raises(OSError): mkdirs('spam.eggs/spam') def test_mkdirs(tmpdir): with tmpdir.as_cwd(): mkdirs('spam.eggs') assert list(itertree(str(tmpdir))) == [] for _ in range(2): mkdirs('spam/eggs/spam.eggs') assert list(itertree(str(tmpdir))) == [(False, 'spam'), (False, 'spam/eggs')]