Simon Willison’s Weblog

Subscribe
Atom feed for httpx Random

8 posts tagged “httpx”

2026

This release of the Anthropic plugin for LLM mainly provides compatibility with the recently released anthropic v1.0.0 Python library, which switches from httpx to httpx2. OpenAI made the same change in their v3.0.0 release two weeks ago.

Anthropic provide this migration guide for upgrading to 1.0, so I prompted Fable 5 in Claude Code with:

Upgrade to anthropic>=1 - read https://raw.githubusercontent.com/anthropics/anthropic-sdk-python/refs/heads/main/MIGRATION.md and get the tests passing

Here's the resulting PR.

Fresh installs of LLM stopped working the other day because the OpenAI Python library dropped its usage of httpx, and it turned out LLM depended on that library but only installed it via a transitive openai dependency.

This dot-release fixes that for the moment by pinning to openai<3, and a soon-to-drop 0.33 release will switch from httpx to httpx2.

2025

Comment My comment on encode/httpx: Version 1.0 public call. — GitHub

I'm not thrilled about the 1.0 version changing the design of HTTPX so thoroughly - it looks like it's splitting httpx and ahttpx into entirely separate packages.

Python's single biggest weakness when it comes to dependency management is that it isn't possible to install two different versions of a package in the same environment. This makes backwards-incompatible changes really painful, because they lead to a prolonged period where different third-party dependencies may themselves require conflicting versions of another dependency.

This happened with Pydantic 2 and it was miserable - there was a solid 8-12 month period where depending on Pydantic could actively harm a project if that project also depended on something else that used Pydantic 1 - you couldn't upgrade to 2 until your dependency also upgraded to 2, and if you wanted to depend on libraries X and Y where X depended on Pydantic 1 and Y depended on Pydantic 2 your project just couldn't be built using those libraries!

I fear that an HTTPX breaking change could be even more painful than the Pydantic one was.

Consider two of the most popular libraries for interfacing with LLMs - Anthropic and OpenAI's.

https://github.com/anthropics/anthropic-sdk-python/blob/main/pyproject.toml depends on "httpx>=0.25.0, <1".

https://github.com/openai/openai-python/blob/main/pyproject.toml depends on "httpx>=0.23.0, <1".

There are plenty of other projects that depend on both - anything that attempts to provide an abstraction layer over multiple LLM providers, for example (cough).

Now what happens if HTTPX 1.0 comes out with a breaking API, and Anthropic upgrade to it but OpenAI don't? Any package that depends on both of those underlying packages will be stuck in a no-mans land - it will be forced to stick with HTTPX<1.0 and pin the older version of the Anthropic package, then will be blocked waiting for OpenAI to ship their upgrade.

It's not just LLM packages though. Show me Python software that doesn't use an HTTP client these days! https://github.com/encode/httpx/network/dependents lists 527,282 repositories and 13,654 packages. Will every one of those need to make changes to handle the switch to HTTPX 1.0?

I understand that complaining about a 0.x to 1.0 having breaking changes is distinctly uncool of me. That's the whole point of a pre-1.0 version number, at least for projects that follow SemVer.

I have to admit: I had optimistically hoped that HTTPX wasn't going to follow SemVer given the Python ecosystem's uniquely painful response to breaking changes in major packages that other packages depend on.

If I'd know this was going to happen I would have tried to find some other post-1.0 HTTP library to build all of my stuff around!

Solution: call the package httpx2!

I don't like complaining without offering solutions, so here's the one way I can see that this change could be implemented while avoiding all of that pain: change the package name.

If httpx2 came out with this new design, leaving httpx in place, all of these problems go away.

Some projects can switch tohttpx2 as their client library. Old projects can stick with httpx. If my project needs to mix and match dependencies that don't agree on that version then it's fine - I can have both httpx and httpx2 installed in the same environment at the same time.

Mark httpx as deprecated and no longer supported (and/or offer to keep on patching it in exchange for paid sponsorship of the work). Make httpx2 clearly the better option.

That way projects get to switch to httpx2 - and handle the breaking changes - on their own time and without causing any pain for other projects that depend on them but are not yet ready to upgrade their other uses.

I really, really wish Pydantic had done this with their Pydantic 2 upgrade.

I get that it feels ugly to have a 2 on the end of the name - jinja2 got stuck with that seventeen years ago. But I think that tiny bit of ugliness may be a price to pay for shipping significant breaking changes to a library with 500,000 existing users.

# 20th August 2025, 3:07 am / open-source, packaging, python, httpx, pydantic

llm-mistral 0.14. I added tool-support to my plugin for accessing the Mistral API from LLM today, plus support for Mistral's new Codestral Embed embedding model.

An interesting challenge here is that I'm not using an official client library for llm-mistral - I rolled my own client on top of their streaming HTTP API using Florimond Manca's httpx-sse library. It's a very pleasant way to interact with streaming APIs - here's my code that does most of the work.

The problem I faced is that Mistral's API documentation for function calling has examples in Python and TypeScript but doesn't include curl or direct documentation of their HTTP endpoints!

I needed documentation at the HTTP level. Could I maybe extract that directly from Mistral's official Python library?

It turns out I could. I started by cloning the repo:

git clone https://github.com/mistralai/client-python
cd client-python/src/mistralai
files-to-prompt . | ttok

My ttok tool gave me a token count of 212,410 (counted using OpenAI's tokenizer, but that's normally a close enough estimate) - Mistral's models tap out at 128,000 so I switched to Gemini 2.5 Flash which can easily handle that many.

I ran this:

files-to-prompt -c . > /tmp/mistral.txt

llm -f /tmp/mistral.txt \
  -m gemini-2.5-flash-preview-05-20 \
  -s 'Generate comprehensive HTTP API documentation showing
how function calling works, include example curl commands for each step'

The results were pretty spectacular! Gemini 2.5 Flash produced a detailed description of the exact set of HTTP APIs I needed to interact with, and the JSON formats I should pass to them.

There are a bunch of steps needed to get tools working in a new model, as described in the LLM plugin authors documentation. I started working through them by hand... and then got lazy and decided to see if I could get a model to do the work for me.

This time I tried the new Claude Opus 4. I fed it three files: my existing, incomplete llm_mistral.py, a full copy of llm_gemini.py with its working tools implementation and a copy of the API docs Gemini had written for me earlier. I prompted:

I need to update this Mistral code to add tool support. I've included examples of that code for Gemini, and a detailed README explaining the Mistral format.

Claude churned away and wrote me code that was most of what I needed. I tested it in a bunch of different scenarios, pasted problems back into Claude to see what would happen, and eventually took over and finished the rest of the code myself. Here's the full transcript.

I'm a little sad I didn't use Mistral to write the code to support Mistral, but I'm pleased to add yet another model family to the list that's supported for tool usage in LLM.

# 29th May 2025, 3:33 am / plugins, projects, python, ai, httpx, generative-ai, llms, ai-assisted-programming, llm, claude, mistral, gemini, llm-tool-use, claude-4

2021

Re-assessing the automatic charset decoding policy in HTTPX (via) Tom Christie ran an analysis of the top 1,000 most accessed websites (according to an older extract from Google’s Ad Planner service) and found that a full 5% of them both omitted a charset parameter and failed to decode as UTF-8. As a result, HTTPX will be depending on the charset-normalizer Python library to handle those cases.

# 13th August 2021, 10:07 pm / unicode, kim-christie, httpx

2020

Datasette 0.50: The annotated release notes

Visit Datasette 0.50: The annotated release notes

I released Datasette 0.50 this morning, with a new user-facing column actions menu feature and a way for plugins to make internal HTTP requests to consume the JSON API of their parent Datasette instance.

[... 792 words]

Weeknotes: datasette-auth-existing-cookies and datasette-sentry

Work on Datasette Cloud continues—I’m tantalizingly close to having a MVP I can start to invite people to try out.

[... 701 words]

Async Support—HTTPX (via) HTTPX is the new async-friendly HTTP library for Python spearheaded by Tom Christie. It works in both async and non-async mode with an API very similar to requests. The async support is particularly interesting - it's a really clean API, and now that Jupyter supports top-level await you can run (await httpx.AsyncClient().get(url)).text directly in a cell and get back the response. Most excitingly the library lets you pass an ASGI app directly to the client and then perform requests against it - ideal for unit tests.

# 10th January 2020, 4:49 am / async, http, python, asgi, kim-christie, httpx