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

Add/complete type annotations #193

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

CoolCat467
Copy link
Member

In this pull request, we add/complete the type annotations for this project.

@CoolCat467 CoolCat467 added the enhancement New feature or request label Jan 13, 2025
@CoolCat467 CoolCat467 requested review from jakkdl and A5rocks January 13, 2025 04:26
@A5rocks
Copy link

A5rocks commented Jan 13, 2025

I'd like @belm0 to comment on whether this is fine now. As of two years ago they preferred not adding type hints without material gain (#167 (comment)) but things have changed since:

  • more changes were necessary due to strict exception groups
  • it's been move into the trio org (I don't think it was here back then? Maybe I'm misremembering)
  • type hints have gotten another 2 years to become more standard and now there's nicer ways to write some stuff (like generic builtins and | for union)

@belm0 while I have you here, mind rereviewing #186?

Comment on lines +3 to +4
CloseReason as CloseReason,
ConnectionClosed as ConnectionClosed,
Copy link
Member

Choose a reason for hiding this comment

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

why is this needed?

Copy link

Choose a reason for hiding this comment

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

This is the syntax to re-export something. The alternatives are:

from a import b as b

or

from a import b

__all__ = ('b',)

(I think?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I understand this looks pretty weird, but this is done to inform type checkers that we are intending on publicly re-exporting these imports. Basically the problem is rooted in that other projects aren't as careful about what they export as Trio and this project, so typecheckers are set up to think that anything imported in your module is not intended to be used by people importing your module. Ie users using sys import from your module instead of importing sys themselves. Issue is though, how to tell type checkers that we are indeed intending on making this import public to consumers? Solution is this, import x as x, which while it's a bit ugly, it's better than making comments or something weight bearing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Without this, anyone using this module will encounter type issues on their end about these attributes not being publicly re-exported. There are several places in the test code that need type ignores because the tests access trio.__version__, which hasn't been marked as publicly re-exported.

Copy link
Member

Choose a reason for hiding this comment

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

mypy.ini Outdated Show resolved Hide resolved
trio_websocket/_impl.py Outdated Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

(the value of strict typing on test code seems relatively low)

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree to some extent, and at the time I did it purely to stop CI from raising errors, but I think it can still be useful for reference purposes in the event there is a CI failure and someone is unsure exactly why. Type annotations are not purely for type checking, they can also be used as a part of better documenting codebases and helping developers better understand what is going on.

Copy link

@A5rocks A5rocks Jan 16, 2025

Choose a reason for hiding this comment

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

Can't we remove the tests from the files mypy checks?

I haven't looked at this PR yet but looking at the other comments left I'm not sure tests are worthwhile to typecheck: things like making a fake SocketListener are obviously impossible to make typecheck. Notably, there's nearly as much of a diff in the tests as in the implementation and it drowns out things.

But also I haven't looked at the tests so it might be that they caught usage issues with types while you were adding them? I assume we could just look at the actual module code itself.

Copy link
Member

@belm0 belm0 Jan 16, 2025

Choose a reason for hiding this comment

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

I don't think strict typing is a good value for tests. It's a burden on top of something that's already hard to do, and there is no argument to be made about being an aid to API users, because it's test code.

I'm neutral on adding typing to the websocket API and impl, but -1 on adding typing to tests.

Copy link
Member

Choose a reason for hiding this comment

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

I'm +1 on adding typing to tests, especially for libraries. Even if you need a bunch of type: ignores or casts they can catch issues with type hints that would otherwise go unnoticed until an end user tries to type their code using your library and hitting arcane errors.
In trio we definitely found a bunch of this.

I don't think you should have strong expectations that the tests shouldn't contain casts or type: ignores though. If your test is doing weird shit that we don't expect users to do, then ignore away.

But e.g. it may be a sign that the types should be loosened if the library is not accepting MemoryStreams - since end users will themselves be doing tests with MemoryStreams+trio-websocket+their stuff, and it all in fact works with MemoryStreams

Copy link
Member

@jakkdl jakkdl left a comment

Choose a reason for hiding this comment

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

Awesome job! Mostly just a bunch of nitpicks

autobahn/client.py Outdated Show resolved Hide resolved
mypy.ini Outdated Show resolved Hide resolved
mypy.ini Outdated Show resolved Hide resolved
mypy.ini Outdated Show resolved Hide resolved
setup.py Outdated Show resolved Hide resolved
Comment on lines +3 to +4
CloseReason as CloseReason,
ConnectionClosed as ConnectionClosed,
Copy link
Member

Choose a reason for hiding this comment

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

trio_websocket/_impl.py Outdated Show resolved Hide resolved
trio_websocket/_impl.py Outdated Show resolved Hide resolved
Comment on lines +1425 to +1430
msg: str | bytes
# Type checker does not understand `_message_parts`
if isinstance(event, BytesMessage):
msg = b''.join(cast("list[bytes]", self._message_parts))
else:
msg = ''.join(cast("list[str]", self._message_parts))
Copy link
Member

Choose a reason for hiding this comment

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

hmm, this could maybe be resolved by making WebSocketConnection generic over bytes vs str?

Copy link
Member Author

@CoolCat467 CoolCat467 Jan 15, 2025

Choose a reason for hiding this comment

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

Would be a pretty good idea if not for the issue that at a protocol level messages can be str | bytes and client doesn't get to choose what they receive

trio_websocket/_impl.py Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants