Skip to content

Crash with slices e.g. Annotated[int, 3:4] #10266

Description

@patrick-kidger

Bug Report / To Reproduce / Actual Behavior

This:

# file.py
from typing import Annotated
def func(x: Annotated[int, 3:4]):
    pass

# command line
mypy file.py

produces:

file.py:4: error: syntax error in type comment
Found 1 error in 1 file (errors prevented further checking)

Your Environment

  • Mypy version used: 0.812
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.9.2
  • Operating system and version: Windows 10

Further details

Any use of slices seems to give the error, e.g. Annotated[int, "a": 4].

I actually ran into this whilst implementing a type with a custom __class_getitem__, using slice notation as a convenient notation to pass pairs of values: MyType["key1": value1, "key2": value2]. Which I realise is a bit rogue -- I don't have any real hope of mypy integration for the type -- but it would at least be nice if it can be used without crashing mypy, with just a # type: ignore where it's imported.

Activity

  1. JelleZijlstra commented on Mar 30, 2021

    @JelleZijlstra
    Member

    That's a fun one! It's probably pretty easy to fix if you track down where the error comes from (probably somewhere in fastparse.py).

  2. domdfcoding commented on Apr 1, 2021

    @domdfcoding
    Contributor

    I did some digging. The error is being raised from visit_Subscript in mypy.fastparse.TypeConverter. The code is different depending on the Python version but the error is the same.

    On Python 3.9 and later:

    mypy/mypy/fastparse.py

    Lines 1546 to 1551 in 2787d49

    sliceval = n.slice # type: Any
    if (isinstance(sliceval, ast3.Slice) or
    (isinstance(sliceval, ast3.Tuple) and
    any(isinstance(x, ast3.Slice) for x in sliceval.elts))):
    self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1))
    return AnyType(TypeOfAny.from_error)

    It is expecting the slice to be either:

    • an ast.Slice
    • an ast.Tuple which doesn't contain any ast.Slice nodes.

    In this case, the slice is an ast.Tuple node containing:

    • an ast.Index (the name int)
    • an ast.Slice (3:4)

    On Python 3.8 and earlier:

    mypy/mypy/fastparse.py

    Lines 1553 to 1557 in 2787d49

    # Python 3.8 or earlier use a different AST structure for subscripts
    if not isinstance(n.slice, Index):
    self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1))
    return AnyType(TypeOfAny.from_error)
    sliceval = n.slice.value

    It is expecting the slice to be an ast.Index but instead it is an ast.ExtSlice containing:

    • an ast.Index (the name int)
    • an ast.Slice (3:4)
  3. amrit110 commented on Apr 23, 2021

    @amrit110

    Hi, Can I take this on? It's my very first issue! From what @domdfcoding has investigated, it seems that for py3.9, we can remove the constraint that the slice which is an ast.Tuple node not contain ast.Slice nodes. Looking at https://docs.python.org/3/library/ast.html#subscripting, I was wondering why that check was there in the first place since it says "It can be a Tuple and contain a Slice". For py3.8 and lower, the API documentation is not as clear as to what the slice can be but https://docs.python.org/3.8/library/ast.html indicates that slice is probably ast.Slice or ast.ExtSlice or ast.Index. So, for that I'm not sure, perhaps we can include that the slice can be ast.ExtSlice as well?

  4. PrasanthChettri commented on Jun 6, 2021

    @PrasanthChettri
    Contributor

    @JelleZijlstra I am trying to fix the bug, for the example given above it's an instance of ast.Tuple(ast.Name, ast.Slice) and the problem is that of stated by @domdfcoding, and we will need to modify the conditions , it is probably not a good idea to just remove the constraint, I will need a little bit of help with the new condition to replace it with.

  5. ap-- commented on Jun 27, 2021

    @ap--
    Sponsor

    It seems like fixing this issue in mypy.fastparse.TypeConverter.visit_Subscript would ultimately lead to allowing either both or at least one of:

    Dict[x:y]
    Dict[int, x:y]

    which is at least in one test explicitly marked to be a blocking error

    [case testIncorrectTypeCommentIndex]
    from typing import Dict
    x = None # type: Dict[x: y]
    [out]
    main:3: error: syntax error in type comment

    see: cd5ff81
    and: 8ac365b

    The docs for typing.Annotated https://docs.python.org/3/library/typing.html#typing.Annotated don't seem to suggest to use slicing syntax.

    @patrick-kidger It looks as if the original use case is basically trying to emulate keyword arguments in getitem similar to pep472/pep637 via the slicing notation. So maybe https://www.python.org/dev/peps/pep-0472/#pass-a-dictionary-as-an-additional-index could be an easy solution to get this working in torchtyping with only a tiny overhead in characters:

    ## the following does not throw an error ##
    # file.py
    from typing import Annotated
    def func(x: Annotated[int, {3:4}]):  # pass a dict instead of slices
       pass
    
    # command line
    mypy file.py

    Cheers,
    Andreas 😃

    P.S.: If the decision is made to lift the currently in-place slice restriction, I can prepare a PR with a fix.

  6. morp007 commented on Aug 9, 2021

    @morp007

    @patrick-kidger, there's no slice in your code. See python spec: Slicings.

    Your code should look like this:

    # file.py
    from typing import Annotated
    def func(x: Annotated[int, slice(3, 4)]):
        pass

    Please, close this issue.

  7. Zac-HD commented on Sep 29, 2021

    @Zac-HD
    Contributor
    Dict[x:y]
    Dict[int, x:y]

    IMO these should still be errors, just not (misleading) syntax error in type comment errors:

    • "expects 2 type arguments, but 1 given" like Dict[int]), with a new "did you mean..." hint for slices.
    • "Invalid type comment or annotation" like Dict[int, {1: 2}]; which already "works" for custom types like torchtyping.TensorType.

    and the tests could be updated accordingly, so that mypy continues to guide naive users towards the right way to express simple cases, without erroring out on more advanced or experimental uses.

  8. sobolevn commented on Oct 1, 2021

    @sobolevn
    Member

    I agree with @Zac-HD here. The error message should be improved, but Dict[int, x:y] and all of the example above should not be allowed (unless new PEPs or typing syntax changes are made). I would be super confused to see dict[x:y] as a type.

    Proposed altertives are:

    1. slice(1, 3) instead of 1:3
    2. {x: y} instead of x: y

    I will send a PR with the better error message today! 👍

  9. added a commit that references this issue on Oct 3, 2021
    eb5e086
  10. Zac-HD commented on Oct 4, 2021

    @Zac-HD
    Contributor

    I don't think that #11241 should be considered as closing this issue without @sobolevn's proposed follow-up:

    from typing_extensions import Annotated
    
    def func(x: Annotated[int, 3:4]):  # still a fatal error, contra (?) PEP-593
        x + "a string"                 # I expect an error here but don't get one

    As above, I think it's fine for slices to be an error in stdlib generics - but IMO ought to be allowed in Annotated and third-party generic types.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions