For a third party library* I have to provide a function which consumes some data. My implementation of the consumption requires the data to be posted to an API. So I came up with this structure below:
def consumer_provider():
with HttpClient() as http_client:
def consumer(data):
http_client.post(data)
return consumer
So I can present the function to the third party lib like so:
third_party_lib.add(consumer=consumer_provider())
In my tests it works quite well, but is this legit? When do I have to expect that the context manager releases the resource (in this case the connection pool)?
* loguru in this case, but it should not really matter for the question
It depends on the context manager. In the code you wrote, the HTTPClient
you created stays alive because the function it returns maintains a reference to it, even though the variable http_client
defined in consumer_provider
goes out of scope.
However, HTTPClient.__exit__
is still called before consumer_provider
returns, so the consumer function may not work as intended.
You may want to do something like
def consumer_provider():
http_client = HttpClient()
def consumer(data):
with http_client:
http_client.post(data)
return consumer
which ensures that the HttpClient
object stays "hidden" inside the closure, but its __enter__
and __exit__
methods aren't called until the function gets called. (Whether the client can be used by multiple function calls also depends on the definition of HttpClient
.)