networkx/networkx — pull request #1269 by ysitu (2014-10-13 21:05:56+00:00)
Title: Robust handling of non-int/float/str/dict data in GML

`generate_gml` uses a syntax not in the GML spec to represent lists and tuples. But since the output is not valid GML after all, `parse_gml` fails to consume it:

```python
>>> G = nx.Graph()
>>> G.add_node(0, data=[1, 2, 3])
>>> print('\n'.join(nx.generate_gml(G)))
graph [
node [
id 0
label "0"
data [1, 2, 3]
]
]
>>> nx.parse_gml('\n'.join(nx.generate_gml(G)))
node [
^
Expected "]" (at char 10), (line:2, col:3)
(traceback snipped)
pyparsing.ParseException: Expected "]" (at char 10), (line:2, col:3)
```

#1261 is an attempt to fix the asymmetry. I do not know for sure why @lpand decided to get rid of the pyparsing-based parser. Probably that is because the special syntax used by `generate_gml` causes the grammar to become LL(2)—in order to decide between a dict and a list when a ``'['`` is encountered, the parser also needs to look at the following token.

Although #1261 can be made to work, I feel that a better fix is probably to remove the special syntax. This will enable other GML parsers to handle the output of `generate_gml` without catering to a NetworkX invention. To be specific, the signature of `generate_gml` can be changed to something like

```python
def generate_gml(G, stringizer):
...
```

where ``stringizer`` is a function which converts non-int/float/dict data into strings. Correspondingly, `parse_gml` is changed to something like

```python
def parse_gml(G, destringizer):
...
```

where ``destringizer`` is a function which recovers the original values from the converted strings. An example stringizer–destringizer pair is ``repr`` and ``ast.literal_eval``. The user can use whatever functions that suit his/her needs.