From 000ad77b6bbbd1b2a898eaa6812b4810796c9354 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Mon, 30 Aug 2021 20:26:02 +0530 Subject: [PATCH 1/7] add destination weather api --- .../config/dest_weather_config.py | 68 +++++++++++++++ .../destination_weather_api.py | 85 +++++++++++++++++++ here_location_services/ls.py | 60 +++++++++++++ here_location_services/responses.py | 12 +++ tests/conftest.py | 8 ++ tests/test_ls.py | 63 +++++++++++++- tests/test_ls_apis.py | 11 +++ 7 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 here_location_services/config/dest_weather_config.py create mode 100644 here_location_services/destination_weather_api.py diff --git a/here_location_services/config/dest_weather_config.py b/here_location_services/config/dest_weather_config.py new file mode 100644 index 0000000..e9f777a --- /dev/null +++ b/here_location_services/config/dest_weather_config.py @@ -0,0 +1,68 @@ +# Copyright (C) 2019-2021 HERE Europe B.V. +# SPDX-License-Identifier: Apache-2.0 + +"""This module defines all the configs which will be required as inputs to + Destination Weather API.""" + +from .base_config import Bunch + + +class DestWeatherProduct(Bunch): + """A class to define constant attributes for ``product`` parameter identifying the + type of report to obtain. + + ``observation``: + current weather conditions from the eight closest locations to the specified location + + ``forecast_7days``: + morning, afternoon, evening and night weather forecasts for the next seven days. + + ``forecast_7days_simple``: + daily weather forecasts for the next seven days + + ``forecast_hourly``: + hourly weather forecasts for the next seven days + + ``alerts``: + forecasted weather alerts for the next 24 hours + + ``nws_alerts``: + all active watches and warnings for the US and Canada + """ + + +product = { + "observation": "observation", + "forecast7days": "forecast7days", + "forecast7daysSimple": "forecast7daysSimple", + "forecastHourly": "forecastHourly", + "alerts": "alerts", + "nwsAlerts": "nwsAlerts", +} + +#: Use this config for ``products``` of Destination Weather API. +#: Example: for ``forecastHourly`` product use ``DEST_WEATHER_PRODUCT.forecastHourly``. +DEST_WEATHER_PRODUCT = DestWeatherProduct(**product) + + +class DestWeatherUnits(Bunch): + """A class to define constant attributes for ``units`` parameter identifying + units of measurement used. + + ``metric``: + Follow metric system of measurements. Default. + + ``imperial``: + Follow imperial system of measurements + + """ + + +units = { + "metric": "metric", + "imperial": "imperial", +} + +#: Use this config for ``units``` of Destination Weather API. +#: Example: for ``metric`` units use ``DEST_WEATHER_UNITS.metric``. +DEST_WEATHER_UNITS = DestWeatherUnits(**units) diff --git a/here_location_services/destination_weather_api.py b/here_location_services/destination_weather_api.py new file mode 100644 index 0000000..7e89c50 --- /dev/null +++ b/here_location_services/destination_weather_api.py @@ -0,0 +1,85 @@ +# Copyright (C) 2019-2021 HERE Europe B.V. +# SPDX-License-Identifier: Apache-2.0 + +"""This module contains classes for accessing `HERE Destination Weather API `_. +""" # noqa E501 + +from datetime import datetime +from typing import Dict, List, Optional + +from here_location_services.platform.auth import Auth + +from .apis import Api +from .exceptions import ApiError + + +class DestinationWeatherApi(Api): + """A class for accessing HERE routing APIs.""" + + def __init__( + self, + api_key: Optional[str] = None, + auth: Optional[Auth] = None, + proxies: Optional[dict] = None, + country: str = "row", + ): + super().__init__(api_key, auth=auth, proxies=proxies, country=country) + self._base_url = f"https://weather.{self._get_url_string()}" + + def get_dest_weather( + self, + products: List[str], + at: Optional[List] = None, + query: Optional[str] = None, + zipcode: Optional[str] = None, + hourly_date: Optional[datetime] = None, + one_observation: Optional[bool] = None, + language: Optional[str] = None, + units: Optional[str] = None, + ): + """Retrieves weather reports, weather forecasts, severe weather alerts and moon and sun rise and set information. + + See further information `Here Destination Weather API _`. + + :param products: List of :class:`DestWeatherProduct` identifying the type of + report to obtain. + :param at: A list of ``latitude`` and ``longitude`` specifying the area covered + by the weather report. + :param query: Free text query. Examples: "125, Berliner, berlin", "Beacon, Boston" + :param zipcode: ZIP code of the location. This parameter is supported only for locations in + the United States of America. + :param hourly_date: Date for which hourly forecasts are to be retrieved. + :param one_observation: Boolean, if set to true, the response only includes the closest + location. Only available when the `product` parameter is set to + `DEST_WEATHER_PRODUCT.observation`. + :param language: Defines the language used in the descriptions in the response. + :param units: Defines whether units or imperial units are used in the response. + :return: :class:`requests.Response` object. + :raises ApiError: If ``status_code`` of API response is not 200. + """ # noqa E501 + + path = "v3/report" + url = f"{self._base_url}/{path}" + params: Dict[str, str] = { + "products": ",".join([str(i) for i in products]), + } + if at: + params["location"] = ",".join([str(i) for i in at]) + if query: + params["q"] = query + if zipcode: + params["zipCode"] = zipcode + if hourly_date: + params["hourlyDate"] = hourly_date.strftime("%Y-%m-%dT%H:%M:%S") + if one_observation: + params["oneObservation"] = "true" if one_observation else "false" + if language: + params["lang"] = language + if units: + params["units"] = units + + resp = self.get(url, params=params, proxies=self.proxies) + if resp.status_code == 200: + return resp + else: + raise ApiError(resp) diff --git a/here_location_services/ls.py b/here_location_services/ls.py index 224421d..5e46ad8 100644 --- a/here_location_services/ls.py +++ b/here_location_services/ls.py @@ -26,6 +26,7 @@ PolygonRegion, WorldRegion, ) +from .destination_weather_api import DestinationWeatherApi from .exceptions import ApiError from .geocoding_search_api import GeocodingSearchApi from .isoline_routing_api import IsolineRoutingApi @@ -33,6 +34,7 @@ from .responses import ( AutosuggestResponse, BrowseResponse, + DestinationWeatherResponse, DiscoverResponse, GeocoderResponse, IsolineResponse, @@ -94,6 +96,12 @@ def __init__( proxies=proxies, country=country, ) + self.destination_weather_api = DestinationWeatherApi( + api_key=api_key, + auth=self.auth, + proxies=proxies, + country=country, + ) def geocode(self, query: str, limit: int = 20, lang: str = "en-US") -> GeocoderResponse: """Calculate coordinates as result of geocoding for the given ``query``. @@ -306,6 +314,58 @@ def autosuggest( return response + def get_dest_weather( + self, + products: List[str], + at: Optional[List] = None, + query: Optional[str] = None, + zipcode: Optional[str] = None, + hourly_date: Optional[datetime] = None, + one_observation: Optional[bool] = None, + language: Optional[str] = None, + units: Optional[str] = None, + ) -> DestinationWeatherResponse: + """Retrieves weather reports, weather forecasts, severe weather alerts + and moon and sun rise and set information. + :param products: List of :class:`DestWeatherProduct` identifying the type of + report to obtain. + :param at: A list of ``latitude`` and ``longitude`` specifying the area covered + by the weather report. + :param query: Free text query. Examples: "125, Berliner, berlin", "Beacon, Boston" + :param zipcode: ZIP code of the location. This parameter is supported only for locations in + the United States of America. + :param hourly_date: Date for which hourly forecasts are to be retrieved. + :param one_observation: Boolean, if set to true, the response only includes the closest + location. Only available when the `product` parameter is set to + `DEST_WEATHER_PRODUCT.observation`. + :param language: Defines the language used in the descriptions in the response. + :param units: Defines whether units or imperial units are used in the response. + :raises ValueError: If neither `at`, `query` or `zipcode` are passed. + :raises ValueError: If `one_observation` is set to true without passing + DEST_WEATHER_PRODUCT.observation in `products` + :return: :class:`DestinationWeatherResponse` object. + """ + if at is None and query is None and zipcode is None: + raise ValueError("please provide either `at` or `query` or `zipcode`.") + if "observation" not in products and one_observation: + raise ValueError( + "`one_observation` can only be set when the `products` parameter " + + "is set to DEST_WEATHER_PRODUCT.observation" + ) + + resp = self.destination_weather_api.get_dest_weather( + products=products, + at=at, + query=query, + zipcode=zipcode, + hourly_date=hourly_date, + one_observation=one_observation, + language=language, + units=units, + ) + response = DestinationWeatherResponse.new(resp.json()) + return response + def discover( self, query: str, diff --git a/here_location_services/responses.py b/here_location_services/responses.py index 161af4c..6db1c16 100644 --- a/here_location_services/responses.py +++ b/here_location_services/responses.py @@ -193,3 +193,15 @@ def __init__(self, **kwargs): } for param, default in self._filters.items(): setattr(self, param, kwargs.get(param, default)) + + +class DestinationWeatherResponse(ApiResponse): + """A class representing the Destination Weather API response data.""" + + def __init__(self, **kwargs): + super().__init__() + self._filters = { + "places": None, + } + for param, default in self._filters.items(): + setattr(self, param, kwargs.get(param, default)) diff --git a/tests/conftest.py b/tests/conftest.py index 1850d8b..42a1fee 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ import pytest from here_location_services.autosuggest_api import AutosuggestApi +from here_location_services.destination_weather_api import DestinationWeatherApi from here_location_services.exceptions import ConfigException from here_location_services.geocoding_search_api import GeocodingSearchApi from here_location_services.isoline_routing_api import IsolineRoutingApi @@ -51,6 +52,13 @@ def autosuggest_api(): return api +@pytest.fixture() +def destination_weather_api(): + """Create shared low level Location services Dest Weather instance as a pytest fixture.""" + api = DestinationWeatherApi(api_key=LS_API_KEY) + return api + + def env_setup_done(): """This function will return env variables required to authenticate APIs using auth token.""" try: diff --git a/tests/test_ls.py b/tests/test_ls.py index 8cafed3..0ec337a 100644 --- a/tests/test_ls.py +++ b/tests/test_ls.py @@ -18,6 +18,10 @@ Truck, WayPointOptions, ) +from here_location_services.config.dest_weather_config import ( + DEST_WEATHER_PRODUCT, + DEST_WEATHER_UNITS, +) from here_location_services.config.isoline_routing_config import ( ISOLINE_ROUTING_AVOID_FEATURES, ISOLINE_ROUTING_TRANSPORT_MODE, @@ -52,6 +56,63 @@ LS_API_KEY = get_apikey() +@pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") +def test_ls_dest_weather(): + """Test destination weather api.""" + ls = LS(api_key=LS_API_KEY) + resp = ls.get_dest_weather(products=[DEST_WEATHER_PRODUCT.observation], query="Chicago") + assert resp.places + assert resp.places[0]["observations"] + + resp2 = ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecastHourly], + query="Chicago", + units=DEST_WEATHER_UNITS.imperial, + ) + assert resp2.places + assert resp2.places[0]["hourlyforecasts"] + + resp3 = ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecast7days], at=["-13.163068,-72.545128"] + ) + assert resp3.places + assert resp3.places[0]["extendedDailyforecasts"] + + resp4 = ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecast7daysSimple, DEST_WEATHER_PRODUCT.observation], + zipcode="10025", + one_observation=True, + ) + assert resp4.places + assert resp4.places[0]["observations"] + + resp5 = ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecast7daysSimple, DEST_WEATHER_PRODUCT.observation], + zipcode="10025", + at=["-13.163068,-72.545128"], + one_observation=True, + ) + assert resp5.places + assert resp5.places[0]["observations"] + + with pytest.raises(ValueError): + ls.get_dest_weather(products=[DEST_WEATHER_PRODUCT.forecast7days]) + + with pytest.raises(ValueError): + ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecast7days], query="Chicago", one_observation=True + ) + + with pytest.raises(ValueError): + ls.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.forecast7days], query="Chicago", one_observation=True + ) + + with pytest.raises(ApiError): + ls2 = LS(api_key="dummy") + ls2.get_dest_weather(products=[DEST_WEATHER_PRODUCT.observation], query="Chicago") + + @pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") def test_ls_autosuggest(): """Test autosuggest api.""" @@ -60,7 +121,7 @@ def test_ls_autosuggest(): assert resp.items assert len(resp.items) <= 5 - search_in_circle1 = SearchCircle(lat=52.53, lng="13.38", radius="10000") + search_in_circle1 = SearchCircle(lat="52.53", lng="13.38", radius="10000") search_in_bbox1 = ("13.08836", "52.33812", "13.761", "52.6755") resp3 = ls.autosuggest(query="bar", limit=5, search_in_circle=search_in_circle1, lang=["en"]) diff --git a/tests/test_ls_apis.py b/tests/test_ls_apis.py index d91b733..c444960 100644 --- a/tests/test_ls_apis.py +++ b/tests/test_ls_apis.py @@ -6,6 +6,7 @@ import pytest import requests +from here_location_services.config.dest_weather_config import DEST_WEATHER_PRODUCT from here_location_services.config.isoline_routing_config import ( ISOLINE_ROUTING_TRANSPORT_MODE, RANGE_TYPE, @@ -18,6 +19,16 @@ LS_API_KEY = get_apikey() +@pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") +def test_destination(destination_weather_api): + """Test Destination Weather api.""" + resp = destination_weather_api.get_dest_weather( + products=[DEST_WEATHER_PRODUCT.observation], query="Chicago" + ) + assert type(resp) == requests.Response + assert resp.status_code == 200 + + @pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") def test_autosuggest(autosuggest_api): """Test autosuggest api.""" From c10fae255f66daa20e25f98c5fa8d3bac285b810 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Tue, 31 Aug 2021 03:59:25 +0530 Subject: [PATCH 2/7] add docs --- docs/notebooks/destination_weather.ipynb | 102 ++++++++++++++++++ docs/source/dest_weather.rst | 57 ++++++++++ ...on_services.config.dest_weather_config.rst | 8 ++ ...ation_services.destination_weather_api.rst | 8 ++ docs/source/here_location_services.rst | 1 + docs/source/index.rst | 6 ++ 6 files changed, 182 insertions(+) create mode 100644 docs/notebooks/destination_weather.ipynb create mode 100644 docs/source/dest_weather.rst create mode 100644 docs/source/here_location_services.config.dest_weather_config.rst create mode 100644 docs/source/here_location_services.destination_weather_api.rst diff --git a/docs/notebooks/destination_weather.ipynb b/docs/notebooks/destination_weather.ipynb new file mode 100644 index 0000000..0a5ef61 --- /dev/null +++ b/docs/notebooks/destination_weather.ipynb @@ -0,0 +1,102 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "source": [ + "import os\n", + "os.environ[\"LS_API_KEY\"] = \"MY-API-KEY\" # replace your API key here." + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": 3, + "source": [ + "import os\n", + "\n", + "from here_location_services import LS\n", + "from here_map_widget import Map, MarkerCluster, ObjectLayer\n", + "from here_location_services.config.dest_weather_config import DEST_WEATHER_PRODUCT\n", + "\n", + "\n", + "LS_API_KEY = os.environ.get(\"LS_API_KEY\")\n", + "ls = LS(api_key=LS_API_KEY)\n", + "\n", + "result1 = ls.get_dest_weather(\n", + " at=[19.1503, 72.8530],\n", + " products=[DEST_WEATHER_PRODUCT.observation]\n", + ")\n", + "\n", + "results = []\n", + "m = Map(\n", + " api_key=LS_API_KEY,\n", + " center=[19.1621, 73.0008],\n", + " zoom=7,\n", + ")\n", + "for observation in result1.places[0][\"observations\"]:\n", + " results.append(\n", + " dict(\n", + " lat=observation[\"place\"][\"location\"][\"lat\"],\n", + " lng=observation[\"place\"][\"location\"][\"lng\"],\n", + " data=observation[\"description\"] + \" \" + str(observation[\"temperature\"]) + \"C\",\n", + " )\n", + " )\n", + "\n", + "provider = MarkerCluster(data_points=results, show_bubble=True)\n", + "layer = ObjectLayer(provider=provider)\n", + "m.add_layer(layer)\n", + "m" + ], + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "Map(api_key='TKURWbpJHcbzmWMrmTZwGAdSTLrX8WY1oddj4S4U-EM', basemap=None, center=[19.1621, 73.0008], layers=(Ob…" + ], + "application/vnd.jupyter.widget-view+json": { + "version_major": 2, + "version_minor": 0, + "model_id": "91639eb7343842f1a4feefac3738ab95" + } + }, + "metadata": {} + } + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [], + "outputs": [], + "metadata": {} + } + ], + "metadata": { + "orig_nbformat": 4, + "language_info": { + "name": "python", + "version": "3.9.6", + "mimetype": "text/x-python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "pygments_lexer": "ipython3", + "nbconvert_exporter": "python", + "file_extension": ".py" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3.9.6 64-bit" + }, + "interpreter": { + "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/docs/source/dest_weather.rst b/docs/source/dest_weather.rst new file mode 100644 index 0000000..3e00b53 --- /dev/null +++ b/docs/source/dest_weather.rst @@ -0,0 +1,57 @@ +Destination Weather +==================== +`Destination Weather API `_ provides weather forecasts and reports on current weather conditions. It also provides information on severe weather alerts along a specified route or a single car location. + +Example +------- + +.. jupyter-execute:: + + import os + from here_location_services import LS + from here_map_widget import Map, MarkerCluster, ObjectLayer + from here_location_services.config.dest_weather_config import DEST_WEATHER_PRODUCT + + + LS_API_KEY = os.environ.get("LS_API_KEY") + ls = LS(api_key=LS_API_KEY) + + result1 = ls.get_dest_weather( + at=[19.1503, 72.8530], + products=[DEST_WEATHER_PRODUCT.observation] + ) + + results = [] + m = Map( + api_key=LS_API_KEY, + center=[19.1621, 73.0008], + zoom=7, + ) + for observation in result1.places[0]["observations"]: + results.append( + dict( + lat=observation["place"]["location"]["lat"], + lng=observation["place"]["location"]["lng"], + data=observation["description"] + " " + str(observation["temperature"]) + "C", + ) + ) + + provider = MarkerCluster(data_points=results, show_bubble=True) + layer = ObjectLayer(provider=provider) + m.add_layer(layer) + m + +Attributes +---------- + +==================== =============================================================================================================== === +Attribute Type Doc +==================== =============================================================================================================== === +products list of :class:`DestWeatherProduct ` A string for free-text query. Example: `res`, `rest` +at list optional Specify the center of the search context expressed as list of coordinates. One of `at`, `search_in_circle` or `search_in_bbox` is required. Parameters "at", "search_in_circle" and "search_in_bbox" are mutually exclusive. Only one of them is allowed. +query str optional Search within a circular geographic area provided as latitude, longitude, and radius (in meters) +hourly_date :func:`datetime.datetime` optional Search within a rectangular bounding box geographic area provided as tuple of west longitude, south latitude, east longitude, north latitude +one_observation bool optional Search within a specific or multiple countries provided as comma-separated ISO 3166-1 alpha-3 country codes. The country codes are to be provided in all uppercase. Must be accompanied by exactly one of `at`, `search_in_circle` or `search_in_bbox`. +language str optional An integer specifiying maximum number of results to be returned. +units :class:`DestWeatherUnits ` optional An integer specifiying maximum number of Query Terms Suggestions to be returned. +==================== =============================================================================================================== === \ No newline at end of file diff --git a/docs/source/here_location_services.config.dest_weather_config.rst b/docs/source/here_location_services.config.dest_weather_config.rst new file mode 100644 index 0000000..8ff1830 --- /dev/null +++ b/docs/source/here_location_services.config.dest_weather_config.rst @@ -0,0 +1,8 @@ +here\_location\_services.config.dest\_weather\_config module +============================================================ + +.. automodule:: here_location_services.config.dest_weather_config + :members: + :undoc-members: + :show-inheritance: + :private-members: diff --git a/docs/source/here_location_services.destination_weather_api.rst b/docs/source/here_location_services.destination_weather_api.rst new file mode 100644 index 0000000..eec691d --- /dev/null +++ b/docs/source/here_location_services.destination_weather_api.rst @@ -0,0 +1,8 @@ +here\_location\_services.destination\_weather\_api module +========================================================= + +.. automodule:: here_location_services.destination_weather_api + :members: + :undoc-members: + :show-inheritance: + :private-members: diff --git a/docs/source/here_location_services.rst b/docs/source/here_location_services.rst index afbf65e..e7f24e3 100644 --- a/docs/source/here_location_services.rst +++ b/docs/source/here_location_services.rst @@ -33,3 +33,4 @@ Submodules here_location_services.routing_api.rst here_location_services.utils here_location_services.platform + here_location_services.destination_weather_api diff --git a/docs/source/index.rst b/docs/source/index.rst index 932e2c2..09a292a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -36,6 +36,12 @@ A Python client for `HERE Location Services`_. Routing Matrix Routing +.. toctree:: + :maxdepth: 1 + :caption: Destination Weather + + Destination Weather + .. toctree:: :maxdepth: 1 :caption: Reference Guide From 1fec5fabe984d44e9ebcc43c90ee6fc82612691c Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Tue, 31 Aug 2021 13:02:01 +0530 Subject: [PATCH 3/7] fix docs --- docs/source/dest_weather.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/source/dest_weather.rst b/docs/source/dest_weather.rst index 3e00b53..4e84d2c 100644 --- a/docs/source/dest_weather.rst +++ b/docs/source/dest_weather.rst @@ -47,11 +47,12 @@ Attributes ==================== =============================================================================================================== === Attribute Type Doc ==================== =============================================================================================================== === -products list of :class:`DestWeatherProduct ` A string for free-text query. Example: `res`, `rest` -at list optional Specify the center of the search context expressed as list of coordinates. One of `at`, `search_in_circle` or `search_in_bbox` is required. Parameters "at", "search_in_circle" and "search_in_bbox" are mutually exclusive. Only one of them is allowed. -query str optional Search within a circular geographic area provided as latitude, longitude, and radius (in meters) -hourly_date :func:`datetime.datetime` optional Search within a rectangular bounding box geographic area provided as tuple of west longitude, south latitude, east longitude, north latitude -one_observation bool optional Search within a specific or multiple countries provided as comma-separated ISO 3166-1 alpha-3 country codes. The country codes are to be provided in all uppercase. Must be accompanied by exactly one of `at`, `search_in_circle` or `search_in_bbox`. -language str optional An integer specifiying maximum number of results to be returned. -units :class:`DestWeatherUnits ` optional An integer specifiying maximum number of Query Terms Suggestions to be returned. +products list of :class:`DestWeatherProduct ` List of strings identifying the type of report to obtain. +at list optional A list of ``latitude`` and ``longitude`` specifying the area covered by the weather report. +query str optional Free text query. Examples: "125, Berliner, berlin", "Beacon, Boston" +zipcode str optional ZIP code of the location. This parameter is supported only for locations in the United States of America. +hourly_date :func:`datetime.datetime` optional Date for which hourly forecasts are to be retrieved. +one_observation bool optional Boolean, if set to true, the response only includes the closest location. Only available when the `product` parameter is set to `DEST_WEATHER_PRODUCT.observation`. +language str optional Defines the language used in the descriptions in the response. +units :class:`DestWeatherUnits ` optional Defines whether units or imperial units are used in the response. ==================== =============================================================================================================== === \ No newline at end of file From 18d8a7d6cfa9efdc3aefc2ec527148c3e31165b0 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Thu, 2 Sep 2021 17:20:48 +0530 Subject: [PATCH 4/7] fix docs --- docs/source/here_location_services.rst | 3 ++- here_location_services/ls.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/here_location_services.rst b/docs/source/here_location_services.rst index e7f24e3..040c57e 100644 --- a/docs/source/here_location_services.rst +++ b/docs/source/here_location_services.rst @@ -19,6 +19,7 @@ Submodules here_location_services.config.base_config here_location_services.config.autosuggest_config here_location_services.config.isoline_routing_config + here_location_services.config.dest_weather_config here_location_services.config.routing_config here_location_services.config.matrix_routing_config here_location_services.config.search_config.rst @@ -33,4 +34,4 @@ Submodules here_location_services.routing_api.rst here_location_services.utils here_location_services.platform - here_location_services.destination_weather_api + here_location_services.destination_weather_api.rst diff --git a/here_location_services/ls.py b/here_location_services/ls.py index 5e46ad8..aeebd78 100644 --- a/here_location_services/ls.py +++ b/here_location_services/ls.py @@ -327,6 +327,7 @@ def get_dest_weather( ) -> DestinationWeatherResponse: """Retrieves weather reports, weather forecasts, severe weather alerts and moon and sun rise and set information. + :param products: List of :class:`DestWeatherProduct` identifying the type of report to obtain. :param at: A list of ``latitude`` and ``longitude`` specifying the area covered @@ -345,6 +346,7 @@ def get_dest_weather( DEST_WEATHER_PRODUCT.observation in `products` :return: :class:`DestinationWeatherResponse` object. """ + if at is None and query is None and zipcode is None: raise ValueError("please provide either `at` or `query` or `zipcode`.") if "observation" not in products and one_observation: From d9335bf8712d0bd8870cb1f087b7ab99fedabbd6 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Fri, 3 Sep 2021 03:47:50 +0530 Subject: [PATCH 5/7] add weather alert endpoint --- .../config/autosuggest_config.py | 2 +- .../config/dest_weather_config.py | 78 ++++++++++++++++++ .../destination_weather_api.py | 80 ++++++++++++++++++- here_location_services/ls.py | 52 +++++++++++- here_location_services/responses.py | 4 +- tests/test_ls.py | 41 +++++++++- tests/test_ls_apis.py | 16 +++- 7 files changed, 262 insertions(+), 11 deletions(-) diff --git a/here_location_services/config/autosuggest_config.py b/here_location_services/config/autosuggest_config.py index e0a90cf..7916151 100644 --- a/here_location_services/config/autosuggest_config.py +++ b/here_location_services/config/autosuggest_config.py @@ -13,7 +13,7 @@ class SearchCircle: defined by its center and radius(in meters). """ - def __init__(self, lat: str, lng: str, radius: int): + def __init__(self, lat: float, lng: float, radius: int): self.lat = lat self.lng = lng self.radius = radius diff --git a/here_location_services/config/dest_weather_config.py b/here_location_services/config/dest_weather_config.py index e9f777a..93e9cbe 100644 --- a/here_location_services/config/dest_weather_config.py +++ b/here_location_services/config/dest_weather_config.py @@ -66,3 +66,81 @@ class DestWeatherUnits(Bunch): #: Use this config for ``units``` of Destination Weather API. #: Example: for ``metric`` units use ``DEST_WEATHER_UNITS.metric``. DEST_WEATHER_UNITS = DestWeatherUnits(**units) + + +class WeatherSeverity(Bunch): + """A class to define the severity of the weather event + + ``insignificant``: + Event doesn't have significance by nature + + ``no_alerts``: + There are no alerts for the location + + ``minor``: + Minor Severity, the event is potentially dangerous but not usual + + ``medium``: + Medium Severity, the event is dangerous + + ``high``: + High Severity, The event is very dangerous + + ``emergency``: + Emergency. Take immediate action to protect life. + """ + + +weather_severity = { + "insignificant": 0, + "no_alerts": 1, + "minor": 2, + "medium": 3, + "high": 4, + "emergency": 5, +} + +#: Use this config for ``weather_severity``` of get weather alerts endpoint. +#: Example: for ``high severity`` events use ``WEATHER_SEVERITY.high``. +WEATHER_SEVERITY = WeatherSeverity(**weather_severity) + + +class WeatherType(Bunch): + """A class to define the type of the weather event""" + + +weather_type = { + "extremely_high_temperature": 1, + "extremely_low_temperature": 2, + "fog": 3, + "ice": 4, + "rain": 5, + "snow": 6, + "thunderstorm": 7, + "wind": 8, + "air_quality": 9, + "volcanic_ashfall": 10, + "avalanche": 11, + "tsunami": 12, + "dust_storm": 13, + "earthquake": 14, + "fire_danger": 15, + "flood": 16, + "high_waves": 17, + "gigh_uv_index": 18, + "low_water": 19, + "smoke": 20, + "volcano": 21, + "ice_in_waterway": 22, + "coastal_event": 23, + "civil_danger": 24, + "evacuation": 25, + "hazardous_material": 26, + "radiological_hazard": 27, + "shelter_in_place": 28, + "warning": 29, +} + +#: Use this config for ``weather_type``` of get weather alerts endpoint of Destination Weather API. +#: Example: for ``fog`` weather type use ``WEATHER_TYPE.fog``. +WEATHER_TYPE = WeatherType(**weather_type) diff --git a/here_location_services/destination_weather_api.py b/here_location_services/destination_weather_api.py index 7e89c50..50ee1ed 100644 --- a/here_location_services/destination_weather_api.py +++ b/here_location_services/destination_weather_api.py @@ -4,8 +4,9 @@ """This module contains classes for accessing `HERE Destination Weather API `_. """ # noqa E501 +import time from datetime import datetime -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional from here_location_services.platform.auth import Auth @@ -32,7 +33,7 @@ def get_dest_weather( at: Optional[List] = None, query: Optional[str] = None, zipcode: Optional[str] = None, - hourly_date: Optional[datetime] = None, + hourly_date: Optional[Any] = None, one_observation: Optional[bool] = None, language: Optional[str] = None, units: Optional[str] = None, @@ -83,3 +84,78 @@ def get_dest_weather( return resp else: raise ApiError(resp) + + def get_weather_alerts( + self, + feature_type: str, + geometry_type: str, + geometry_coordinates: List, + start_time: datetime, + id: Optional[str] = None, + weather_severity: Optional[int] = None, + weather_type: Optional[str] = None, + country: Optional[str] = None, + end_time: Optional[datetime] = None, + width: Optional[int] = 50000, + ): + """Retrieves weather reports, weather forecasts, severe weather alerts and moon and sun rise and set information. + + See further information `Here Destination Weather API _`. + + :param feature_type: String to define feature type + :param geometry_type: Point or LineString or Polygon or MultiPolygon + :param geometry_coordinates: Array of coordinates corressponding to type provided + :param start_time: Start time of the event + :param id: Unique weather alert id. + :param weather_severity: Defines the severity of the weather event as defined + in :class:`WeatherSeverity`. + :param weather_type: Defines the type of the weather event as defined + in :class:`WeatherType`. + :param country: String for ISO-3166-1 2-letter country code. + :param end_time: End time of the event. If not present, warning is valid until + it is not removed from the feed by national weather institutes + (valid until warning is present in the response) + :param width: int. default 50000 + :return: :class:`requests.Response` object. + :raises ApiError: If ``status_code`` of API response is not 200. + """ # noqa E501 + + path = "v3/alerts" + url = f"{self._base_url}/{path}" + data: Dict[str, Any] = { + "type": "FeatureCollection", + } + features: Dict[str, Any] = { + "type": feature_type, + } + + if id: + features["id"] = id + + geometry: Dict[str, Any] = {"type": geometry_type, "coordinates": geometry_coordinates} + + properties: Dict[str, Any] = { + "width": width, + } + weather_warnings: Dict[str, Any] = { + "startTime": time.mktime(start_time.timetuple()), + } + + if weather_severity: + weather_warnings["severity"] = weather_severity + if weather_type: + weather_warnings["type"] = weather_type + if country: + weather_warnings["country"] = country + if end_time: + weather_warnings["endTime"] = time.mktime(end_time.timetuple()) + + properties["warnings"] = [weather_warnings] + features["properties"] = properties + features["geometry"] = geometry + data["features"] = [features] + resp = self.post(url, data=data) + if resp.status_code == 200: + return resp + else: + raise ApiError(resp) diff --git a/here_location_services/ls.py b/here_location_services/ls.py index aeebd78..f1fae07 100644 --- a/here_location_services/ls.py +++ b/here_location_services/ls.py @@ -8,7 +8,7 @@ import urllib.request from datetime import datetime from time import sleep -from typing import Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple, Union from here_location_services.config.routing_config import Scooter, Via from here_location_services.platform.apis.aaa_oauth2_api import AAAOauth2Api @@ -320,7 +320,7 @@ def get_dest_weather( at: Optional[List] = None, query: Optional[str] = None, zipcode: Optional[str] = None, - hourly_date: Optional[datetime] = None, + hourly_date: Optional[Any] = None, one_observation: Optional[bool] = None, language: Optional[str] = None, units: Optional[str] = None, @@ -368,6 +368,54 @@ def get_dest_weather( response = DestinationWeatherResponse.new(resp.json()) return response + def get_weather_alerts( + self, + feature_type: str, + geometry_type: str, + geometry_coordinates: List, + start_time: datetime, + id: Optional[str] = None, + weather_severity: Optional[int] = None, + weather_type: Optional[str] = None, + country: Optional[str] = None, + end_time: Optional[datetime] = None, + width: Optional[int] = 50000, + ) -> DestinationWeatherResponse: + """Retrieves weather reports, weather forecasts, severe weather alerts + and moon and sun rise and set information. + + :param feature_type: String to define feature type + :param geometry_type: Point or LineString or Polygon or MultiPolygon + :param geometry_coordinates: Array of coordinates corressponding to type provided + :param start_time: Start time of the event + :param id: Unique weather alert id. + :param weather_severity: Defines the severity of the weather event as defined + in :class:`WeatherSeverity`. + :param weather_type: Defines the type of the weather event as defined + in :class:`WeatherType`. + :param country: String for ISO-3166-1 2-letter country code. + :param end_time: End time of the event. If not present, warning is valid until + it is not removed from the feed by national weather institutes + (valid until warning is present in the response) + :param width: int. default 50000 + :return: :class:`DestinationWeatherResponse` object. + """ + + resp = self.destination_weather_api.get_weather_alerts( + feature_type=feature_type, + geometry_type=geometry_type, + geometry_coordinates=geometry_coordinates, + id=id, + weather_severity=weather_severity, + weather_type=weather_type, + country=country, + start_time=start_time, + end_time=end_time, + width=width, + ) + response = DestinationWeatherResponse.new(resp.json()) + return response + def discover( self, query: str, diff --git a/here_location_services/responses.py b/here_location_services/responses.py index 6db1c16..08b6313 100644 --- a/here_location_services/responses.py +++ b/here_location_services/responses.py @@ -200,8 +200,6 @@ class DestinationWeatherResponse(ApiResponse): def __init__(self, **kwargs): super().__init__() - self._filters = { - "places": None, - } + self._filters = {"places": None, "features": None} for param, default in self._filters.items(): setattr(self, param, kwargs.get(param, default)) diff --git a/tests/test_ls.py b/tests/test_ls.py index 0ec337a..8d97544 100644 --- a/tests/test_ls.py +++ b/tests/test_ls.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 import json -from datetime import datetime +from datetime import datetime, timedelta import pandas as pd import pytest @@ -21,6 +21,8 @@ from here_location_services.config.dest_weather_config import ( DEST_WEATHER_PRODUCT, DEST_WEATHER_UNITS, + WEATHER_SEVERITY, + WEATHER_TYPE, ) from here_location_services.config.isoline_routing_config import ( ISOLINE_ROUTING_AVOID_FEATURES, @@ -56,6 +58,41 @@ LS_API_KEY = get_apikey() +@pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") +def test_ls_weather_alerts(): + """Test weather alerts endpoint of destination weather api.""" + ls = LS(api_key=LS_API_KEY) + resp = ls.get_weather_alerts( + feature_type="Feature", + geometry_type="Point", + geometry_coordinates=[15.256, 23.456], + start_time=datetime.now(), + width=3000, + ) + assert resp + + resp2 = ls.get_weather_alerts( + feature_type="Feature", + geometry_type="Point", + geometry_coordinates=[15.256, 23.456], + start_time=datetime.now(), + weather_type=WEATHER_TYPE.ice, + weather_severity=WEATHER_SEVERITY.high, + country="US", + end_time=datetime.now() + timedelta(days=7), + ) + assert resp2 + + with pytest.raises(ApiError): + ls2 = LS(api_key="dummy") + ls2.get_weather_alerts( + feature_type="Feature", + geometry_type="Point", + geometry_coordinates=[15.256, 23.456], + start_time=datetime.now(), + ) + + @pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") def test_ls_dest_weather(): """Test destination weather api.""" @@ -121,7 +158,7 @@ def test_ls_autosuggest(): assert resp.items assert len(resp.items) <= 5 - search_in_circle1 = SearchCircle(lat="52.53", lng="13.38", radius="10000") + search_in_circle1 = SearchCircle(lat=52.53, lng=13.38, radius="10000") search_in_bbox1 = ("13.08836", "52.33812", "13.761", "52.6755") resp3 = ls.autosuggest(query="bar", limit=5, search_in_circle=search_in_circle1, lang=["en"]) diff --git a/tests/test_ls_apis.py b/tests/test_ls_apis.py index c444960..1dc4d84 100644 --- a/tests/test_ls_apis.py +++ b/tests/test_ls_apis.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 from argparse import Namespace +from datetime import datetime import pytest import requests @@ -20,7 +21,7 @@ @pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") -def test_destination(destination_weather_api): +def test_destination_weather(destination_weather_api): """Test Destination Weather api.""" resp = destination_weather_api.get_dest_weather( products=[DEST_WEATHER_PRODUCT.observation], query="Chicago" @@ -29,6 +30,19 @@ def test_destination(destination_weather_api): assert resp.status_code == 200 +@pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") +def test_weather_alerts(destination_weather_api): + """Test Destination Weather api.""" + resp = destination_weather_api.get_weather_alerts( + feature_type="Feature", + geometry_type="Point", + geometry_coordinates=[15.256, 23.456], + start_time=datetime.now(), + ) + assert type(resp) == requests.Response + assert resp.status_code == 200 + + @pytest.mark.skipif(not LS_API_KEY, reason="No api key found.") def test_autosuggest(autosuggest_api): """Test autosuggest api.""" From 79d9bdd28495cab46a8736a30bce896fcaf475c5 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Mon, 6 Sep 2021 03:08:26 +0530 Subject: [PATCH 6/7] fixes --- .../destination_weather_api.py | 53 ++++++++++--------- here_location_services/ls.py | 24 ++++----- tests/test_ls.py | 14 ++--- tests/test_ls_apis.py | 5 +- 4 files changed, 44 insertions(+), 52 deletions(-) diff --git a/here_location_services/destination_weather_api.py b/here_location_services/destination_weather_api.py index 50ee1ed..eb33b77 100644 --- a/here_location_services/destination_weather_api.py +++ b/here_location_services/destination_weather_api.py @@ -5,8 +5,10 @@ """ # noqa E501 import time -from datetime import datetime -from typing import Any, Dict, List, Optional +from datetime import date, datetime +from typing import Any, Dict, List, Optional, Union + +from geojson import Feature, FeatureCollection, LineString, MultiPolygon, Point, Polygon from here_location_services.platform.auth import Auth @@ -33,7 +35,7 @@ def get_dest_weather( at: Optional[List] = None, query: Optional[str] = None, zipcode: Optional[str] = None, - hourly_date: Optional[Any] = None, + hourly_date: Optional[Union[date, datetime]] = None, one_observation: Optional[bool] = None, language: Optional[str] = None, units: Optional[str] = None, @@ -49,7 +51,8 @@ def get_dest_weather( :param query: Free text query. Examples: "125, Berliner, berlin", "Beacon, Boston" :param zipcode: ZIP code of the location. This parameter is supported only for locations in the United States of America. - :param hourly_date: Date for which hourly forecasts are to be retrieved. + :param hourly_date: Date for which hourly forecasts are to be retrieved. Can be either a `date` or + `datetime` object :param one_observation: Boolean, if set to true, the response only includes the closest location. Only available when the `product` parameter is set to `DEST_WEATHER_PRODUCT.observation`. @@ -71,7 +74,10 @@ def get_dest_weather( if zipcode: params["zipCode"] = zipcode if hourly_date: - params["hourlyDate"] = hourly_date.strftime("%Y-%m-%dT%H:%M:%S") + if type(hourly_date) is datetime.date: + params["hourlyDate"] = hourly_date.strftime("%Y-%m-%d") + else: + params["hourlyDate"] = hourly_date.strftime("%Y-%m-%dT%H:%M:%S") if one_observation: params["oneObservation"] = "true" if one_observation else "false" if language: @@ -87,9 +93,7 @@ def get_dest_weather( def get_weather_alerts( self, - feature_type: str, - geometry_type: str, - geometry_coordinates: List, + geometry: Union[Point, LineString, Polygon, MultiPolygon], start_time: datetime, id: Optional[str] = None, weather_severity: Optional[int] = None, @@ -102,9 +106,8 @@ def get_weather_alerts( See further information `Here Destination Weather API _`. - :param feature_type: String to define feature type - :param geometry_type: Point or LineString or Polygon or MultiPolygon - :param geometry_coordinates: Array of coordinates corressponding to type provided + :param geometry: Point or LineString or Polygon or MultiPolygon defining the route or + a single location :param start_time: Start time of the event :param id: Unique weather alert id. :param weather_severity: Defines the severity of the weather event as defined @@ -122,17 +125,6 @@ def get_weather_alerts( path = "v3/alerts" url = f"{self._base_url}/{path}" - data: Dict[str, Any] = { - "type": "FeatureCollection", - } - features: Dict[str, Any] = { - "type": feature_type, - } - - if id: - features["id"] = id - - geometry: Dict[str, Any] = {"type": geometry_type, "coordinates": geometry_coordinates} properties: Dict[str, Any] = { "width": width, @@ -151,10 +143,19 @@ def get_weather_alerts( weather_warnings["endTime"] = time.mktime(end_time.timetuple()) properties["warnings"] = [weather_warnings] - features["properties"] = properties - features["geometry"] = geometry - data["features"] = [features] - resp = self.post(url, data=data) + + f = Feature( + geometry=geometry, + properties=properties, + ) + + if id: + f.id = id + + feature_collection = FeatureCollection([]) + feature_collection.features.append(f) + + resp = self.post(url, data=feature_collection) if resp.status_code == 200: return resp else: diff --git a/here_location_services/ls.py b/here_location_services/ls.py index f1fae07..0aecb64 100644 --- a/here_location_services/ls.py +++ b/here_location_services/ls.py @@ -6,9 +6,11 @@ import os import urllib import urllib.request -from datetime import datetime +from datetime import date, datetime from time import sleep -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union + +from geojson import LineString, MultiPolygon, Point, Polygon from here_location_services.config.routing_config import Scooter, Via from here_location_services.platform.apis.aaa_oauth2_api import AAAOauth2Api @@ -320,7 +322,7 @@ def get_dest_weather( at: Optional[List] = None, query: Optional[str] = None, zipcode: Optional[str] = None, - hourly_date: Optional[Any] = None, + hourly_date: Optional[Union[date, datetime]] = None, one_observation: Optional[bool] = None, language: Optional[str] = None, units: Optional[str] = None, @@ -335,7 +337,8 @@ def get_dest_weather( :param query: Free text query. Examples: "125, Berliner, berlin", "Beacon, Boston" :param zipcode: ZIP code of the location. This parameter is supported only for locations in the United States of America. - :param hourly_date: Date for which hourly forecasts are to be retrieved. + :param hourly_date: Date for which hourly forecasts are to be retrieved. Can be either a + `date` or `datetime` object :param one_observation: Boolean, if set to true, the response only includes the closest location. Only available when the `product` parameter is set to `DEST_WEATHER_PRODUCT.observation`. @@ -370,9 +373,7 @@ def get_dest_weather( def get_weather_alerts( self, - feature_type: str, - geometry_type: str, - geometry_coordinates: List, + geometry: Union[Point, LineString, Polygon, MultiPolygon], start_time: datetime, id: Optional[str] = None, weather_severity: Optional[int] = None, @@ -384,9 +385,8 @@ def get_weather_alerts( """Retrieves weather reports, weather forecasts, severe weather alerts and moon and sun rise and set information. - :param feature_type: String to define feature type - :param geometry_type: Point or LineString or Polygon or MultiPolygon - :param geometry_coordinates: Array of coordinates corressponding to type provided + :param geometry: Point or LineString or Polygon or MultiPolygon defining the route or + a single location :param start_time: Start time of the event :param id: Unique weather alert id. :param weather_severity: Defines the severity of the weather event as defined @@ -402,9 +402,7 @@ def get_weather_alerts( """ resp = self.destination_weather_api.get_weather_alerts( - feature_type=feature_type, - geometry_type=geometry_type, - geometry_coordinates=geometry_coordinates, + geometry=geometry, id=id, weather_severity=weather_severity, weather_type=weather_type, diff --git a/tests/test_ls.py b/tests/test_ls.py index 8d97544..6449c5f 100644 --- a/tests/test_ls.py +++ b/tests/test_ls.py @@ -7,7 +7,7 @@ import pandas as pd import pytest import pytz -from geojson import FeatureCollection +from geojson import FeatureCollection, Point from here_location_services import LS from here_location_services.config.autosuggest_config import POLITICAL_VIEW, SHOW, SearchCircle @@ -63,18 +63,14 @@ def test_ls_weather_alerts(): """Test weather alerts endpoint of destination weather api.""" ls = LS(api_key=LS_API_KEY) resp = ls.get_weather_alerts( - feature_type="Feature", - geometry_type="Point", - geometry_coordinates=[15.256, 23.456], + geometry=Point(coordinates=[15.256, 23.456]), start_time=datetime.now(), width=3000, ) assert resp resp2 = ls.get_weather_alerts( - feature_type="Feature", - geometry_type="Point", - geometry_coordinates=[15.256, 23.456], + geometry=Point(coordinates=[15.256, 23.456]), start_time=datetime.now(), weather_type=WEATHER_TYPE.ice, weather_severity=WEATHER_SEVERITY.high, @@ -86,9 +82,7 @@ def test_ls_weather_alerts(): with pytest.raises(ApiError): ls2 = LS(api_key="dummy") ls2.get_weather_alerts( - feature_type="Feature", - geometry_type="Point", - geometry_coordinates=[15.256, 23.456], + geometry=Point(coordinates=[15.256, 23.456]), start_time=datetime.now(), ) diff --git a/tests/test_ls_apis.py b/tests/test_ls_apis.py index 1dc4d84..eddbbca 100644 --- a/tests/test_ls_apis.py +++ b/tests/test_ls_apis.py @@ -6,6 +6,7 @@ import pytest import requests +from geojson import Point from here_location_services.config.dest_weather_config import DEST_WEATHER_PRODUCT from here_location_services.config.isoline_routing_config import ( @@ -34,9 +35,7 @@ def test_destination_weather(destination_weather_api): def test_weather_alerts(destination_weather_api): """Test Destination Weather api.""" resp = destination_weather_api.get_weather_alerts( - feature_type="Feature", - geometry_type="Point", - geometry_coordinates=[15.256, 23.456], + geometry=Point(coordinates=[15.256, 23.456]), start_time=datetime.now(), ) assert type(resp) == requests.Response From 78a3e4f28f94ec62ec35b86ff58e78f80a2547ba Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Mon, 6 Sep 2021 03:31:57 +0530 Subject: [PATCH 7/7] fix documentation --- docs/notebooks/README.md | 8 +++-- docs/notebooks/destination_weather.ipynb | 37 ++++++++++++---------- docs/source/dest_weather.rst | 40 +++++++++++++++++++++++- 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/docs/notebooks/README.md b/docs/notebooks/README.md index ab8d716..10f8116 100644 --- a/docs/notebooks/README.md +++ b/docs/notebooks/README.md @@ -3,11 +3,12 @@ The example notebooks in this directory demonstrate various functionalities of `HERE Location Services`. ## Prerequisites + Before you run the Notebooks make sure you have: + - A HERE developer account, free and available under [HERE Developer Portal](https://developer.here.com) - An [API key](https://developer.here.com/documentation/identity-access-management/dev_guide/topics/dev-apikey.html) from the [HERE Developer Portal](https://developer.here.com) - ## Preparing for visualization In order to run these Notebooks, you will need a few third-party dependencies. Please copy the following text to a file name anything you like, e.g. `requirements.txt`: @@ -23,10 +24,11 @@ For visualization requirements please install [here-map-widget-for-jupyter](http Follow installation steps from here: [here-map-widget-for-jupyter](https://github.com/heremaps/here-map-widget-for-jupyter#installation). - ## Notebooks - [Location Services](./location_services.ipynb) - Examples of various location services. - [Restaurant Search](./isoline_routing_restaurant_search.ipynb) - Usecase of restarant search using isoline routing. - [Routing](./routing.ipynb) - Examples of routing API. -- [Matrix Routing](./matrix_routing.ipynb) - Examples of Matrix routing API. \ No newline at end of file +- [Matrix Routing](./matrix_routing.ipynb) - Examples of Matrix routing API. +- [Autosuggest](./autosuggest.ipynb) - Examples of Autosuggest API. +- [Destination Weather](./destination_weather.ipynb) - Examples of Destination Weather API. diff --git a/docs/notebooks/destination_weather.ipynb b/docs/notebooks/destination_weather.ipynb index 0a5ef61..18aaa48 100644 --- a/docs/notebooks/destination_weather.ipynb +++ b/docs/notebooks/destination_weather.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "source": [ "import os\n", "os.environ[\"LS_API_KEY\"] = \"MY-API-KEY\" # replace your API key here." @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "source": [ "import os\n", "\n", @@ -49,22 +49,25 @@ "m.add_layer(layer)\n", "m" ], - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - "Map(api_key='TKURWbpJHcbzmWMrmTZwGAdSTLrX8WY1oddj4S4U-EM', basemap=None, center=[19.1621, 73.0008], layers=(Ob…" - ], - "application/vnd.jupyter.widget-view+json": { - "version_major": 2, - "version_minor": 0, - "model_id": "91639eb7343842f1a4feefac3738ab95" - } - }, - "metadata": {} - } + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "from geojson import Point\n", + "from datetime import datetime\n", + "\n", + "result2 = ls.get_weather_alerts(\n", + " geometry=Point(coordinates=[15.256, 23.456]),\n", + " start_time=datetime.now(),\n", + " width=3000,\n", + " )\n", + "\n", + "print(result2)" ], + "outputs": [], "metadata": {} }, { diff --git a/docs/source/dest_weather.rst b/docs/source/dest_weather.rst index 4e84d2c..0203e3b 100644 --- a/docs/source/dest_weather.rst +++ b/docs/source/dest_weather.rst @@ -55,4 +55,42 @@ hourly_date :func:`datetime.datetime` one_observation bool optional Boolean, if set to true, the response only includes the closest location. Only available when the `product` parameter is set to `DEST_WEATHER_PRODUCT.observation`. language str optional Defines the language used in the descriptions in the response. units :class:`DestWeatherUnits ` optional Defines whether units or imperial units are used in the response. -==================== =============================================================================================================== === \ No newline at end of file +==================== =============================================================================================================== === + +Getting Weather Alerts +---------------------- +Can be used to get information on severe weather alerts along a specified route or a single car location. + +.. jupyter-execute:: + + import os + from here_location_services import LS + from geojson import Point + from datetime import datetime + + LS_API_KEY = os.environ.get("LS_API_KEY") + ls = LS(api_key=LS_API_KEY) + result = ls.get_weather_alerts( + geometry=Point(coordinates=[15.256, 23.456]), + start_time=datetime.now(), + width=3000, + ) + + print(result) + + +Attributes +---------- + +==================== =============================================================================================================== === +Attribute Type Doc +==================== =============================================================================================================== === +geometry Point or LineString or Polygon or MultiPolygon Point or LineString or Polygon or MultiPolygon defining the route or a single location +start_time :func:`datetime.datetime` Start time of the event +id str optional Unique weather alert id. +weather_severity :class:`WeatherSeverity ` optional Defines the severity of the weather event +weather_type :class:`WeatherType ` optional Defines the type of the weather event +country str optional String for ISO-3166-1 2-letter country code. +end_time :func:`datetime.datetime` optional End time of the event. If not present, warning is valid until it is not removed from the feed by national weather institutes (valid until warning is present in the response) +width int optional int. default 50000 +==================== =============================================================================================================== ===