Repository: networkx/networkx
Pull request: Modify GML test to fix invalid octal character warning.
Closes #7149

Problem statement:
networkx-3.2.1_1: /usr/lib/python3.12/site-packages/networkx/readwrite/tests/test_gml.py:557: SyntaxWarning: invalid octal escape sequence '\420'
Installing through distribution package manager, at the *"Byte-compiling python3.12 code for module networkx..."* stage, the following errors are reported:

```
python3-networkx-3.2.1_1: configuring ...
Byte-compiling python3.12 code for module networkx...
usr/lib/python3.12/site-packages/networkx/readwrite/tests/test_gml.py:557: SyntaxWarning: invalid octal escape sequence '\420'
  "graph [edge [ source u'u\4200' target u'u\4200' ] "
usr/lib/python3.12/site-packages/networkx/readwrite/tests/test_gml.py:558: SyntaxWarning: invalid octal escape sequence '\420'
  + "node [ id u'u\4200' label b ] ]"
usr/lib/python3.12/site-packages/networkx/readwrite/tests/test_gml.py:557: SyntaxWarning: invalid octal escape sequence '\420'
  "graph [edge [ source u'u\4200' target u'u\4200' ] "
usr/lib/python3.12/site-packages/networkx/readwrite/tests/test_gml.py:558: SyntaxWarning: invalid octal escape sequence '\420'
  + "node [ id u'u\4200' label b ] ]"
```

Hints from issue discussion:
Hmm, which package manager is this? We only package pypi and conda-forge.
It's installed through my Linux distribution's package manager as some other package's sub-dependency. But that doesn't matter, because the issue can be easily found here 

https://github.com/networkx/networkx/blob/9cc8b422a512e7e7819238d597fd6815ec9c1c8e/networkx/readwrite/tests/test_gml.py#L557

*Don't shoot the messenger!* Paste that string into the Python REPL:

```
Python 3.12.0 (main, Oct  6 2023, 16:16:58) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print( "graph [edge [ source u'u\4200' target u'u\4200' ] " )
<stdin>:1: SyntaxWarning: invalid octal escape sequence '\420'
```

The code is broken, namely some escape sequences written incorrectly.
Yeah thanks for the report!
It's just weird our tests (or us) didn't catch this, we had similar issues https://github.com/networkx/networkx/issues/7064, https://github.com/networkx/networkx/issues/7032 before which were fixed.

Which linux distribution is this? How did you arrive at this step? (just trying to debug this)
It's Voidlinux. Their basic philosophy is, to take upstream as is with zero custom patches. On my system `networkx` is pulled in as a dependency of `python3-scikit-image`
Interesting that the syntax warning says the octal sequence is `\420` when the actual string says `\4200`

Commit message: Modify GML test to fix invalid octal character warning.

Patch to review:
diff --git a/networkx/readwrite/tests/test_gml.py b/networkx/readwrite/tests/test_gml.py
index 869b21f6bb2..ab7f20fb84e 100644
--- a/networkx/readwrite/tests/test_gml.py
+++ b/networkx/readwrite/tests/test_gml.py
@@ -554,8 +554,8 @@ def assert_parse_error(gml):
             "directed 1 multigraph 1 ]"
         )
         assert_parse_error(
-            "graph [edge [ source u'u\4200' target u'u\4200' ] "
-            + "node [ id u'u\4200' label b ] ]"
+            "graph [edge [ source u'u\\4200' target u'u\\4200' ] "
+            + "node [ id u'u\\4200' label b ] ]"
         )
 
         def assert_generate_error(*args, **kwargs):


Code review comments:
diff_hunk: @@ -554,8 +554,8 @@ def assert_parse_error(gml):
             "directed 1 multigraph 1 ]"
         )
         assert_parse_error(
-            "graph [edge [ source u'u\4200' target u'u\4200' ] "
-            + "node [ id u'u\4200' label b ] ]"
+            "graph [edge [ source u'u\\4200' target u'u\\4200' ] "
+            + "node [ id u'u\\4200' label b ] ]"
path: networkx/readwrite/tests/test_gml.py
text: @user1:
I'm not too sure what is even being tested here?

``` python
>>> gml = "graph [edge [ source wow target wow ] node [ id wow label lol ]]"
>>> nx.parse_gml(gml)._adj
{'lol': {'lol': {}}}
>>>  gml = "graph [edge [ source wow target wow ] node [ id wow label 䈀 ]]"
>>> nx.parse_gml(gml)._adj
...
...
NetworkXError: cannot tokenize 䈀 ]] at (1, 59)
```

Why can't a unicode character just be tokenised like a string? The GML parser doesn't seem right here?

This was added in https://github.com/networkx/networkx/pull/3603/

@author:
> Why can't a unicode character just be tokenised like a string? The GML parser doesn't seem right here?

I don't know - maybe gml only supports a limited unicode character range (or ascii only)?

FWIW there's a slightly more informative chained exception with the following:

```python
# Taken directly from the updated test:
>>> gml = "graph [edge [ source u'u\\4200' target u'u\\4200' ] node [ id u'u\\4200' label b ] ]"
Traceback (most recent call last)
   ...
NetworkXError: cannot tokenize 'u\4200' target u'u\4200' ] node [ id u'u\4200' label b ] ] at (1, 23)

During handling of the above exception, another exception occurred:

Traceback (most recent call last)
   ...
NetworkXError: expected an int, float, string, '[' or string convertible ASCII value for node id or label, found 'u' at (1, 22)
```

@user2:
The link on our docs (which is a webarchive link) has a link to [a technical report pdf](https://web.archive.org/web/20190303094704/http://www.fim.uni-passau.de/fileadmin/files/lehrstuhl/brandenburg/projekte/gml/gml-technical-report.pdf) whcih on page two says:

> Further reglementations are a maximum line length and a maximum key size of 254 characters (this is necessary since some operating systems and editors do not handle longer lines), and the use of 7-bit ASCII characters only. Any other characters are coded in the ISO 8859-1 character set, and have the form &name;. Especially, the characters " and & within strings must be coded this way to avoid ambiguity. The ISO 8859-1 ist also used by HTML, which is the most common format for distributing data on the world wide web.

So if we want unicode, I think the preferred option is to store it in ASCII form by converting it to [ISO 8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1) which is a pretty restricted set of characters compared to unicode.  If we want to store unicode more generally, we can break the GML minimal standard by writing and reading some other thing. Our [current parser](https://github.com/networkx/networkx/blob/1c2fa4b9372df1a1428444d89fe6a72359e1a2cb/networkx/readwrite/gml.py#L312) doesn't seem to handle unicode explicitly.  

So then... what is this test doing?  I think it is trying to test that we are using a string with a unicode character **not** represented properly.

I propose that we make this:  `  ...  '\u4200'` as that is IIC a standard python way to represent the unicode character with code 4200. Does this make any sense? I am way out of my wheelhouse here. :}

@user1:
> I propose that we make this:   ...  '\u4200' as that is IIC a standard python way to represent the unicode character with code 4200. Does this make any sense? I am way out of my wheelhouse here. :}

Yes I think that's sounds good for now. I guess the first priority here is to fix the syntaxwarning.

@author:
> I propose that we make this:   ...  '\u4200' as that is IIC a standard python way to represent the unicode character with code 4200. Does this make any sense? I am way out of my wheelhouse here. :}

The test is an `assert_parse_error` test, i.e. checking that the nx gml parser *fails* to read the line correctly... Funnily enough all three proposals (`u\4200`, `u\\4200` and `\u4200`) pass the test :upside_down_face: . So there likely is a deeper issue with the gml parser tokenization - but for the purposes of fixing the syntax warning, I switched to `\u4200` in e5e528c

@user2:
The GML technical doc explicitly says it does NOT support unicode (must be converted to html style 8859-1 chars like &amp).  So I think we want to put in valid unicode and check that it doesn't work.

Do we need the `u` in front of the single quotes?  I think we should probs remove them too (?? python2 historical cruft??).

@author:
>  So I think we want to put in valid unicode and check that it doesn't work.

Sounds good - as of e5e528c the `\u4200` values are valid unicode characters!

> Do we need the u in front of the single quotes? I think we should probs remove them too (?? python2 historical cruft??).

Nope, those are no longer necessary either - removed in 62887bd