Skip to content

Define types for AsyncIOWrapper and trio.Path#2706

Merged
jakkdl merged 31 commits intopython-trio:masterfrom
TeamSpen210:typed-filewrapper
Jul 28, 2023
Merged

Define types for AsyncIOWrapper and trio.Path#2706
jakkdl merged 31 commits intopython-trio:masterfrom
TeamSpen210:typed-filewrapper

Conversation

@TeamSpen210
Copy link
Contributor

This fully types both these wrapper classes. Dealing with the complicated hierarchy of IO methods was tricky, until I realised self-type-protocols can be used to make AsyncIOWrapper only have the methods that the underlying file does. It does unfortunately require a rather verbose set of definitions. It could be simplified a little by grouping methods that always are defined together, but that's less accurate.

Due to the length of the stub definitions, I did turn off Black formatting there so they could be formatted compactly like type stubs, otherwise the line count would get much longer and harder to read. Not sure what's desirable either way?

@codecov
Copy link

codecov bot commented Jul 16, 2023

Codecov Report

Merging #2706 (d90a4ed) into master (e545484) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2706   +/-   ##
=======================================
  Coverage   98.89%   98.89%           
=======================================
  Files         113      113           
  Lines       16490    16552   +62     
  Branches     3000     3006    +6     
=======================================
+ Hits        16307    16369   +62     
  Misses        126      126           
  Partials       57       57           
Files Changed Coverage Δ
trio/_file_io.py 100.00% <100.00%> (ø)
trio/_path.py 100.00% <100.00%> (ø)
trio/_tests/test_file_io.py 100.00% <100.00%> (ø)
trio/_util.py 100.00% <100.00%> (ø)

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.

Looks ... about as good as it could look 😅

I would like to see you enable stricter checks for these files in pyproject.toml as I've done in my PR's: https://github.com/python-trio/trio/pull/2705/files#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711
At least disallow_untyped_defs - but disallow_any_expr would be nice as well. My thinking was that we'll gradually allow those for all files (at some point, transitioning to it being an ignore-list instead of an enable-list).

Are there really no changes to _tests/verify_types.json? Looks like there's 14 lines referencing _path atm:

"trio._path.AsyncAutoWrapperType.__init__",
"trio._path.AsyncAutoWrapperType.generate_forwards",
"trio._path.AsyncAutoWrapperType.generate_iter",
"trio._path.AsyncAutoWrapperType.generate_magic",
"trio._path.AsyncAutoWrapperType.generate_wraps",
"trio._path.Path",
"trio._path.Path.__bytes__",
"trio._path.Path.__dir__",
"trio._path.Path.__fspath__",
"trio._path.Path.__init__",
"trio._path.Path.__repr__",
"trio._path.Path.__rtruediv__",
"trio._path.Path.__truediv__",
"trio._path.Path.open",

and open_file & wrap_file seems to be in there as well.

Comment on lines +77 to +83
FileT = TypeVar("FileT")
FileT_co = TypeVar("FileT_co", covariant=True)
T = TypeVar("T")
T_co = TypeVar("T_co", covariant=True)
T_contra = TypeVar("T_contra", contravariant=True)
AnyStr_co = TypeVar("AnyStr_co", str, bytes, covariant=True)
AnyStr_contra = TypeVar("AnyStr_contra", str, bytes, contravariant=True)
Copy link
Member

Choose a reason for hiding this comment

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

These types might also warrant some comments. One day I'll get comfortable with co- & contravariant - but some brief comments here saying which ones are used where and why will probably help readers and any future people trying to modify it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I mainly picked/needed them because protocols complain if you don't have the right ones :)

@TeamSpen210 TeamSpen210 requested a review from jakkdl July 17, 2023 02:27
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.

Looks great!

@A5rocks A5rocks added the typing Adding static types to trio's interface label Jul 18, 2023
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.

My eyes glazed over when looking over trio/_path.py. I'll take a look later.

trio/_file_io.py Outdated

class _HasNewlines(Protocol):
@property
def newlines(self) -> Any: ... # None, str or tuple
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really understand this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I preserved it from the io type hints, looks like the docs say this returns those but typeshed chose to make it Any. Actually we could just use a typevar here to do whatever the file object says it returns.

newline: str | None = None,
closefd: bool = True,
opener: _Opener | None = None,
) -> AsyncIOWrapper[IO[Any]]:
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really like this Any but I suppose practicality over purity...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It corresponds to what's in typeshed for regular open. That overload's only going to be taken for a non-literal mode, where we don't really have any idea what IO object we're getting...

@Fuyukai
Copy link
Member

Fuyukai commented Jul 21, 2023

Posting in this issue too that type hinting trio.Path implies it is a legitimate class and not a bastard hack that needs to be prosecuted with prejudice.

@jakkdl jakkdl requested a review from A5rocks July 26, 2023 11:42
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 just going to trust this is all good!

@jakkdl jakkdl merged commit 2fd005b into python-trio:master Jul 28, 2023
@jakkdl
Copy link
Member

jakkdl commented Jul 28, 2023

🚀

@TeamSpen210 TeamSpen210 deleted the typed-filewrapper branch July 28, 2023 18:09
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.

4 participants