Skip to content

gh-151303 : Improve SyntaxError suggestions for common operator typos and cross-language mistakes#151375

Open
Aniketsy wants to merge 11 commits into
python:mainfrom
Aniketsy:fix-151303
Open

gh-151303 : Improve SyntaxError suggestions for common operator typos and cross-language mistakes#151375
Aniketsy wants to merge 11 commits into
python:mainfrom
Aniketsy:fix-151303

Conversation

@Aniketsy

@Aniketsy Aniketsy commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

@skirpichev

This comment was marked as resolved.

Comment thread Grammar/python.gram Outdated
Comment thread Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-03-41-39.gh-issue-151303.mzlJxi.rst Outdated
Comment thread Grammar/python.gram Outdated
| invalid_eqeqeq

invalid_diamond_op:
| a='<' b='>' { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '!=' instead of '<>'?") }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this break when __future__.CO_FUTURE_BARRY_AS_BDFL is true?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm , yes

aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "
__futu> from __future__ import barry_as_FLUFL
> 1 < > 2
> "
  File "<string>", line 3
    1 < > 2
      ^^^
SyntaxError: invalid syntax.  Maybe you meant '!=' instead of '<>'?

please let me know your thoughts on this ...

aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ git diff Grammar/python.gram
diff --git a/Grammar/python.gram b/Grammar/python.gram
index 61a6d5ea90..19ef406437 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -805,7 +805,11 @@ compare_op_bitwise_or_pair[CmpopExprPair*]:
     | invalid_eqeqeq

 invalid_diamond_op:
-    | a='<' b='>' { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax.  Maybe you meant '!=' instead of '<>'?") }
+    | a='<' b='>' {
+        (p->flags & PyPARSE_BARRY_AS_BDFL)
+        ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax.  Maybe you meant '<>' instead of '< >'?")
+        : RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax.  Maybe you meant '!=' instead of '<>'?")
+    }
 eq_bitwise_or[CmpopExprPair*]: '==' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Eq, a) }
 invalid_eqeqeq:
     | a='==' b='=' { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax.  Maybe you meant '==' instead of '==='?") }

output:

aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "1 < > 2"
  File "<string>", line 1
    1 < > 2
      ^^^
SyntaxError: invalid syntax.  Maybe you meant '!=' instead of '<>'?
aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "
__futu> from __future__ import barry_as_FLUFL
> 1 < > 2
> "
  File "<string>", line 3
    1 < > 2
      ^^^
SyntaxError: invalid syntax.  Maybe you meant '<>' instead of '< >'?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, yes

No, this example doesn't break __future__ import. But I suspect, that __future__.CO_FUTURE_BARRY_AS_BDFL is the reason that your code doesn't work without spaces. This can be "fixed" by this patch:

diff --git a/Tools/build/generate_token.py b/Tools/build/generate_token.py
index 9ee5ec86e75..28a0ce1ff78 100755
--- a/Tools/build/generate_token.py
+++ b/Tools/build/generate_token.py
@@ -178,7 +178,7 @@ def generate_chars_to_token(mapping, n=1):
 
 def make_c(infile, outfile='Parser/token.c'):
     tok_names, ERRORTOKEN, string_to_tok = load_tokens(infile)
-    string_to_tok['<>'] = string_to_tok['!=']
+#   string_to_tok['<>'] = string_to_tok['!=']
     chars_to_token = {}
     for string, value in string_to_tok.items():
         assert 1 <= len(string) <= 3

Look at the difference:

$ cat a.py
1 =! 2
$ cat a.py | ./python -m tokenize
1,0-1,1:            NUMBER         '1'            
1,2-1,3:            OP             '='            
1,3-1,4:            OP             '!'            
1,5-1,6:            NUMBER         '2'            
1,6-1,7:            NEWLINE        '\n'           
2,0-2,0:            ENDMARKER      ''             

vs

$ cat a.py
1 <> 2
$ cat a.py | ./python -m tokenize
1,0-1,1:            NUMBER         '1'            
1,2-1,4:            OP             '<>'           
1,5-1,6:            NUMBER         '2'            
1,6-1,7:            NEWLINE        '\n'           
2,0-2,0:            ENDMARKER      ''             

Regardless on a joke, it looks as a tokenizer bug. I'll open a separate issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for looking into this, i'll revert the changes

@StanFromIreland StanFromIreland Jun 14, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this example doesn't break future import.

It still does break it, we're suggesting != for < > which is invalid syntax when __future__.CO_FUTURE_BARRY_AS_BDFL is true.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is wrong, see my comment below. But nothing to do with __future__.barry_as_FLUFL.

Currently, we have a hidden token (<> is alias for !=) in the grammar. So, this patch will not produce an error without a space between. See #151464.

Comment thread Grammar/python.gram Outdated
@skirpichev

This comment was marked as resolved.

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like in the previous PR, check that there is no gap between tokens.

Comment thread Grammar/python.gram Outdated
Comment thread Lib/test/test_syntax.py Outdated

def test_diamond_operator(self):
self._check_error(
"1 < > 2",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should not be space in the middle.

Comment thread Grammar/python.gram Outdated
Comment thread Grammar/python.gram Outdated
Comment thread Grammar/python.gram Outdated
Comment thread Lib/test/test_syntax.py
Comment thread Lib/test/test_syntax.py
Comment thread Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-03-41-39.gh-issue-151303.mzlJxi.rst Outdated
@Aniketsy

Copy link
Copy Markdown
Contributor Author

@skirpichev thanks for the review, i've updated with helper function

Comment thread Lib/test/test_syntax.py
Comment thread Parser/action_helpers.c Outdated
Comment on lines +934 to +937
if (strcmp(tok_str, "<>") == 0) {
RAISE_SYNTAX_ERROR("invalid syntax. Are you trying to overthrow the SC? Use operator \"!=\"!");
return -1;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer not use this workaround for #151464. Leave "<>" case for another PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should i revert the changes for this case ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my suggestion, yes.

@serhiy-storchaka

Copy link
Copy Markdown
Member

We wait for other PR to be merged first.

@serhiy-storchaka

Copy link
Copy Markdown
Member

For future -- never use rebase, amend and force-push. This forces us to review the entire PR from the beginning, instead of just the new changes.

@Aniketsy

Copy link
Copy Markdown
Contributor Author

For future -- never use rebase, amend and force-push. This forces us to review the entire PR from the beginning, instead of just the new changes.

sorry for creating extra works, i didn't know we can solve conflicts without rebase, i'll keep in mind and i always wanted to never use rebase as i used to mess with this in past and this leads to creating my PR dirty that's the reason i built grebase(https://github.com/Aniketsy/grebase) But now i think i got alternative way to do . Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve SyntaxError suggestions for common operator typos and cross-language mistakes

4 participants