El lun, 21 jun 2021 a las 23:19, <ucodery@gmail.com> escribió:
I just arrived on this thread after chasing down a particularly unintuitive set of type checking errors. I had just created a subclass of ZipFile in a repository that is 100% typed. This new class only added methods to the builtin ZipFile yet I was getting errors all over when I actually use this class to open a zip file in a context manager. After much looking around, and digging in the typeshed directly, I figured out that this is because ZipFile.__enter__ has a return annotation of ZipFile. So even though I did not want to alter any of the base class's ability to actually open a zip, didn't even want to have to think about how it did exactly that, I ended up having to reimplement __enter__ in my base class to keep type coverage at the level it was.

I submitted https://github.com/python/typeshed/pull/5675 to fix this in typeshed. But I agree with your larger point that this would be easier if we had `Self`.
I was not able to simply return super() as that gave the error `Incompatible return value type (got "ZipFile", expected "MyZipFile")`. For ZipFile this was not a big deal, as the entire body is just returning self, but for a more complicated __enter__ I could see this being a very annoying way to keep type information.
Even with pyright, I get the same set of seemingly wrong error about using the variable bound by the with statement as a MyZipFile object and not just a ZipFile object, since in typeshed this function that is explicitly annotated to return ZipFile. This seems like a problem that will keep coming up as subclassing built in classes is very common and there are a handful of protocols that very often return self besides __enter__, __iter__, __getitem__, __add__, and others, all of which get explicit types in the standard lib. Are pythonistas expected to remember if the class they are inheriting from use any of these, and if they return self, and if they have an explicit type hint, and then to rebind them just to get correct types?

For reference I made this minimum example when I was going to open an issue for the typeshed. I only stopped because I don't think there is any better annotation currently that can be put on ZipFile.
# myzip.py
from typing import Sequence, TYPE_CHECKING, cast
from zipfile import ZipFile

class MyZipFile(ZipFile):
    zip_sep = "/"

    def get_zip_path_components(self, path: str) -> Sequence[str]:
        return path.split(self.zip_sep)

with ZipFile("./example.zip") as zf:

my_zip = MyZipFile("./example.zip")

with my_zip as zf:
    cast(MyZipFile, zf)
    print(list(component for name in zf.namelist() for component in zf.get_zip_path_components(name)))
There are no errors in this script, it runs fine and produces the output you would expect. However this is what mypy says about it
❯ python3 -m mypy newzip.py
newzip.py:22: note: Revealed type is 'newzip.MyZipFile'
newzip.py:28: note: Revealed type is 'zipfile.ZipFile'
newzip.py:31: note: Revealed type is 'zipfile.ZipFile'
newzip.py:32: error: "ZipFile" has no attribute "zip_sep"
newzip.py:33: error: "ZipFile" has no attribute "get_zip_path_components"
Found 2 errors in 1 file (checked 1 source file)
pyright will generate the same notes and errors.
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
Member address: jelle.zijlstra@gmail.com