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 TypeVarTuple in our APIs #2881

Merged
merged 29 commits into from Dec 13, 2023

Conversation

TeamSpen210
Copy link
Contributor

With Mypy 1.7 being released, variadic generics are now supported. This works real well for Nursery.start_soon(), to_thread.run_sync(), etc. However the complex types for Nursery.start() + TaskStatus are producing a bunch of spurious errors for code that just calls it and ignores the return type. That might need to be fixed first in Mypy...

@TeamSpen210 TeamSpen210 added the typing Adding static types to trio's interface label Nov 19, 2023
Copy link

codecov bot commented Nov 19, 2023

Codecov Report

Merging #2881 (9f94f97) into master (31b87ad) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2881   +/-   ##
=======================================
  Coverage   99.54%   99.54%           
=======================================
  Files         115      115           
  Lines       17663    17673   +10     
  Branches     3158     3159    +1     
=======================================
+ Hits        17583    17593   +10     
  Misses         52       52           
  Partials       28       28           
Files Coverage Δ
src/trio/_core/_entry_queue.py 100.00% <100.00%> (ø)
src/trio/_core/_run.py 100.00% <100.00%> (ø)
src/trio/_core/_tests/test_guest_mode.py 100.00% <ø> (ø)
src/trio/_core/_tests/test_local.py 100.00% <100.00%> (ø)
src/trio/_core/_tests/test_run.py 100.00% <ø> (ø)
src/trio/_dtls.py 96.76% <100.00%> (ø)
src/trio/_subprocess.py 98.29% <100.00%> (+0.02%) ⬆️
src/trio/_tests/test_channel.py 100.00% <100.00%> (ø)
src/trio/_tests/test_scheduler_determinism.py 100.00% <100.00%> (ø)
src/trio/_tests/test_subprocess.py 100.00% <100.00%> (ø)
... and 3 more

@TeamSpen210 TeamSpen210 linked an issue Nov 19, 2023 that may be closed by this pull request
@A5rocks
Copy link
Contributor

A5rocks commented Nov 19, 2023

Could you add some type tests?

"""Type of functions passed to `nursery.start() <trio.Nursery.start>`."""

def __call__(
self, *args: Unpack[PosArgT], task_status: TaskStatus[StatusT_co]
Copy link
Contributor

@A5rocks A5rocks Nov 19, 2023

Choose a reason for hiding this comment

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

Suggested change
self, *args: Unpack[PosArgT], task_status: TaskStatus[StatusT_co]
self, *args: Unpack[PosArgT], *, task_status: TaskStatus[StatusT_co]

edit: I thought that would work (and it does if *args: Unpack[PosArgT] is gone) but it doesn't. I believe the issue is that the type var tuple can have a finite amount of arguments and then... kinda overflow, at least in some cases right? So like, calling with int, str, TaskStatus[str] when PosArgT is just [int, str] would mean that StatusT_co would be str right?

Errr, so we're promising that anything with this protocol can call it as such. But we're also passing functions that don't allow that? (actually, maybe not, and that's an actual bug. But as is our protocol shouldn't accept (a: int, *, task_status: TaskStatus[str]))

edit edit: ok my analysis above is totally incorrect, only keeping it to prevent someone from going down the same path i went down.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately no, the *args already makes it keyword-only.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah sorry about the repeated confusion with this thread, TypeVarTuple is getting to my head :(

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah it's real confusing. Since task_status is keyword-only it shouldn't get mixed up. As you can see with the type-tests, if it's being assigned to an annotated type, Mypy can do bidirectional inference and figure it out. But if it's not annotated or just a bare call, it gets confused and assumes it's Never. I think it's a bug.

Copy link
Contributor

@A5rocks A5rocks Nov 19, 2023

Choose a reason for hiding this comment

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

I agree. I took a look at mypy's code for the last 45 minutes and spotted:

  1. It looks like it isn't generating constraints for the typevar. (inference works by figuring out all constraints on a typevar and then constraining it -- if there are no constraints, then it returns UninhabitedType (str value: Never ... not literally Never) to us)
  2. This is because the constraints only get generated for a callback protocol if the type being assigned is a subtype of the callback protocol w/ erased tvars (I assume this is to make less confusing error messages). Unfortunately, TypeVarTuple gets erased to tuple[Any, ...] and our callable doesn't take in infinite parameters.
  3. Even if that problem were to be solved, it looks like mypy only generates constraints for either a bunch of type vars or a single unpack. This isn't a problem normally (Callable[[Unpack[Ts], T], None] has an implicit Unpack) but means that mypy focuses on the typevartuple, not making a constraint for our type variable.

I'm not really sure how to solve this myself, a bug report would probably work nicely.

Copy link
Member

Choose a reason for hiding this comment

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

@A5rocks probably worth cross-posting your analysis in the issue that teamspen opened.

@jakkdl
Copy link
Member

jakkdl commented Nov 22, 2023

for this PR: probably worth merging the signatures that work / type:ignoring the fails, so we don't have this lying around as a draft until the bug is resolved in mypy and get the incremental improvement. Especially as it pertains to deprecation of trio-typing

@A5rocks
Copy link
Contributor

A5rocks commented Nov 22, 2023

I think it depends on whether we want to release our next bug fix release sooner or later. Specifically due to the pyright issue w/ current release. Might not be good to have regressions in a common function!

@TeamSpen210
Copy link
Contributor Author

I'll split off the start() annotations to their own PR, since that's the only part that's not working right.

@TeamSpen210
Copy link
Contributor Author

I removed the start() signatures, making Mypy pass this fine. However, Pyright seems to be failing - if I do the full check offline, it seems to not be recognising typing_extensions.Unpack as something special?

@TeamSpen210 TeamSpen210 marked this pull request as ready for review November 28, 2023 03:58
Copy link
Contributor

@A5rocks A5rocks left a comment

Choose a reason for hiding this comment

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

I'm not sure why you're getting that from pyright, given it accepts this following program in VSCode on my machine:

from typing import Callable
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")

def x(f: Callable[[Unpack[Ts]], None], *args: Unpack[Ts]) -> None:
    return f(*args)

x(lambda x: print(x + 42), 42)

---

re: pyright looks like it's not seeing the TypeVarTuple right?

pyproject.toml Outdated Show resolved Hide resolved
@A5rocks
Copy link
Contributor

A5rocks commented Nov 28, 2023

Looks like pyright just hates the name PosArgT? If I ctrl+f and replace then all with PosArgTs then it all works ...???

EDIT: looks like it hates the import from _generated_run.py. If you remove that then it works.

@A5rocks
Copy link
Contributor

A5rocks commented Nov 30, 2023

Just a bump on this before I review!:

(Also I think you should add this to check.sh under the existing pyright run on type tests: pyright src/trio/_core/_tests/type_tests || EXIT_STATUS=$?)

edit: plus, now that I look at it, a newsfragment would be useful too!

@TeamSpen210
Copy link
Contributor Author

We may want to hold off on merging until the next Pyright version. It’ll have support for handling a callable with default arguments, making those optional parts of the TypeVarTuple. (microsoft/pyright#6623) We can then enable the test for that.

@A5rocks
Copy link
Contributor

A5rocks commented Dec 2, 2023

Pyright goes out in a weekly release and iirc pylance will pick it up in a month -- I think it's fine to merge and disregard this specific edge case that will resolve itself in <1 month.

(Hopefully I'm remembering my release schedules right)

@TeamSpen210
Copy link
Contributor Author

In bbd436d I added a pyright:ignore, since it was failing the test case I added for this. So we'd want to wait, so I can remove that ignore. Otherwise it'll start failing next time we update Pyright.

@jakkdl
Copy link
Member

jakkdl commented Dec 2, 2023

eh, we can just remove the ignore when updating it - that's probably less work than maintaining merge conflicts

@A5rocks
Copy link
Contributor

A5rocks commented Dec 6, 2023

Well pyright released a new version so... (I'll go run autodeps rn)

Copy link
Contributor

@A5rocks A5rocks left a comment

Choose a reason for hiding this comment

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

Looks good!

pyproject.toml Show resolved Hide resolved
pyproject.toml Outdated Show resolved Hide resolved
@CoolCat467
Copy link
Contributor

Oop, there's that segfault issue in pypy3.9 again. https://github.com/python-trio/trio/actions/runs/7120585043/job/19388115101

Co-authored-by: EXPLOSION <git@helvetica.moe>
@A5rocks
Copy link
Contributor

A5rocks commented Dec 7, 2023

Oop, there's that segfault issue in pypy3.9 again. https://github.com/python-trio/trio/actions/runs/7120585043/job/19388115101

This one's different from the other one you might be thinking about (iirc?) and it's one where I've provided more info in the issue so hopefully it'll resolve itself soon!

@A5rocks
Copy link
Contributor

A5rocks commented Dec 13, 2023

Mind checking my changes seem fine then merging? @TeamSpen210

@TeamSpen210 TeamSpen210 merged commit 597e345 into python-trio:master Dec 13, 2023
29 checks passed
@TeamSpen210 TeamSpen210 deleted the use-typevartuple branch December 13, 2023 04:20
@Zac-HD
Copy link
Member

Zac-HD commented Dec 13, 2023

Woohoo! Can we release this soon, to get the lovely typing benefits without waiting to sort out the ExceptionGroup transitions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typing Adding static types to trio's interface
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TypeVarTuple support
5 participants