From 884d0e8a195afe9d537f207a6e99d50da5c52de1 Mon Sep 17 00:00:00 2001 From: Tomasz Prus Date: Wed, 18 Mar 2020 02:00:32 +0100 Subject: [PATCH] [python/asyncio] explicitly close client session via async context manager --- .../main/resources/python/api_client.mustache | 14 +++++++++- .../resources/python/asyncio/rest.mustache | 5 ++-- .../python-asyncio/petstore_api/api_client.py | 9 ++++--- .../python-asyncio/petstore_api/rest.py | 5 ++-- .../python-asyncio/tests/test_api_client.py | 27 +++++++++++++++++++ .../python-asyncio/tests/test_pet_api.py | 11 +------- .../petstore/python-asyncio/tests/util.py | 9 ++++++- 7 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 samples/client/petstore/python-asyncio/tests/test_api_client.py diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index 52b2ec2f3d9a..c69e7d5945ef 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -76,13 +76,25 @@ class ApiClient(object): self.user_agent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{packageVersion}}}/python{{/httpUserAgent}}' self.client_side_validation = configuration.client_side_validation + {{#asyncio}} + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + await self.close() + {{/asyncio}} + {{^asyncio}} def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.close() + {{/asyncio}} - def close(self): + {{#asyncio}}async {{/asyncio}}def close(self): + {{#asyncio}} + await self.rest_client.close() + {{/asyncio}} if self._pool: self._pool.close() self._pool.join() diff --git a/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache b/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache index 4585f1c6ad5e..e797d0ae7a4d 100644 --- a/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache @@ -10,7 +10,6 @@ import ssl import aiohttp import certifi -import asyncio # python 2 and python 3 compatibility library from six.moves.urllib.parse import urlencode @@ -77,8 +76,8 @@ class RESTClientObject(object): connector=connector ) - def __del__(self): - asyncio.ensure_future(self.pool_manager.close()) + async def close(self): + await self.pool_manager.close() async def request(self, method, url, query_params=None, headers=None, body=None, post_params=None, _preload_content=True, diff --git a/samples/client/petstore/python-asyncio/petstore_api/api_client.py b/samples/client/petstore/python-asyncio/petstore_api/api_client.py index 4f33e8108061..bed70584efb9 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/api_client.py +++ b/samples/client/petstore/python-asyncio/petstore_api/api_client.py @@ -81,13 +81,14 @@ def __init__(self, configuration=None, header_name=None, header_value=None, self.user_agent = 'OpenAPI-Generator/1.0.0/python' self.client_side_validation = configuration.client_side_validation - def __enter__(self): + async def __aenter__(self): return self - def __exit__(self, exc_type, exc_value, traceback): - self.close() + async def __aexit__(self, exc_type, exc_value, traceback): + await self.close() - def close(self): + async def close(self): + await self.rest_client.close() if self._pool: self._pool.close() self._pool.join() diff --git a/samples/client/petstore/python-asyncio/petstore_api/rest.py b/samples/client/petstore/python-asyncio/petstore_api/rest.py index e13f81b45279..37616f185367 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/rest.py +++ b/samples/client/petstore/python-asyncio/petstore_api/rest.py @@ -18,7 +18,6 @@ import aiohttp import certifi -import asyncio # python 2 and python 3 compatibility library from six.moves.urllib.parse import urlencode @@ -85,8 +84,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None): connector=connector ) - def __del__(self): - asyncio.ensure_future(self.pool_manager.close()) + async def close(self): + await self.pool_manager.close() async def request(self, method, url, query_params=None, headers=None, body=None, post_params=None, _preload_content=True, diff --git a/samples/client/petstore/python-asyncio/tests/test_api_client.py b/samples/client/petstore/python-asyncio/tests/test_api_client.py new file mode 100644 index 000000000000..bf4ab329f296 --- /dev/null +++ b/samples/client/petstore/python-asyncio/tests/test_api_client.py @@ -0,0 +1,27 @@ +# coding: utf-8 + +# flake8: noqa + +import unittest +import weakref + +from tests.util import async_test +import petstore_api + + +class TestApiClient(unittest.TestCase): + + @async_test + async def test_context_manager_closes_client(self): + + async with petstore_api.ApiClient() as client: + # thread pool + self.assertIsNotNone(client.pool) + pool_ref = weakref.ref(client._pool) + self.assertIsNotNone(pool_ref()) + # pool_manager + self.assertFalse(client.rest_client.pool_manager.closed) + rest_pool_ref = client.rest_client.pool_manager + + self.assertIsNone(pool_ref()) + self.assertTrue(rest_pool_ref.closed) diff --git a/samples/client/petstore/python-asyncio/tests/test_pet_api.py b/samples/client/petstore/python-asyncio/tests/test_pet_api.py index 32a336a4ac7d..d37b2e091305 100644 --- a/samples/client/petstore/python-asyncio/tests/test_pet_api.py +++ b/samples/client/petstore/python-asyncio/tests/test_pet_api.py @@ -18,7 +18,7 @@ from petstore_api import Configuration from petstore_api.rest import ApiException -from .util import id_gen +from .util import id_gen, async_test import json @@ -27,15 +27,6 @@ HOST = 'http://localhost:80/v2' -def async_test(f): - def wrapper(*args, **kwargs): - coro = asyncio.coroutine(f) - future = coro(*args, **kwargs) - loop = asyncio.get_event_loop() - loop.run_until_complete(future) - return wrapper - - class TestPetApiTests(unittest.TestCase): def setUp(self): diff --git a/samples/client/petstore/python-asyncio/tests/util.py b/samples/client/petstore/python-asyncio/tests/util.py index 39fba1514b33..8edec7570093 100644 --- a/samples/client/petstore/python-asyncio/tests/util.py +++ b/samples/client/petstore/python-asyncio/tests/util.py @@ -1,5 +1,6 @@ # flake8: noqa +import asyncio import random @@ -8,4 +9,10 @@ def id_gen(bits=32): return int(random.getrandbits(bits)) - +def async_test(f): + def wrapper(*args, **kwargs): + coro = asyncio.coroutine(f) + future = coro(*args, **kwargs) + loop = asyncio.get_event_loop() + loop.run_until_complete(future) + return wrapper