|
43 | 43 | Union, |
44 | 44 | cast, |
45 | 45 | overload, |
| 46 | + runtime_checkable, |
46 | 47 | ) |
47 | 48 | from urllib.error import HTTPError |
48 | 49 | from urllib.parse import ParseResult, urlparse, urlunparse |
@@ -140,12 +141,14 @@ class ReadableBinStream(Protocol): |
140 | 141 | def read(self, size: int = -1) -> bytes: ... |
141 | 142 |
|
142 | 143 |
|
| 144 | +@runtime_checkable |
143 | 145 | class WriteSeekableBinStream(Protocol): |
144 | 146 | def write(self, b: bytes) -> int: ... |
145 | 147 | def seek(self, offset: int, whence: int = 0) -> int: ... |
146 | 148 | def tell(self) -> int: ... |
147 | 149 |
|
148 | 150 |
|
| 151 | +@runtime_checkable |
149 | 152 | class ReadSeekableBinStream(Protocol): |
150 | 153 | def seek(self, offset: int, whence: int = 0) -> int: ... |
151 | 154 | def tell(self) -> int: ... |
@@ -2465,19 +2468,34 @@ def _ensure_file_obj( |
2465 | 2468 | exit_stack.enter_context(fp) |
2466 | 2469 | return cast(FileProtoT, fp) |
2467 | 2470 |
|
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): |
2475 | 2473 | 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 |
2476 | 2482 | raise ExceptionClass( |
2477 | 2483 | f"Unsupported file-like object: {f}. Must satisfy: {FileProto}" |
2478 | 2484 | ) |
2479 | 2485 |
|
2480 | 2486 |
|
| 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 | + |
2481 | 2499 | class DbfReader(_FileChecker[ReadSeekableBinStream]): |
2482 | 2500 | """Reads a dbf file. You can instantiate a DbfReader without specifying a shapefile.""" |
2483 | 2501 |
|
|
0 commit comments