-
-
Notifications
You must be signed in to change notification settings - Fork 343
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
Use TypeVarTuple in our APIs #2881
Conversation
Codecov Report
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
|
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] |
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.
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.
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.
Unfortunately no, the *args
already makes it keyword-only.
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.
Yeah sorry about the repeated confusion with this thread, TypeVarTuple
is getting to my head :(
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.
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.
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 agree. I took a look at mypy's code for the last 45 minutes and spotted:
- 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 literallyNever
) to us) - 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 totuple[Any, ...]
and our callable doesn't take in infinite parameters. - 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 implicitUnpack
) 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.
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.
@A5rocks probably worth cross-posting your analysis in the issue that teamspen opened.
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 |
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! |
I'll split off the |
e7eb824
to
749ef94
Compare
I removed the |
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'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?
Looks like pyright just hates the name EDIT: looks like it hates the import from |
Just a bump on this before I review!:
edit: plus, now that I look at it, a newsfragment would be useful too! |
9bf6a36
to
972961e
Compare
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. |
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) |
In bbd436d I added a |
eh, we can just remove the ignore when updating it - that's probably less work than maintaining merge conflicts |
Well pyright released a new version so... (I'll go run autodeps rn) |
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.
Looks good!
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 <[email protected]>
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! |
Mind checking my changes seem fine then merging? @TeamSpen210 |
Woohoo! Can we release this soon, to get the lovely typing benefits without waiting to sort out the ExceptionGroup transitions? |
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 forNursery.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...