Skip to content

Commit c55fbee

Browse files
committed
Restore runtime_checkable & isinstance. Register _TemporaryFileWrapper as WriteSeekableBin too
1 parent d458da8 commit c55fbee

1 file changed

Lines changed: 25 additions & 7 deletions

File tree

src/shapefile.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
Union,
4444
cast,
4545
overload,
46+
runtime_checkable,
4647
)
4748
from urllib.error import HTTPError
4849
from urllib.parse import ParseResult, urlparse, urlunparse
@@ -140,12 +141,14 @@ class ReadableBinStream(Protocol):
140141
def read(self, size: int = -1) -> bytes: ...
141142

142143

144+
@runtime_checkable
143145
class WriteSeekableBinStream(Protocol):
144146
def write(self, b: bytes) -> int: ...
145147
def seek(self, offset: int, whence: int = 0) -> int: ...
146148
def tell(self) -> int: ...
147149

148150

151+
@runtime_checkable
149152
class ReadSeekableBinStream(Protocol):
150153
def seek(self, offset: int, whence: int = 0) -> int: ...
151154
def tell(self) -> int: ...
@@ -2465,19 +2468,34 @@ def _ensure_file_obj(
24652468
exit_stack.enter_context(fp)
24662469
return cast(FileProtoT, fp)
24672470

2468-
# Ugly, but we need to apply this to TemporaryFiles, and tempfile
2469-
# is a platform-inconsistent stick mess of dynamic wrappers,
2470-
# leading to weird Python 3.14 specific bug in run_benchmarks.py
2471-
# on Windows
2472-
attrs = FileProto.__protocol_attrs__ # type: ignore[attr-defined]
2473-
2474-
if all(hasattr(f, attr) for attr in attrs):
2471+
# See Minor hack below.
2472+
if isinstance(f, FileProto):
24752473
return f
2474+
2475+
# Ugly, but perhaps needed to avoid weird Python 3.14
2476+
# specific bug in run_benchmarks.py on Windows
2477+
# if (
2478+
# (attrs := getattr(FileProto, "__protocol_attrs__", None))
2479+
# and all(hasattr(f, attr) for attr in attrs)
2480+
# ):
2481+
# return f
24762482
raise ExceptionClass(
24772483
f"Unsupported file-like object: {f}. Must satisfy: {FileProto}"
24782484
)
24792485

24802486

2487+
# Minor hack. Relies on Protocols being ABC subclasses.
2488+
# They are currently ABCs anyway, so why not use that
2489+
# for something useful?
2490+
#
2491+
# tempfile.NamedTemporaryFile is a dynamic wrapper
2492+
# https://github.com/python/cpython/blob/2dd91d2b92a6c74d78cd3385ede328190cd8eaa9/Lib/tempfile.py#L510
2493+
# so normal (naive) isinstance checks of tempfile.NamedTemporaryFiles
2494+
# against @runtime_checkable Protocols are not possible.
2495+
ReadSeekableBinStream.register(tempfile._TemporaryFileWrapper)
2496+
WriteSeekableBinStream.register(tempfile._TemporaryFileWrapper)
2497+
2498+
24812499
class DbfReader(_FileChecker[ReadSeekableBinStream]):
24822500
"""Reads a dbf file. You can instantiate a DbfReader without specifying a shapefile."""
24832501

0 commit comments

Comments
 (0)