Skip to content

Commit 11c8a9e

Browse files
authored
Merge pull request #1211 from PyThaiNLP/copilot/reduce-dependencies-in-pythainlp
Replace requests with urllib.request to reduce core dependencies
2 parents 717c185 + 16fbdc1 commit 11c8a9e

3 files changed

Lines changed: 52 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ Some features and fixes in this version are AI assisted.
1919
See PR for prompt and details.
2020

2121
- Lazy load dictionaries to reduce memory usage #1186
22+
- Fix KeyError when transliterating text with Thai alphabet Kho Khon (U+0E05) #1187
2223
- Consolidate configuration into pyproject.toml #1188
2324
- Update type hints; Use Python 3.9 features #1189 #1190
24-
- Fix KeyError when transliterating text with Thai alphabet Kho Khon (U+0E05) #1187
25+
- Replace requests library with urllib.request from standard library to reduce
26+
core dependencies #1211
2527

2628
## Version 5.1.2 -> 5.2.0
2729

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ classifiers = [
6161
]
6262

6363
# Core dependencies
64-
dependencies = ["requests>=2.31", "tzdata; sys_platform == 'win32'"]
64+
dependencies = ["tzdata; sys_platform == 'win32'"]
6565

6666
[project.optional-dependencies]
6767

pythainlp/corpus/core.py

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,55 @@
99
import json
1010
import os
1111
import re
12+
import sys
1213

1314
from pythainlp import __version__
1415
from pythainlp.corpus import corpus_db_path, corpus_db_url, corpus_path
1516
from pythainlp.tools import get_full_data_path
1617

1718
_CHECK_MODE = os.getenv("PYTHAINLP_READ_MODE")
19+
_USER_AGENT = (
20+
f"PyThaiNLP/{__version__} "
21+
f"(Python/{sys.version_info.major}.{sys.version_info.minor}; "
22+
f"{sys.platform})"
23+
)
24+
25+
26+
class _ResponseWrapper:
27+
"""Wrapper to provide requests.Response-like interface for urllib response."""
28+
29+
def __init__(self, response):
30+
self.status_code = response.status
31+
self.headers = response.headers
32+
self._content = response.read()
33+
34+
def json(self):
35+
"""Parse JSON content from response."""
36+
try:
37+
return json.loads(self._content.decode("utf-8"))
38+
except (json.JSONDecodeError, UnicodeDecodeError) as err:
39+
raise ValueError(f"Failed to parse JSON response: {err}")
1840

1941

2042
def get_corpus_db(url: str):
2143
"""Get corpus catalog from server.
2244
2345
:param str url: URL corpus catalog
2446
"""
25-
import requests
47+
from urllib.error import HTTPError, URLError
48+
from urllib.request import Request, urlopen
2649

2750
corpus_db = None
2851
try:
29-
corpus_db = requests.get(url, timeout=10)
30-
except requests.exceptions.HTTPError as http_err:
52+
req = Request(url, headers={"User-Agent": _USER_AGENT})
53+
with urlopen(req, timeout=10) as response:
54+
corpus_db = _ResponseWrapper(response)
55+
except HTTPError as http_err:
3156
print(f"HTTP error occurred: {http_err}")
32-
except requests.exceptions.RequestException as err:
33-
print(f"Non-HTTP error occurred: {err}")
57+
except URLError as err:
58+
print(f"URL error occurred: {err}")
59+
except Exception as err:
60+
print(f"Error occurred: {err}")
3461

3562
return corpus_db
3663

@@ -284,30 +311,28 @@ def _download(url: str, dst: str) -> int:
284311
"""
285312
CHUNK_SIZE = 64 * 1024 # 64 KiB
286313

287-
from urllib.request import urlopen
288-
289-
import requests
314+
from urllib.request import Request, urlopen
290315

291-
file_size = int(urlopen(url).info().get("Content-Length", -1))
292-
r = requests.get(url, stream=True, timeout=10)
293-
with open(get_full_data_path(dst), "wb") as f:
294-
pbar = None
295-
try:
296-
from tqdm.auto import tqdm
297-
298-
pbar = tqdm(total=int(r.headers["Content-Length"]))
299-
except ImportError:
316+
req = Request(url, headers={"User-Agent": _USER_AGENT})
317+
with urlopen(req, timeout=10) as response:
318+
file_size = int(response.info().get("Content-Length", -1))
319+
with open(get_full_data_path(dst), "wb") as f:
300320
pbar = None
321+
try:
322+
from tqdm.auto import tqdm
323+
324+
pbar = tqdm(total=file_size)
325+
except ImportError:
326+
pbar = None
301327

302-
for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
303-
if chunk:
328+
while chunk := response.read(CHUNK_SIZE):
304329
f.write(chunk)
305330
if pbar:
306331
pbar.update(len(chunk))
307-
if pbar:
308-
pbar.close()
309-
else:
310-
print("Done.")
332+
if pbar:
333+
pbar.close()
334+
else:
335+
print("Done.")
311336
return file_size
312337

313338

0 commit comments

Comments
 (0)