11from __future__ import annotations
22
33import functools
4+ import io
45import itertools
6+ import os
57import re
68import sys
79import textwrap
1315 Protocol ,
1416 SupportsIndex ,
1517 TypeVar ,
18+ Union ,
19+ cast ,
1620 overload ,
1721)
1822
3135 _T_co = TypeVar ("_T_co" , covariant = True )
3236 # Same as builtins._GetItemIterable from typeshed
3337 _GetItemIterable : TypeAlias = SupportsGetItem [int , _T_co ]
38+ Openable : TypeAlias = FileDescriptorOrPath
39+ else :
40+ Openable = Union [str , bytes , os .PathLike , int ]
3441
3542_T = TypeVar ("_T" )
3643
@@ -688,9 +695,15 @@ def join_continuation(lines: _GetItemIterable[str]) -> Generator[str]:
688695 yield item
689696
690697
698+ # https://docs.python.org/3/library/io.html#io.TextIOBase.newlines
699+ NewlineSpec : TypeAlias = Union [str , tuple [str , ...], None ]
700+
701+
702+ @functools .singledispatch
691703def read_newlines (
692- filename : FileDescriptorOrPath , limit : int | None = 1024
693- ) -> str | tuple [str , ...] | None :
704+ filename : Union [Openable , io .TextIOWrapper ], # noqa: UP007 # singledispatch uses the annotation at runtime (python 3.9)
705+ limit : int | None = 1024 ,
706+ ) -> NewlineSpec :
694707 r"""
695708 >>> tmp_path = getfixture('tmp_path')
696709 >>> filename = tmp_path / 'out.txt'
@@ -704,9 +717,21 @@ def read_newlines(
704717 >>> read_newlines(filename)
705718 ('\r', '\n', '\r\n')
706719 """
720+ if sys .version_info >= (3 , 10 ):
721+ assert isinstance (filename , Openable )
722+ else : # pragma: no cover
723+ filename = cast (Openable , filename )
707724 with open (filename , encoding = 'utf-8' ) as fp :
708- fp .read (limit )
709- return fp .newlines
725+ return read_newlines (fp , limit = limit )
726+
727+
728+ @read_newlines .register
729+ def _ (
730+ filename : io .TextIOWrapper ,
731+ limit : Union [int , None ] = 1024 , # noqa: UP007 # singledispatch uses the annotation at runtime (python 3.9)
732+ ) -> NewlineSpec :
733+ filename .read (limit )
734+ return filename .newlines
710735
711736
712737def lines_from (input : Traversable ) -> Generator [str ]:
0 commit comments