async def test_custom_logger(aresponses, caplog): """Test that a custom logger is used when provided to the client.""" caplog.set_level(logging.DEBUG) custom_logger = logging.getLogger("custom") aresponses.add( "www.pollen.com", f"/api/forecast/current/pollen/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_current_response.json"), status=200, headers={"Content-Type": "application/json; charset=utf-8"}, ), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session, logger=custom_logger) await client.allergens.current() assert any( record.name == "custom" and "Received data" in record.message for record in caplog.records ) aresponses.assert_plan_strictly_followed()
async def async_setup_entry(hass, config_entry): """Set up IQVIA as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) try: iqvia = IQVIAData( Client(config_entry.data[CONF_ZIP_CODE], websession), config_entry.data.get(CONF_MONITORED_CONDITIONS, list(SENSORS))) await iqvia.async_update() except InvalidZipError: _LOGGER.error('Invalid ZIP code provided: %s', config_entry.data[CONF_ZIP_CODE]) return False hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = iqvia hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, 'sensor')) async def refresh(event_time): """Refresh IQVIA data.""" _LOGGER.debug('Updating IQVIA data') await iqvia.async_update() async_dispatcher_send(hass, TOPIC_DATA_UPDATE) hass.data[DOMAIN][DATA_LISTENER][ config_entry.entry_id] = async_track_time_interval( hass, refresh, DEFAULT_SCAN_INTERVAL) return True
async def main(): """Run.""" async with ClientSession() as session: try: client = Client("17015", session=session) print(f'Client instantiated for ZIP "{client.zip_code}"') print() print("Allergen Data:") print(await client.allergens.current()) print(await client.allergens.extended()) print(await client.allergens.historic()) print(await client.allergens.outlook()) print() print("Disease Data:") print(await client.disease.current()) print(await client.disease.extended()) print(await client.disease.historic()) print() print("Asthma Data:") print(await client.asthma.current()) print(await client.asthma.extended()) print(await client.asthma.historic()) except IQVIAError as err: print(err)
async def async_setup(hass, config): """Set up the IQVIA component.""" hass.data[DOMAIN] = {} hass.data[DOMAIN][DATA_CLIENT] = {} hass.data[DOMAIN][DATA_LISTENER] = {} conf = config[DOMAIN] websession = aiohttp_client.async_get_clientsession(hass) try: iqvia = IQVIAData(Client(conf[CONF_ZIP_CODE], websession), conf[CONF_MONITORED_CONDITIONS]) await iqvia.async_update() except IQVIAError as err: _LOGGER.error('Unable to set up IQVIA: %s', err) return False hass.data[DOMAIN][DATA_CLIENT] = iqvia hass.async_create_task( async_load_platform(hass, 'sensor', DOMAIN, {}, config)) async def refresh(event_time): """Refresh IQVIA data.""" _LOGGER.debug('Updating IQVIA data') await iqvia.async_update() async_dispatcher_send(hass, TOPIC_DATA_UPDATE) hass.data[DOMAIN][DATA_LISTENER] = async_track_time_interval( hass, refresh, DEFAULT_SCAN_INTERVAL) return True
async def async_setup_entry(hass, config_entry): """Set up IQVIA as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if not config_entry.unique_id: # If the config entry doesn't already have a unique ID, set one: hass.config_entries.async_update_entry( config_entry, **{"unique_id": config_entry.data[CONF_ZIP_CODE]} ) iqvia = IQVIAData(hass, Client(config_entry.data[CONF_ZIP_CODE], websession)) try: await iqvia.async_update() except InvalidZipError: _LOGGER.error("Invalid ZIP code provided: %s", config_entry.data[CONF_ZIP_CODE]) return False hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = iqvia hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, "sensor") ) return True
async def test_request_timeout(): """Test a request timeout.""" with patch( "aiohttp.ClientSession.request", side_effect=asyncio.exceptions.TimeoutError ), pytest.raises(RequestError): async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session, request_retries=1) await client.allergens.outlook()
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up IQVIA as config entry.""" hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = {} if not entry.unique_id: # If the config entry doesn't already have a unique ID, set one: hass.config_entries.async_update_entry( entry, **{"unique_id": entry.data[CONF_ZIP_CODE]}) websession = aiohttp_client.async_get_clientsession(hass) client = Client(entry.data[CONF_ZIP_CODE], session=websession) async def async_get_data_from_api( api_coro: Callable[..., Awaitable]) -> dict[str, Any]: """Get data from a particular API coroutine.""" try: data = await api_coro() except IQVIAError as err: raise UpdateFailed from err return cast(Dict[str, Any], data) coordinators = {} init_data_update_tasks = [] for sensor_type, api_coro in ( (TYPE_ALLERGY_FORECAST, client.allergens.extended), (TYPE_ALLERGY_INDEX, client.allergens.current), (TYPE_ALLERGY_OUTLOOK, client.allergens.outlook), (TYPE_ASTHMA_FORECAST, client.asthma.extended), (TYPE_ASTHMA_INDEX, client.asthma.current), (TYPE_DISEASE_FORECAST, client.disease.extended), (TYPE_DISEASE_INDEX, client.disease.current), ): coordinator = coordinators[sensor_type] = DataUpdateCoordinator( hass, LOGGER, name=f"{entry.data[CONF_ZIP_CODE]} {sensor_type}", update_interval=DEFAULT_SCAN_INTERVAL, update_method=partial(async_get_data_from_api, api_coro), ) init_data_update_tasks.append(coordinator.async_refresh()) results = await asyncio.gather(*init_data_update_tasks, return_exceptions=True) if all(isinstance(result, Exception) for result in results): # The IQVIA API can be selectively flaky, meaning that any number of the setup # API calls could fail. We only retry integration setup if *all* of the initial # API calls fail: raise ConfigEntryNotReady() hass.data[DOMAIN][entry.entry_id] = coordinators hass.config_entries.async_setup_platforms(entry, PLATFORMS) return True
async def test_current_no_explicit_session(aresponses): """Test getting current allergen data without an explicit aiohttp ClientSession.""" aresponses.add( "www.pollen.com", f"/api/forecast/current/pollen/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_current_response.json"), status=200), ) client = Client(TEST_ZIP) current = await client.allergens.current() assert len(current["Location"]["periods"]) == 3
async def test_extended(aresponses): """Test getting extended asthma info.""" aresponses.add( "www.asthmaforecast.com", f"/api/forecast/extended/asthma/{TEST_ZIP}", "get", aresponses.Response(text=load_fixture("asthma_extended_response.json"), status=200), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) extended = await client.asthma.extended() assert len(extended["Location"]["periods"]) == 5
async def test_extended(aresponses): """Test getting extended cold and flu data.""" aresponses.add( "www.pollen.com", f"/api/forecast/extended/cold/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("disease_extended_response.json"), status=200), ) async with aiohttp.ClientSession() as websession: client = Client(TEST_ZIP, websession) extended = await client.disease.extended() assert len(extended["Location"]["periods"]) == 4
async def test_endpoints(aresponses): """Test getting historic asthma info.""" aresponses.add( "www.asthmaforecast.com", f"/api/forecast/historic/asthma/{TEST_ZIP}", "get", aresponses.Response(text=load_fixture("asthma_historic_response.json"), status=200), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) historic = await client.asthma.historic() assert len(historic["Location"]["periods"]) == 30
async def test_outlook(aresponses): """Test getting outlook allergen info.""" aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_outlook_response.json"), status=200), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) outlook = await client.allergens.outlook() assert outlook["Trend"] == "subsiding"
async def test_historic(aresponses): """Test getting historic allergen info.""" aresponses.add( "www.pollen.com", f"/api/forecast/historic/pollen/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_historic_response.json"), status=200), ) async with aiohttp.ClientSession() as websession: client = Client(TEST_ZIP, websession) historic = await client.allergens.historic() assert len(historic["Location"]["periods"]) == 30
async def test_historic(aresponses): """Test getting historic cold and flu data.""" aresponses.add( "www.flustar.com", f"/api/forecast/historic/cold/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("disease_historic_response.json"), status=200), ) async with aiohttp.ClientSession() as websession: client = Client(TEST_ZIP, websession) historic = await client.disease.historic() assert len(historic["Location"]["periods"]) == 26
async def test_current(aresponses): """Test getting current asthma.""" aresponses.add( "www.asthmaforecast.com", f"/api/forecast/current/asthma/{TEST_ZIP}", "get", aresponses.Response(text=load_fixture("asthma_current_response.json"), status=200), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) current = await client.asthma.current() assert len(current["Location"]["periods"]) == 3
async def test_current(aresponses): """Test getting current cold and flu data.""" aresponses.add( "flustar.com", f"/api/forecast/current/cold/{TEST_ZIP}", "get", aresponses.Response(text=load_fixture("disease_current_response.json"), status=200), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) current = await client.disease.current() assert len(current["Location"]["periods"]) == 2
async def async_setup_entry(hass, entry): """Set up IQVIA as config entry.""" hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id] = {} if not entry.unique_id: # If the config entry doesn't already have a unique ID, set one: hass.config_entries.async_update_entry( entry, **{"unique_id": entry.data[CONF_ZIP_CODE]} ) websession = aiohttp_client.async_get_clientsession(hass) client = Client(entry.data[CONF_ZIP_CODE], websession) async def async_get_data_from_api(api_coro): """Get data from a particular API coroutine.""" try: return await api_coro() except IQVIAError as err: raise UpdateFailed from err init_data_update_tasks = [] for sensor_type, api_coro in [ (TYPE_ALLERGY_FORECAST, client.allergens.extended), (TYPE_ALLERGY_INDEX, client.allergens.current), (TYPE_ALLERGY_OUTLOOK, client.allergens.outlook), (TYPE_ASTHMA_FORECAST, client.asthma.extended), (TYPE_ASTHMA_INDEX, client.asthma.current), (TYPE_DISEASE_FORECAST, client.disease.extended), (TYPE_DISEASE_INDEX, client.disease.current), ]: coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][ sensor_type ] = DataUpdateCoordinator( hass, LOGGER, name=f"{entry.data[CONF_ZIP_CODE]} {sensor_type}", update_interval=DEFAULT_SCAN_INTERVAL, update_method=lambda coro=api_coro: async_get_data_from_api(coro), ) init_data_update_tasks.append(coordinator.async_refresh()) await asyncio.gather(*init_data_update_tasks) for component in PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, component) ) return True
async def test_http_error(aresponses): """Test an HTTP error.""" aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response(text="", status=500), ) with pytest.raises(RequestError): async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session, request_retries=1) await client.allergens.outlook() aresponses.assert_plan_strictly_followed()
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: return await self._show_form() if user_input[CONF_ZIP_CODE] in configured_instances(self.hass): return await self._show_form({CONF_ZIP_CODE: "identifier_exists"}) websession = aiohttp_client.async_get_clientsession(self.hass) try: Client(user_input[CONF_ZIP_CODE], websession) except InvalidZipError: return await self._show_form({CONF_ZIP_CODE: "invalid_zip_code"}) return self.async_create_entry(title=user_input[CONF_ZIP_CODE], data=user_input)
async def test_historic(aresponses): """Test getting historic cold and flu data.""" aresponses.add( "flustar.com", f"/api/forecast/historic/cold/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("disease_historic_response.json"), status=200, headers={"Content-Type": "application/json; charset=utf-8"}, ), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) historic = await client.disease.historic() assert len(historic["Location"]["periods"]) == 26
async def pollen(self, ctx, zip_code: str): """3 day pollen index. Pulls a 3 day pollen index with allergen information from `pollen.com` using the `pyiqvia` wrapper. Parameters: zip_code (str): Converted to string for convenience with piqvia. Returns: message (class Embed): The pollen index and allergen information (allergen name, genus, and plant type) for the day. """ client = Client(zip_code) data = await client.allergens.current() allergens = WeatherCog._format_pollen_data(data) await ctx.send(embed=allergens)
async def test_extended(aresponses): """Test getting extended allergen info.""" aresponses.add( "www.pollen.com", f"/api/forecast/extended/pollen/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_extended_response.json"), status=200, headers={"Content-Type": "application/json; charset=utf-8"}, ), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) extended = await client.allergens.extended() assert len(extended["Location"]["periods"]) == 5
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: return self.async_show_form(step_id="user", data_schema=self.data_schema) await self.async_set_unique_id(user_input[CONF_ZIP_CODE]) self._abort_if_unique_id_configured() websession = aiohttp_client.async_get_clientsession(self.opp) try: Client(user_input[CONF_ZIP_CODE], session=websession) except InvalidZipError: return self.async_show_form( step_id="user", data_schema=self.data_schema, errors={CONF_ZIP_CODE: "invalid_zip_code"}, ) return self.async_create_entry(title=user_input[CONF_ZIP_CODE], data=user_input)
async def test_request_error(aresponses): """Test authenticating the device.""" aresponses.add( "www.pollen.com", f"/api/bad_endpoint/{TEST_ZIP}", "get", aresponses.Response(text="", status=404), ) aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response(text="", status=500), ) with pytest.raises(RequestError): async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) await client._request("get", "https://www.pollen.com/api/bad_endpoint") await client.allergens.outlook()
async def test_request_retries(aresponses): """Test the request retry logic.""" aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response(text="", status=500), ) aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response(text="", status=500), ) aresponses.add( "www.pollen.com", f"/api/forecast/outlook/{TEST_ZIP}", "get", aresponses.Response( text=load_fixture("allergens_outlook_response.json"), status=200, headers={"Content-Type": "application/json; charset=utf-8"}, ), ) async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) client.disable_request_retries() with pytest.raises(RequestError): await client.allergens.outlook() client.enable_request_retries() await client.allergens.outlook() aresponses.assert_plan_strictly_followed()
async def test_bad_zip(): """Test attempting to create a client with a bad ZIP code.""" with pytest.raises(InvalidZipError): async with aiohttp.ClientSession() as session: _ = Client(TEST_BAD_ZIP, session=session)
async def test_create(): """Test the creation of a client.""" async with aiohttp.ClientSession() as session: client = Client(TEST_ZIP, session=session) assert client.zip_code == TEST_ZIP