|
24 | 24 | # |
25 | 25 | # -------------------------------------------------------------------------- |
26 | 26 | from __future__ import annotations |
| 27 | +from functools import cache |
27 | 28 | import sys |
28 | 29 | from typing import ( |
29 | 30 | Any, |
| 31 | + Callable, |
| 32 | + NoReturn, |
30 | 33 | Optional, |
31 | 34 | AsyncIterator as AsyncIteratorType, |
32 | 35 | TYPE_CHECKING, |
|
35 | 38 | Union, |
36 | 39 | Type, |
37 | 40 | MutableMapping, |
| 41 | + Mapping, |
38 | 42 | ) |
39 | 43 | from types import TracebackType |
40 | 44 | from collections.abc import AsyncIterator |
|
88 | 92 | class ConnectionTimeoutError(Exception): ... # type: ignore[no-redef] |
89 | 93 |
|
90 | 94 |
|
| 95 | +@cache |
| 96 | +def _get_detect() -> Callable[[bytes], Mapping[str, Any]]: |
| 97 | + try: |
| 98 | + from cchardet import detect |
| 99 | + |
| 100 | + return detect |
| 101 | + except ImportError: # pragma: no cover |
| 102 | + try: |
| 103 | + from chardet import detect |
| 104 | + |
| 105 | + return detect |
| 106 | + except ImportError: # pragma: no cover |
| 107 | + try: |
| 108 | + from charset_normalizer import detect |
| 109 | + |
| 110 | + return detect |
| 111 | + except ImportError as e: # pragma: no cover |
| 112 | + charset_import_err = e |
| 113 | + |
| 114 | + def error_detect(_: bytes) -> NoReturn: |
| 115 | + raise charset_import_err |
| 116 | + |
| 117 | + return error_detect |
| 118 | + |
| 119 | + |
91 | 120 | class AioHttpTransport(AsyncHttpTransport): |
92 | 121 | """AioHttp HTTP sender implementation. |
93 | 122 |
|
@@ -525,16 +554,7 @@ def text(self, encoding: Optional[str] = None) -> str: |
525 | 554 | elif body is None: |
526 | 555 | raise RuntimeError("Cannot guess the encoding of a not yet read body") |
527 | 556 | else: |
528 | | - try: |
529 | | - import cchardet as chardet |
530 | | - except ImportError: # pragma: no cover |
531 | | - try: |
532 | | - import chardet # type: ignore |
533 | | - except ImportError: # pragma: no cover |
534 | | - import charset_normalizer as chardet # type: ignore[no-redef] |
535 | | - # While "detect" can return a dict of float, in this context this won't happen |
536 | | - # The cast is for pyright to be happy |
537 | | - encoding = cast(Optional[str], chardet.detect(body)["encoding"]) |
| 557 | + encoding = _get_detect()(body)["encoding"] |
538 | 558 | if encoding == "utf-8" or encoding is None: |
539 | 559 | encoding = "utf-8-sig" |
540 | 560 |
|
|
0 commit comments