pygraphviz icon indicating copy to clipboard operation
pygraphviz copied to clipboard

Tests fail because of missing png support ???

Open mcepl opened this issue 4 years ago • 4 comments

When packaging pygraphviz 1.7 for openSUSE I get following tests failing:

[   36s] + PYTHONPATH=/home/abuild/rpmbuild/BUILDROOT/python-pygraphviz-1.7-0.x86_64/usr/lib64/python3.9/site-packages
[   36s] + PYTHONDONTWRITEBYTECODE=1
[   36s] + pytest-3.9 --ignore=_build. --ignore=_build.python39 --ignore=_build.python38 -v
[   36s] ============================= test session starts ==============================
[   36s] platform linux -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-0.13.1 -- /usr/bin/python3.9
[   36s] cachedir: .pytest_cache
[   36s] rootdir: /home/abuild/rpmbuild/BUILD/pygraphviz-1.7
[   36s] collecting ... collected 123 items

[ ... remove passing tests ... ]

[   36s] =================================== FAILURES ===================================
[   36s] _________ TestExperimentalGraphvizLibInterface.test_drawing_makes_file _________
[   36s]
[   36s] self = <test_drawing.TestExperimentalGraphvizLibInterface object at 0x7fbcbdb3fa60>
[   36s]
[   36s]     def test_drawing_makes_file(self):
[   36s]         A = pgv.AGraph(name="test graph")
[   36s]         A.add_path([1, 2, 3, 4])
[   36s]         with TemporaryFile() as fh:
[   36s] >           A._draw(fh, format="png", prog="twopi")
[   36s]
[   36s] pygraphviz/tests/test_drawing.py:140:
[   36s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[   36s]
[   36s] self = <AGraph b'test graph' <Swig Object of type 'Agraph_t *' at 0x7fbcbdb8bde0>>
[   36s] path = <_io.BufferedRandom name=11>, format = b'png', prog = b'twopi', args = ''
[   36s]
[   36s]     def _draw(self, path=None, format=None, prog=None, args=""):
[   36s]         """Output graph to path in specified format.
[   36s]
[   36s]         .. caution:: EXPERIMENTAL
[   36s]
[   36s]         This version of the draw command uses libgvc for drawing instead
[   36s]         of command line GraphViz tools like in versions <1.6 and the default.
[   36s]
[   36s]         An attempt will be made to guess the output format based on the file
[   36s]         extension of `path`.  If that fails, then the `format` parameter will
[   36s]         be used.
[   36s]
[   36s]         Note, if `path` is a file object returned by a call to os.fdopen(),
[   36s]         then the method for discovering the format will not work.  In such
[   36s]         cases, one should explicitly set the `format` parameter; otherwise, it
[   36s]         will default to 'dot'.
[   36s]
[   36s]         If path is None, the result is returned as a Bytes object.
[   36s]
[   36s]         Formats (not all may be available on every system depending on
[   36s]         how Graphviz was built)
[   36s]
[   36s]             'canon', 'cmap', 'cmapx', 'cmapx_np', 'dia', 'dot',
[   36s]             'fig', 'gd', 'gd2', 'gif', 'hpgl', 'imap', 'imap_np',
[   36s]             'ismap', 'jpe', 'jpeg', 'jpg', 'mif', 'mp', 'pcl', 'pdf',
[   36s]             'pic', 'plain', 'plain-ext', 'png', 'ps', 'ps2', 'svg',
[   36s]             'svgz', 'vml', 'vmlz', 'vrml', 'vtx', 'wbmp', 'xdot', 'xlib'
[   36s]
[   36s]
[   36s]         If prog is not specified and the graph has positions
[   36s]         (see layout()) then no additional graph positioning will
[   36s]         be performed.
[   36s]
[   36s]         Optional prog=['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop']
[   36s]         will use specified graphviz layout method.
[   36s]
[   36s]         >>> import pygraphviz as pgv
[   36s]         >>> G = pgv.AGraph()
[   36s]         >>> G.add_edges_from([(0, 1), (1, 2), (2, 0), (2, 3)])
[   36s]         >>> G.layout()
[   36s]
[   36s]         # use current node positions, output pdf in 'file.pdf'
[   36s]         >>> G.draw("file.pdf")
[   36s]
[   36s]         # use dot to position, output png in 'file'
[   36s]         >>> G.draw("file", format="png", prog="dot")
[   36s]
[   36s]         # use keyword 'args' to pass additional arguments to graphviz
[   36s]         >>> G.draw("test.pdf", prog="twopi", args="-Gepsilon=1")
[   36s]         >>> G.draw("test2.pdf", args="-Nshape=box -Edir=forward -Ecolor=red ")
[   36s]
[   36s]         The layout might take a long time on large graphs.
[   36s]
[   36s]         """
[   36s]         # try to guess format from extension
[   36s]         if format is None and path is not None:
[   36s]             p = path
[   36s]             # in case we got a file handle get its name instead
[   36s]             if not isinstance(p, str):
[   36s]                 p = path.name
[   36s]             format = os.path.splitext(p)[-1].lower()[1:]
[   36s]
[   36s]         if format is None or format == "":
[   36s]             format = "dot"
[   36s]
[   36s]         if prog is None:
[   36s]             if self.has_layout:
[   36s]                 prog = "neato"
[   36s]                 args += " -n2"
[   36s]             else:
[   36s]                 raise AttributeError(
[   36s]                     """Graph has no layout information, see layout() or specify prog=%s."""
[   36s]                     % ("|".join(["neato", "dot", "twopi", "circo", "fdp", "nop"]))
[   36s]                 )
[   36s]
[   36s]         else:
[   36s]             if self.number_of_nodes() > 1000:
[   36s]                 sys.stderr.write(
[   36s]                     "Warning: graph has %s nodes...layout may take a long time.\n"
[   36s]                     % self.number_of_nodes()
[   36s]                 )
[   36s]
[   36s]         # process args
[   36s]         format, prog = self._manually_parse_args(args, format, prog)
[   36s]
[   36s]         # convert input strings to type bytes (encode it)
[   36s]         if isinstance(format, str):
[   36s]             format = format.encode(self.encoding)
[   36s]         if isinstance(prog, str):
[   36s]             prog = prog.encode(self.encoding)
[   36s]
[   36s]         # Start the drawing
[   36s]         gvc = gv.gvContext()
[   36s]         G = self.handle
[   36s]
[   36s]         # Layout
[   36s]         err = gv.gvLayout(gvc, G, prog)
[   36s]         if err:
[   36s]             if err != -1:
[   36s]                 raise ValueError("Graphviz raised a layout error.")
[   36s]             prog = prog.decode(self.encoding)
[   36s]             raise ValueError(f"Can't find prog={prog} in this graphviz installation")
[   36s]
[   36s]         # Render
[   36s]         if path is None:
[   36s]             out = gv.gvRenderData(gvc, G, format)
[   36s]             if out[0]:
[   36s]                 raise ValueError(f"Graphviz Error creating dot representation:{out[0]}")
[   36s]             err, dot_string, length = out
[   36s]             assert len(dot_string) == length
[   36s]             gv.gvFreeLayout(gvc, G)
[   36s]             gv.gvFreeContext(gvc)
[   36s]             return dot_string
[   36s]
[   36s]         # path is string holding the filename, a file handle, or pathlib.Path
[   36s]         fh = self._get_fh(path, "wb")
[   36s]         err = gv.gvRender(gvc, G, format, fh)
[   36s]         if err:
[   36s] >           raise ValueError("Graphviz raised a render error. Maybe bad format?")
[   36s] E           ValueError: Graphviz raised a render error. Maybe bad format?
[   36s]
[   36s] ../../BUILDROOT/python-pygraphviz-1.7-0.x86_64/usr/lib64/python3.9/site-packages/pygraphviz/agraph.py:1726: ValueError
[   36s] ----------------------------- Captured stderr call -----------------------------
[   36s] Error: renderer for png is unavailable
[   36s] ________ TestExperimentalGraphvizLibInterface.test_drawing_makes_file1 _________
[   36s]
[   36s] self = <test_drawing.TestExperimentalGraphvizLibInterface object at 0x7fbcbdad6a00>
[   36s]
[   36s]     def test_drawing_makes_file1(self):
[   36s]         A = pgv.AGraph(name="test graph")
[   36s]         A.add_path([1, 2, 3, 4])
[   36s]         with TemporaryFile() as fh:
[   36s] >           A._draw(path=fh, prog="circo", format="png")
[   36s]
[   36s] pygraphviz/tests/test_drawing.py:147:
[   36s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[   36s]
[   36s] self = <AGraph b'test graph' <Swig Object of type 'Agraph_t *' at 0x7fbcbdad6d50>>
[   36s] path = <_io.BufferedRandom name=11>, format = b'png', prog = b'circo', args = ''
[   36s]
[   36s]     def _draw(self, path=None, format=None, prog=None, args=""):
[   36s]         """Output graph to path in specified format.
[   36s]
[   36s]         .. caution:: EXPERIMENTAL
[   36s]
[   36s]         This version of the draw command uses libgvc for drawing instead
[   36s]         of command line GraphViz tools like in versions <1.6 and the default.
[   36s]
[   36s]         An attempt will be made to guess the output format based on the file
[   36s]         extension of `path`.  If that fails, then the `format` parameter will
[   36s]         be used.
[   36s]
[   36s]         Note, if `path` is a file object returned by a call to os.fdopen(),
[   36s]         then the method for discovering the format will not work.  In such
[   36s]         cases, one should explicitly set the `format` parameter; otherwise, it
[   36s]         will default to 'dot'.
[   36s]
[   36s]         If path is None, the result is returned as a Bytes object.
[   36s]
[   36s]         Formats (not all may be available on every system depending on
[   36s]         how Graphviz was built)
[   36s]
[   36s]             'canon', 'cmap', 'cmapx', 'cmapx_np', 'dia', 'dot',
[   36s]             'fig', 'gd', 'gd2', 'gif', 'hpgl', 'imap', 'imap_np',
[   36s]             'ismap', 'jpe', 'jpeg', 'jpg', 'mif', 'mp', 'pcl', 'pdf',
[   36s]             'pic', 'plain', 'plain-ext', 'png', 'ps', 'ps2', 'svg',
[   36s]             'svgz', 'vml', 'vmlz', 'vrml', 'vtx', 'wbmp', 'xdot', 'xlib'
[   36s]
[   36s]
[   36s]         If prog is not specified and the graph has positions
[   36s]         (see layout()) then no additional graph positioning will
[   36s]         be performed.
[   36s]
[   36s]         Optional prog=['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop']
[   36s]         will use specified graphviz layout method.
[   36s]
[   36s]         >>> import pygraphviz as pgv
[   36s]         >>> G = pgv.AGraph()
[   36s]         >>> G.add_edges_from([(0, 1), (1, 2), (2, 0), (2, 3)])
[   36s]         >>> G.layout()
[   36s]
[   36s]         # use current node positions, output pdf in 'file.pdf'
[   36s]         >>> G.draw("file.pdf")
[   36s]
[   36s]         # use dot to position, output png in 'file'
[   36s]         >>> G.draw("file", format="png", prog="dot")
[   36s]
[   36s]         # use keyword 'args' to pass additional arguments to graphviz
[   36s]         >>> G.draw("test.pdf", prog="twopi", args="-Gepsilon=1")
[   36s]         >>> G.draw("test2.pdf", args="-Nshape=box -Edir=forward -Ecolor=red ")
[   36s]
[   36s]         The layout might take a long time on large graphs.
[   36s]
[   36s]         """
[   36s]         # try to guess format from extension
[   36s]         if format is None and path is not None:
[   36s]             p = path
[   36s]             # in case we got a file handle get its name instead
[   36s]             if not isinstance(p, str):
[   36s]                 p = path.name
[   36s]             format = os.path.splitext(p)[-1].lower()[1:]
[   36s]
[   36s]         if format is None or format == "":
[   36s]             format = "dot"
[   36s]
[   36s]         if prog is None:
[   36s]             if self.has_layout:
[   36s]                 prog = "neato"
[   36s]                 args += " -n2"
[   36s]             else:
[   36s]                 raise AttributeError(
[   36s]                     """Graph has no layout information, see layout() or specify prog=%s."""
[   36s]                     % ("|".join(["neato", "dot", "twopi", "circo", "fdp", "nop"]))
[   36s]                 )
[   36s]
[   36s]         else:
[   36s]             if self.number_of_nodes() > 1000:
[   36s]                 sys.stderr.write(
[   36s]                     "Warning: graph has %s nodes...layout may take a long time.\n"
[   36s]                     % self.number_of_nodes()
[   36s]                 )
[   36s]
[   36s]         # process args
[   36s]         format, prog = self._manually_parse_args(args, format, prog)
[   36s]
[   36s]         # convert input strings to type bytes (encode it)
[   36s]         if isinstance(format, str):
[   36s]             format = format.encode(self.encoding)
[   36s]         if isinstance(prog, str):
[   36s]             prog = prog.encode(self.encoding)
[   36s]
[   36s]         # Start the drawing
[   36s]         gvc = gv.gvContext()
[   36s]         G = self.handle
[   36s]
[   36s]         # Layout
[   36s]         err = gv.gvLayout(gvc, G, prog)
[   36s]         if err:
[   36s]             if err != -1:
[   36s]                 raise ValueError("Graphviz raised a layout error.")
[   36s]             prog = prog.decode(self.encoding)
[   36s]             raise ValueError(f"Can't find prog={prog} in this graphviz installation")
[   36s]
[   36s]         # Render
[   36s]         if path is None:
[   36s]             out = gv.gvRenderData(gvc, G, format)
[   36s]             if out[0]:
[   36s]                 raise ValueError(f"Graphviz Error creating dot representation:{out[0]}")
[   36s]             err, dot_string, length = out
[   36s]             assert len(dot_string) == length
[   36s]             gv.gvFreeLayout(gvc, G)
[   36s]             gv.gvFreeContext(gvc)
[   36s]             return dot_string
[   36s]
[   36s]         # path is string holding the filename, a file handle, or pathlib.Path
[   36s]         fh = self._get_fh(path, "wb")
[   36s]         err = gv.gvRender(gvc, G, format, fh)
[   36s]         if err:
[   36s] >           raise ValueError("Graphviz raised a render error. Maybe bad format?")
[   36s] E           ValueError: Graphviz raised a render error. Maybe bad format?
[   36s]
[   36s] ../../BUILDROOT/python-pygraphviz-1.7-0.x86_64/usr/lib64/python3.9/site-packages/pygraphviz/agraph.py:1726: ValueError
[   36s] ----------------------------- Captured stderr call -----------------------------
[   36s] Error: renderer for png is unavailable
[   36s] ___________________________ test_drawing_makes_file ____________________________
[   36s]
[   36s]     def test_drawing_makes_file():
[   36s]         A = pgv.AGraph(name="test graph")
[   36s]         A.add_path([1, 2, 3, 4])
[   36s]         with TemporaryFile() as fh:
[   36s] >           A.draw(fh, format="png", prog="twopi")
[   36s]
[   36s] pygraphviz/tests/test_drawing.py:30:
[   36s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[   36s] ../../BUILDROOT/python-pygraphviz-1.7-0.x86_64/usr/lib64/python3.9/site-packages/pygraphviz/agraph.py:1596: in draw
[   36s]     data = self._run_prog(prog, args)
[   36s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[   36s]
[   36s] self = <AGraph b'test graph' <Swig Object of type 'Agraph_t *' at 0x7fbcbd773c90>>
[   36s] prog = 'twopi', args = ' -Tpng'
[   36s]
[   36s]     def _run_prog(self, prog="nop", args=""):
[   36s]         """Apply graphviz program to graph and return the result as a string.
[   36s]
[   36s]         >>> import pygraphviz as pgv
[   36s]         >>> A = pgv.AGraph()
[   36s]         >>> s = A._run_prog()  # doctest: +SKIP
[   36s]         >>> s = A._run_prog(prog="acyclic")  # doctest: +SKIP
[   36s]
[   36s]         Use keyword args to add additional arguments to graphviz programs.
[   36s]         """
[   36s]         runprog = r'"%s"' % self._get_prog(prog)
[   36s]         cmd = " ".join([runprog, args])
[   36s]         dotargs = shlex.split(cmd)
[   36s]         p = subprocess.Popen(
[   36s]             dotargs,
[   36s]             shell=False,
[   36s]             stdin=subprocess.PIPE,
[   36s]             stdout=subprocess.PIPE,
[   36s]             stderr=subprocess.PIPE,
[   36s]             close_fds=False,
[   36s]         )
[   36s]         (child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr)
[   36s]         # Use threading to avoid blocking
[   36s]         data = []
[   36s]         errors = []
[   36s]         threads = [PipeReader(data, child_stdout), PipeReader(errors, child_stderr)]
[   36s]         for t in threads:
[   36s]             t.start()
[   36s]
[   36s]         self.write(child_stdin)
[   36s]         child_stdin.close()
[   36s]
[   36s]         for t in threads:
[   36s]             t.join()
[   36s]         p.wait()
[   36s]
[   36s]         if not data:
[   36s] >           raise OSError(b"".join(errors).decode(self.encoding))
[   36s] E           OSError: Format: "png" not recognized. Use one of: canon cmap cmapx cmapx_np dot dot_json eps fig gv imap imap_np ismap json json0 mp pic plain plain-ext pov ps ps2 svg svgz tk vml vmlz xdot xdot1.2 xdot1.4 xdot_json
[   36s]
[   36s] ../../BUILDROOT/python-pygraphviz-1.7-0.x86_64/usr/lib64/python3.9/site-packages/pygraphviz/agraph.py:1387: OSError
[   36s] =========================== short test summary info ============================
[   36s] FAILED pygraphviz/tests/test_drawing.py::TestExperimentalGraphvizLibInterface::test_drawing_makes_file
[   36s] FAILED pygraphviz/tests/test_drawing.py::TestExperimentalGraphvizLibInterface::test_drawing_makes_file1
[   36s] FAILED pygraphviz/tests/test_drawing.py::test_drawing_makes_file - OSError: F...
[   36s] =================== 3 failed, 119 passed, 1 skipped in 0.67s ===================

Complete build log

mcepl avatar Oct 19 '21 22:10 mcepl

The graphviz build must not include support for png files. In part of your log, our docstring talks about that and those words come from the Graphviz docs. The docstring says:

Formats (not all may be available on every system depending on how Graphviz was built
[   36s]             'canon', 'cmap', 'cmapx', 'cmapx_np', 'dia', 'dot',
[   36s]             'fig', 'gd', 'gd2', 'gif', 'hpgl', 'imap', 'imap_np',
[   36s]             'ismap', 'jpe', 'jpeg', 'jpg', 'mif', 'mp', 'pcl', 'pdf',
[   36s]             'pic', 'plain', 'plain-ext', 'png', 'ps', 'ps2', 'svg',
[   36s]             'svgz', 'vml', 'vmlz', 'vrml', 'vtx', 'wbmp', 'xdot', 'xlib'

I'm not sure how openSUSE packages graphviz, but if possible, find a package of graphviz that includes support for png files. ??? maybe ???

dschult avatar Oct 19 '21 23:10 dschult

The graphviz build must not include support for png files. In part of your log, our docstring talks about that and those words come from the Graphviz docs. The docstring says:

My point was that the test suite should skip those tests when png support is not available and not fail them.

mcepl avatar Oct 20 '21 05:10 mcepl

That would be nice. Do you happen to know a reasonable way to check if that support is available? Otherwise we'll look for it...

Thanks!

dschult avatar Oct 20 '21 13:10 dschult

Sorry, no idea. I am not that much into graphviz anyway, I am a maintainer of Python packages for openSUSE so I got to this only because this package is failing to build.

mcepl avatar Oct 20 '21 14:10 mcepl