def test_get_alerts(self): cond = Condition('humidity', 'LESS_THAN', 10) alert1 = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": cond }], { "lon": 37, "lat": 53 }, 1481802090232) alert2 = Alert('alert2', 'trigger1', [{ "current_value": 111.576, "condition": cond }], { "lon": 37, "lat": 53 }, 1481802100000) alerts = [alert1, alert2] instance = Trigger(1526809375, 1527809375, [cond], [geo.Point(13.6, 46.9)], alerts=alerts, alert_channels=None) result = instance.get_alerts() self.assertTrue(isinstance(result, list)) self.assertTrue(alert1 in result) self.assertTrue(alert2 in result)
def test_get_alerts_since(self): cond = Condition('humidity', 'LESS_THAN', 10) alert1 = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": cond }], { "lon": 37, "lat": 53 }, 1000) alert2 = Alert('alert2', 'trigger1', [{ "current_value": 111.576, "condition": cond }], { "lon": 37, "lat": 53 }, 3000) alert3 = Alert('alert3', 'trigger1', [{ "current_value": 119.332, "condition": cond }], { "lon": 37, "lat": 53 }, 9000) alert4 = Alert('alert4', 'trigger1', [{ "current_value": 119.332, "condition": cond }], { "lon": 37, "lat": 53 }, 12000) alerts = [alert1, alert2, alert3, alert4] instance = Trigger(1526809375, 1527809375, [cond], [geo.Point(13.6, 46.9)], alerts=alerts, alert_channels=None) result = instance.get_alerts_since(4000) self.assertEqual(2, len(result)) self.assertTrue(alert3 in result) self.assertTrue(alert4 in result) result = instance.get_alerts_since(3000) self.assertEqual(3, len(result)) self.assertTrue(alert2 in result) self.assertTrue(alert3 in result) self.assertTrue(alert4 in result) result = instance.get_alerts_since(15000) self.assertEqual(0, len(result))
def test_get_alerts_on(self): cond1 = Condition('humidity', 'LESS_THAN', 10) cond2 = Condition('temp', 'GREATER_THAN_EQUAL', 100.6) alert1 = Alert('alert1', 'trigger1', [{ "current_value": 8.576, "condition": cond1 }], { "lon": 37, "lat": 53 }, 1000) alert2 = Alert('alert2', 'trigger1', [{ "current_value": 111.576, "condition": cond2 }], { "lon": 37, "lat": 53 }, 3000) alert3 = Alert('alert3', 'trigger1', [{ "current_value": 119.332, "condition": cond2 }], { "lon": 37, "lat": 53 }, 9000) alert4 = Alert('alert4', 'trigger1', [{ "current_value": 7.332, "condition": cond1 }], { "lon": 37, "lat": 53 }, 12000) alerts = [alert1, alert2, alert3, alert4] instance = Trigger(1526809375, 1527809375, [cond1, cond2], [geo.Point(13.6, 46.9)], alerts=alerts, alert_channels=None) result = instance.get_alerts_on('temp') self.assertEqual(2, len(result)) self.assertTrue(alert2 in result) self.assertTrue(alert3 in result) result = instance.get_alerts_on('humidity') self.assertEqual(2, len(result)) self.assertTrue(alert1 in result) self.assertTrue(alert4 in result) result = instance.get_alerts_on('wind_direction') self.assertEqual(0, len(result))
def test_to_dict(self): condition = Condition('humidity', 'LESS_THAN', 10) instance = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": condition.to_dict()}], {"lon": 37, "lat": 53}, 1481802090232) result = instance.to_dict() self.assertIsInstance(result, dict) self.assertEqual('alert1', result['id']) self.assertEqual('trigger1', result['trigger_id']) self.assertEqual(1, len(result['met_conditions'])) mc = result['met_conditions'][0] self.assertEqual(dict(current_value=263.576, condition=condition.to_dict()), mc) self.assertEqual({"lon": 37, "lat": 53}, result['coordinates']) self.assertEqual(1481802090232, result['last_update'])
def parse_JSON(self, JSON_string): """ Parses a `pyowm.alertapi30.alert.Alert` instance out of raw JSON data. :param JSON_string: a raw JSON string :type JSON_string: str :return: a `pyowm.alertapi30.alert.Alert` instance or ``None`` if no data is available :raises: *ParseResponseError* if it is impossible to find or parse the data needed to build the result """ if JSON_string is None: raise parse_response_error.ParseResponseError('JSON data is None') d = json.loads(JSON_string) try: alert_id = d['_id'] t = d['last_update'].split('.')[0].replace('T', ' ') + '+00' alert_last_update = timeformatutils._ISO8601_to_UNIXtime(t) alert_trigger_id = d['triggerId'] alert_met_conds = [ dict(current_value=c['current_value']['min'], condition=Condition.from_dict(c['condition'])) for c in d['conditions'] ] alert_coords = d['coordinates'] return Alert(alert_id, alert_trigger_id, alert_met_conds, alert_coords, last_update=alert_last_update) except ValueError as e: raise parse_response_error.ParseResponseError('Impossible to parse JSON: %s' % e) except KeyError as e: raise parse_response_error.ParseResponseError('Impossible to parse JSON: %s' % e)
def test_repr(self): the_dict = { '_id': '5853dbe27416a400011b1b77', 'conditions': [{'_id': '5853dbe27416a400011b1b78', 'condition': {'amount': 273, 'expression': '$lt', 'name': 'temp'}, 'current_value': {'max': 258.62, 'min': 258.62}}], 'coordinates': {'lat': '53', 'lon': '37'}, 'date': '2016-12-17T00:00:00.000Z', 'last_update': '2016-12-16T11:19:46.352Z', 'triggerId': '5852816a9aaacb00153134a3'} instance = Alert.from_dict(the_dict) print(instance)
def get_alerts_for(self, trigger): """ Retrieves all of the alerts that were fired for the specified Trigger :param trigger: the trigger :type trigger: `pyowm.alertapi30.trigger.Trigger` :return: list of `pyowm.alertapi30.alert.Alert` objects """ assert trigger is not None assert isinstance(trigger.id, str), "Value must be a string" status, data = self.http_client.get_json( ALERTS_URI % trigger.id, params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return [Alert.from_dict(item) for item in data]
def test_get_alert(self): cond = Condition('humidity', 'LESS_THAN', 10) alert = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": cond }], { "lon": 37, "lat": 53 }, 1481802090232) alerts = [alert] instance = Trigger(1526809375, 1527809375, [cond], [geo.Point(13.6, 46.9)], alerts=alerts, alert_channels=None) self.assertEqual(alert, instance.get_alert('alert1'))
def get_alert(self, alert_id, trigger): """ Retrieves info about the alert record on the Alert API that has the specified ID and belongs to the specified parent Trigger object :param trigger: the parent trigger :type trigger: `pyowm.alertapi30.trigger.Trigger` :param alert_id: the ID of the alert :type alert_id `pyowm.alertapi30.alert.Alert` :return: an `pyowm.alertapi30.alert.Alert` instance """ assert trigger is not None assert alert_id is not None assert isinstance(alert_id, str), "Value must be a string" assert isinstance(trigger.id, str), "Value must be a string" status, data = self.http_client.get_json( NAMED_ALERT_URI % (trigger.id, alert_id), params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return Alert.from_dict(data)
def test_get_alert(self): cond = Condition('humidity', 'LESS_THAN', 10) alert = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": cond }], { "lon": 37, "lat": 53 }, 1481802090232) alert_two = copy.deepcopy(alert) alert_two.id = 'alert_two' alerts = [alert_two, alert ] # Second alert has to be 1st element to have full coverage instance = Trigger(1526809375, 1527809375, [cond], [geo.Point(13.6, 46.9)], alerts=alerts, alert_channels=None) self.assertEqual(alert, instance.get_alert('alert1')) # Trigger without alerts instance.alerts = [] self.assertIsNone(instance.get_alert(alert_id='alert1'))
def test_from_dict(self): the_dict = { '_id': '5853dbe27416a400011b1b77', 'conditions': [{'_id': '5853dbe27416a400011b1b78', 'condition': {'amount': 273, 'expression': '$lt', 'name': 'temp'}, 'current_value': {'max': 258.62, 'min': 258.62}}], 'coordinates': {'lat': '53', 'lon': '37'}, 'date': '2016-12-17T00:00:00.000Z', 'last_update': '2016-12-16T11:19:46.352Z', 'triggerId': '5852816a9aaacb00153134a3'} result = Alert.from_dict(the_dict) self.assertIsInstance(result, Alert) with self.assertRaises(pyowm.commons.exceptions.ParseAPIResponseError): Alert.from_dict(None) with self.assertRaises(pyowm.commons.exceptions.ParseAPIResponseError): Alert.from_dict(dict(nonexistent='key')) value_error_dict = copy.deepcopy(the_dict) value_error_dict['last_update'] = 'not_valid_timestamp' with self.assertRaises(pyowm.commons.exceptions.ParseAPIResponseError): Alert.from_dict(value_error_dict)
def test_alert_last_updated_is_none(self): alert = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": Condition('humidity', 'LESS_THAN', 10)}], {"lon": 37, "lat": 53}) self.assertIsNone(alert.last_update)
def from_dict(cls, the_dict): if the_dict is None: raise pyowm.commons.exceptions.ParseAPIResponseError( 'Data is None') try: # trigger id trigger_id = the_dict.get('_id', None) # start timestamp start_dict = the_dict['time_period']['start'] expr = start_dict['expression'] if expr != 'after': raise ValueError( 'Invalid time expression: "%s" on start timestamp. Only: "after" is supported' % expr) start = start_dict['amount'] # end timestamp end_dict = the_dict['time_period']['end'] expr = end_dict['expression'] if expr != 'after': raise ValueError( 'Invalid time expression: "%s" on end timestamp. Only: "after" is supported' % expr) end = end_dict['amount'] # conditions conditions = [ Condition.from_dict(c) for c in the_dict['conditions'] ] # alerts alerts_dict = the_dict['alerts'] alerts = list() for key in alerts_dict: alert_id = key alert_data = alerts_dict[alert_id] alert_last_update = alert_data['last_update'] alert_met_conds = [] for c in alert_data['conditions']: if isinstance(c['current_value'], int): cv = c['current_value'] else: cv = c['current_value']['min'] item = dict(current_value=cv, condition=Condition.from_dict(c['condition'])) alert_met_conds.append(item) alert_coords = alert_data['coordinates'] alert = Alert(alert_id, trigger_id, alert_met_conds, alert_coords, last_update=alert_last_update) alerts.append(alert) # area area_list = the_dict['area'] area = [GeometryBuilder.build(a_dict) for a_dict in area_list] # alert channels alert_channels = None # defaulting except ValueError as e: raise pyowm.commons.exceptions.ParseAPIResponseError( 'Impossible to parse JSON: %s' % e) except KeyError as e: raise pyowm.commons.exceptions.ParseAPIResponseError( 'Impossible to parse JSON: %s' % e) return Trigger(start, end, conditions, area=area, alerts=alerts, alert_channels=alert_channels, id=trigger_id)
def parse_JSON(self, JSON_string): """ Parses a `pyowm.alertapi30.trigger.Trigger` instance out of raw JSON data. As per OWM documentation, start and end times are expressed with respect to the moment when you create/update the Trigger. By design, PyOWM will only allow users to specify *absolute* datetimes - which is, with the `exact` expression - for start/end timestamps (will otherwise result in a `ParseResponseError` be raised) :param JSON_string: a raw JSON string :type JSON_string: str :return: a `pyowm.alertapi30.trigger.Trigger` instance or ``None`` if no data is available :raises: *ParseResponseError* if it is impossible to find or parse the data needed to build the result """ if JSON_string is None: raise parse_response_error.ParseResponseError('JSON data is None') d = json.loads(JSON_string) try: # trigger id trigger_id = d.get('_id', None) # start timestamp start_dict = d['time_period']['start'] expr = start_dict['expression'] if expr != 'after': raise ValueError('Invalid time expression: "%s" on start timestamp. Only: "after" is supported' % expr) start = start_dict['amount'] # end timestamp end_dict = d['time_period']['end'] expr = end_dict['expression'] if expr != 'after': raise ValueError('Invalid time expression: "%s" on end timestamp. Only: "after" is supported' % expr) end = end_dict['amount'] # conditions conditions = [Condition.from_dict(c) for c in d['conditions']] # alerts alerts_dict = d['alerts'] alerts = list() for key in alerts_dict: alert_id = key alert_data = alerts_dict[alert_id] alert_last_update = alert_data['last_update'] alert_met_conds = [ dict(current_value=c['current_value']['min'], condition=Condition.from_dict(c['condition'])) for c in alert_data['conditions'] ] alert_coords = alert_data['coordinates'] alert = Alert(alert_id, trigger_id, alert_met_conds, alert_coords, last_update=alert_last_update) alerts.append(alert) # area area_list = d['area'] area = [GeometryBuilder.build(a_dict) for a_dict in area_list] # alert channels alert_channels = None # defaulting except ValueError as e: raise parse_response_error.ParseResponseError('Impossible to parse JSON: %s' % e) except KeyError as e: raise parse_response_error.ParseResponseError('Impossible to parse JSON: %s' % e) return Trigger(start, end, conditions, area=area, alerts=alerts, alert_channels=alert_channels, id=trigger_id)
class TestAlertManager(unittest.TestCase): _cond1 = Condition('humidity', 'LESS_THAN', 10) _cond2 = Condition('temp', 'GREATER_THAN_EQUAL', 100.6) _trigger = Trigger(1526809375, 1527809375, [_cond1, _cond2], [geo.Point(13.6, 46.9)], alerts=[], alert_channels=None, id='trigger-id') _alert = Alert('alert1', 'trigger1', [{ "current_value": 263.576, "condition": _cond1 }], { "lon": 37, "lat": 53 }, 1481802090232) def factory(self, _kls): sm = AlertManager('APIKey') sm.http_client = _kls() return sm def test_instantiation_fails_without_api_key(self): self.assertRaises(AssertionError, AlertManager, None) def test_get_alert_api_version(self): instance = AlertManager('APIKey') result = instance.alert_api_version() self.assertIsInstance(result, tuple) self.assertEqual(result, ALERT_API_VERSION) def test_get_triggers(self): instance = self.factory(MockHttpClientTwoTriggers) results = instance.get_triggers() self.assertEqual(2, len(results)) t = results[0] self.assertIsInstance(t, Trigger) def test_get_trigger_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.get_trigger(None) with self.assertRaises(AssertionError): instance.get_trigger(123) def test_get_trigger(self): instance = self.factory(MockHttpClientOneTrigger) result = instance.get_trigger('any-id') self.assertIsInstance(result, Trigger) def test_create_trigger(self): instance = self.factory(MockHttpClient) result = instance.create_trigger(1526809375, 1527809375, [self._cond1, self._cond2], [geo.Point(13.6, 46.9)], alert_channels=None) self.assertIsInstance(result, Trigger) def test_create_trigger_fails_with_wrong_inputs(self): instance = self.factory(MockHttpClient) with self.assertRaises(AssertionError): instance.create_trigger(None, 1527809375, [self._cond1, self._cond2], [geo.Point(13.6, 46.9)], alert_channels=None) with self.assertRaises(AssertionError): instance.create_trigger(1526809375, None, [self._cond1, self._cond2], [geo.Point(13.6, 46.9)], alert_channels=None) with self.assertRaises(ValueError): instance.create_trigger(1526809375, 1327809375, [self._cond1, self._cond2], [geo.Point(13.6, 46.9)], alert_channels=None) with self.assertRaises(AssertionError): instance.create_trigger(1526809375, 1527809375, None, [geo.Point(13.6, 46.9)], alert_channels=None) with self.assertRaises(ValueError): instance.create_trigger(1526809375, 1527809375, [], [geo.Point(13.6, 46.9)], alert_channels=None) with self.assertRaises(AssertionError): instance.create_trigger(1526809375, 1527809375, [self._cond1, self._cond2], None, alert_channels=None) with self.assertRaises(ValueError): instance.create_trigger(1526809375, 1527809375, [self._cond1, self._cond2], [], alert_channels=None) def test_delete_trigger_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.delete_trigger(None) with self.assertRaises(AssertionError): self._trigger.id = 123 instance.delete_trigger(self._trigger) def test_delete_trigger(self): instance = self.factory(MockHttpClient) parser = TriggerParser() trigger = parser.parse_JSON(MockHttpClient.test_trigger_json) result = instance.delete_trigger(trigger) self.assertIsNone(result) def test_update_trigger_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.update_trigger(None) with self.assertRaises(AssertionError): self._trigger.id = 123 instance.update_trigger(self._trigger) def test_update_trigger(self): instance = self.factory(MockHttpClient) parser = TriggerParser() modified_trigger = parser.parse_JSON(MockHttpClient.test_trigger_json) modified_trigger.id = '5852816a9aaacb00153134a3' modified_trigger.end = self._trigger.end_after_millis + 10000 result = instance.update_trigger(modified_trigger) self.assertIsNone(result) def test_get_alerts_for_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.get_alerts_for(None) with self.assertRaises(AssertionError): self._trigger.id = 123 instance.get_alerts_for(self._trigger) def test_get_alerts_for(self): instance = self.factory(MockHttpClientTwoAlerts) self._trigger.id = 'trigger-id' results = instance.get_alerts_for(self._trigger) self.assertEqual(2, len(results)) self.assertIsInstance(results[0], Alert) self.assertIsInstance(results[1], Alert) def test_get_alert_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.get_alert(None, self._trigger) with self.assertRaises(AssertionError): instance.get_alert(123, self._trigger) with self.assertRaises(AssertionError): instance.get_alert('alert-id', None) with self.assertRaises(AssertionError): self._trigger.id = 123 instance.get_alert('alert-id', self._trigger) def test_get_alert(self): self._trigger.id = 'trigger-id' instance = self.factory(MockHttpClientOneAlert) result = instance.get_alert('alert-id', self._trigger) self.assertIsInstance(result, Alert) def test_delete_all_alerts_for_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.delete_all_alerts_for(None) with self.assertRaises(AssertionError): self._trigger.id = 123 instance.delete_all_alerts_for(self._trigger) def test_delete_all_alerts_for(self): instance = self.factory(MockHttpClientTwoAlerts) result = instance.delete_all_alerts_for(self._trigger) self.assertIsNone(result) def test_delete_alert_fails_with_wrong_input(self): instance = AlertManager('APIKey') with self.assertRaises(AssertionError): instance.delete_alert(None) with self.assertRaises(AssertionError): self._alert.id = 123 instance.delete_alert(self._alert) self._alert.id = 'alert-id' self._alert.trigger_id = None with self.assertRaises(AssertionError): instance.delete_alert(self._alert) self._alert.trigger_id = 789 with self.assertRaises(AssertionError): instance.delete_alert(self._alert) def test_delete_alert(self): instance = self.factory(MockHttpClientOneAlert) result = instance.delete_alert(self._alert) self.assertIsNone(result)