Since 3.10, the parser provides excellent targeted hints for dict literal mistakes:
>>> {1: 2, 3: 4, 5}
SyntaxError: ':' expected after dictionary key
>>> {1: 2, 3: 4, 5:}
SyntaxError: expression expected after dictionary key and ':'
>>> {1: *a}
SyntaxError: cannot use a starred expression in a dictionary value
However, using the wrong delimiters for ‘key: value’ pairs still produces a bare invalid syntax.
In my experience, this is a common error for beginners: sometimes as a typo, sometimes because they’re not used to differentiating between tuples, lists and dicts. And a bare invalid syntax doesn’t help them figure out what’s wrong.
On 3.14.6 these all give a bare invalid syntax, and invalid.gram in main has no rules for them:
>>> x = ["a": 1, "b": 2]
SyntaxError: invalid syntax
>>> x = ("a": 1, "b": 2)
SyntaxError: invalid syntax
>>> x = [k: v for k, v in pairs]
SyntaxError: invalid syntax
>>> x = (k: v for k, v in pairs)
SyntaxError: invalid syntax
>>> f(a: 1)
SyntaxError: invalid syntax
My proposal is to add rules to provide better hints:
>>> x = ["a": 1, "b": 2]
SyntaxError: invalid syntax. Did you mean to use '{' and '}' instead of '[' and ']' to create a dictionary?
>>> x = ("a": 1, "b": 2)
SyntaxError: invalid syntax. Did you mean to use '{' and '}' instead of '(' and ')' to create a dictionary?
>>> x = [k: v for k, v in pairs] # or (k: v ...)
SyntaxError: invalid syntax. Did you mean to use '{' and '}' instead of '[' and ']' for a dict comprehension?
>>> f(a: 1)
SyntaxError: invalid syntax. Did you mean to use '=' instead of ':' to pass a keyword argument in a function call?
I’m less sure about the last one, though. I think it’s much more likely that someone is making a function call and mixing up = with : than trying to slice a dict with ( instead of [. So the hint only suggests the keyword argument, since mentioning a dict could end up making things more confusing.
To avoid false positives, the new rules must account for valid uses of colons inside brackets or parentheses:
- Slicing:
d["a": 1]is valid. The rule must apply only to list displays, never to subscripts. - Annotated assignments:
(a): int = 1is valid. The parentheses rule must apply only in expression contexts.
I couldn’t find a similar previous proposal. Would this be welcome? I’d be happy to open an issue and work on a PR.