1+ from __future__ import annotations
2+
13import io
24import threading
35import time
46from contextlib import AbstractContextManager
57from queue import Queue
6- from typing import Optional
8+ from types import TracebackType
9+ from typing import TYPE_CHECKING , Any , Optional , overload
710
811from ._pygit2 import Blob , Oid
912from .enums import BlobFilter
1013
14+ if TYPE_CHECKING :
15+ from _typeshed import WriteableBuffer
16+
1117
1218class _BlobIO (io .RawIOBase ):
1319 """Low-level wrapper for streaming blob content.
@@ -26,7 +32,7 @@ def __init__(
2632 ):
2733 super ().__init__ ()
2834 self ._blob = blob
29- self ._queue = Queue (maxsize = 1 )
35+ self ._queue : Queue [ bytes | None ] | None = Queue (maxsize = 1 )
3036 self ._ready = threading .Event ()
3137 self ._writer_closed = threading .Event ()
3238 self ._chunk : Optional [bytes ] = None
@@ -42,10 +48,15 @@ def __init__(
4248 )
4349 self ._thread .start ()
4450
45- def __exit__ (self , exc_type , exc_value , traceback ):
51+ def __exit__ (
52+ self ,
53+ exc_type : type [BaseException ] | None ,
54+ exc_value : BaseException | None ,
55+ traceback : TracebackType | None ,
56+ ) -> None :
4657 self .close ()
4758
48- def isatty ():
59+ def isatty (self ):
4960 return False
5061
5162 def readable (self ):
@@ -57,7 +68,14 @@ def writable(self):
5768 def seekable (self ):
5869 return False
5970
60- def readinto (self , b , / ):
71+ # workaround for type checking
72+ if TYPE_CHECKING :
73+ @overload
74+ def readinto (self , b : WriteableBuffer , / ) -> int : ... # type: ignore
75+
76+ def readinto (self , b : Any , / ) -> int :
77+ if not self ._queue :
78+ raise RuntimeError ('Blob I/O is closed' )
6179 try :
6280 while self ._chunk is None :
6381 self ._ready .wait ()
@@ -96,7 +114,7 @@ def close(self):
96114 self ._queue = None
97115
98116
99- class BlobIO (io .BufferedReader , AbstractContextManager ):
117+ class BlobIO (io .BufferedReader , AbstractContextManager [ 'BlobIO' ] ):
100118 """Read-only wrapper for streaming blob content.
101119
102120 Supports reading both raw and filtered blob content.
@@ -147,7 +165,12 @@ def __init__(
147165 raw = _BlobIO (blob , as_path = as_path , flags = flags , commit_id = commit_id )
148166 super ().__init__ (raw )
149167
150- def __exit__ (self , exc_type , exc_value , traceback ):
168+ def __exit__ (
169+ self ,
170+ exc_type : type [BaseException ] | None ,
171+ exc_value : BaseException | None ,
172+ traceback : TracebackType | None ,
173+ ) -> None :
151174 self .close ()
152175
153176
0 commit comments