Skip to content

2.0.0

Latest

Choose a tag to compare

@FlorianREGAZ FlorianREGAZ released this 10 Oct 15:15

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.
  • TLSClientExeption is renamed to TLSClientException.
  • An unknown client_identifier raises ValueError and 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_2 is gone because upstream removed it.
  • response.content is the exact bytes the server sent. Before, it was the library's UTF-8 text encoded again, which corrupted binary bodies.
  • response.text is read-only. It is decoded from content using the charset in Content-Type, or UTF-8 when there is none. HTML <meta charset> is no longer read. For those pages, set the encoding before reading text:
    r.encoding = "iso-8859-1"
    r.text
  • session.headers no longer picks up a Content-Type after a json= or data= 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.cookies is 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.
  • Redirects are followed in Python, the way requests does it.
    • There is a limit of 30 hops, after which TooManyRedirects is raised.
    • 301/302 turn POST into GET, and 303 turns everything except HEAD into GET.
    • Authorization and any Cookie header you passed are dropped when the redirect goes to another origin.
    • response.cookies holds the cookies from every hop.
    • allow_redirects still defaults to False.
  • Requests with different timeout or insecure_skip_verify values 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_decode has no effect any more because upstream removed the feature. The argument is still accepted.
  • A Response() you build yourself starts with empty values instead of None.

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"})
  • AsyncSession for asyncio. It takes the same arguments as Session, plus executor=.
  • files= sends multipart uploads, with the same forms requests accepts.
  • 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, and tls_client.exceptions.TooManyRedirects are new.
  • alpn_protocols and alps_protocols for custom TLS clients, which now produce the requested fingerprint.
  • 83 client profiles, matching upstream. New ones include chrome_144 to chrome_152, brave_146, firefox_147, firefox_148, safari_ios_18_5, safari_ios_26_0 and cloudscraper.
  • 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-Type no 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).
  • params on a URL that already has a query string gives ?a=1&b=2 instead of ?a=1?b=2. params={} no longer adds a bare ?.
  • session.params is sent with every request.
  • Per-request timeout and insecure_skip_verify now take effect.
  • A proxy dict with only an "https" entry is used.
  • jar["name"] works for cookies with empty values, and multiple_domains() gives the right answer.
  • A Set-Cookie without 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