There's an inconsistency in how user-supplied httpx clients are handled depending on which method you call. The README even documents this for queries(), but I think this deserves a second look.
The whole point of allowing client injection is giving users control over connection pooling, auth, timeouts, and lifecycle. When the library accepts a client but then closes it, that contract falls apart.
This results in
- Connection pooling becoming useless for batch operations. If I want to run several
queries() calls against the same endpoint, I can't reuse connections - which is exactly the scenario where pooling would help most.
- Users having to remember which methods are "safe" with a shared client and which will kill it.
- Blocking some reasonable patterns - say, a long-running service that keeps a client pool, and dispatches queries through sparqlx. Right now you have to defensively recreate clients or avoid
queries()/updates() entirely.
ClientManager already does the right thing in context() and acontext() - it knows whether a client is auto-managed or user-supplied and acts accordingly. That's the correct design. The issue is that SPARQLWrapper.__exit__ and __aexit__ sidestep this and close unconditionally. Then queries()/updates() use async with on a SPARQLWrapper internally, triggering that unconditional close.
Some possible approaches:
- Have
__exit__/__aexit__ delegate to ClientManager rather than calling close directly, since the manager already has the ownership logic
- Have
queries()/updates() use ClientManager.acontext() directly instead of going through SPARQLWrapper's context protocol since thhey only need the async client anyway.
- Some combination of the above.
There's an inconsistency in how user-supplied httpx clients are handled depending on which method you call. The README even documents this for
queries(), but I think this deserves a second look.The whole point of allowing client injection is giving users control over connection pooling, auth, timeouts, and lifecycle. When the library accepts a client but then closes it, that contract falls apart.
This results in
queries()calls against the same endpoint, I can't reuse connections - which is exactly the scenario where pooling would help most.queries()/updates()entirely.ClientManageralready does the right thing incontext()andacontext()- it knows whether a client is auto-managed or user-supplied and acts accordingly. That's the correct design. The issue is thatSPARQLWrapper.__exit__and__aexit__sidestep this and close unconditionally. Thenqueries()/updates()useasync withon a SPARQLWrapper internally, triggering that unconditional close.Some possible approaches:
__exit__/__aexit__delegate to ClientManager rather than calling close directly, since the manager already has the ownership logicqueries()/updates()useClientManager.acontext()directly instead of going through SPARQLWrapper's context protocol since thhey only need the async client anyway.