Repository: MatthewFlamm/pynws

Issue:
Icon format in forecast change
API used to return something like:

```
"icon": "https://api.weather.gov/icons/land/night/sct?size=small",
```

now it returns something like

```
"icon": "/icons/land/night/sct?size=small",
```

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/MatthewFlamm/pynws/pull/208?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 93.69%. Comparing base [(`aae2aee`)](https://app.codecov.io/gh/MatthewFlamm/pynws/commit/aae2aeefc87bd422c532fc2adeeffac2755dd8ce?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) to head [(`1c8ffb1`)](https://app.codecov.io/gh/MatthewFlamm/pynws/commit/1c8ffb12612ba8abfc73268285157d5a3503e766?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #208      +/-   ##
==========================================
+ Coverage   93.67%   93.69%   +0.01%     
==========================================
  Files           9        9              
  Lines         632      634       +2     
==========================================
+ Hits          592      594       +2     
  Misses         40       40              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/MatthewFlamm/pynws/pull/208?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/pyproject.toml b/pyproject.toml
index dd36143..1ff17fd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,7 +8,8 @@ name = "pynws"
 requires-python = ">=3.8"
 dependencies = [
     "aiohttp",
-    "metar"
+    "metar",
+    "yarl"
 ]
 description = "Python library to retrieve observations and forecasts from NWS/NOAA"
 readme = {file = "README.md", content-type = "text/markdown"}
diff --git a/src/pynws/simple_nws.py b/src/pynws/simple_nws.py
index 6b30cc8..5b6bf92 100644
--- a/src/pynws/simple_nws.py
+++ b/src/pynws/simple_nws.py
@@ -23,6 +23,7 @@ if TYPE_CHECKING:
 
 from aiohttp import ClientResponseError, ClientSession
 from metar import Metar
+from yarl import URL
 
 from .const import ALERT_ID, API_WEATHER_CODE, Final
 from .forecast import DetailedForecast
@@ -177,9 +178,10 @@ def parse_icon(icon: str) -> Tuple[str, _WeatherCodes]:
     Example return:
     ('day', (('skc', None), ('tsra', 40),))
     """
-    icon_list = icon.split("/")
-    time = icon_list[5]
-    weather = [i.split("?")[0] for i in icon_list[6:]]
+    icon_url = URL(icon)
+    icon_parts = icon_url.parts
+    time = icon_parts[3]
+    weather = icon_parts[4:]
     code = [w.split(",")[0] for w in weather]
     chance = [int(w.split(",")[1]) if len(w.split(",")) == 2 else None for w in weather]
     return time, list(zip(code, chance))


Test patch:
diff --git a/requirements-test.txt b/requirements-test.txt
index 90426da..84a67cf 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -7,3 +7,4 @@ pytest-cov==5.0.0
 pytest-aiohttp==1.0.5
 mypy==1.10.0
 tenacity==8.3.0
+yarl==1.9.4
\ No newline at end of file
diff --git a/tests/fixtures/gridpoints_forecast_relative_icon.json b/tests/fixtures/gridpoints_forecast_relative_icon.json
new file mode 100644
index 0000000..c0cd9f6
--- /dev/null
+++ b/tests/fixtures/gridpoints_forecast_relative_icon.json
@@ -0,0 +1,119 @@
+{
+    "@context": [
+        "https://raw.githubusercontent.com/geojson/geojson-ld/master/contexts/geojson-base.jsonld",
+        {
+            "wx": "https://api.weather.gov/ontology#",
+            "geo": "http://www.opengis.net/ont/geosparql#",
+            "unit": "http://codes.wmo.int/common/unit/",
+            "@vocab": "https://api.weather.gov/ontology#"
+        }
+    ],
+    "type": "Feature",
+    "geometry": {
+        "type": "GeometryCollection",
+        "geometries": [
+            {
+                "type": "Point",
+                "coordinates": [
+                    -84.956046999999998,
+                    29.995017300000001
+                ]
+            },
+            {
+                "type": "Polygon",
+                "coordinates": [
+                    [
+                        [
+                            -84.968174099999999,
+                            30.007206
+                        ],
+                        [
+                            -84.970116500000003,
+                            29.984511300000001
+                        ],
+                        [
+                            -84.943922400000005,
+                            29.982827500000003
+                        ],
+                        [
+                            -84.941974999999999,
+                            30.005522000000003
+                        ],
+                        [
+                            -84.968174099999999,
+                            30.007206
+                        ]
+                    ]
+                ]
+            }
+        ]
+    },
+    "properties": {
+        "updated": "2019-10-13T18:16:20+00:00",
+        "units": "us",
+        "forecastGenerator": "BaselineForecastGenerator",
+        "generatedAt": "2019-10-13T18:42:44+00:00",
+        "updateTime": "2019-10-13T18:16:20+00:00",
+        "validTimes": "2019-10-13T12:00:00+00:00/P6DT22H",
+        "elevation": {
+            "value": 7.9248000000000003,
+            "unitCode": "unit:m"
+        },
+        "periods": [
+            {
+                "number": 1,
+                "name": "This Afternoon",
+                "startTime": "2019-10-13T14:00:00-04:00",
+                "endTime": "2019-10-13T18:00:00-04:00",
+                "isDaytime": true,
+                "temperature": 41,
+                "temperatureUnit": "F",
+                "temperatureTrend": null,
+                "probabilityOfPrecipitation": {
+                    "unitCode": "wmoUnit:percent",
+                    "value": 20
+                },
+                "dewpoint": {
+                    "unitCode": "wmoUnit:degC",
+                    "value": 5
+                },
+                "relativeHumidity": {
+                    "unitCode": "wmoUnit:percent",
+                    "value": 63
+                },
+                "windSpeed": "10 mph",
+                "windDirection": "S",
+                "icon": "/icons/land/day/tsra,40/ovc?size=medium",
+                "shortForecast": "Chance Showers And Thunderstorms",
+                "detailedForecast": ""
+            },
+            {
+                "number": 2,
+                "name": "Tonight",
+                "startTime": "2019-10-13T18:00:00-04:00",
+                "endTime": "2019-10-14T06:00:00-04:00",
+                "isDaytime": false,
+                "temperature": 68,
+                "temperatureUnit": "F",
+                "temperatureTrend": null,
+                "probabilityOfPrecipitation": {
+                    "unitCode": "wmoUnit:percent",
+                    "value": null
+                },
+                "dewpoint": {
+                    "unitCode": "wmoUnit:degC",
+                    "value": 5
+                },
+                "relativeHumidity": {
+                    "unitCode": "wmoUnit:percent",
+                    "value": 63
+                },
+                "windSpeed": "0 to 5 mph",
+                "windDirection": "S",
+                "icon": "/icons/land/night/few?size=medium",
+                "shortForecast": "Mostly Clear",
+                "detailedForecast": "Mostly clear, with a low around 68. South wind 0 to 5 mph."
+            }
+        ]
+    }
+}
diff --git a/tests/fixtures/stations_observations_relative_icon.json b/tests/fixtures/stations_observations_relative_icon.json
new file mode 100644
index 0000000..0ccd17e
--- /dev/null
+++ b/tests/fixtures/stations_observations_relative_icon.json
@@ -0,0 +1,168 @@
+{
+    "@context": [
+        "https://raw.githubusercontent.com/geojson/geojson-ld/master/contexts/geojson-base.jsonld",
+        {
+            "wx": "https://api.weather.gov/ontology#",
+            "s": "https://schema.org/",
+            "geo": "http://www.opengis.net/ont/geosparql#",
+            "unit": "http://codes.wmo.int/common/unit/",
+            "@vocab": "https://api.weather.gov/ontology#",
+            "geometry": {
+                "@id": "s:GeoCoordinates",
+                "@type": "geo:wktLiteral"
+            },
+            "city": "s:addressLocality",
+            "state": "s:addressRegion",
+            "distance": {
+                "@id": "s:Distance",
+                "@type": "s:QuantitativeValue"
+            },
+            "bearing": {
+                "@type": "s:QuantitativeValue"
+            },
+            "value": {
+                "@id": "s:value"
+            },
+            "unitCode": {
+                "@id": "s:unitCode",
+                "@type": "@id"
+            },
+            "forecastOffice": {
+                "@type": "@id"
+            },
+            "forecastGridData": {
+                "@type": "@id"
+            },
+            "publicZone": {
+                "@type": "@id"
+            },
+            "county": {
+                "@type": "@id"
+            }
+        }
+    ],
+    "type": "FeatureCollection",
+    "features": [
+        {
+            "id": "https://api.weather.gov/stations/KFLL/observations/2019-06-27T10:53:00+00:00",
+            "type": "Feature",
+            "geometry": {
+                "type": "Point",
+                "coordinates": [
+                    -80.150000000000006,
+                    26.07
+                ]
+            },
+            "properties": {
+                "@id": "https://api.weather.gov/stations/KFLL/observations/2019-06-27T10:53:00+00:00",
+                "@type": "wx:ObservationStation",
+                "elevation": {
+                    "value": 10,
+                    "unitCode": "unit:m"
+                },
+                "station": "https://api.weather.gov/stations/KFLL",
+                "timestamp": "2019-06-27T10:53:00+00:00",
+                "rawMessage": "KFLL 271053Z 35005KT 10SM FEW025 FEW250 26/23 A3005 RMK AO2 SLP176 T02560228",
+                "textDescription": "Mostly Clear",
+                "icon": "/icons/land/day/few?size=medium",
+                "presentWeather": [],
+                "temperature": {
+                    "value": 10,
+                    "unitCode": "unit:degC",
+                    "qualityControl": "qc:V"
+                },
+                "dewpoint": {
+                    "value": 10,
+                    "unitCode": "unit:degC",
+                    "qualityControl": "qc:V"
+                },
+                "windDirection": {
+                    "value": 10,
+                    "unitCode": "unit:degree_(angle)",
+                    "qualityControl": "qc:V"
+                },
+                "windSpeed": {
+                    "value": 10,
+                    "unitCode": "unit:m_s-1",
+                    "qualityControl": "qc:V"
+                },
+                "windGust": {
+                    "value": 10,
+                    "unitCode": "unit:m_s-1",
+                    "qualityControl": "qc:Z"
+                },
+                "barometricPressure": {
+                    "value": 100000,
+                    "unitCode": "unit:Pa",
+                    "qualityControl": "qc:V"
+                },
+                "seaLevelPressure": {
+                    "value": 100000,
+                    "unitCode": "unit:Pa",
+                    "qualityControl": "qc:V"
+                },
+                "visibility": {
+                    "value": 10000,
+                    "unitCode": "unit:m",
+                    "qualityControl": "qc:C"
+                },
+                "maxTemperatureLast24Hours": {
+                    "value": null,
+                    "unitCode": "unit:degC",
+                    "qualityControl": null
+                },
+                "minTemperatureLast24Hours": {
+                    "value": null,
+                    "unitCode": "unit:degC",
+                    "qualityControl": null
+                },
+                "precipitationLastHour": {
+                    "value": null,
+                    "unitCode": "unit:m",
+                    "qualityControl": "qc:Z"
+                },
+                "precipitationLast3Hours": {
+                    "value": null,
+                    "unitCode": "unit:m",
+                    "qualityControl": "qc:Z"
+                },
+                "precipitationLast6Hours": {
+                    "value": null,
+                    "unitCode": "unit:m",
+                    "qualityControl": "qc:Z"
+                },
+                "relativeHumidity": {
+                    "value": 10,
+                    "unitCode": "unit:percent",
+                    "qualityControl": "qc:C"
+                },
+                "windChill": {
+                    "value": null,
+                    "unitCode": "unit:degC",
+                    "qualityControl": "qc:V"
+                },
+                "heatIndex": {
+                    "value": 10,
+                    "unitCode": "unit:degC",
+                    "qualityControl": "qc:V"
+                },
+                "cloudLayers": [
+                    {
+                        "base": {
+                            "value": 760,
+                            "unitCode": "unit:m"
+                        },
+                        "amount": "FEW"
+                    },
+                    {
+                        "base": {
+                            "value": 7620,
+                            "unitCode": "unit:m"
+                        },
+                        "amount": "FEW"
+                    }
+                ]
+            }
+        }
+    ]
+}
diff --git a/tests/test_simple_nws.py b/tests/test_simple_nws.py
index c39114d..22b5173 100644
--- a/tests/test_simple_nws.py
+++ b/tests/test_simple_nws.py
@@ -40,6 +40,7 @@ async def test_nws_set_station_none(aiohttp_client, mock_urls):
         "stations_observations_strings.json",
         "stations_observations_other_unitcode.json",
         "stations_observations_multiple_unsorted.json",
+        "stations_observations_relative_icon.json",
     ],
 )
 async def test_nws_observation(aiohttp_client, mock_urls, observation_json):
@@ -230,9 +231,15 @@ async def test_nws_observation_missing_value(aiohttp_client, mock_urls):
     assert observation["iconWeather"] is None
 
 
+@pytest.mark.parametrize(
+    "gridpoints_forecast",
+    ["gridpoints_forecast.json", "gridpoints_forecast_relative_icon.json"],
+)
 @freeze_time("2019-10-13T14:30:00-04:00")
-async def test_nws_forecast(aiohttp_client, mock_urls):
-    app = setup_app()
+async def test_nws_forecast(aiohttp_client, mock_urls, gridpoints_forecast):
+    app = setup_app(
+        gridpoints_forecast=gridpoints_forecast,
+    )
     client = await aiohttp_client(app)
     nws = SimpleNWS(*LATLON, USERID, client)
     await nws.update_forecast()