Skip to content

Commit

Permalink
Allow character detection dependencies to be optional in post-packagi…
Browse files Browse the repository at this point in the history
…ng steps
  • Loading branch information
nateprewitt committed May 14, 2024
1 parent d6dded3 commit 555b870
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 23 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,23 @@ jobs:
- name: Run tests
run: |
make ci
no_chardet:
name: "No Character Detection"
runs-on: ubuntu-latest
strategy:
fail-fast: true

steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: 'Set up Python 3.8'
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
with:
python-version: '3.8'
- name: Install dependencies
run: |
make
python -m pip uninstall -y "charset_normalizer" "chardet"
- name: Run tests
run: |
make ci
6 changes: 5 additions & 1 deletion src/requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ def check_compatibility(urllib3_version, chardet_version, charset_normalizer_ver
# charset_normalizer >= 2.0.0 < 4.0.0
assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0)
else:
raise Exception("You need either charset_normalizer or chardet installed")
warnings.warn(
"Unable to find acceptable character detection dependency "
"(chardet or charset_normalizer).",
RequestsDependencyWarning,
)


def _check_cryptography(cryptography_version):
Expand Down
25 changes: 20 additions & 5 deletions src/requests/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@
compatibility until the next major version.
"""

try:
import chardet
except ImportError:
import charset_normalizer as chardet

import importlib
import sys

# -------------------
# Character Detection
# -------------------


def _resolve_char_detection():
"""Find supported character detection libraries."""
chardet = None
for lib in ("chardet", "charset_normalizer"):
if chardet is None:
try:
chardet = importlib.import_module(lib)
except ImportError:
pass
return chardet


chardet = _resolve_char_detection()

# -------
# Pythons
# -------
Expand Down
7 changes: 6 additions & 1 deletion src/requests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,12 @@ def next(self):
@property
def apparent_encoding(self):
"""The apparent encoding, provided by the charset_normalizer or chardet libraries."""
return chardet.detect(self.content)["encoding"]
if chardet is not None:
return chardet.detect(self.content)["encoding"]
else:
# If no character detection library is available, we'll fall back
# to a standard Python utf-8 str.
return "utf-8"

def iter_content(self, chunk_size=1, decode_unicode=False):
"""Iterates over the response data. When stream=True is set on the
Expand Down
25 changes: 9 additions & 16 deletions src/requests/packages.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import sys

try:
import chardet
except ImportError:
import warnings

import charset_normalizer as chardet

warnings.filterwarnings("ignore", "Trying to detect", module="charset_normalizer")
from .compat import chardet

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

target = chardet.__name__
for mod in list(sys.modules):
if mod == target or mod.startswith(f"{target}."):
imported_mod = sys.modules[mod]
sys.modules[f"requests.packages.{mod}"] = imported_mod
mod = mod.replace(target, "chardet")
sys.modules[f"requests.packages.{mod}"] = imported_mod
# Kinda cool, though, right?
if chardet is not None:
target = chardet.__name__
for mod in list(sys.modules):
if mod == target or mod.startswith(f"{target}."):
imported_mod = sys.modules[mod]
sys.modules[f"requests.packages.{mod}"] = imported_mod
mod = mod.replace(target, "chardet")
sys.modules[f"requests.packages.{mod}"] = imported_mod

0 comments on commit 555b870

Please sign in to comment.