Skip to content

Commit 2df97a6

Browse files
authored
Merge pull request #242 from crytic/requests
Replace urllib with requests
2 parents 032a571 + f0d3a4e commit 2df97a6

File tree

5 files changed

+232
-30
lines changed

5 files changed

+232
-30
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ version = "1.1.0"
88
dependencies = [
99
"pycryptodome>=3.4.6",
1010
"packaging",
11+
"requests>=2.32.4",
1112
]
1213
requires-python = ">= 3.8"
1314
authors = [

solc_select/solc_select.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import argparse
22
import contextlib
33
import hashlib
4-
import json
54
import os
65
import re
76
import shutil
87
import subprocess
98
import sys
10-
import urllib.request
119
from pathlib import Path
1210
from typing import Dict, List, Optional, Tuple
1311
from zipfile import ZipFile
@@ -30,6 +28,7 @@
3028
WINDOWS_AMD64,
3129
)
3230
from .utils import (
31+
create_http_session,
3332
get_arch,
3433
mac_binary_is_native,
3534
mac_binary_is_universal,
@@ -242,7 +241,13 @@ def install_artifacts(versions: List[str], silent: bool = False) -> bool:
242241
Path.mkdir(artifact_file_dir, parents=True, exist_ok=True)
243242
if not silent:
244243
print(f"Installing solc '{version}'...")
245-
urllib.request.urlretrieve(url, artifact_file_dir.joinpath(f"solc-{version}"))
244+
session = create_http_session()
245+
response = session.get(url)
246+
response.raise_for_status()
247+
248+
with open(artifact_file_dir.joinpath(f"solc-{version}"), "wb") as f:
249+
for chunk in response.iter_content(chunk_size=8192):
250+
f.write(chunk)
246251

247252
verify_checksum(version)
248253

@@ -310,9 +315,10 @@ def verify_checksum(version: str) -> None:
310315

311316
def get_soliditylang_checksums(version: str) -> Tuple[str, Optional[str]]:
312317
(_, list_url) = get_url(version=version)
313-
# pylint: disable=consider-using-with
314-
list_json = urllib.request.urlopen(list_url).read()
315-
builds = json.loads(list_json)["builds"]
318+
session = create_http_session()
319+
response = session.get(list_url)
320+
response.raise_for_status()
321+
builds = response.json()["builds"]
316322
matches = list(filter(lambda b: b["version"] == version, builds))
317323

318324
if not matches or not matches[0]["sha256"]:
@@ -414,21 +420,24 @@ def get_installable_versions() -> List[str]:
414420
return installable
415421

416422

417-
# pylint: disable=consider-using-with
418423
def get_available_versions() -> Dict[str, str]:
424+
session = create_http_session()
419425
(_, list_url) = get_url()
420-
list_json = urllib.request.urlopen(list_url).read()
421-
available_releases = json.loads(list_json)["releases"]
422-
# pylint: disable=consider-using-with
426+
response = session.get(list_url)
427+
response.raise_for_status()
428+
available_releases = response.json()["releases"]
429+
423430
if soliditylang_platform() == LINUX_AMD64:
424431
(_, list_url) = get_url(version=EARLIEST_RELEASE[LINUX_AMD64])
425-
github_json = urllib.request.urlopen(list_url).read()
426-
additional_linux_versions = json.loads(github_json)["releases"]
432+
response = session.get(list_url)
433+
response.raise_for_status()
434+
additional_linux_versions = response.json()["releases"]
427435
available_releases.update(additional_linux_versions)
428436
elif sys.platform == "darwin" and get_arch() == "arm64":
429437
# Fetch Alloy versions for ARM64 Darwin
430-
alloy_json = urllib.request.urlopen(ALLOY_SOLC_JSON).read()
431-
alloy_releases = json.loads(alloy_json)["releases"]
438+
response = session.get(ALLOY_SOLC_JSON)
439+
response.raise_for_status()
440+
alloy_releases = response.json()["releases"]
432441
# Filter to only include versions in the supported range (0.8.24+ are already universal)
433442
filtered_alloy_releases = {
434443
version: release
@@ -455,7 +464,9 @@ def soliditylang_platform() -> str:
455464

456465

457466
def get_latest_release() -> str:
467+
session = create_http_session()
458468
(_, list_url) = get_url()
459-
list_json = urllib.request.urlopen(list_url).read()
460-
latest_release = json.loads(list_json)["latestRelease"]
469+
response = session.get(list_url)
470+
response.raise_for_status()
471+
latest_release = response.json()["latestRelease"]
461472
return latest_release

solc_select/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,31 @@
44
from pathlib import Path
55
from typing import List
66

7+
import requests
78
from packaging.version import Version
9+
from requests.adapters import HTTPAdapter
10+
from requests.packages.urllib3.util.retry import Retry
11+
12+
13+
def create_http_session() -> requests.Session:
14+
"""Create a new HTTP session with retry logic for rate limits and server errors."""
15+
session = requests.Session()
16+
17+
# Configure retry strategy for 429s and server errors
18+
retry_strategy = Retry(
19+
total=5,
20+
backoff_factor=1,
21+
status_forcelist=[429, 500, 502, 503, 504],
22+
)
23+
24+
adapter = HTTPAdapter(max_retries=retry_strategy)
25+
session.mount("http://", adapter)
26+
session.mount("https://", adapter)
27+
28+
# Set standard timeouts (connect_timeout, read_timeout)
29+
session.timeout = (10, 60) # 10s connection, 60s read for downloads
30+
31+
return session
832

933

1034
def get_arch() -> str:

tests/test_platform_specific.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
This module contains tests that are specific to Linux, macOS, and Windows.
55
"""
66

7-
import json
8-
import urllib.request
9-
107
import pytest
8+
import requests
119

1210
from .utils import run_command
1311

@@ -61,9 +59,10 @@ def test_version_boundaries(self, platform, config, isolated_solc_data):
6159
)
6260

6361
# Get and test latest version
64-
with urllib.request.urlopen(api_url) as response:
65-
data = json.loads(response.read())
66-
latest_release = data["latestRelease"]
62+
response = requests.get(api_url)
63+
response.raise_for_status()
64+
data = response.json()
65+
latest_release = data["latestRelease"]
6766

6867
result = run_command(f"solc-select use {latest_release}", check=False)
6968
assert result.returncode == 0

0 commit comments

Comments
 (0)