Source: python-pygraphviz
Version: 1.4~rc1-1+b2
Severity: grave
Tags: patch
Justification: renders package unusable

Hi,

steps to reproduce:

$ python3 --version
Python 3.7.1
$ python3 -c 'import pygraphviz; A=pygraphviz.AGraph(); A.graph_attr.keys()'
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pygraphviz/agraph.py", line 1743, in 
iteritems
    ah = gv.agnxtattr(self.handle, self.type, ah)
StopIteration: agnxtattr

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/pygraphviz/agraph.py", line 1733, in keys
    return list(self.__iter__())
  File "/usr/lib/python3/dist-packages/pygraphviz/agraph.py", line 1736, in 
__iter__
    for (k, v) in self.iteritems():
RuntimeError: generator raised StopIteration

This problem does not happen with snapshot 20181121T102052Z but does
happen with snapshot 20181121T232318Z. There is only one change between
chroots made from these two snapshots, the following packages have been
upgraded from version 3.6.7-1 to 3.7.1-1:

libpython3-stdlib, libpython3.6-minimal, libpython3.6-stdlib, python3,
python3-minimal, python3.6, python3.6-minimal

Thus I conclude that this problem was introduced because of the upgrade
of Python from 3.6 to 3.7.

Upstream has a fix here:

https://github.com/pygraphviz/pygraphviz/commit/b5df022700669ae496f65d20dd9cd387d6af948e

I backported that commit on top of the version of python-pygraphviz from
Debian unstable. Please find the patch attached.

I see that this package did not see an upload since January 2017. If you
are okay with me NMU-ing the package for this fix, then please tell me.

Alternatively, this bug can also be fixed by packaging the latest
upstream version 1.5 of pygraphviz which includes the above commit.

Thanks!

cheers, josch
diff -Nru python-pygraphviz-1.4~rc1/debian/changelog 
python-pygraphviz-1.4~rc1/debian/changelog
--- python-pygraphviz-1.4~rc1/debian/changelog  2017-01-08 21:03:20.000000000 
+0100
+++ python-pygraphviz-1.4~rc1/debian/changelog  2018-11-22 19:31:03.000000000 
+0100
@@ -1,3 +1,10 @@
+python-pygraphviz (1.4~rc1-1.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix StopIteration with Python 3.7
+
+ -- Johannes 'josch' Schauer <jo...@debian.org>  Thu, 22 Nov 2018 19:31:03 
+0100
+
 python-pygraphviz (1.4~rc1-1) unstable; urgency=medium
 
   * New upstream release candidate
diff -Nru 
python-pygraphviz-1.4~rc1/debian/patches/catch_stopiterations_created_by_c_code 
python-pygraphviz-1.4~rc1/debian/patches/catch_stopiterations_created_by_c_code
--- 
python-pygraphviz-1.4~rc1/debian/patches/catch_stopiterations_created_by_c_code 
    1970-01-01 01:00:00.000000000 +0100
+++ 
python-pygraphviz-1.4~rc1/debian/patches/catch_stopiterations_created_by_c_code 
    2018-11-22 19:30:55.000000000 +0100
@@ -0,0 +1,174 @@
+From b5df022700669ae496f65d20dd9cd387d6af948e Mon Sep 17 00:00:00 2001
+From: Dan Schult <dsch...@colgate.edu>
+Date: Thu, 2 Aug 2018 21:32:47 -0400
+Subject: [PATCH] catch StopIterations created by C code
+
+--- a/pygraphviz/agraph.py
++++ b/pygraphviz/agraph.py
+@@ -374,8 +374,10 @@ class AGraph(object):
+         nh = gv.agfstnode(self.handle)
+         while nh is not None:
+             yield Node(self, nh=nh)
+-            nh = gv.agnxtnode(self.handle, nh)
+-        raise StopIteration
++            try:
++                nh = gv.agnxtnode(self.handle, nh)
++            except StopIteration:
++                return
+ 
+     iternodes = nodes_iter
+ 
+@@ -597,8 +599,10 @@ class AGraph(object):
+                 yield Node(self, t)
+             else:
+                 yield Node(self, s)
+-            eh = gv.agnxtedge(self.handle, eh, nh)
+-        raise StopIteration
++            try:
++                eh = gv.agnxtedge(self.handle, eh, nh)
++            except StopIteration:
++                return
+ 
+     def neighbors(self, n):
+         """Return a list of the nodes attached to n."""
+@@ -627,8 +631,14 @@ class AGraph(object):
+                         yield (e[0], e[1], e.name)
+                     else:
+                         yield e
+-                    eh = gv.agnxtout(self.handle, eh)
+-                nh = gv.agnxtnode(self.handle, nh)
++                    try:
++                        eh = gv.agnxtout(self.handle, eh)
++                    except StopIteration:
++                        break
++                try:
++                    nh = gv.agnxtnode(self.handle, nh)
++                except StopIteration:
++                    return
+         elif nbunch in self: # if nbunch is a single node
+             n = Node(self, nbunch)
+             nh = n.handle
+@@ -639,7 +649,10 @@ class AGraph(object):
+                     yield (e[0], e[1], e.name)
+                 else:
+                     yield e
+-                eh = gv.agnxtout(self.handle, eh)
++                try:
++                    eh = gv.agnxtout(self.handle, eh)
++                except StopIteration:
++                    return
+         else:                # if nbunch is a sequence of nodes
+             try:
+                 bunch = [n for n in nbunch if n in self]
+@@ -657,8 +670,10 @@ class AGraph(object):
+                         yield (e[0], e[1], e.name)
+                     else:
+                         yield e
+-                    eh = gv.agnxtout(self.handle, eh)
+-        raise StopIteration
++                    try:
++                        eh = gv.agnxtout(self.handle, eh)
++                    except StopIteration:
++                        break
+ 
+ 
+     iteroutedges = out_edges_iter
+@@ -683,8 +698,14 @@ class AGraph(object):
+                         yield (e[0], e[1], e.name)
+                     else:
+                         yield e
+-                    eh = gv.agnxtin(self.handle, eh)
+-                nh = gv.agnxtnode(self.handle, nh)
++                    try:
++                        eh = gv.agnxtin(self.handle, eh)
++                    except StopIteration:
++                        break
++                try:
++                    nh = gv.agnxtnode(self.handle, nh)
++                except StopIteration:
++                    return
+         elif nbunch in self: # if nbunch is a single node
+             n = Node(self, nbunch)
+             nh = n.handle
+@@ -695,7 +716,10 @@ class AGraph(object):
+                     yield (e[0], e[1], e.name)
+                 else:
+                     yield e
+-                eh = gv.agnxtin(self.handle, eh)
++                try:
++                    eh = gv.agnxtin(self.handle, eh)
++                except StopIteration:
++                    break
+         else:                # if nbunch is a sequence of nodes
+             try:
+                 bunch = [n for n in nbunch if n in self]
+@@ -713,8 +737,10 @@ class AGraph(object):
+                         yield (e[0], e[1], e.name)
+                     else:
+                         yield e
+-                    eh = gv.agnxtin(self.handle, eh)
+-        raise StopIteration
++                    try:
++                        eh = gv.agnxtin(self.handle, eh)
++                    except StopIteration:
++                        break
+ 
+     def edges_iter(self, nbunch=None, keys=False):
+         """Return iterator over edges in the graph.
+@@ -780,8 +806,10 @@ class AGraph(object):
+                 yield Node(self, t)
+             else:
+                 yield Node(self, s)
+-            eh = gv.agnxtin(self.handle, eh)
+-        raise StopIteration
++            try:
++                eh = gv.agnxtin(self.handle, eh)
++            except StopIteration:
++                return
+ 
+ 
+     iterpred = predecessors_iter
+@@ -802,8 +830,10 @@ class AGraph(object):
+                 yield Node(self, t)
+             else:
+                 yield Node(self, s)
+-            eh = gv.agnxtout(self.handle, eh)
+-        raise StopIteration
++            try:
++                eh = gv.agnxtout(self.handle, eh)
++            except StopIteration:
++                return
+ 
+     itersucc = successors_iter
+ 
+@@ -1089,8 +1119,10 @@ class AGraph(object):
+             yield self.__class__(strict=self.strict,
+                                  directed=self.directed,
+                                  handle=handle)
+-            handle = gv.agnxtsubg(handle)
+-        raise StopIteration
++            try:
++                handle = gv.agnxtsubg(handle)
++            except StopIteration:
++                return
+ 
+     def subgraphs(self):
+         """Return a list of all subgraphs in the graph."""
+@@ -1745,6 +1777,8 @@ class Attribute(MutableMapping):
+                        gv.agattrdefval(ah).decode(self.encoding))
+             except KeyError: # gv.agattrdefval returned KeyError, skip
+                 continue
++            except StopIteration:  # gv.agnxtattr is done, as are we
++                return
+ 
+ 
+ class ItemAttribute(Attribute):
+@@ -1816,6 +1850,8 @@ class ItemAttribute(Attribute):
+                        value.decode(self.encoding))
+             except KeyError: # gv.agxget returned KeyError, skip
+                 continue
++            except StopIteration:  # gv.agnxtattr is done, as are we
++                return
+ 
+ def _test_suite():
+     import doctest
diff -Nru python-pygraphviz-1.4~rc1/debian/patches/series 
python-pygraphviz-1.4~rc1/debian/patches/series
--- python-pygraphviz-1.4~rc1/debian/patches/series     2017-01-08 
21:03:20.000000000 +0100
+++ python-pygraphviz-1.4~rc1/debian/patches/series     2018-11-22 
19:19:32.000000000 +0100
@@ -1 +1,2 @@
 dont_install_data.patch
+catch_stopiterations_created_by_c_code

Reply via email to