def test_close(self): conn = self.make_open_connector() session = ClientSession(loop=self.loop, connector=conn) session.close() self.assertIsNone(session.connector) self.assertTrue(conn.closed)
def test_init_cookies_with_list_of_tuples(self): session = ClientSession( cookies=[("c1", "cookie1"), ("c2", "cookie2")], loop=self.loop) self.assertEqual(set(session.cookies), {'c1', 'c2'}) self.assertEqual(session.cookies['c1'].value, 'cookie1') self.assertEqual(session.cookies['c2'].value, 'cookie2') session.close()
def test_detach(self): session = ClientSession(loop=self.loop) conn = session.connector self.assertFalse(conn.closed) session.detach() self.assertIsNone(session.connector) self.assertTrue(session.closed) self.assertFalse(conn.closed) conn.close()
def test_init_cookies_with_simple_dict(self): session = ClientSession( cookies={ "c1": "cookie1", "c2": "cookie2" }, loop=self.loop) self.assertEqual(set(session.cookies), {'c1', 'c2'}) self.assertEqual(session.cookies['c1'].value, 'cookie1') self.assertEqual(session.cookies['c2'].value, 'cookie2') session.close()
def test_init_headers_simple_dict(self): session = ClientSession( headers={ "h1": "header1", "h2": "header2" }, loop=self.loop) self.assertEqual( sorted(session._default_headers.items()), ([("H1", "header1"), ("H2", "header2")])) session.close()
def test_merge_headers_with_multi_dict(self): session = ClientSession( headers={ "h1": "header1", "h2": "header2" }, loop=self.loop) headers = session._prepare_headers(MultiDict([("h1", "h1")])) self.assertIsInstance(headers, CIMultiDict) self.assertEqual(headers, CIMultiDict([ ("h1", "h1"), ("h2", "header2") ]))
def test_init_headers_list_of_tuples(self): session = ClientSession( headers=[("h1", "header1"), ("h2", "header2"), ("h3", "header3")], loop=self.loop) self.assertEqual( session._default_headers, CIMultiDict([("h1", "header1"), ("h2", "header2"), ("h3", "header3")])) session.close()
def test_init_headers_MultiDict(self): session = ClientSession( headers=MultiDict( [("h1", "header1"), ("h2", "header2"), ("h3", "header3")]), loop=self.loop) self.assertEqual( session._default_headers, CIMultiDict([("H1", "header1"), ("H2", "header2"), ("H3", "header3")])) session.close()
def test_merge_headers(self): # Check incoming simple dict session = ClientSession( headers={ "h1": "header1", "h2": "header2" }, loop=self.loop) headers = session._prepare_headers({ "h1": "h1" }) self.assertIsInstance(headers, CIMultiDict) self.assertEqual(headers, CIMultiDict([ ("h1", "h1"), ("h2", "header2") ]))
def test_merge_headers_with_list_of_tuples_duplicated_names(self): session = ClientSession( headers={ "h1": "header1", "h2": "header2" }, loop=self.loop) headers = session._prepare_headers([("h1", "v1"), ("h1", "v2")]) self.assertIsInstance(headers, CIMultiDict) self.assertEqual(headers, CIMultiDict([ ("H2", "header2"), ("H1", "v1"), ("H1", "v2"), ])) session.close()
def go(): err = OSError(1, "permission error") req = mock.Mock() req_factory = mock.Mock(return_value=req) req.send = mock.Mock(side_effect=err) session = ClientSession(loop=self.loop, request_class=req_factory) @asyncio.coroutine def create_connection(req): # return self.transport, self.protocol return mock.Mock(), mock.Mock() session._connector._create_connection = create_connection with self.assertRaises(aiohttp.ClientOSError) as ctx: yield from session.request('get', 'http://example.com') e = ctx.exception self.assertEqual(e.errno, err.errno) self.assertEqual(e.strerror, err.strerror)
def __init__(self, rest_service_name='GenericService', spec=None, plugins=None, config=None, parser=None, serializer=None, base_path='', loop=None, logger=None): self._plugins = [] self.logger = logger or logging.getLogger('serviceClient.{}'.format(rest_service_name)) self.rest_service_name = rest_service_name self.spec = spec or {} self.add_plugins(plugins or []) self.config = config or {} self.parser = parser or (lambda x, *args, **kwargs: x) self.serializer = serializer or (lambda x, *args, **kwargs: x) self.base_path = base_path self.loop = loop or get_event_loop() self.connector = TCPConnector(loop=self.loop, **self.config.get('connector', {})) self.session = ClientSession(connector=self.connector, loop=self.loop)
async def fetch(self, request: Request, session: ClientSession): if self.use_proxy: # method, url, *, # params = None, # data = None, # json = None, # headers = None, # skip_auto_headers = None, # auth = None, # allow_redirects = True, # max_redirects = 10, # compress = None, # chunked = None, pass try: biu = session.request(request.method, request.url, headers=request.header, data=request.body) async with biu as req: text = await req.text() return Response(request, text, req.status) except Exception: pass
async def async_method_wrapper(self, *args, **kwargs): async with ClientSession() as http_session: kwargs['http_session'] = http_session return await async_method(self, *args, **kwargs)
async def aiohttp_client_session( loop, # pylint: disable=unused-argument ) -> ClientSession: """Initialize an aiohttp HTTP client session.""" async with ClientSession() as http_session: yield http_session
async def receive( # pylint: disable=too-many-arguments,too-many-locals ctx: click.Context, event: str, event_payload: TextIOWrapper, token: str, app: int, private_key: TextIOWrapper, entrypoint_module: str, event_routers: Iterable[str], ) -> None: """Webhook event receive command.""" app_missing_private_key = app is not None and not private_key if app_missing_private_key: ctx.fail(click.style('App requires a private key', fg='red')) creds_present = token or (app and private_key) if not creds_present: ctx.fail(click.style('GitHub auth credentials are missing', fg='red')) too_many_creds_present = token and (app or private_key) if too_many_creds_present: ctx.fail( click.style( 'Please choose between a token or ' 'an app id with a private key', fg='red', ), ) make_event = GitHubEvent if app is None else GitHubWebhookEvent try: gh_event = make_event.from_fixture_fd(event_payload, event=event) except ValueError as val_err: ctx.fail(click.style(str(val_err), fg='red')) os.environ.update(get_extra_env_vars(gh_event, token, app, private_key)) try: target_routers = set( load_event_routers( entrypoint_module, # pylint: disable=fixme event_routers, # type: ignore[arg-type] # FIXME: typing ), ) except AttributeError as attr_err: ctx.fail( click.style( f'Could not find an event router: {attr_err!s}', fg='red', ), ) except ImportError as imp_err: ctx.fail( click.style(f'Could not load a module: {imp_err!s}', fg='red'), ) config = BotAppConfig.from_dotenv() gh_app_kwargs = {'config': config.github} make_gh_app = GitHubApp if app is None: make_gh_app = GitHubAction gh_app_kwargs['metadata'] = config.action async with ClientSession() as http_client_session: github_app = make_gh_app( http_session=http_client_session, # FIXME: typing # pylint: disable=fixme event_routers=target_routers or None, # type: ignore[arg-type] **gh_app_kwargs, ) await route_github_event( github_event=gh_event, github_app=github_app, ) click.echo( click.style( f'Finished processing {gh_event.name!s} event!', fg='green', ), )
def test_http_methods(self, patched): session = ClientSession(loop=self.loop) add_params = dict( headers={"Authorization": "Basic ..."}, max_redirects=2, encoding="latin1", version=aiohttp.HttpVersion10, compress="deflate", chunked=True, expect100=True, read_until_eof=False) run = self.loop.run_until_complete # Check GET run(session.get( "http://test.example.com", params={"x": 1}, **add_params)) self.assertEqual( patched.call_count, 1, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("GET", "http://test.example.com",), dict( params={"x": 1}, allow_redirects=True, **add_params)]) # Check OPTIONS run(session.options( "http://opt.example.com", params={"x": 2}, **add_params)) self.assertEqual( patched.call_count, 2, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("OPTIONS", "http://opt.example.com",), dict( params={"x": 2}, allow_redirects=True, **add_params)]) # Check HEAD run(session.head( "http://head.example.com", params={"x": 2}, **add_params)) self.assertEqual( patched.call_count, 3, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("HEAD", "http://head.example.com",), dict( params={"x": 2}, allow_redirects=False, **add_params)]) # Check POST run(session.post( "http://post.example.com", params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)) self.assertEqual( patched.call_count, 4, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("POST", "http://post.example.com",), dict( params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)]) # Check PUT run(session.put( "http://put.example.com", params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)) self.assertEqual( patched.call_count, 5, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("PUT", "http://put.example.com",), dict( params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)]) # Check PATCH run(session.patch( "http://patch.example.com", params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)) self.assertEqual( patched.call_count, 6, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("PATCH", "http://patch.example.com",), dict( params={"x": 2}, data="Some_data", files={"x": '1'}, **add_params)]) # Check DELETE run(session.delete( "http://delete.example.com", params={"x": 2}, **add_params)) self.assertEqual( patched.call_count, 7, "`ClientSession.request` not called") self.assertEqual( list(patched.call_args), [("DELETE", "http://delete.example.com",), dict( params={"x": 2}, **add_params)])
def test_context_manager(self): conn = self.make_open_connector() with ClientSession(loop=self.loop, connector=conn) as session: pass self.assertTrue(session.closed)
class AIOResponsesTestCase(TestCase): def setUp(self): self.url = 'http://example.com/api' self.loop = asyncio.get_event_loop() self.session = ClientSession() def tearDown(self): self.session.close() @data( hdrs.METH_GET, hdrs.METH_POST, hdrs.METH_PUT, hdrs.METH_PATCH, hdrs.METH_DELETE, hdrs.METH_OPTIONS, ) @patch('aioresponses.aioresponses.add') def test_shortcut_method(self, http_method, mocked): with aioresponses() as m: getattr(m, http_method.lower())(self.url) mocked.assert_called_once_with(self.url, method=http_method) @aioresponses() def test_returned_instance(self, m): m.get(self.url) response = self.loop.run_until_complete(self.session.get(self.url)) self.assertIsInstance(response, ClientResponse) @aioresponses() def test_returned_response_headers(self, m): m.get(self.url, content_type='text/html', headers={'Connection': 'keep-alive'}) response = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(response.headers['Connection'], 'keep-alive') self.assertEqual(response.headers[hdrs.CONTENT_TYPE], 'text/html') @aioresponses() def test_method_dont_match(self, m): m.get(self.url) with self.assertRaises(ClientConnectionError): self.loop.run_until_complete(self.session.post(self.url)) @aioresponses() def test_streaming(self, m): m.get(self.url, body='Test') resp = self.loop.run_until_complete(self.session.get(self.url)) content = self.loop.run_until_complete(resp.content.read()) self.assertEqual(content, b'Test') @aioresponses() def test_streaming_up_to(self, m): m.get(self.url, body='Test') resp = self.loop.run_until_complete(self.session.get(self.url)) content = self.loop.run_until_complete(resp.content.read(2)) self.assertEqual(content, b'Te') content = self.loop.run_until_complete(resp.content.read(2)) self.assertEqual(content, b'st') def test_mocking_as_context_manager(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) payload = self.loop.run_until_complete(resp.json()) self.assertDictEqual(payload, {'foo': 'bar'}) def test_mocking_as_decorator(self): @aioresponses() def foo(m): m.add(self.url, payload={'foo': 'bar'}) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) payload = self.loop.run_until_complete(resp.json()) self.assertDictEqual(payload, {'foo': 'bar'}) foo() def test_passing_argument(self): @aioresponses(param='mocked') def foo(mocked): mocked.add(self.url, payload={'foo': 'bar'}) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) foo() def test_mocking_as_decorator_wrong_mocked_arg_name(self): @aioresponses(param='foo') def foo(bar): # no matter what is here it should raise an error pass with self.assertRaises(TypeError) as cm: foo() exc = cm.exception self.assertIn("foo() got an unexpected keyword argument 'foo'", str(exc)) def test_unknown_request(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) with self.assertRaises(ClientConnectionError): self.loop.run_until_complete( self.session.get('http://example.com/foo') ) def test_raising_custom_error(self): with aioresponses() as aiomock: aiomock.get(self.url, exception=HttpProcessingError(message='foo')) with self.assertRaises(HttpProcessingError): self.loop.run_until_complete( self.session.get(self.url) ) def test_multiple_requests(self): with aioresponses() as m: m.get(self.url, status=200) m.get(self.url, status=201) m.get(self.url, status=202) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 201) resp = self.loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 202) key = ('GET', self.url) self.assertIn(key, m.requests) self.assertEqual(len(m.requests[key]), 3) self.assertEqual(m.requests[key][0].args, tuple()) self.assertEqual(m.requests[key][0].kwargs, {'allow_redirects': True}) def test_address_as_instance_of_url_combined_with_pass_through(self): external_api = 'http://google.com' @asyncio.coroutine def doit(): api_resp = yield from self.session.get(self.url) # we have to hit actual url, # otherwise we do not test pass through option properly ext_rep = yield from self.session.get(URL(external_api)) return api_resp, ext_rep with aioresponses(passthrough=[external_api]) as m: m.get(self.url, status=200) api, ext = self.loop.run_until_complete(doit()) self.assertEqual(api.status, 200) self.assertEqual(ext.status, 200)
async def test_context_manager(connector, loop) -> None: with pytest.raises(TypeError): with ClientSession(loop=loop, connector=connector) as session: pass assert session.closed
def test_borrow_connector_loop(self): conn = self.make_open_connector() session = ClientSession(connector=conn) self.assertIs(session._loop, self.loop) session.close()
def test_client_session_custom_attr(loop) -> None: session = ClientSession(loop=loop) with pytest.warns(DeprecationWarning): session.custom = None
async def make_sess(): return ClientSession(connector=connector, loop=loop)
def __init__(self, config: AppleConfig): super().__init__(config) self._session = ClientSession()
async def prepare(self): """ Acquires HTTP connection pool. """ self._session = ClientSession()
class Crawler: """ Simple asynchronous HTTP client, which encapsulates the logic of web requests inside itself. All descendants are specialized on concrete web sites, but the current class supplies simple interface of the web interaction with any site. It's reusable and portable, that's why any crawler can easily fetch data via the Internet. Class properties: _limit: the max number of concurrent connections to the same site _timeout: default HTTP request timeout Instance properties: _session: HTTP connection pool _scribbler: statistics entity which writes success & failure shapes _semaphore: HTTP connection "restriction frame" """ _limit = 10 _timeout = 1 def __init__(self): self._session = None self._semaphore = Semaphore(self._limit) async def prepare(self): """ Acquires HTTP connection pool. """ self._session = ClientSession() async def get_json(self, url: str, **kwargs: Any) -> Union[List, Dict]: """ Makes an HTTP request and returns response in JSON format. :param url: request's URL :param kwargs: additional config like timeout, content-type, etc. :return: JSON content via native python objects """ return await self.__get_content(url, 'json', **kwargs) @networking async def __get_content(self, url: str, content_type: str, **kwargs: Any) -> Any: """ Makes an HTTP request and returns response in a specified format. :param url: request's URL :param content_type: response's data type, like JSON, text, etc. :param kwargs: additional config like timeout, content-type, etc. :return: response's content """ kwargs['timeout'] = kwargs.get('timeout', self._timeout) async with kwargs.pop('semaphore', self._semaphore): async with self._session.get(url, **kwargs) as response: return await getattr(response, content_type)() async def get_text(self, url: str, **kwargs: Any) -> str: """ Makes an HTTP request and returns response in HTML (text) format. :param url: request's URL :param kwargs: additional config like timeout, content-type, etc. :return: HTML file's markup """ return await self.__get_content(url, 'text', **kwargs) async def spare(self): """ Releases HTTP connection pool. """ await self._session.close()
def test_connector(self): connector = TCPConnector(loop=self.loop) session = ClientSession(connector=connector, loop=self.loop) self.assertIs(session.connector, connector) session.close()
async def test_borrow_connector_loop(connector, create_session, loop) -> None: session = ClientSession(connector=connector, loop=None) try: assert session._loop, loop finally: await session.close()
def __init__(self, base, http_session=None): self.base = base if http_session: self.http = http_session or ClientSession()
async def test_client_session_custom_attr(loop) -> None: session = ClientSession(loop=loop) with pytest.raises(AttributeError): session.custom = None
async def _async_get_swagger(url) -> Dict: async with ClientSession() as session: async with session.request(url=url, method=METH_GET) as resp: return json.loads(await resp.text())
async def test_requote_redirect_url_default() -> None: session = ClientSession() assert session.requote_redirect_url
def __init__(self): super().__init__() self.session = ClientSession()
async def test_requote_redirect_url_default_disable() -> None: session = ClientSession(requote_redirect_url=False) assert not session.requote_redirect_url
def test_close(self): session = ClientSession(loop=self.loop) session._connector = mock.Mock(BaseConnector) session.close() session._connector.close.assert_called_once_with()
async def test_requote_redirect_setter() -> None: session = ClientSession() assert session.requote_redirect_url with pytest.warns(DeprecationWarning): session.requote_redirect_url = False assert not session.requote_redirect_url
async def run(download_list: list[template_media_table]): session_m = subscription.session_manager proxies = session_m.proxies proxy = (session_m.proxies[random.randint(0, len(proxies) - 1)] if proxies else "") connector = ProxyConnector.from_url(proxy) if proxy else None final_cookies: dict[Any, Any] = session_m.auth.auth_details.cookie.format( ) if session_m.use_cookies else {} async with ClientSession( connector=connector, cookies=final_cookies, read_timeout=None, ) as session: tasks = [] # Get content_lengths for download_item in download_list: link = download_item.link if link: task = asyncio.ensure_future( session_m.json_request( download_item.link, session, method="HEAD", json_format=False, )) tasks.append(task) responses = await asyncio.gather(*tasks) tasks.clear() async def check(download_item: template_media_table, response: ClientResponse): filepath = os.path.join(download_item.directory, download_item.filename) response_status = False if response.status == 200: response_status = True if response.content_length: download_item.size = response.content_length if os.path.exists(filepath): if os.path.getsize(filepath) == response.content_length: download_item.downloaded = True else: return download_item else: if response_status: return download_item for download_item in download_list: temp_response = [ response for response in responses if response and str(response.url) == download_item.link ] if temp_response: temp_response = temp_response[0] task = check(download_item, temp_response) tasks.append(task) result = await asyncio.gather(*tasks) download_list = [x for x in result if x] tasks.clear() progress_bar = None if download_list: progress_bar = download_session() progress_bar.start(unit="B", unit_scale=True, miniters=1) [progress_bar.update_total_size(x.size) for x in download_list] async def process_download(download_item: template_media_table): while True: result = await session_m.download_content( download_item, session, progress_bar, subscription) if result: response, download_item = result.values() if response: download_path = os.path.join( download_item.directory, download_item.filename) status_code = await write_data( response, download_path, progress_bar) if not status_code: pass elif status_code == 1: continue elif status_code == 2: break timestamp = download_item.created_at.timestamp() await format_image(download_path, timestamp) download_item.size = response.content_length download_item.downloaded = True break max_threads = api_helper.calculate_max_threads( session_m.max_threads) download_groups = grouper(max_threads, download_list) for download_group in download_groups: tasks = [] for download_item in download_group: task = process_download(download_item) if task: tasks.append(task) await asyncio.gather(*tasks) if isinstance(progress_bar, download_session): progress_bar.close() return True
async def _fetch_website(url: str, session: client.ClientSession): try: async with session.get(url) as response: await response.text() except ClientError: pass # information is saved in on_request_exception
class ServiceClient: def __init__(self, rest_service_name='GenericService', spec=None, plugins=None, config=None, parser=None, serializer=None, base_path='', loop=None, logger=None): self._plugins = [] self.logger = logger or logging.getLogger('serviceClient.{}'.format(rest_service_name)) self.rest_service_name = rest_service_name self.spec = spec or {} self.add_plugins(plugins or []) self.config = config or {} self.parser = parser or (lambda x, *args, **kwargs: x) self.serializer = serializer or (lambda x, *args, **kwargs: x) self.base_path = base_path self.loop = loop or get_event_loop() self.connector = TCPConnector(loop=self.loop, **self.config.get('connector', {})) self.session = ClientSession(connector=self.connector, loop=self.loop) @coroutine def call(self, service_name, payload=None, **kwargs): self.logger.debug("Calling service_client {0}...".format(service_name)) service_desc = self.spec[service_name].copy() service_desc['service_name'] = service_name request_params = kwargs session = yield from self.prepare_session(service_desc, request_params) request_params['url'] = yield from self.generate_path(service_desc, session, request_params) request_params['method'] = service_desc.get('method', 'GET').upper() yield from self.prepare_request_params(service_desc, session, request_params) self.logger.info("Calling service_client {0} using {1} {2}".format(service_name, request_params['method'], request_params['url'])) payload = yield from self.prepare_payload(service_desc, session, request_params, payload) try: if request_params['method'] not in ['GET', 'DELETE']: try: stream_request = service_desc['stream_request'] except KeyError: stream_request = False if payload and not stream_request: request_params['data'] = self.serializer(payload, session=session, service_desc=service_desc, request_params=request_params) yield from self.before_request(service_desc, session, request_params) response = yield from session.request(**request_params) except Exception as e: self.logger.warn("Exception calling service_client {0}: {1}".format(service_name, e)) yield from self.on_exception(service_desc, session, request_params, e) raise e yield from self.on_response(service_desc, session, request_params, response) try: if service_desc['stream_response']: return response except KeyError: pass try: self.logger.info("Parsing response from {0}...".format(service_name)) response.data = self.parser((yield from response.read()), session=session, service_desc=service_desc, response=response) yield from self.on_parsed_response(service_desc, session, request_params, response) except Exception as e: self.logger.warn("[Response code: {0}] Exception parsing response from service_client " "{1}: {2}".format(response.status, service_name, e)) yield from self.on_parse_exception(service_desc, session, request_params, response, e) e.response = response raise e return response @coroutine def prepare_session(self, service_desc, request_params): session = SessionWrapper(self.session) yield from self._execute_plugin_hooks('prepare_session', service_desc=service_desc, session=session, request_params=request_params) return session @coroutine def generate_path(self, service_desc, session, request_params): path = service_desc.get('path', '') url = list(urlparse(self.base_path)) url[2] = '/'.join([url[2].rstrip('/'), path.lstrip('/')]) url.pop() path = urlunsplit(url) hooks = [getattr(plugin, 'prepare_path') for plugin in self._plugins if hasattr(plugin, 'prepare_path')] self.logger.debug("Calling {0} plugin hooks...".format('prepare_path')) for func in hooks: path = yield from func(service_desc=service_desc, session=session, request_params=request_params, path=path) return path @coroutine def prepare_request_params(self, service_desc, session, request_params): yield from self._execute_plugin_hooks('prepare_request_params', service_desc=service_desc, session=session, request_params=request_params) @coroutine def prepare_payload(self, service_desc, session, request_params, payload): hooks = [getattr(plugin, 'prepare_payload') for plugin in self._plugins if hasattr(plugin, 'prepare_payload')] self.logger.debug("Calling {0} plugin hooks...".format('prepare_payload')) for func in hooks: payload = yield from func(service_desc=service_desc, session=session, request_params=request_params, payload=payload) return payload @coroutine def before_request(self, service_desc, session, request_params): yield from self._execute_plugin_hooks('before_request', service_desc=service_desc, session=session, request_params=request_params) @coroutine def on_exception(self, service_desc, session, request_params, ex): yield from self._execute_plugin_hooks('on_exception', service_desc=service_desc, session=session, request_params=request_params, ex=ex) @coroutine def on_response(self, service_desc, session, request_params, response): yield from self._execute_plugin_hooks('on_response', service_desc=service_desc, session=session, request_params=request_params, response=response) @coroutine def on_parse_exception(self, service_desc, session, request_params, response, ex): yield from self._execute_plugin_hooks('on_parse_exception', service_desc=service_desc, session=session, request_params=request_params, response=response, ex=ex) @coroutine def on_parsed_response(self, service_desc, session, request_params, response): yield from self._execute_plugin_hooks('on_parsed_response', service_desc=service_desc, session=session, request_params=request_params, response=response) @coroutine def _execute_plugin_hooks(self, hook, *args, **kwargs): hooks = [getattr(plugin, hook) for plugin in self._plugins if hasattr(plugin, hook)] self.logger.debug("Calling {0} plugin hooks...".format(hook)) for func in hooks: yield from func(*args, **kwargs) def add_plugins(self, plugins): self._plugins.extend(plugins) hook = 'assign_service_client' hooks = [getattr(plugin, hook) for plugin in self._plugins if hasattr(plugin, hook)] self.logger.debug("Calling {0} plugin hooks...".format(hook)) for func in hooks: func(service_client=self) def __getattr__(self, item): @coroutine def wrap(*args, **kwargs): return self.call(item, *args, **kwargs) return wrap def __del__(self): # pragma: no cover self.session.close()
def test_borrow_connector_loop(connector, create_session, loop): session = ClientSession(connector=connector, loop=None) try: assert session._loop, loop finally: session.close()
def test_client_session_custom_attr(loop): session = ClientSession(loop=loop) with pytest.warns(DeprecationWarning): session.custom = None
def setUp(self): self.url = 'http://example.com/api' self.session = ClientSession() super().setUp()
def test_closed(self): session = ClientSession(loop=self.loop) self.assertFalse(session.closed) session.close() self.assertTrue(session.closed)
def test_close_flag_for_closed_connector(self): session = ClientSession(loop=self.loop) conn = session.connector self.assertFalse(session.closed) conn.close() self.assertTrue(session.closed)
def test_cookies_are_readonly(self): session = ClientSession(loop=self.loop) with self.assertRaises(AttributeError): session.cookies = 123 session.close()
async def download_multiple(url_start: str, url_endings: list): async with ClientSession() as client: await asyncio.gather(*(download_to_file(client, url_start + x, x) for x in url_endings))
def go(): session = ClientSession(loop=self.loop) session.close() with self.assertRaises(RuntimeError): yield from session.request('get', '/')
def maker(*args, **kwargs): nonlocal session session = ClientSession(*args, loop=loop, **kwargs) return session
def test_context_manager(connector, loop): with pytest.warns(DeprecationWarning): with ClientSession(loop=loop, connector=connector) as session: pass assert session.closed
def test_create_session_outside_of_coroutine(loop): with pytest.warns(ResourceWarning): sess = ClientSession(loop=loop) sess.close()
def setUp(self): self.url = 'http://example.com/api' self.loop = asyncio.get_event_loop() self.session = ClientSession()
class AIOResponsesTestCase(TestCase): use_default_loop = False @asyncio.coroutine def setUp(self): self.url = 'http://example.com/api?foo=bar#fragment' self.session = ClientSession() super().setUp() @asyncio.coroutine def tearDown(self): close_result = self.session.close() if close_result is not None: yield from close_result super().tearDown() def run_async(self, coroutine: Union[Coroutine, Generator]): return self.loop.run_until_complete(coroutine) @asyncio.coroutine def request(self, url: str): return (yield from self.session.get(url)) @data( hdrs.METH_HEAD, hdrs.METH_GET, hdrs.METH_POST, hdrs.METH_PUT, hdrs.METH_PATCH, hdrs.METH_DELETE, hdrs.METH_OPTIONS, ) @patch('aioresponses.aioresponses.add') @fail_on(unused_loop=False) def test_shortcut_method(self, http_method, mocked): with aioresponses() as m: getattr(m, http_method.lower())(self.url) mocked.assert_called_once_with(self.url, method=http_method) @aioresponses() def test_returned_instance(self, m): m.get(self.url) response = self.run_async(self.session.get(self.url)) self.assertIsInstance(response, ClientResponse) @aioresponses() @asyncio.coroutine def test_returned_instance_and_status_code(self, m): m.get(self.url, status=204) response = yield from self.session.get(self.url) self.assertIsInstance(response, ClientResponse) self.assertEqual(response.status, 204) @aioresponses() @asyncio.coroutine def test_returned_response_headers(self, m): m.get(self.url, content_type='text/html', headers={'Connection': 'keep-alive'}) response = yield from self.session.get(self.url) self.assertEqual(response.headers['Connection'], 'keep-alive') self.assertEqual(response.headers[hdrs.CONTENT_TYPE], 'text/html') @aioresponses() @asyncio.coroutine def test_returned_response_raw_headers(self, m): m.get(self.url, content_type='text/html', headers={'Connection': 'keep-alive'}) response = yield from self.session.get(self.url) expected_raw_headers = ((b'Content-Type', b'text/html'), (b'Connection', b'keep-alive')) self.assertEqual(response.raw_headers, expected_raw_headers) @aioresponses() @asyncio.coroutine def test_raise_for_status(self, m): m.get(self.url, status=400) with self.assertRaises(ClientResponseError) as cm: response = yield from self.session.get(self.url) response.raise_for_status() self.assertEqual(cm.exception.message, http.RESPONSES[400][0]) @aioresponses() @asyncio.coroutine @skipIf(condition=AIOHTTP_VERSION < '3.4.0', reason='aiohttp<3.4.0 does not support raise_for_status ' 'arguments for requests') def test_request_raise_for_status(self, m): m.get(self.url, status=400) with self.assertRaises(ClientResponseError) as cm: yield from self.session.get(self.url, raise_for_status=True) self.assertEqual(cm.exception.message, http.RESPONSES[400][0]) @aioresponses() @asyncio.coroutine def test_returned_instance_and_params_handling(self, m): expected_url = 'http://example.com/api?foo=bar&x=42#fragment' m.get(expected_url) response = yield from self.session.get(self.url, params={'x': 42}) self.assertIsInstance(response, ClientResponse) self.assertEqual(response.status, 200) expected_url = 'http://example.com/api?x=42#fragment' m.get(expected_url) response = yield from self.session.get( 'http://example.com/api#fragment', params={'x': 42}) self.assertIsInstance(response, ClientResponse) self.assertEqual(response.status, 200) @aioresponses() def test_method_dont_match(self, m): m.get(self.url) with self.assertRaises(ClientConnectionError): self.run_async(self.session.post(self.url)) @aioresponses() @asyncio.coroutine def test_streaming(self, m): m.get(self.url, body='Test') resp = yield from self.session.get(self.url) content = yield from resp.content.read() self.assertEqual(content, b'Test') @aioresponses() @asyncio.coroutine def test_streaming_up_to(self, m): m.get(self.url, body='Test') resp = yield from self.session.get(self.url) content = yield from resp.content.read(2) self.assertEqual(content, b'Te') content = yield from resp.content.read(2) self.assertEqual(content, b'st') @asyncio.coroutine def test_mocking_as_context_manager(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) payload = yield from resp.json() self.assertDictEqual(payload, {'foo': 'bar'}) def test_mocking_as_decorator(self): @aioresponses() def foo(loop, m): m.add(self.url, payload={'foo': 'bar'}) resp = loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) payload = loop.run_until_complete(resp.json()) self.assertDictEqual(payload, {'foo': 'bar'}) foo(self.loop) @asyncio.coroutine def test_passing_argument(self): @aioresponses(param='mocked') @asyncio.coroutine def foo(mocked): mocked.add(self.url, payload={'foo': 'bar'}) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) yield from foo() @fail_on(unused_loop=False) def test_mocking_as_decorator_wrong_mocked_arg_name(self): @aioresponses(param='foo') def foo(bar): # no matter what is here it should raise an error pass with self.assertRaises(TypeError) as cm: foo() exc = cm.exception self.assertIn("foo() got an unexpected keyword argument 'foo'", str(exc)) @asyncio.coroutine def test_unknown_request(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) with self.assertRaises(ClientConnectionError): yield from self.session.get('http://example.com/foo') @asyncio.coroutine def test_raising_custom_error(self): with aioresponses() as aiomock: aiomock.get(self.url, exception=HttpProcessingError(message='foo')) with self.assertRaises(HttpProcessingError): yield from self.session.get(self.url) @asyncio.coroutine def test_multiple_requests(self): with aioresponses() as m: m.get(self.url, status=200) m.get(self.url, status=201) m.get(self.url, status=202) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 201) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 202) key = ('GET', URL(self.url)) self.assertIn(key, m.requests) self.assertEqual(len(m.requests[key]), 3) self.assertEqual(m.requests[key][0].args, tuple()) self.assertEqual(m.requests[key][0].kwargs, {'allow_redirects': True}) @asyncio.coroutine def test_address_as_instance_of_url_combined_with_pass_through(self): external_api = 'http://httpbin.org/status/201' @asyncio.coroutine def doit(): api_resp = yield from self.session.get(self.url) # we have to hit actual url, # otherwise we do not test pass through option properly ext_rep = yield from self.session.get(URL(external_api)) return api_resp, ext_rep with aioresponses(passthrough=[external_api]) as m: m.get(self.url, status=200) api, ext = yield from doit() self.assertEqual(api.status, 200) self.assertEqual(ext.status, 201) @aioresponses() @asyncio.coroutine def test_custom_response_class(self, m): class CustomClientResponse(ClientResponse): pass m.get(self.url, body='Test', response_class=CustomClientResponse) resp = yield from self.session.get(self.url) self.assertTrue(isinstance(resp, CustomClientResponse)) @aioresponses() def test_exceptions_in_the_middle_of_responses(self, mocked): mocked.get(self.url, payload={}, status=204) mocked.get( self.url, exception=ValueError('oops'), ) mocked.get(self.url, payload={}, status=204) mocked.get( self.url, exception=ValueError('oops'), ) mocked.get(self.url, payload={}, status=200) @asyncio.coroutine def doit(): return (yield from self.session.get(self.url)) self.assertEqual(self.run_async(doit()).status, 204) with self.assertRaises(ValueError): self.run_async(doit()) self.assertEqual(self.run_async(doit()).status, 204) with self.assertRaises(ValueError): self.run_async(doit()) self.assertEqual(self.run_async(doit()).status, 200) @aioresponses() @asyncio.coroutine def test_request_should_match_regexp(self, mocked): mocked.get(re.compile(r'^http://example\.com/api\?foo=.*$'), payload={}, status=200) response = yield from self.request(self.url) self.assertEqual(response.status, 200) @aioresponses() @asyncio.coroutine def test_request_does_not_match_regexp(self, mocked): mocked.get(re.compile(r'^http://exampleexample\.com/api\?foo=.*$'), payload={}, status=200) with self.assertRaises(ClientConnectionError): yield from self.request(self.url) @aioresponses() def test_timeout(self, mocked): mocked.get(self.url, timeout=True) with self.assertRaises(asyncio.TimeoutError): self.run_async(self.request(self.url)) @aioresponses() def test_callback(self, m): body = b'New body' def callback(url, **kwargs): self.assertEqual(str(url), self.url) self.assertEqual(kwargs, {'allow_redirects': True}) return CallbackResult(body=body) m.get(self.url, callback=callback) response = self.run_async(self.request(self.url)) data = self.run_async(response.read()) assert data == body @aioresponses() def test_callback_coroutine(self, m): body = b'New body' event = asyncio.Event() @asyncio.coroutine def callback(url, **kwargs): yield from event.wait() self.assertEqual(str(url), self.url) self.assertEqual(kwargs, {'allow_redirects': True}) return CallbackResult(body=body) m.get(self.url, callback=callback) future = asyncio.ensure_future(self.request(self.url)) self.run_async(asyncio.wait([future], timeout=0)) assert not future.done() event.set() self.run_async(asyncio.wait([future], timeout=0)) assert future.done() response = future.result() data = self.run_async(response.read()) assert data == body
class GraphitePlugin(BasePlugin): _type = 'graphite' condition_map = { '>': operator.gt, '>=': operator.ge, '<': operator.lt, '<=': operator.le, '==': operator.eq } def __init__(self): super().__init__() self.session = ClientSession() def supported_types(self): return settings.GRAPHITE_TYPES def init(self, *args): super().init(*args) def get_graphite_url(self, env): return 'http://{}/render'.format( settings.ENVIRONMENTS[env]['metrics_service']['host'] ) def get_graph_url(self, env: str): """Returns a formatted URL for a graph.""" return settings.ENVIRONMENTS[env]['metrics_service'].get( 'graph_url', self.get_graphite_url(env) ) @asyncio.coroutine @stats.increment(metric_name='graphite.execute') @stats.timer(metric_name='graphite.execute') def execute(self, check): logger.info( 'Processing check: id="{}", metric="{}"'.format( check['id'], check['fields']['metric'] ) ) fields = check['fields'] check['target'] = fields['metric'] env = check.get('environment', 'test') url = self.get_graphite_url(env) try: metric = fields['metric'] with Timeout(settings.GRAPHITE_TIMEOUT): response = yield from self.session.get( url, params={ 'target': metric, 'from': settings.GRAPHITE_TIME_RANGE, 'format': 'json' } ) response.raise_for_status() data = yield from response.json() self.process(check, data, env) except (ValueError, HttpProcessingError, TimeoutError, ClientOSError) as e: message = self.exception_repr(e, pattern='{}: {}') logger.error('Could not execute plugin for check `%s`, %s', check['id'], message) self.set_check_status(check, RESULT_UNKNOWN, message) def add_meta(self, check, trigger, env, threshold=None): threshold = threshold or 0.0 now = datetime.now() # - 1 hour from_date = now - timedelta(0, 3600) params = [ ('width', settings.GRAPHITE_CHART_WIDTH), ('height', settings.GRAPHITE_CHART_HEIGHT), ('tz', settings.GRAPHITE_TIME_ZONE), ('from', from_date.strftime('%H:%M_%Y%m%d')), ('until', now.strftime('%H:%M_%Y%m%d')), ('target', check['fields']['metric']), ('target', 'threshold({}, \"{}\", red)'.format( threshold, 'threshold = {}'.format(threshold), )), ] graphite_url = "{}?{}".format( self.get_graph_url(env), urlencode(params) ) trigger['meta']['links']['graphite_url'] = dict( type='link', href=graphite_url ) @stats.increment(metric_name='graphite.process') @stats.timer(metric_name='graphite.process') def process(self, check, data, env): frequency = int(check['fields']['frequency']) expected_num_hosts = check['fields'].get('expected_num_hosts', 0) ret = Result() for result in data: datapoints = result['datapoints'] values = [float(t[0]) for t in datapoints[-int(frequency / 60) - 1:-1] if t[0] is not None] ret.num_series_with_data += 1 if values else 0 ret.num_series_no_data += 0 if values else 1 ret.all_values.extend(values) for trigger in check['triggers']: status, failed_values, message = RESULT_OK, [], '' hyst_status, hystfail_values = RESULT_OK, [] debounce = trigger.get('debounce') or check['fields'].get( 'debounce', 1) trigger_expected_num_hosts = int( trigger.get('expected_num_hosts', 0) or expected_num_hosts ) try: threshold = float(trigger.get('threshold')) condition = self.condition_map[trigger.get('condition')] hysteresis_value = float(trigger.get('hysteresis', "0.0")) except (ValueError, TypeError) as e: message = INVALID_THRESHOLD.format( trigger.get('threshold', '<unknown>'), check['id'], e ) logger.error(message) self.set_status( trigger, RESULT_UNKNOWN, message, hysteresis=RESULT_UNKNOWN ) continue except KeyError: message = INVALID_OPERATOR.format( trigger.get('condition'), list(self.condition_map.keys()) ) logger.error(message) self.set_status( trigger, RESULT_UNKNOWN, message, hysteresis=RESULT_UNKNOWN ) self.add_meta(check, trigger, env, threshold=threshold) continue if trigger.get('condition') in ['<', '<=']: hyst_threshold = threshold + hysteresis_value elif trigger.get('condition') in ['>', '>=']: hyst_threshold = threshold - hysteresis_value else: hyst_threshold = threshold failed_values = list(filter( lambda x: condition(x, threshold), ret.all_values )) hystfail_values = list(filter( lambda x: condition(x, hyst_threshold), ret.all_values )) if failed_values: status = hyst_status = RESULT_FAILED values = ', '.join( [str(x) for x in failed_values[-int(debounce):]] ) message = '[{}] {} {}'.format( values, trigger['condition'], threshold ) elif hystfail_values: # if hysteresis is off or hardfail threshold hits, # we won't even reach here hyst_status = RESULT_FAILED hysteresis_sign = '-' if hyst_threshold < threshold else '+' values = ', '.join( [str(x) for x in hystfail_values[-int(debounce):]] ) message = '[{}] {} ({} {} {} hysteresis)'.format( values, trigger['condition'], threshold, hysteresis_sign, hysteresis_value ) if ret.num_series_with_data < trigger_expected_num_hosts: status = hyst_status = RESULT_FAILED msg = MESSAGE_TPL.format( ret.num_series_with_data, trigger_expected_num_hosts ) message = '\n '.join(msg for msg in [msg, message] if msg) self.set_status(trigger, status, message, hysteresis=hyst_status) self.add_meta(check, trigger, env, threshold=threshold)
class AIOResponsesTestCase(TestCase): use_default_loop = False @asyncio.coroutine def setUp(self): self.url = 'http://example.com/api' self.session = ClientSession() super().setUp() @asyncio.coroutine def tearDown(self): self.session.close() super().tearDown() @data( hdrs.METH_HEAD, hdrs.METH_GET, hdrs.METH_POST, hdrs.METH_PUT, hdrs.METH_PATCH, hdrs.METH_DELETE, hdrs.METH_OPTIONS, ) @patch('aioresponses.aioresponses.add') @fail_on(unused_loop=False) def test_shortcut_method(self, http_method, mocked): with aioresponses() as m: getattr(m, http_method.lower())(self.url) mocked.assert_called_once_with(self.url, method=http_method) @aioresponses() def test_returned_instance(self, m): m.get(self.url) response = self.loop.run_until_complete(self.session.get(self.url)) self.assertIsInstance(response, ClientResponse) @aioresponses() @asyncio.coroutine def test_returned_instance_and_status_code(self, m): m.get(self.url, status=204) response = yield from self.session.get(self.url) self.assertIsInstance(response, ClientResponse) self.assertEqual(response.status, 204) @aioresponses() @asyncio.coroutine def test_returned_response_headers(self, m): m.get(self.url, content_type='text/html', headers={'Connection': 'keep-alive'}) response = yield from self.session.get(self.url) self.assertEqual(response.headers['Connection'], 'keep-alive') self.assertEqual(response.headers[hdrs.CONTENT_TYPE], 'text/html') @aioresponses() def test_method_dont_match(self, m): m.get(self.url) with self.assertRaises(ClientConnectionError): self.loop.run_until_complete(self.session.post(self.url)) @aioresponses() @asyncio.coroutine def test_streaming(self, m): m.get(self.url, body='Test') resp = yield from self.session.get(self.url) content = yield from resp.content.read() self.assertEqual(content, b'Test') @aioresponses() @asyncio.coroutine def test_streaming_up_to(self, m): m.get(self.url, body='Test') resp = yield from self.session.get(self.url) content = yield from resp.content.read(2) self.assertEqual(content, b'Te') content = yield from resp.content.read(2) self.assertEqual(content, b'st') @asyncio.coroutine def test_mocking_as_context_manager(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) payload = yield from resp.json() self.assertDictEqual(payload, {'foo': 'bar'}) def test_mocking_as_decorator(self): @aioresponses() def foo(loop, m): m.add(self.url, payload={'foo': 'bar'}) resp = loop.run_until_complete(self.session.get(self.url)) self.assertEqual(resp.status, 200) payload = loop.run_until_complete(resp.json()) self.assertDictEqual(payload, {'foo': 'bar'}) foo(self.loop) @asyncio.coroutine def test_passing_argument(self): @aioresponses(param='mocked') @asyncio.coroutine def foo(mocked): mocked.add(self.url, payload={'foo': 'bar'}) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) yield from foo() @fail_on(unused_loop=False) def test_mocking_as_decorator_wrong_mocked_arg_name(self): @aioresponses(param='foo') def foo(bar): # no matter what is here it should raise an error pass with self.assertRaises(TypeError) as cm: foo() exc = cm.exception self.assertIn("foo() got an unexpected keyword argument 'foo'", str(exc)) @asyncio.coroutine def test_unknown_request(self): with aioresponses() as aiomock: aiomock.add(self.url, payload={'foo': 'bar'}) with self.assertRaises(ClientConnectionError): yield from self.session.get('http://example.com/foo') @asyncio.coroutine def test_raising_custom_error(self): with aioresponses() as aiomock: aiomock.get(self.url, exception=HttpProcessingError(message='foo')) with self.assertRaises(HttpProcessingError): yield from self.session.get(self.url) @asyncio.coroutine def test_multiple_requests(self): with aioresponses() as m: m.get(self.url, status=200) m.get(self.url, status=201) m.get(self.url, status=202) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 200) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 201) resp = yield from self.session.get(self.url) self.assertEqual(resp.status, 202) key = ('GET', self.url) self.assertIn(key, m.requests) self.assertEqual(len(m.requests[key]), 3) self.assertEqual(m.requests[key][0].args, tuple()) self.assertEqual(m.requests[key][0].kwargs, {'allow_redirects': True}) @asyncio.coroutine def test_address_as_instance_of_url_combined_with_pass_through(self): external_api = 'http://httpbin.org/status/201' @asyncio.coroutine def doit(): api_resp = yield from self.session.get(self.url) # we have to hit actual url, # otherwise we do not test pass through option properly ext_rep = yield from self.session.get(URL(external_api)) return api_resp, ext_rep with aioresponses(passthrough=[external_api]) as m: m.get(self.url, status=200) api, ext = yield from doit() self.assertEqual(api.status, 200) self.assertEqual(ext.status, 201)
def setUp(self): self.url = 'http://example.com/api?foo=bar#fragment' self.session = ClientSession() super().setUp()
def setUp(self): self.url = 'http://example.com/api?foo=bar#fragment' self.session = ClientSession(raise_for_status=True) super().setUp()