Repository navigation
2.0.0
First release since 1.0.1. The native library goes from bogdanfinn/tls-client v1.7.2 to v1.16.0, every platform gets its own wheel, and requests and responses now behave much more like requests. Several of those fixes change behaviour, so read Breaking changes before upgrading.
Breaking changes
- Python 3.10 or newer is required.
TLSClientExeptionis renamed toTLSClientException.- An unknown
client_identifierraisesValueErrorand suggests close matches. Before, the native library silently fell back to its default profile. Some names in the old README never existed (chrome109,Chrome110,chrome111,chrome112,firefox108,Firefox110,safari_15_3).confirmed_android_2is gone because upstream removed it. response.contentis the exact bytes the server sent. Before, it was the library's UTF-8 text encoded again, which corrupted binary bodies.response.textis read-only. It is decoded fromcontentusing the charset inContent-Type, or UTF-8 when there is none. HTML<meta charset>is no longer read. For those pages, set the encoding before readingtext:r.encoding = "iso-8859-1" r.text
session.headersno longer picks up aContent-Typeafter ajson=ordata=request. If you relied on that, set the header yourself.- Cookies live only in
session.cookies. The native library's cookie jar is off.- A cookie you delete from
session.cookiesis no longer sent. - A cookie the server expires is removed from the jar.
- Cookie values are sent exactly as stored. The native library used to strip
"from them.
- A cookie you delete from
- Redirects are followed in Python, the way
requestsdoes it.- There is a limit of 30 hops, after which
TooManyRedirectsis raised. - 301/302 turn POST into GET, and 303 turns everything except HEAD into GET.
Authorizationand anyCookieheader you passed are dropped when the redirect goes to another origin.response.cookiesholds the cookies from every hop.allow_redirectsstill defaults toFalse.
- There is a limit of 30 hops, after which
- Requests with different
timeoutorinsecure_skip_verifyvalues use separate native sessions, so they don't share connections. - Unsupported platforms raise
UnsupportedPlatformError. Before, they loaded a library built for the wrong platform. musl (Alpine) and ARMv6 (Raspberry Pi 1 and Zero) are not supported. - The native library is loaded on the first request instead of at import.
additional_decodehas no effect any more because upstream removed the feature. The argument is still accepted.- A
Response()you build yourself starts with empty values instead ofNone.
New
async with tls_client.AsyncSession(client_identifier="chrome_120") as session:
r = await session.get("https://example.com")session.post(url, files={"file": open("report.pdf", "rb")}, data={"name": "report"})AsyncSessionfor asyncio. It takes the same arguments asSession, plusexecutor=.files=sends multipart uploads, with the same formsrequestsaccepts.timeout=takes seconds as an int or a float, so fractions of a second work.timeout_seconds=still works.header_order=can be set per request.response.history,response.encoding, andtls_client.exceptions.TooManyRedirectsare new.alpn_protocolsandalps_protocolsfor custom TLS clients, which now produce the requested fingerprint.- 83 client profiles, matching upstream. New ones include
chrome_144tochrome_152,brave_146,firefox_147,firefox_148,safari_ios_18_5,safari_ios_26_0andcloudscraper. - The package ships
py.typed, its type hints pass mypy strict, and it has no runtime dependencies.
Fixes
- Binary downloads arrive intact (#143).
- Response headers are case-insensitive (#129).
- The inferred
Content-Typeno longer sticks to the session (#117). - Deleted cookies are no longer sent (#25).
- Cookies set during redirects are kept (#120).
- Large bodies use half the peak memory (#135).
- Child processes no longer hang after
fork()(#101). - 32-bit Linux and Raspberry Pi are supported (#145, #111).
paramson a URL that already has a query string gives?a=1&b=2instead of?a=1?b=2.params={}no longer adds a bare?.session.paramsis sent with every request.- Per-request
timeoutandinsecure_skip_verifynow take effect. - A proxy dict with only an
"https"entry is used. jar["name"]works for cookies with empty values, andmultiple_domains()gives the right answer.- A
Set-Cookiewithout a value no longer breaks the next request. - Dict subclasses are accepted wherever a dict is.
Platforms
Each wheel contains only the native library for its platform:
| OS | Architectures |
|---|---|
| macOS | x86_64, arm64 |
| Linux (glibc, manylinux_2_17) | x86_64, i686, aarch64, armv7l |
| Windows | 32-bit, 64-bit |
The sdist doesn't contain a native library.
Contributors
Thanks to @HarshRajSinghania, @biggie0344 and @rl1987.
Full changelog: 1.0.1...2.0.0