Skip to content

Commit 0c030f7

Browse files
authored
Merge pull request #6702 from nateprewitt/no_char_detection
Allow optional char detection dependencies in post-packaging
2 parents d6dded3 + 555b870 commit 0c030f7

File tree

5 files changed

+60
-23
lines changed

5 files changed

+60
-23
lines changed

.github/workflows/run-tests.yml

+20
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,23 @@ jobs:
3737
- name: Run tests
3838
run: |
3939
make ci
40+
41+
no_chardet:
42+
name: "No Character Detection"
43+
runs-on: ubuntu-latest
44+
strategy:
45+
fail-fast: true
46+
47+
steps:
48+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
49+
- name: 'Set up Python 3.8'
50+
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
51+
with:
52+
python-version: '3.8'
53+
- name: Install dependencies
54+
run: |
55+
make
56+
python -m pip uninstall -y "charset_normalizer" "chardet"
57+
- name: Run tests
58+
run: |
59+
make ci

src/requests/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ def check_compatibility(urllib3_version, chardet_version, charset_normalizer_ver
8383
# charset_normalizer >= 2.0.0 < 4.0.0
8484
assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0)
8585
else:
86-
raise Exception("You need either charset_normalizer or chardet installed")
86+
warnings.warn(
87+
"Unable to find acceptable character detection dependency "
88+
"(chardet or charset_normalizer).",
89+
RequestsDependencyWarning,
90+
)
8791

8892

8993
def _check_cryptography(cryptography_version):

src/requests/compat.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,28 @@
77
compatibility until the next major version.
88
"""
99

10-
try:
11-
import chardet
12-
except ImportError:
13-
import charset_normalizer as chardet
14-
10+
import importlib
1511
import sys
1612

13+
# -------------------
14+
# Character Detection
15+
# -------------------
16+
17+
18+
def _resolve_char_detection():
19+
"""Find supported character detection libraries."""
20+
chardet = None
21+
for lib in ("chardet", "charset_normalizer"):
22+
if chardet is None:
23+
try:
24+
chardet = importlib.import_module(lib)
25+
except ImportError:
26+
pass
27+
return chardet
28+
29+
30+
chardet = _resolve_char_detection()
31+
1732
# -------
1833
# Pythons
1934
# -------

src/requests/models.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,12 @@ def next(self):
789789
@property
790790
def apparent_encoding(self):
791791
"""The apparent encoding, provided by the charset_normalizer or chardet libraries."""
792-
return chardet.detect(self.content)["encoding"]
792+
if chardet is not None:
793+
return chardet.detect(self.content)["encoding"]
794+
else:
795+
# If no character detection library is available, we'll fall back
796+
# to a standard Python utf-8 str.
797+
return "utf-8"
793798

794799
def iter_content(self, chunk_size=1, decode_unicode=False):
795800
"""Iterates over the response data. When stream=True is set on the

src/requests/packages.py

+9-16
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import sys
22

3-
try:
4-
import chardet
5-
except ImportError:
6-
import warnings
7-
8-
import charset_normalizer as chardet
9-
10-
warnings.filterwarnings("ignore", "Trying to detect", module="charset_normalizer")
3+
from .compat import chardet
114

125
# This code exists for backwards compatibility reasons.
136
# I don't like it either. Just look the other way. :)
@@ -20,11 +13,11 @@
2013
if mod == package or mod.startswith(f"{package}."):
2114
sys.modules[f"requests.packages.{mod}"] = sys.modules[mod]
2215

23-
target = chardet.__name__
24-
for mod in list(sys.modules):
25-
if mod == target or mod.startswith(f"{target}."):
26-
imported_mod = sys.modules[mod]
27-
sys.modules[f"requests.packages.{mod}"] = imported_mod
28-
mod = mod.replace(target, "chardet")
29-
sys.modules[f"requests.packages.{mod}"] = imported_mod
30-
# Kinda cool, though, right?
16+
if chardet is not None:
17+
target = chardet.__name__
18+
for mod in list(sys.modules):
19+
if mod == target or mod.startswith(f"{target}."):
20+
imported_mod = sys.modules[mod]
21+
sys.modules[f"requests.packages.{mod}"] = imported_mod
22+
mod = mod.replace(target, "chardet")
23+
sys.modules[f"requests.packages.{mod}"] = imported_mod

0 commit comments

Comments
 (0)