Skip to content

Complete the tokenize module type hints #984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 15, 2017

Conversation

mjpieters
Copy link
Contributor

Note that I used the 3.6 syntax for the TokenInfo namedtuple; @ambv stated he plans to move all of typeshed to that syntax.

@JelleZijlstra
Copy link
Member

Can you fix the Travis failures? Looks like mypy doesn't actually support variable annotation syntax in pre-3.6 stubs.

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Mar 12, 2017

@ambv Is it true that you plan to move all stubs to 3.6 variable annotations?
I am asking because I have a small tool that does this automatically (the interface is still a bit "raw", but otherwise it works very well, preserves formatting, removes ellipses if necessary, etc.) see https://github.com/ilevkivskyi/com2ann.

It was out my focus for few months, but I am going to improve it and add opposite transformation (annotation to comments), support for function type comments (2.7 syntax), support for docstrings etc.

@gvanrossum
Copy link
Member

Even if we were in agreement that we should use the 3.6 notation for all stubs I still would not want to do a mass conversion. Instead I would just do it opportunistically over time.

@gvanrossum
Copy link
Member

gvanrossum commented Mar 14, 2017

I am a bit mystified by the test failures. I can repro these too and there seem to be two sets:

  • When running with --python-version 3.6 we run into a limitation on NamedTuple subclasses (they currently can't have properties or methods -- IIRC @ilevkivskyi is working on a fix?)

  • Also there's a missing import of Optional.

  • With earlier Python 3 versions we get "stdlib/3/tokenize.pyi:16: error: Variable annotation syntax is only supported in Python 3.6 and greater" -- this seems to indicate that mypy actually still checks stubs using an earlier Python version despite Default to type checking in Python 3.6 mode mypy#2915.

@ilevkivskyi
Copy link
Member

@gvanrossum

they currently can't have properties or methods -- IIRC @ilevkivskyi is working on a fix?

I only did the runtime implementation in typing. I thought @JelleZijlstra wanted to try this
python/mypy#2719 (comment) after python/mypy#2719 is merged (the latter is ready if I remember correctly).

@JelleZijlstra
Copy link
Member

JelleZijlstra commented Mar 14, 2017

Sure, I can work on that once python/mypy#2719 is in mypy.

@gvanrossum
Copy link
Member

So now that python/mypy#3000 has landed, there are two remaining issues:

  • Missing import of Optional
  • We still get "NamedTuple class syntax is only supported in Python 3.6". That may be caused by the way that the typeshed tests pass the stub files on the command line?
  • The property definition isn't supported.

@mjpieters
Copy link
Contributor Author

mjpieters commented Mar 15, 2017

The property definition isn't supported.

Would an instance variable annotation work? It'd communicate what type to expect when accessing the attribute:

class TokenInfo(NamedTuple):
    # ...
    # @property
    exact_type: int

Otherwise, is the next option to retain exact_type as a method (so drop the @property decorator), or drop exact_type from the stub altogether?

def untokenize(iterable): ...
def detect_encoding(readline): ...
def tokenize(readline): ...
def untokenize(iterable: Iterable[_Token]) -> Union[str, bytes]: ...
Copy link
Member

Choose a reason for hiding this comment

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

We should almost never return a Union because Union handling is often buggy in mypy and using Unions forces calling code into tedious isinstance checks. I think this one should just return Any.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, no, we should use AnyStr.

Copy link
Member

Choose a reason for hiding this comment

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

AnyStr doesn't make sense here because it's a type variable; see Jukka's discussion in #871.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, good point. The caller will only get str if they pass in an encoding, at which point they shouldn't have to deal with bytes. Any it is.

@JelleZijlstra
Copy link
Member

I think the best option would be to make the NamedTuple class private and inherit from that, something like this:

class _TokenInfo(typing.NamedTuple):
    encoding: str

class TokenInfo(_TokenInfo):
    @property
    def exact_type(self) -> int: ...

I haven't tested it but I believe mypy supports this. It's also consistent with the way this class is actually implemented in tokenize.py.

@gvanrossum
Copy link
Member

It's a NamedTuple -- a plain attribute sounds like a fine idea to me.

@JelleZijlstra
Copy link
Member

If we make it a plain attribute, type checkers will think that you need to pass in six arguments (including exact_type) in order to construct a TokenInfo, but you really only need five.

@gvanrossum
Copy link
Member

gvanrossum commented Mar 15, 2017 via email

@mjpieters
Copy link
Contributor Author

But there's still the issue of the PEP 526 syntax not being supported
(yet?) by mypy in stubs for Python 3.2--3.5. If we're not fixing that we
should just cave and use the classic NamedTuple syntax.

I'll cave and use the 3.5 style for now. @ambv can upgrade it to 3.6 if and when support is there.

def tokenize(readline): ...
def untokenize(iterable: Iterable[_Token]) -> Any: ...
def detect_encoding(readline: Callable[[], bytes]) -> Tuple[str, Sequence[bytes]]: ...
def tokenize(readline: Callable[[], bytes]) -> Generator[TokenInfo, None, None]: ...
Copy link
Contributor

Choose a reason for hiding this comment

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

@mjpieters This is fine but in the future, if you're type hinting the return value of a simple generator, simply use -> Iterator[SomeType].

@ambv ambv merged commit 3f0eb99 into python:master Mar 15, 2017
ENCODING = 0
COMMENT = ... # type: int
NL = ... # type: int
ENCODING = ... # type: int
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You'll want to update token.py too in that case; I followed the style from that stub here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Will do :)

Copy link
Member

Choose a reason for hiding this comment

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

Might be good to add this to CONTRIBUTING.md or the linter; I've been unsure in the past what style to use for this kind of thing.

@gvanrossum
Copy link
Member

Whee! Thanks everyone for the truly multidisciplinary review and improvements.

@ambv ambv removed the blocked label Mar 15, 2017
@mjpieters mjpieters deleted the tokenize_update branch March 15, 2017 17:02
@ambv
Copy link
Contributor

ambv commented Mar 21, 2017

If this is not clear from the comments below:

In other words, if we change variables in tokenize.pyi to use PEP 526 annotations, everything works fine when running with --python-version 3.5. But, if you use the 3.6 NamedTuple syntax, you'll get:

error: NamedTuple class syntax is only supported in Python 3.6

@gvanrossum
Copy link
Member

gvanrossum commented Mar 21, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants