> The Python version of this does have a `void *ctx`, but I am not sure if the use for this is actually valuable for the NumPy use-cases.

Do you mean "the CPython version"? If so, can you link a reference?

>  While I like the `PyObject *` idea, I am also not sure that it helps much.  If we want allocation specific state, the user should overallocate and save it before the actual allocation.

I was talking about allocator- not allocation- specific state. I agree that the correct place to store the latter is by overallocating, but it doesn't make much sense to me to duplicate state about the allocator itself in each allocation.

> But if we don't mind the churn it creates, the only serious idea I would have right now is using a `FromSpec` API. We could allow get/set functions on it though

We don't even need to go as far as a flexible `FromSpec` API. Simply having a function to allocate (and free) the opaque struct and a handful of getters ought to be enough to let us change the allocator to be stateful in future.
On the other hand, this is probably about as much work as just making it a PyObject in the first place.