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

How much runtime introspection of types is a good thing? #2687

Closed
A5rocks opened this issue Jul 6, 2023 · 6 comments
Closed

How much runtime introspection of types is a good thing? #2687

A5rocks opened this issue Jul 6, 2023 · 6 comments
Labels
typing Adding static types to trio's interface

Comments

@A5rocks
Copy link
Contributor

A5rocks commented Jul 6, 2023

As I write this, one of the open typing PRs has a function reference a type behind a if typing.TYPE_CHECKING branch. This means that the function is not very introspectable.

I'm just opening this issue as a quick way to dump thoughts if I get any and to resolve that specific conversation. I don't have solutions and I don't really understand the tradeoffs. Here's the problem as I understand it:

The upsides are:

  • nicer types
  • nicer type syntax
  • slightly lower import times (... there's probably some low-hanging fruit here so I don't think this is too much a concern)

The downsides are:

  • ... runtime introspection?

See, I don't really understand the downsides. I know that there's use cases related to this but I don't know what or if they're even relevant here!

@TeamSpen210
Copy link
Contributor

In general it means the annotations at runtime are invalid, and can't be evaluated. Anyone passing an affected Trio type or function into a runtime typing library is going to unexpectedly get strange errors. It's also not really possible at all in some cases, like if you wanted to inherit from Protocol.

Additionally, I know Sphinx does runtime introspection for the autoXXX feature, so if we enable showing annotations there'll be piles of errors there as Sphinx tries to resolve the non-existent types. Not a problem for the syntax changes since docs would be run on the latest versions, but TYPE_CHECKING would break there.

@A5rocks
Copy link
Contributor Author

A5rocks commented Jul 6, 2023

We talked a bit about this on Gitter and my current opinion is that we should allow language/syntax changes (e.g. newer aliases) but not a blunt application of if typing.TYPE_CHECKING. I'm still fine with using it to lie to type checkers about the type of something, but I don't want imaginary types floating around annotations. This way, if something does come up, people can just use a new version of Python (e.g. if Sphinx works better with runtime introspection of types instead of just doing its own thing with the string-version annotation).

@jakkdl
Copy link
Member

jakkdl commented Jul 6, 2023

While hiding imports being a type-checking guard does improve import speed, in my experience the main reason is to avoid import cycles. I've many times encountered straight up two-way import dependencies A <-> B introduced due to adding type hints, and guarding the imports (or doing very fancy stuff like putting imports at the bottom of the file) has been the best way of resolving them. I also like the distinction in the import list between what's actually needed for the program to run, vs what's just type imports, to get a better sense of what's going on.

But I've never used any runtime type checker, so I haven't really encountered the downsides myself. But trio is... messed up enough, with enough function signatures being behind TYPE_CHECKING-guards due to weird wrapping / typing limitations / tradeoffs between speed vs signature / typing not having been considered until very recently, that a thorough level of support for runtime checking is a ways away.
And I've yet to try tackle the really tricky signatures of trio.run or trio.open_nursery.

I could try to default to not hiding anything behind type-checking guards unless it's especially needed though, though at that point I really want #2686 since the import list is going to grow a lot and will be changing frequently.

@jakkdl
Copy link
Member

jakkdl commented Jul 13, 2023

If we really do want runtime introspection we could probably get most of the way if we stopped doing

from .foo.blah import FooType

def foo(f: FooType):
  ...

and resorted to doing

import trio

def foo(f: trio.foo.blah.FooType):
  ...

I'm used to doing the former, but could do the latter if you want runtime introspection. But it'll lead to quite messy and verbose signatures.

@Fuyukai
Copy link
Member

Fuyukai commented Jul 21, 2023

The only possible usecases I can think of for runtime introspection is autodocumenting type hints, or serialisation. I fail to see why you would ever serialise a Trio class. I vote for just using 3.11+ syntax behind if TYPE_CHECKING for the sake of maintainer wellbeing.

@A5rocks
Copy link
Contributor Author

A5rocks commented Nov 4, 2023

I think status quo works. We can just continue to allow just as much runtime introspection as Sphinx needs to work nicely. (We've had several PRs where we needed to move something to runtime so that Sphinx could see it!)

If anyone does actually need runtime introspection, they can raise an issue with their use case! Genuinely not sure what it could be.

If I forgot something, feel free to reopen.

@A5rocks A5rocks closed this as completed Nov 4, 2023
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

No branches or pull requests

4 participants