Skip to content

Commit 9530b67

Browse files
committed
Refactor imports, add tests, and clean up dependencies
- Replaced local `CaseInsensitiveDict` with `requests.structures.CaseInsensitiveDict` across multiple files - Added comprehensive test suite including: * Basic request tests (GET/POST) * Error handling tests * Session feature tests (cookies, headers, TLS) * Test configuration in `conftest.py` - Added `requests` as a dependency in `pyproject.toml` - Cleaned up `ClientIdentifiers` type formatting for better readability Cleanup notes: 1. The removal of `async_tls_client/structures.py` (commit 8283627) should have been part of this changeset since we're migrating to `requests.structures`. 2. The test-related `pyproject.toml` configuration (added in 9c38840) should have been included here instead, as it logically belongs with the new test suite. This change completes the transition away from internal structures while adding proper test coverage.
1 parent 9c38840 commit 9530b67

File tree

9 files changed

+125
-69
lines changed

9 files changed

+125
-69
lines changed

async_tls_client/cookies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import Any, MutableMapping, Union
55
from urllib.parse import urlparse, urlunparse
66

7-
from .structures import CaseInsensitiveDict
7+
from requests.structures import CaseInsensitiveDict
88

99
try:
1010
import threading

async_tls_client/response.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
import json
33
from typing import Union
44

5+
from requests.structures import CaseInsensitiveDict
6+
57
from .cookies import RequestsCookieJar, cookiejar_from_dict
6-
from .structures import CaseInsensitiveDict
78

89

910
class Response:

async_tls_client/session/async_session.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
from json import dumps, loads
77
from typing import Any, Optional, Union
88

9+
from requests.structures import CaseInsensitiveDict
10+
911
from async_tls_client.cffi import destroySession, freeMemory, request
1012
from async_tls_client.cookies import cookiejar_from_dict, extract_cookies_to_jar, merge_cookies
1113
from async_tls_client.exceptions import TLSClientException
1214
from async_tls_client.response import Response, build_response
13-
from async_tls_client.structures import CaseInsensitiveDict
1415
from async_tls_client.types import ClientIdentifiers, Curves, DelegatedSignatureAlgorithms, H2Settings, \
1516
SignatureAlgorithms, \
1617
TLSVersions

async_tls_client/types.py

Lines changed: 41 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,53 @@
22

33
ClientIdentifiers: TypeAlias = Literal[
44
# Chrome
5-
"chrome_103",
6-
"chrome_104",
7-
"chrome_105",
8-
"chrome_106",
9-
"chrome_107",
10-
"chrome_108",
11-
"chrome_109",
12-
"chrome_110",
13-
"chrome_111",
14-
"chrome_112",
15-
"chrome_116_PSK",
16-
"chrome_116_PSK_PQ",
17-
"chrome_117",
18-
"chrome_120",
19-
"chrome_124",
20-
"chrome_131",
21-
"chrome_131_PSK",
22-
"chrome_133",
23-
"chrome_133_PSK",
5+
"chrome_103", "chrome_104", "chrome_105", "chrome_106", "chrome_107",
6+
"chrome_108", "chrome_109", "chrome_110", "chrome_111", "chrome_112",
7+
"chrome_116_PSK", "chrome_116_PSK_PQ", "chrome_117", "chrome_120",
8+
"chrome_124", "chrome_131", "chrome_131_PSK", "chrome_133", "chrome_133_PSK",
249
# Safari
25-
"safari_15_6_1",
26-
"safari_16_0",
10+
"safari_15_6_1", "safari_16_0",
2711
# iOS (Safari)
28-
"safari_ios_15_5",
29-
"safari_ios_15_6",
30-
"safari_ios_16_0",
31-
"safari_ios_17_0",
32-
"safari_ios_18_0",
12+
"safari_ios_15_5", "safari_ios_15_6", "safari_ios_16_0", "safari_ios_17_0", "safari_ios_18_0",
3313
# iPadOS (Safari)
3414
"safari_ipad_15_6",
3515
# FireFox
36-
"firefox_102",
37-
"firefox_104",
38-
"firefox_105",
39-
"firefox_106",
40-
"firefox_108",
41-
"firefox_110",
42-
"firefox_117",
43-
"firefox_120",
44-
"firefox_123",
45-
"firefox_132",
46-
"firefox_133",
47-
"firefox_135",
16+
"firefox_102", "firefox_104", "firefox_105", "firefox_106", "firefox_108",
17+
"firefox_110", "firefox_117", "firefox_120", "firefox_123", "firefox_132",
18+
"firefox_133", "firefox_135",
4819
# Opera
49-
"opera_89",
50-
"opera_90",
51-
"opera_91",
20+
"opera_89", "opera_90", "opera_91",
5221
# OkHttp4
53-
"okhttp4_android_7",
54-
"okhttp4_android_8",
55-
"okhttp4_android_9",
56-
"okhttp4_android_10",
57-
"okhttp4_android_11",
58-
"okhttp4_android_12",
59-
"okhttp4_android_13",
22+
"okhttp4_android_7", "okhttp4_android_8", "okhttp4_android_9", "okhttp4_android_10",
23+
"okhttp4_android_11", "okhttp4_android_12", "okhttp4_android_13",
6024
# Custom
61-
"zalando_ios_mobile",
62-
"zalando_android_mobile",
63-
"nike_ios_mobile",
64-
"nike_android_mobile",
65-
"cloudscraper",
66-
"mms_ios",
67-
"mms_ios_1",
68-
"mms_ios_2",
69-
"mms_ios_3",
70-
"mesh_ios",
71-
"mesh_ios_1",
72-
"mesh_ios_2",
73-
"mesh_android",
74-
"mesh_android_1",
75-
"mesh_android_2",
76-
"confirmed_ios",
77-
"confirmed_android",
78-
"confirmed_android_2",
25+
"zalando_ios_mobile", "zalando_android_mobile", "nike_ios_mobile", "nike_android_mobile",
26+
"cloudscraper", "mms_ios", "mms_ios_1", "mms_ios_2", "mms_ios_3", "mesh_ios", "mesh_ios_1",
27+
"mesh_ios_2", "mesh_android", "mesh_android_1", "mesh_android_2", "confirmed_ios", "confirmed_android",
28+
"confirmed_android_2"
29+
]
30+
31+
# https://github.com/bogdanfinn/tls-client/blob/7a71edbf6e05acd4ade8e910e4c29c968003e27b/mapper.go#L29
32+
SignatureAlgorithms: TypeAlias = Literal[
33+
"PKCS1WithSHA256", "PKCS1WithSHA384", "PKCS1WithSHA512", "PSSWithSHA256", "PSSWithSHA384",
34+
"PSSWithSHA512", "ECDSAWithP256AndSHA256", "ECDSAWithP384AndSHA384", "ECDSAWithP521AndSHA512",
35+
"PKCS1WithSHA1", "ECDSAWithSHA1", "Ed25519", "SHA224_RSA", "SHA224_ECDSA"
36+
]
37+
38+
DelegatedSignatureAlgorithms: TypeAlias = SignatureAlgorithms
39+
40+
41+
# https://github.com/bogdanfinn/tls-client/blob/7a71edbf6e05acd4ade8e910e4c29c968003e27b/mapper.go#L21
42+
TLSVersions: TypeAlias = Literal["GREASE", "1.3", "1.2", "1.1", "1.0"]
43+
44+
# https://github.com/bogdanfinn/tls-client/blob/7a71edbf6e05acd4ade8e910e4c29c968003e27b/mapper.go#L75
45+
Curves: TypeAlias = Literal[
46+
"GREASE", "P256", "P384", "P521", "X25519", "P256Kyber768", "X25519Kyber512D",
47+
"X25519Kyber768", "X25519Kyber768Old", "X25519MLKEM768"
48+
]
49+
50+
# https://github.com/bogdanfinn/tls-client/blob/7a71edbf6e05acd4ade8e910e4c29c968003e27b/mapper.go#L9
51+
H2Settings: TypeAlias = Literal[
52+
"HEADER_TABLE_SIZE", "ENABLE_PUSH", "MAX_CONCURRENT_STREAMS", "INITIAL_WINDOW_SIZE", "MAX_FRAME_SIZE",
53+
"MAX_HEADER_LIST_SIZE", "UNKNOWN_SETTING_7", "UNKNOWN_SETTING_8", "UNKNOWN_SETTING_9"
7954
]

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ classifiers = [
2828
requires-python = ">=3.9"
2929
dependencies = [
3030
"typing-extensions>=4.0",
31+
"requests" # tested with 2.32.2
3132
]
3233

3334
[project.urls]

tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import pytest
2+
from async_tls_client import AsyncSession
3+
4+
@pytest.fixture
5+
async def session():
6+
async with AsyncSession(client_identifier="chrome120") as sess:
7+
yield sess

tests/test_basic_requests.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
3+
@pytest.mark.asyncio
4+
async def test_get_request(session):
5+
response = await session.get("https://httpbin.org/get")
6+
assert response.status_code == 200
7+
assert response.url == "https://httpbin.org/get"
8+
assert "headers" in response.json()
9+
10+
@pytest.mark.asyncio
11+
async def test_post_with_data(session):
12+
response = await session.post(
13+
"https://httpbin.org/post",
14+
data={"key": "value"}
15+
)
16+
assert response.status_code == 200
17+
assert response.json()["form"] == {"key": "value"}
18+
19+
@pytest.mark.asyncio
20+
async def test_post_with_json(session):
21+
response = await session.post(
22+
"https://httpbin.org/post",
23+
json={"key": "value"}
24+
)
25+
assert response.status_code == 200
26+
assert response.json()["json"] == {"key": "value"}

tests/test_errors.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pytest
2+
from async_tls_client.exceptions import TLSClientException
3+
4+
@pytest.mark.asyncio
5+
async def test_invalid_url(session):
6+
with pytest.raises(TLSClientException):
7+
await session.get("invalid://invalid-url")
8+
9+
@pytest.mark.asyncio
10+
async def test_timeout(session):
11+
with pytest.raises(TLSClientException):
12+
await session.get(
13+
"https://httpbin.org/delay/5",
14+
timeout_seconds=1
15+
)
16+
17+
@pytest.mark.asyncio
18+
async def test_nonexistent_domain(session):
19+
with pytest.raises(TLSClientException):
20+
await session.get("https://nonexistent-domain-12345.com")

tests/test_session_features.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pytest
2+
3+
@pytest.mark.asyncio
4+
async def test_cookie_handling(session):
5+
# Set cookie
6+
await session.get("https://httpbin.org/cookies/set/sessioncookie/12345")
7+
# Verify persistence
8+
response = await session.get("https://httpbin.org/cookies")
9+
assert response.json()["cookies"] == {"sessioncookie": "12345"}
10+
11+
@pytest.mark.asyncio
12+
async def test_custom_headers(session):
13+
response = await session.get(
14+
"https://httpbin.org/headers",
15+
headers={"X-Test-Header": "value"}
16+
)
17+
assert response.json()["headers"]["X-Test-Header"] == "value"
18+
19+
@pytest.mark.asyncio
20+
async def test_tls_fingerprinting(session):
21+
response = await session.get("https://tls.peet.ws/api/all")
22+
data = response.json()
23+
assert "tls" in data
24+
assert "ja3_hash" in data["tls"]
25+
assert len(data["tls"]["ja3_hash"]) == 32 # MD5 hash length

0 commit comments

Comments
 (0)