diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3cb791c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + language_version: python3 diff --git a/aio_georss_gdacs/consts.py b/aio_georss_gdacs/consts.py index b627bad..a4b47a5 100644 --- a/aio_georss_gdacs/consts.py +++ b/aio_georss_gdacs/consts.py @@ -5,22 +5,22 @@ XML_ATTRIBUTE_VALUE = "@value" XML_TEXT = "#text" -XML_TAG_DC_SUBJECT = 'dc:subject' -XML_TAG_GDACS_ALERT_LEVEL = 'gdacs:alertlevel' -XML_TAG_GDACS_COUNTRY = 'gdacs:country' -XML_TAG_GDACS_DURATION_IN_WEEK = 'gdacs:durationinweek' -XML_TAG_GDACS_EVENT_ID = 'gdacs:eventid' -XML_TAG_GDACS_EVENT_NAME = 'gdacs:eventname' -XML_TAG_GDACS_EVENT_TYPE = 'gdacs:eventtype' -XML_TAG_GDACS_FROM_DATE = 'gdacs:fromdate' -XML_TAG_GDACS_ICON = 'gdacs:icon' -XML_TAG_GDACS_IS_CURRENT = 'gdacs:iscurrent' -XML_TAG_GDACS_POPULATION = 'gdacs:population' -XML_TAG_GDACS_SEVERITY = 'gdacs:severity' -XML_TAG_GDACS_TEMPORARY = 'gdacs:temporary' -XML_TAG_GDACS_TO_DATE = 'gdacs:todate' -XML_TAG_GDACS_VERSION = 'gdacs:version' -XML_TAG_GDACS_VULNERABILITY = 'gdacs:vulnerability' +XML_TAG_DC_SUBJECT = "dc:subject" +XML_TAG_GDACS_ALERT_LEVEL = "gdacs:alertlevel" +XML_TAG_GDACS_COUNTRY = "gdacs:country" +XML_TAG_GDACS_DURATION_IN_WEEK = "gdacs:durationinweek" +XML_TAG_GDACS_EVENT_ID = "gdacs:eventid" +XML_TAG_GDACS_EVENT_NAME = "gdacs:eventname" +XML_TAG_GDACS_EVENT_TYPE = "gdacs:eventtype" +XML_TAG_GDACS_FROM_DATE = "gdacs:fromdate" +XML_TAG_GDACS_ICON = "gdacs:icon" +XML_TAG_GDACS_IS_CURRENT = "gdacs:iscurrent" +XML_TAG_GDACS_POPULATION = "gdacs:population" +XML_TAG_GDACS_SEVERITY = "gdacs:severity" +XML_TAG_GDACS_TEMPORARY = "gdacs:temporary" +XML_TAG_GDACS_TO_DATE = "gdacs:todate" +XML_TAG_GDACS_VERSION = "gdacs:version" +XML_TAG_GDACS_VULNERABILITY = "gdacs:vulnerability" EVENT_TYPE_MAP = { "DR": "Drought", @@ -28,7 +28,7 @@ "FL": "Flood", "TC": "Tropical Cyclone", "TS": "Tsunami", - "VO": "Volcano" + "VO": "Volcano", } URL = "https://www.gdacs.org/xml/rss.xml" diff --git a/aio_georss_gdacs/feed.py b/aio_georss_gdacs/feed.py index a4b44b3..2b37aa0 100644 --- a/aio_georss_gdacs/feed.py +++ b/aio_georss_gdacs/feed.py @@ -15,21 +15,27 @@ class GdacsFeed(GeoRssFeed[GdacsFeedEntry]): """GDACS feed.""" - def __init__(self, - websession: ClientSession, - home_coordinates: Tuple[float, float], - filter_radius: float = None, - filter_categories: List[str] = None): + def __init__( + self, + websession: ClientSession, + home_coordinates: Tuple[float, float], + filter_radius: float = None, + filter_categories: List[str] = None, + ): """Initialise this service.""" - super().__init__(websession, - home_coordinates, - URL, - filter_radius=filter_radius, - filter_categories=filter_categories) + super().__init__( + websession, + home_coordinates, + URL, + filter_radius=filter_radius, + filter_categories=filter_categories, + ) - def _new_entry(self, - home_coordinates: Tuple[float, float], - feature: FeedItem, - global_data: Dict) -> GdacsFeedEntry: + def _new_entry( + self, + home_coordinates: Tuple[float, float], + feature: FeedItem, + global_data: Dict, + ) -> GdacsFeedEntry: """Generate a new entry.""" return GdacsFeedEntry(home_coordinates, feature) diff --git a/aio_georss_gdacs/feed_entry.py b/aio_georss_gdacs/feed_entry.py index 4f3887b..e050172 100644 --- a/aio_georss_gdacs/feed_entry.py +++ b/aio_georss_gdacs/feed_entry.py @@ -8,23 +8,33 @@ from aio_georss_client.xml_parser.feed_item import FeedItem from aio_georss_client.xml_parser.geometry import Geometry, Polygon, Point -from .consts import (ATTRIBUTION, EVENT_TYPE_MAP, XML_ATTRIBUTE_VALUE, - XML_TAG_GDACS_ALERT_LEVEL, XML_TAG_GDACS_COUNTRY, - XML_TAG_GDACS_DURATION_IN_WEEK, XML_TAG_GDACS_EVENT_NAME, - XML_TAG_GDACS_EVENT_TYPE, XML_TAG_GDACS_FROM_DATE, - XML_TAG_GDACS_ICON, XML_TAG_GDACS_IS_CURRENT, - XML_TAG_GDACS_POPULATION, XML_TAG_GDACS_SEVERITY, - XML_TAG_GDACS_TEMPORARY, XML_TAG_GDACS_TO_DATE, - XML_TAG_GDACS_VERSION, XML_TAG_GDACS_VULNERABILITY, - XML_TEXT, XML_TAG_GDACS_EVENT_ID) +from .consts import ( + ATTRIBUTION, + EVENT_TYPE_MAP, + XML_ATTRIBUTE_VALUE, + XML_TAG_GDACS_ALERT_LEVEL, + XML_TAG_GDACS_COUNTRY, + XML_TAG_GDACS_DURATION_IN_WEEK, + XML_TAG_GDACS_EVENT_NAME, + XML_TAG_GDACS_EVENT_TYPE, + XML_TAG_GDACS_FROM_DATE, + XML_TAG_GDACS_ICON, + XML_TAG_GDACS_IS_CURRENT, + XML_TAG_GDACS_POPULATION, + XML_TAG_GDACS_SEVERITY, + XML_TAG_GDACS_TEMPORARY, + XML_TAG_GDACS_TO_DATE, + XML_TAG_GDACS_VERSION, + XML_TAG_GDACS_VULNERABILITY, + XML_TEXT, + XML_TAG_GDACS_EVENT_ID, +) class GdacsFeedEntry(FeedEntry): """GDACS feed entry.""" - def __init__(self, - home_coordinates: Tuple[float, float], - feature: FeedItem): + def __init__(self, home_coordinates: Tuple[float, float], feature: FeedItem): """Initialise this service.""" super().__init__(home_coordinates, feature) @@ -47,16 +57,14 @@ def category(self) -> Optional[str]: def alert_level(self) -> Optional[str]: """Return the alert level of this entry.""" if self._rss_entry: - return self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_ALERT_LEVEL) + return self._rss_entry.get_additional_attribute(XML_TAG_GDACS_ALERT_LEVEL) return None @property def country(self) -> Optional[str]: """Return the country of this entry.""" if self._rss_entry: - return self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_COUNTRY) + return self._rss_entry.get_additional_attribute(XML_TAG_GDACS_COUNTRY) return None @property @@ -67,7 +75,8 @@ def duration_in_week(self) -> Optional[int]: # 1 = Second week # etc. duration_in_week = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_DURATION_IN_WEEK) + XML_TAG_GDACS_DURATION_IN_WEEK + ) if duration_in_week: return int(duration_in_week) return None @@ -76,8 +85,7 @@ def duration_in_week(self) -> Optional[int]: def event_id(self) -> Optional[int]: """Return the event id of this entry.""" if self._rss_entry: - event_id = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_EVENT_ID) + event_id = self._rss_entry.get_additional_attribute(XML_TAG_GDACS_EVENT_ID) if event_id: return int(event_id) return None @@ -86,16 +94,14 @@ def event_id(self) -> Optional[int]: def event_name(self) -> Optional[str]: """Return the event name of this entry.""" if self._rss_entry: - return self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_EVENT_NAME) + return self._rss_entry.get_additional_attribute(XML_TAG_GDACS_EVENT_NAME) return None @property def event_type_short(self) -> Optional[str]: """Return the short event type of this entry.""" if self._rss_entry: - return self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_EVENT_TYPE) + return self._rss_entry.get_additional_attribute(XML_TAG_GDACS_EVENT_TYPE) return None @property @@ -111,7 +117,8 @@ def from_date(self) -> Optional[datetime]: """Return the from date of this entry.""" if self._rss_entry: from_date = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_FROM_DATE) + XML_TAG_GDACS_FROM_DATE + ) if from_date: return dateparser.parse(from_date) return None @@ -120,8 +127,7 @@ def from_date(self) -> Optional[datetime]: def icon_url(self) -> Optional[str]: """Return the icon url of this entry.""" if self._rss_entry: - return self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_ICON) + return self._rss_entry.get_additional_attribute(XML_TAG_GDACS_ICON) return None @property @@ -129,7 +135,8 @@ def is_current(self) -> Optional[bool]: """Return if this entry is current.""" if self._rss_entry: is_current = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_IS_CURRENT) + XML_TAG_GDACS_IS_CURRENT + ) if is_current: return FeedEntry._string2boolean(is_current) return None @@ -139,7 +146,8 @@ def population(self) -> Optional[str]: """Return the population of this entry.""" if self._rss_entry: population = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_POPULATION) + XML_TAG_GDACS_POPULATION + ) if population: if isinstance(population, Mapping): if XML_TEXT in population: @@ -152,8 +160,7 @@ def population(self) -> Optional[str]: def severity(self) -> Optional[str]: """Return the severity of this entry.""" if self._rss_entry: - severity = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_SEVERITY) + severity = self._rss_entry.get_additional_attribute(XML_TAG_GDACS_SEVERITY) if severity: if isinstance(severity, Mapping): if XML_TEXT in severity: @@ -167,7 +174,8 @@ def temporary(self) -> Optional[bool]: """Return if this entry is temporary.""" if self._rss_entry: temporary = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_TEMPORARY) + XML_TAG_GDACS_TEMPORARY + ) if temporary: return FeedEntry._string2boolean(temporary) return None @@ -176,8 +184,7 @@ def temporary(self) -> Optional[bool]: def to_date(self) -> Optional[datetime]: """Return the to date of this entry.""" if self._rss_entry: - to_date = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_TO_DATE) + to_date = self._rss_entry.get_additional_attribute(XML_TAG_GDACS_TO_DATE) if to_date: return dateparser.parse(to_date) return None @@ -186,8 +193,7 @@ def to_date(self) -> Optional[datetime]: def version(self) -> Optional[int]: """Return the version of this entry.""" if self._rss_entry: - version = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_VERSION) + version = self._rss_entry.get_additional_attribute(XML_TAG_GDACS_VERSION) if version: return int(version) return None @@ -197,7 +203,8 @@ def vulnerability(self) -> Optional[Union[str, float]]: """Return the vulnerability of this entry.""" if self._rss_entry: vulnerability = self._rss_entry.get_additional_attribute( - XML_TAG_GDACS_VULNERABILITY) + XML_TAG_GDACS_VULNERABILITY + ) if vulnerability: if isinstance(vulnerability, Mapping): # 1. See if there is a textual value. diff --git a/aio_georss_gdacs/feed_manager.py b/aio_georss_gdacs/feed_manager.py index ec676b2..8553981 100644 --- a/aio_georss_gdacs/feed_manager.py +++ b/aio_georss_gdacs/feed_manager.py @@ -11,24 +11,28 @@ class GdacsFeedManager(FeedManagerBase): """Feed Manager for GDACS feed.""" - def __init__(self, - websession: ClientSession, - generate_async_callback: Callable[[str], Awaitable[None]], - update_async_callback: Callable[[str], Awaitable[None]], - remove_async_callback: Callable[[str], Awaitable[None]], - coordinates, - filter_radius: float = None, - filter_categories: List[str] = None, - status_async_callback: Callable[[StatusUpdate], - Awaitable[None]] = None): + def __init__( + self, + websession: ClientSession, + generate_async_callback: Callable[[str], Awaitable[None]], + update_async_callback: Callable[[str], Awaitable[None]], + remove_async_callback: Callable[[str], Awaitable[None]], + coordinates, + filter_radius: float = None, + filter_categories: List[str] = None, + status_async_callback: Callable[[StatusUpdate], Awaitable[None]] = None, + ): """Initialize the GDACS Feed Manager.""" feed = GdacsFeed( websession, coordinates, filter_radius=filter_radius, - filter_categories=filter_categories) - super().__init__(feed, - generate_async_callback, - update_async_callback, - remove_async_callback, - status_async_callback) + filter_categories=filter_categories, + ) + super().__init__( + feed, + generate_async_callback, + update_async_callback, + remove_async_callback, + status_async_callback, + ) diff --git a/tests/test_feed.py b/tests/test_feed.py index 509ae03..9ac02e9 100644 --- a/tests/test_feed.py +++ b/tests/test_feed.py @@ -16,20 +16,21 @@ async def test_update_ok(aresponses, event_loop): """Test updating feed is ok.""" home_coordinates = (-41.2, 174.7) aresponses.add( - 'www.gdacs.org', - '/xml/rss.xml', - 'get', - aresponses.Response(text=load_fixture('gdacs-1.xml'), - status=200), + "www.gdacs.org", + "/xml/rss.xml", + "get", + aresponses.Response(text=load_fixture("gdacs-1.xml"), status=200), match_querystring=True, ) async with aiohttp.ClientSession(loop=event_loop) as websession: feed = GdacsFeed(websession, home_coordinates) - assert repr(feed) == "" + assert ( + repr(feed) == "" + ) status, entries = await feed.update() assert status == UPDATE_OK assert entries is not None @@ -37,10 +38,12 @@ async def test_update_ok(aresponses, event_loop): feed_entry = entries[0] assert feed_entry is not None - assert feed_entry.title == "Green alert for tropical cyclone " \ - "CALVINIA-19. Population affected by " \ - "Category 1 (120 km/h) wind speeds or " \ - "higher is 0." + assert ( + feed_entry.title == "Green alert for tropical cyclone " + "CALVINIA-19. Population affected by " + "Category 1 (120 km/h) wind speeds or " + "higher is 0." + ) assert feed_entry.external_id == "TC1000643" assert feed_entry.coordinates[0] == pytest.approx(-19.4) assert feed_entry.coordinates[1] == pytest.approx(59.8) @@ -48,35 +51,45 @@ async def test_update_ok(aresponses, event_loop): assert repr(feed_entry) == "" assert feed_entry.attribution == ATTRIBUTION assert feed_entry.category == "Tropical Cyclone" - assert feed_entry.alert_level == 'Green' - assert feed_entry.country == 'Mauritius' + assert feed_entry.alert_level == "Green" + assert feed_entry.country == "Mauritius" assert feed_entry.duration_in_week == 0 assert feed_entry.event_id == 1000643 - assert feed_entry.event_name == 'CALVINIA-19' - assert feed_entry.event_type_short == 'TC' + assert feed_entry.event_name == "CALVINIA-19" + assert feed_entry.event_type_short == "TC" assert feed_entry.event_type == "Tropical Cyclone" - assert feed_entry.from_date == datetime.datetime(2019, 12, 29, 12, - 0, 0, tzinfo=pytz.utc) - assert feed_entry.to_date == datetime.datetime(2019, 12, 29, 12, - 0, 0, tzinfo=pytz.utc) - assert feed_entry.icon_url == 'http://www.gdacs.org/Images/' \ - 'gdacs_icons/alerts/Green/TC.png' + assert feed_entry.from_date == datetime.datetime( + 2019, 12, 29, 12, 0, 0, tzinfo=pytz.utc + ) + assert feed_entry.to_date == datetime.datetime( + 2019, 12, 29, 12, 0, 0, tzinfo=pytz.utc + ) + assert ( + feed_entry.icon_url == "http://www.gdacs.org/Images/" + "gdacs_icons/alerts/Green/TC.png" + ) assert feed_entry.is_current == True - assert feed_entry.population == "Population affected by Category 1 " \ - "(120 km/h) wind speeds or higher is 0" - assert feed_entry.severity == "Tropical Storm (maximum wind speed " \ - "of 93 km/h)" + assert ( + feed_entry.population == "Population affected by Category 1 " + "(120 km/h) wind speeds or higher is 0" + ) + assert ( + feed_entry.severity == "Tropical Storm (maximum wind speed " "of 93 km/h)" + ) assert feed_entry.temporary == False assert feed_entry.version == 1 - assert feed_entry.vulnerability == 'Medium' - assert feed_entry.published == datetime.datetime(2019, 12, 29, 12, - 0, 0, tzinfo=pytz.utc) + assert feed_entry.vulnerability == "Medium" + assert feed_entry.published == datetime.datetime( + 2019, 12, 29, 12, 0, 0, tzinfo=pytz.utc + ) feed_entry = entries[1] assert feed_entry is not None - assert feed_entry.title == "Green earthquake alert (Magnitude 5.5M, " \ - "Depth:10km) in South Africa 28/12/2019 " \ - "15:36 UTC, No people within 100km." + assert ( + feed_entry.title == "Green earthquake alert (Magnitude 5.5M, " + "Depth:10km) in South Africa 28/12/2019 " + "15:36 UTC, No people within 100km." + ) assert feed_entry.external_id == "EQ1199929" assert feed_entry.vulnerability == 5.01535213120674 @@ -89,22 +102,21 @@ async def test_update_ok_with_categories_filter(aresponses, event_loop): """Test updating feed is ok with categories filter.""" home_coordinates = (-41.2, 174.7) aresponses.add( - 'www.gdacs.org', - '/xml/rss.xml', - 'get', - aresponses.Response(text=load_fixture('gdacs-1.xml'), - status=200), + "www.gdacs.org", + "/xml/rss.xml", + "get", + aresponses.Response(text=load_fixture("gdacs-1.xml"), status=200), match_querystring=True, ) async with aiohttp.ClientSession(loop=event_loop) as websession: - feed = GdacsFeed(websession, - home_coordinates, - filter_categories=['Drought']) - assert repr(feed) == "" + feed = GdacsFeed(websession, home_coordinates, filter_categories=["Drought"]) + assert ( + repr(feed) == "" + ) status, entries = await feed.update() assert status == UPDATE_OK assert entries is not None @@ -112,8 +124,9 @@ async def test_update_ok_with_categories_filter(aresponses, event_loop): feed_entry = entries[0] assert feed_entry is not None - assert feed_entry.title == "Drought is on going in Bulgaria, " \ - "Iraq, Iran, Turkey" + assert ( + feed_entry.title == "Drought is on going in Bulgaria, " "Iraq, Iran, Turkey" + ) assert feed_entry.external_id == "DR1013682" assert feed_entry.coordinates[0] == pytest.approx(39.544) assert feed_entry.coordinates[1] == pytest.approx(31.926) @@ -130,20 +143,21 @@ async def test_empty_feed(aresponses, event_loop): """Test updating feed is ok when feed does not contain any entries.""" home_coordinates = (-41.2, 174.7) aresponses.add( - 'www.gdacs.org', - '/xml/rss.xml', - 'get', - aresponses.Response(text=load_fixture('gdacs-2.xml'), - status=200), + "www.gdacs.org", + "/xml/rss.xml", + "get", + aresponses.Response(text=load_fixture("gdacs-2.xml"), status=200), match_querystring=True, ) async with aiohttp.ClientSession(loop=event_loop) as websession: feed = GdacsFeed(websession, home_coordinates) - assert repr(feed) == "" + assert ( + repr(feed) == "" + ) status, entries = await feed.update() assert status == UPDATE_OK assert entries is not None diff --git a/tests/test_feed_manager.py b/tests/test_feed_manager.py index cc391f4..460ad74 100644 --- a/tests/test_feed_manager.py +++ b/tests/test_feed_manager.py @@ -14,11 +14,10 @@ async def test_feed_manager(aresponses, event_loop): """Test the feed manager.""" home_coordinates = (-41.2, 174.7) aresponses.add( - 'www.gdacs.org', - '/xml/rss.xml', - 'get', - aresponses.Response(text=load_fixture('gdacs-1.xml'), - status=200), + "www.gdacs.org", + "/xml/rss.xml", + "get", + aresponses.Response(text=load_fixture("gdacs-1.xml"), status=200), match_querystring=True, ) @@ -41,22 +40,27 @@ async def _remove_entity(external_id: str) -> None: """Remove entity.""" removed_entity_external_ids.append(external_id) - feed_manager = GdacsFeedManager(websession, - _generate_entity, - _update_entity, - _remove_entity, - home_coordinates) - assert repr(feed_manager) == ")>" + feed_manager = GdacsFeedManager( + websession, + _generate_entity, + _update_entity, + _remove_entity, + home_coordinates, + ) + assert ( + repr(feed_manager) == ")>" + ) await feed_manager.update() entries = feed_manager.feed_entries assert entries is not None assert len(entries) == 4 - assert feed_manager.last_timestamp \ - == datetime.datetime(2019, 12, 30, 1, 27, 0, tzinfo=pytz.utc) + assert feed_manager.last_timestamp == datetime.datetime( + 2019, 12, 30, 1, 27, 0, tzinfo=pytz.utc + ) assert len(generated_entity_external_ids) == 4 assert len(updated_entity_external_ids) == 0 assert len(removed_entity_external_ids) == 0 diff --git a/tests/utils.py b/tests/utils.py index 0bba672..485a1b4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,6 +4,6 @@ def load_fixture(filename): """Load a fixture.""" - path = os.path.join(os.path.dirname(__file__), 'fixtures', filename) - with open(path, encoding='utf-8') as fptr: + path = os.path.join(os.path.dirname(__file__), "fixtures", filename) + with open(path, encoding="utf-8") as fptr: return fptr.read()