Skip to content
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

Use "|" union syntax in type aliases and base classes too #6612

Closed
wants to merge 12 commits into from

Conversation

Akuli
Copy link
Collaborator

@Akuli Akuli commented Dec 16, 2021

No description provided.

…ript

import sys

for line in sys.stdin:
    filename, lineno, message = line.split(":")
    lineno = int(lineno) - 1
    assert "Use PEP 604 syntax" in message

    new = message.split("`")[1]
    parts = new.split(" | ")
    assert all(part.count("[") == part.count("]") for part in parts)

    olds = []
    olds.append("Union[" + ", ".join(parts) + "]")
    if len(parts) == 2 and parts.count("None") == 1:
        [x] = [p for p in parts if p != "None"]
        olds.append("Optional[" + x + "]")

    lines = open(filename).readlines()
    for old in olds:
        if lines[lineno].count(old) == 1:
            lines[lineno] = lines[lineno].replace(old, new)
    open(filename, "w").writelines(lines)
import sys

for line in sys.stdin:
    filename, lineno, _, message = line.split(":")
    filename = filename.strip()
    lineno = int(lineno) - 1
    to_remove = message.split('"')[1]
    lines = open(filename).readlines()
    if lines[lineno].count(to_remove) == 1:
        lines[lineno] = lines[lineno].replace(to_remove + ",", "")
        lines[lineno] = lines[lineno].replace(to_remove, "")
    open(filename, "w").writelines(lines)
@Akuli Akuli changed the title Big diff: use "|" union syntax in type aliases and base classes too Use "|" union syntax in type aliases and base classes too Dec 16, 2021
Copy link
Member

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

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

Checked the first couple of files

@github-actions

This comment has been minimized.

@Akuli Akuli marked this pull request as draft December 16, 2021 18:14
@AlexWaygood
Copy link
Member

Not sure it's going to be possible to get the stubtest tests to pass right now, since stubtest is still pinned to MyPy 0.910? No idea about why the other mypy tests are still failing, though.

@Akuli
Copy link
Collaborator Author

Akuli commented Dec 16, 2021

I just realized that this will have to wait until #6589 is merged.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@srittau srittau closed this Dec 17, 2021
@srittau srittau reopened this Dec 17, 2021
@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@JukkaL
Copy link
Contributor

JukkaL commented Dec 17, 2021

FWIW, I'd prefer to figure out why the new syntax doesn't work in some files before merging this PR. Maybe the issue affects additional stubs but some errors are just not caught by mypy_primer.

Also it seems like this will make some new versions of third-party stubs at least somewhat unusable on mypy releases earlier than 0.920? I think it would be a good idea to give users some time to update before starting to use new features in stubs. One option would be to first update stdlib stubs, since they will be shipped with mypy and thus won't cause issues.

@Akuli
Copy link
Collaborator Author

Akuli commented Dec 17, 2021

I'm confused about the remaining CI failures, and I can reproduce them locally. If I just run mypy, everything works, but if I run mypy.stubtest it fails with "mypy build errors":

(env310) akuli@akuli-desktop:~/typeshed$ python3 -m mypy --custom-typeshed-dir . $(find stdlib -name '*.pyi' | grep -v @)
Success: no issues found in 480 source files

(env310) akuli@akuli-desktop:~/typeshed$ python3 -m mypy.stubtest --check-typeshed --custom-typeshed-dir .
error: not checking stubs due to mypy build errors:
stdlib/os/__init__.pyi:620: error: Variable "os._FdOrAnyPath" is not valid as a type
stdlib/os/__init__.pyi:620: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib/os/__init__.pyi:622: error: Variable "os._FdOrAnyPath" is not valid as a type
stdlib/os/__init__.pyi:622: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
...

@srittau
Copy link
Collaborator

srittau commented Dec 17, 2021

Also it seems like this will make some new versions of third-party stubs at least somewhat unusable on mypy releases earlier than 0.920? I think it would be a good idea to give users some time to update before starting to use new features in stubs. One option would be to first update stdlib stubs, since they will be shipped with mypy and thus won't cause issues.

I really don't think we should wait longer than a mypy release to update our third-party stubs. Frankly, mypy is what is holding us back most. Other type checkers can benefit from improved types and I don't want to wait longer than necessary to improve our stubs. I also don't want to remember what features we can use and what features we can't use, this is what our tests are for.

I find it completely acceptable for our users to continue to use older stubs when they are unable to upgrade mypy.

@JukkaL
Copy link
Contributor

JukkaL commented Dec 17, 2021

I really don't think we should wait longer than a mypy release to update our third-party stubs.

I'm not asking to wait indefinitely, but I don't think it's unreasonable to wait, say, a few weeks after a release before using new features. This would also give mypy developers and the mypy plugin community time to fix any potential regressions the latest mypy release might have while being able to use the latest stubs.

(We are also actively working on speeding up the mypy release process.)

I find it completely acceptable for our users to continue to use older stubs when they are unable to upgrade mypy.

I agree with the sentiment, but it turns out that a lot of mypy users like to use the latest and the greatest, and sometimes there are regressions blocking the use of the latest mypy by some projects, even if we try to carefully avoid them. A little extra time could make the experience better for users that don't pin mypy or stub package versions -- they could continue using the latest stubs, even if they have to pin to a slightly older mypy release temporarily.

@AlexWaygood
Copy link
Member

AlexWaygood commented Jan 1, 2022

I've been trying to narrow some of these errors down, and it's been driving me nuts.

If I change a single line in _typeshed.__init__.pyi (line numbers are different to how they appear in this PR, because master has changed):

--- a/stdlib/_typeshed/__init__.pyi
+++ b/stdlib/_typeshed/__init__.pyi
@@ -189,7 +189,7 @@ ReadOnlyBuffer = bytes  # stable
 # for it. Instead we have to list the most common stdlib buffer classes in a Union.
 WriteableBuffer = Union[bytearray, memoryview, array.array[Any], mmap.mmap, ctypes._CData]  # stable
 # Same as _WriteableBuffer, but also includes read-only buffer types (like bytes).
-ReadableBuffer = Union[ReadOnlyBuffer, WriteableBuffer]  # stable
+ReadableBuffer = ReadOnlyBuffer | WriteableBuffer  # stable
then I get the following output from mypy 0.930 when I run it on the typeshed repo (using Python 3.10):
stdlib\io.pyi:44: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\io.pyi:44: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\io.pyi:54: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\io.pyi:54: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\io.pyi:61: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\io.pyi:61: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\io.pyi:74: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\io.pyi:74: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\io.pyi:104: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\io.pyi:104: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\mmap.pyi:52: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\mmap.pyi:52: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\mmap.pyi:53: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\mmap.pyi:53: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\mmap.pyi:55: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\mmap.pyi:55: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\mmap.pyi:64: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\mmap.pyi:64: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\ctypes\__init__.pyi:89: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\ctypes\__init__.pyi:89: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\builtins.pyi:672: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\builtins.pyi:672: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:9: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:9: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:10: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:10: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:11: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:11: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:23: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:23: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:24: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:24: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\struct.pyi:25: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\struct.pyi:25: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\lzma.pyi:90: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\lzma.pyi:90: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hmac.pyi:19: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hmac.pyi:19: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hmac.pyi:30: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hmac.pyi:30: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hmac.pyi:31: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hmac.pyi:31: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hmac.pyi:37: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hmac.pyi:37: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hmac.pyi:42: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hmac.pyi:42: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:12: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:12: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:16: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:16: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:19: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:19: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:20: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:20: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:21: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:21: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:22: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:22: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:23: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:23: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:24: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:24: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:25: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:25: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:49: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:49: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:56: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:56: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:60: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:60: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:70: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:70: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:72: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:72: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:89: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:89: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:92: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:92: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:93: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:93: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\hashlib.pyi:94: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\hashlib.pyi:94: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\_socket.pyi:14: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\_socket.pyi:14: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\_socket.pyi:560: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\_socket.pyi:560: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\_socket.pyi:561: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\_socket.pyi:561: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\_socket.pyi:563: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\_socket.pyi:563: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\_socket.pyi:565: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\_socket.pyi:565: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\socket.pyi:603: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\socket.pyi:603: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\gzip.pyi:136: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\gzip.pyi:136: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\bz2.pyi:127: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\bz2.pyi:127: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\bz2.pyi:128: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\bz2.pyi:128: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\ssl.pyi:343: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\ssl.pyi:343: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\ssl.pyi:344: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\ssl.pyi:344: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\ssl.pyi:346: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\ssl.pyi:346: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
stdlib\ssl.pyi:348: error: Variable "_typeshed.ReadableBuffer" is not valid as a type
stdlib\ssl.pyi:348: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases

But I'm really struggling to reproduce this error outside the typeshed repo!

@JelleZijlstra
Copy link
Member

Once #4913 is done, maybe TypeAlias will help?

@AlexWaygood
Copy link
Member

Once #4913 is done, maybe TypeAlias will help?

Hopefully. But I still don't understand why this only appear to error inside the typeshed repo.

I tried creating the following directory structure:

test_union
|    __init__.pyi
|    hashlib.pyi
|    py.typed
|
└─── _typeshed
           |    __init__.pyi

test_union/__init__.pyi and test_union/py.typed are empty files.

`test_union/_typeshed/__init__.pyi` contains the following code:
import array
import ctypes
import mmap
from typing import Any, Union

ReadOnlyBuffer = bytes  # stable
WriteableBuffer = Union[bytearray, memoryview, array.array[Any], mmap.mmap, ctypes._CData]  # stable
ReadableBuffer = ReadOnlyBuffer | WriteableBuffer  # stable
`test_union/hashlib.pyi` contains the following code:
from ._typeshed import ReadableBuffer

class _Hash(object):
    def __init__(self, data: ReadableBuffer = ...) -> None: ...

It appears as though this exact same code/directory structure causes mypy to error when it's inside the typeshed repo. But when I run mypy test_union, no errors are reported.

Am I doing something obviously wrong here?

@Akuli
Copy link
Collaborator Author

Akuli commented Jan 1, 2022

If nothing else works, I'll try to just start deleting files from a local copy of typeshed until the errors go away. I have done that with big projects in the past, and even though this technique takes some time, it seems to work every time, no matter how weird the problem is.

@AlexWaygood
Copy link
Member

AlexWaygood commented Jan 2, 2022

Using @Akuli's technique, I have managed to narrow down the bug significantly. The bug is still reproducible in a branch of typeshed I've created over here, in which the vast majority of the standard library has been deleted. I now strongly suspect that the bug has something to do with cyclic imports between mmap, _typeshed and builtins.

@AlexWaygood
Copy link
Member

Well, this is my best stab at a bug report: python/mypy#11887

@Akuli Akuli closed this Jan 13, 2022
@Akuli Akuli deleted the newsyntax branch January 13, 2022 10:35
@Akuli
Copy link
Collaborator Author

Akuli commented Jan 13, 2022

There's another blocker for this too: _Color = str | tuple[float, float, float] is a mypy error "Type application has too many types (1 expected)" (python/mypy#11098). I'll make a new PR if both of these mypy problems ever get fixed.

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