GeezerVison is showing github.com — [3.15] gh-151464: exclude '<>' token from tokenize output (GH-154854)… · python/cpython@2168416
File treeExpand file treeCollapse file tree Open diff view settings Misc/NEWS.d/next/Core_and_Builtins
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Grammar/python.gram +8Lines changed: 8 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -794,6 +794,7 @@ compare_op_bitwise_or_pair[CmpopExprPair*]: | 794 | 794 | | eq_bitwise_or | 795 | 795 | | noteq_bitwise_or | 796 | 796 | | lte_bitwise_or | | 797 | + | invalid_noteq | 797 | 798 | | lt_bitwise_or | 798 | 799 | | gte_bitwise_or | 799 | 800 | | gt_bitwise_or | @@ -1643,3 +1644,10 @@ invalid_type_params: | 1643 | 1644 | RAISE_SYNTAX_ERROR_STARTING_FROM( | 1644 | 1645 | token, | 1645 | 1646 | "Type parameter list cannot be empty")} | | 1647 | + | | 1648 | +invalid_noteq: | | 1649 | + | a='<' b='>' { | | 1650 | + _PyPegen_tokens_are_adjacent(a, b) | | 1651 | + ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '!=' instead of '<>'?") | | 1652 | + : NULL | | 1653 | + } |
Collapse file Copy file name to clipboardExpand all lines: Lib/test/test_syntax.py +24Lines changed: 24 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -3592,6 +3592,30 @@ def test_ifexp_body_stmt_else_stmt(self): | 3592 | 3592 | ]: | 3593 | 3593 | self._check_error(f"x = {lhs_stmt} if 1 else {rhs_stmt}", msg) | 3594 | 3594 |
| | 3595 | + def test_diamond_operator(self): | | 3596 | + self._check_error( | | 3597 | + "1<>2", | | 3598 | + r"Maybe you meant '!=' instead of '<>'\?", | | 3599 | + lineno=1, | | 3600 | + end_lineno=1, | | 3601 | + offset=2, | | 3602 | + end_offset=4, | | 3603 | + ) | | 3604 | + | | 3605 | + def test_diamond_operator_barry_as_flufl(self): | | 3606 | + compile( | | 3607 | + "from __future__ import barry_as_FLUFL\n1<>2", | | 3608 | + "<test>", "exec", | | 3609 | + ) | | 3610 | + self._check_error( | | 3611 | + "from __future__ import barry_as_FLUFL\na != b", | | 3612 | + "with Barry as BDFL, use '<>' instead of '!='", | | 3613 | + lineno=2, | | 3614 | + end_lineno=2, | | 3615 | + offset=3, | | 3616 | + end_offset=5, | | 3617 | + ) | | 3618 | + | 3595 | 3619 |
| 3596 | 3620 | class LazyImportRestrictionTestCase(SyntaxErrorTestCase): | 3597 | 3621 | """Test syntax restrictions for lazy imports.""" | |
Collapse file Copy file name to clipboardExpand all lines: Lib/test/test_tokenize.py +14Lines changed: 14 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1233,6 +1233,20 @@ def test_multiline_non_ascii_fstring_with_expr(self): | 1233 | 1233 | FSTRING_END \'"\' (2, 2) (2, 3) | 1234 | 1234 | """) | 1235 | 1235 |
| | 1236 | + def test_ineq_tokens(self): | | 1237 | + self.check_tokenize("1 != 2", """\ | | 1238 | + NUMBER '1' (1, 0) (1, 1) | | 1239 | + OP '!=' (1, 2) (1, 4) | | 1240 | + NUMBER '2' (1, 5) (1, 6) | | 1241 | +""") | | 1242 | + self.check_tokenize("1 <> 2", """\ | | 1243 | + NUMBER '1' (1, 0) (1, 1) | | 1244 | + OP '<' (1, 2) (1, 3) | | 1245 | + OP '>' (1, 3) (1, 4) | | 1246 | + NUMBER '2' (1, 5) (1, 6) | | 1247 | +""") | | 1248 | + | | 1249 | + | 1236 | 1250 | class GenerateTokensTest(TokenizeTest): | 1237 | 1251 | def check_tokenize(self, s, expected): | 1238 | 1252 | # Format the tokens in s in a table format. | |
Collapse file Copy file name to clipboard +2Lines changed: 2 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +Exclude invalid token ``<>`` from :mod:`tokenize` output. :exc:`SyntaxError` | | 2 | +for ``<>`` now suggests ``!=``. |
Collapse file Copy file name to clipboardExpand all lines: Parser/action_helpers.c +2Lines changed: 2 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 6 | 6 |
| 7 | 7 | #include "pegen.h" | 8 | 8 | #include "string_parser.h" // _PyPegen_decode_string() | | 9 | +#include "lexer/state.h" // tok_state | 9 | 10 |
| 10 | 11 |
| 11 | 12 | void * | @@ -2095,6 +2096,7 @@ _PyPegen_checked_from_import(Parser *p, asdl_seq *dots, expr_ty module_name, | 2095 | 2096 | alias_ty alias = asdl_seq_GET(names, i); | 2096 | 2097 | if (PyUnicode_CompareWithASCIIString(alias->name, "barry_as_FLUFL") == 0) { | 2097 | 2098 | p->flags |= PyPARSE_BARRY_AS_BDFL; | | 2099 | + p->tok->barry_as_bdfl = 1; | 2098 | 2100 | } | 2099 | 2101 | } | 2100 | 2102 | } | |
Collapse file Copy file name to clipboardExpand all lines: Parser/lexer/lexer.c +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1245,6 +1245,9 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t | 1245 | 1245 | { | 1246 | 1246 | int c2 = tok_nextc(tok); | 1247 | 1247 | int current_token = _PyToken_TwoChars(c, c2); | | 1248 | + if (c == '<' && c2 == '>' && !tok->barry_as_bdfl) { | | 1249 | + current_token = OP; | | 1250 | + } | 1248 | 1251 | if (current_token != OP) { | 1249 | 1252 | int c3 = tok_nextc(tok); | 1250 | 1253 | int current_token3 = _PyToken_ThreeChars(c, c2, c3); | |
Collapse file Copy file name to clipboardExpand all lines: Parser/lexer/state.h +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -138,6 +138,7 @@ struct tok_state { | 138 | 138 | #ifdef Py_DEBUG | 139 | 139 | int debug; | 140 | 140 | #endif | | 141 | + int barry_as_bdfl; | 141 | 142 | }; | 142 | 143 |
| 143 | 144 | int _PyLexer_type_comment_token_setup(struct tok_state *tok, struct token *token, int type, int col_offset, | |
|