GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Convert selected ABCs to Protocols by ilevkivskyi · Pull Request #1220 · python/typeshed

Conversation

@ilevkivskyi

@ilevkivskyi ilevkivskyi commented Apr 26, 2017

Copy link
Copy Markdown
Member

A basic set of updates to typing that converts selected ABCs to protocols, see PEP 544.

This accompanies python/mypy#3132 and python/typing#417
The tests will fail, so that this PR can be merged after the mypy one.
Then, if everything goes OK, we could convert more types in typeshed to protocols.

Attn: @JukkaL @ambv @gvanrossum

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

tebanep reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
JelleZijlstra
JelleZijlstra reviewed Apr 26, 2017
View reviewed changes
Comment thread stdlib/2/typing.pyi Outdated
_promote = object()
no_type_check = object()
ClassVar = object()
Protocol = object()

@JelleZijlstra JelleZijlstra Apr 26, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I know we have a lot of similar definitions already, but I'd prefer to keep the stub closer to reality, maybe with just class Protocol: pass

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Apr 26, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

This form is actually necessary (in some sense) since mypy will prohibit any other operations with Protocol in runtime context, like:

Protocol()  # instantiating is a runtime error
Protocol[int]  # type application is a runtime error
def make_one(cls: type) -> Any: ...
make_one(Protocol)  # passing to a function is not a good idea
def fun(x: Protocol) -> int: # Using it in type context is not a good idea either
    ...

This could be fixed by additional special-casing, but a simpler way is just make it an object().

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@JelleZijlstra JelleZijlstra Apr 26, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

It's special either way: if I do Protocol = object() elsewhere, mypy probably won't let me do class SupportsFloat(Protocol): pass. Using a class is at least a little closer to what Protocol actually does at runtime, even if Protocol obviously isn't a normal class.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Apr 26, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Yes, but if I write class Protocol: ... then mypy will allow most things I mentioned above. This is why object() is used also for Generic and friends. Otherwise prohibiting all possible invalid scenarios will require a lot of effort.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@JelleZijlstra JelleZijlstra Apr 26, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Oh I see, I thought it would just ignore the implementation in the stub. Ignore this then.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@JelleZijlstra

JelleZijlstra commented May 20, 2017

Copy link
Copy Markdown
Member

This looks good to merge once the mypy PR is in.

I fixed a merge conflict that happened because I added typing.ContextManager. Not sure though if it should have the @runtime decorator.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JelleZijlstra JelleZijlstra added the blocked label May 20, 2017
@ilevkivskyi

ilevkivskyi commented May 21, 2017

Copy link
Copy Markdown
Member Author

Not sure though if it should have the @runtime decorator.

Yes, this is a runtime protocol (since contextlib.AbstractContextManager supports runtime structural checks via __subclasshook__). Also AsyncConetxtManager should be marked as @runtime when added.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JukkaL JukkaL mentioned this pull request Aug 10, 2017
Protocols python/mypy#3132
Merged
@JukkaL

JukkaL commented Aug 10, 2017

Copy link
Copy Markdown
Contributor

A few notes:

  • Please don't merge this until you get an okay here from me, even if the corresponding mypy PR is merged.
  • I think that the explicit SupportsFoo base classes in the stubs for builtins (for example, SupportsInt in int) should be removed. The rationale is that they are unnecessary as these are now protocols, and they also confuse mypy type inference as implemented in Protocols mypy#3132 by generating inferred types such as List[SupportsInt] instead List[object] that are unexpected.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ilevkivskyi

ilevkivskyi commented Aug 10, 2017

Copy link
Copy Markdown
Member Author

OK, I have updated builtins (removed the Supports* bases).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ilevkivskyi

ilevkivskyi commented Aug 19, 2017

Copy link
Copy Markdown
Member Author

OK, now all tests pass except for one. We are now in an interesting situation, since pythoneval tests are run with full stubs, this means that I cannot fix this in mypy before this one is merged and vice-versa. This means that either mypy of typeshed would need to merge a failing PR or this will involve a long loop of PRs with temporarily disabling this test in mypy then merging this PR and then re-enabling this one test again. @JelleZijlstra how such situations are typically treated?

I think this can be considered unblocked and ready for review, since python/mypy#3132 is now merged. Also, we could think now what are other classes in stdlib that may be made protocols (maybe PathLike?), and where removing an explicit bases could improve situation (for example, currently mypy does not attempt structural check, if there is an explicit base, and subtype check fails because of type variables, variance, etc.)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

JelleZijlstra
JelleZijlstra reviewed Aug 19, 2017
View reviewed changes
Comment thread stdlib/2/typing.pyi Outdated
_T_contra = TypeVar('_T_contra', contravariant=True) # Ditto contravariant.

class SupportsInt(metaclass=ABCMeta):
def runtime(cls: _T) -> _T: ...

@JelleZijlstra JelleZijlstra Aug 19, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Should the argument be a TypeVar bound to Type[object] or even Type[Protocol], so that type checkers will give an error when this decorator is applied to something that's not a class?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Aug 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Type[Protocol] will not work, since it does not appear explicitly in MRO, but Type[object] looks like a good idea.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread stdlib/3/typing.pyi Outdated
traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]]: ...

class Mapping(_Collection[_KT], Generic[_KT, _VT_co]):
@runtime # type: ignore

@JelleZijlstra JelleZijlstra Aug 19, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Why do you need the # type: ignore here?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Aug 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Actually, it looks like is is not necessary anymore. The point is that Mapping is not really covariant in value (see signature of get) and mypy is deliberately very strict about such situations with protocols, however it looks like treatment of unions has changed since this was added. I will remove it just in case.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Aug 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Weird, somehow this works in Python 3 but fails in Python 2, will investigate later, have to run now.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Aug 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Ah, found it, the return types for values() etc. are list[_VT_co], so on Python 2 it is indeed clearly invariant in value and we need #type: ignore.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@JelleZijlstra

JelleZijlstra commented Aug 19, 2017

Copy link
Copy Markdown
Member

I guess it makes the most sense to have the same person merge the mypy and typeshed changes at approximately the same time. I believe Jukka has push privileges to typeshed, so it might make the most sense for him to do it. I could also take care of doing the actual merges if Jukka or another mypy core team member approves the corresponding mypy PR.

As for uses of protocols, my recent experience has been that protocols would be mostly useful in IO-related argument types, where now we often have to write IO when really we only need an object with a .read() method. I'm on really bad airport wifi now so I can't look up examples easily.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ilevkivskyi ilevkivskyi mentioned this pull request Aug 19, 2017
Update pythoneval test according to PR typeshed/#1220 (ABCs -> Protocols) python/mypy#3846
Merged
@ilevkivskyi

ilevkivskyi commented Aug 19, 2017

Copy link
Copy Markdown
Member Author

@JelleZijlstra @JukkaL OK, here is the corresponding mypy PR with an updated test output python/mypy#3846

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum gvanrossum changed the title Protocols Convert selected ABCs to Protocols Sep 19, 2017
@ilevkivskyi ilevkivskyi mentioned this pull request Sep 23, 2017
bytes(obj) rejected even when obj implements __bytes__ python/mypy#3989
Closed
@ilevkivskyi ilevkivskyi mentioned this pull request Nov 1, 2017
Protocols (a.k.a. structural subtyping) python/typing#11
Closed
@ilevkivskyi

ilevkivskyi commented Nov 17, 2017

Copy link
Copy Markdown
Member Author

@JelleZijlstra @JukkaL
OK, I have removed Sequence and Mapping from this PR as @gvanrossum proposed in python/typing#11 (comment) so this PR can be merged now. Sequence and Mapping can be considered later, since they are not yet protocols at runtime.

The logistic issue here is that this PR and python/mypy#3846 mutually depend on each other. As proposed above the simplest way would be to just merge them simultaneously.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

gvanrossum
gvanrossum reviewed Nov 17, 2017
View reviewed changes

@gvanrossum gvanrossum left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

See also my suggestion at python/mypy#3846 (comment) on how to avoid the mutual dependency between the two PRs.

Finally, can you rebase? There are no merge conflicts but it's really old, which surprised me when testing this manually. (OTOH the manual test on internal codebases found no new issues, so green light from that POV.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread stdlib/2/typing.pyi
class SupportsInt(metaclass=ABCMeta):
def runtime(cls: _TC) -> _TC: ...

@runtime

@gvanrossum gvanrossum Nov 17, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Since this is a stub, why does it need @runtime?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Nov 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Otherwise mypy will complain about e.g. issubclass(it, collections.abc.Iterable) something like isinstance() can be used only with @runtime protocols.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread stdlib/2/typing.pyi
_TC = TypeVar('_TC', bound=Type[object])

class SupportsInt(metaclass=ABCMeta):
def runtime(cls: _TC) -> _TC: ...

@gvanrossum gvanrossum Nov 17, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

IIUC @runtime is not defined (yet) in typing.py but (only) in typing_extensions.py?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ilevkivskyi ilevkivskyi Nov 19, 2017

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Yes, and the same for Protocol (there is only old internal _Protocol in typing). We however need them in typeshed to avoid circular dependencies with typing_extensions. We discussed this with @JukkaL few moths ago, the plan (which I like) is this:

  1. Iterate on PR Make python 2 subprocess consistent with python 3 #3132 until it's approved.
  2. Publish Protocol in typing_extensions. Also include it in the stub for typing_extensions.
  3. Merge PR Make python 2 subprocess consistent with python 3 #3132 but don't merge typeshed changes yet. This lets mypy users (at least those who use GitHub master) experiment with user-defined protocols.
  4. Get an okay from PyCharm and Pytype that they are fine with merging the typeshed PR. They might need to implement some support for the Protocol special form first, but if they don't use the typing typeshed stub this may be a non-issue.
  5. If major issues are found in the mypy implementation of protocols, fix them.
  6. Release a new mypy version with protocols as an experimental feature!
  7. Merge the typeshed PR and use it in mypy.
  8. Seek acceptance of the protocols PEP once we have some practical experience and protocols seem to work fine.
  9. Officially support using protocols in typeshed once Pytype and PyCharm are okay with it.
  10. Release Protocol in Python stdlib typing module.

This PR is step number 7

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ilevkivskyi
ilevkivskyi force-pushed the protocols branch from b3bcce4 to 4cfddfd Compare November 19, 2017 08:24
@ilevkivskyi

ilevkivskyi commented Nov 19, 2017

Copy link
Copy Markdown
Member Author

@gvanrossum OK, I rebased (but also squashed, since there were previous merge conflicts I don't want to fix them all again).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Ivan Levkivskyi
Recognize standard ABCs in typing as protocols
f6d7dea
@ilevkivskyi
ilevkivskyi force-pushed the protocols branch from 4cfddfd to f6d7dea Compare November 19, 2017 08:32
Ivan Levkivskyi
Restart tests
b2fc6db
@ilevkivskyi

ilevkivskyi commented Nov 19, 2017

Copy link
Copy Markdown
Member Author

OK, all tests pass now, this is ready to be merged.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum
gvanrossum merged commit ec2cb8e into python:master Nov 19, 2017
@ilevkivskyi
ilevkivskyi deleted the protocols branch November 19, 2017 17:51
@ilevkivskyi ilevkivskyi mentioned this pull request Nov 19, 2017
Sync typeshed python/mypy#4267
Merged
ilevkivskyi added a commit to python/mypy that referenced this pull request Nov 19, 2017
@ilevkivskyi
Update pythoneval test according to PR typeshed/#1220 (ABCs -> Protoc…
608b6a6
…ols) (#3846)

This PR contains the tests output after python/typeshed#1220 is merged
and synced (note that pythoneval tests are run with full typeshed stubs).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@JelleZijlstra JelleZijlstra JelleZijlstra left review comments
@gvanrossum gvanrossum gvanrossum left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@ilevkivskyi @JelleZijlstra @JukkaL @gvanrossum
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.