New apps Added
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
"""Taken from the fantastic Dark Sky library: https://github.com/ZeevG/python-forecast.io in October 2024. Updated in April 2025 using the Pirate Weather library: https://github.com/cloneofghosts/python-pirate-weather."""
|
||||
|
||||
import datetime
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class UnicodeMixin:
|
||||
"""Provide string representation for Python 2/3 compatibility."""
|
||||
|
||||
def __str__(self):
|
||||
"""Return the unicode representation of the object for Python 2/3 compatibility."""
|
||||
return self.__unicode__()
|
||||
|
||||
|
||||
"""Models used in the Pirate Weather library."""
|
||||
|
||||
|
||||
class Forecast(UnicodeMixin):
|
||||
"""Represent the forecast data and provide methods to access weather blocks."""
|
||||
|
||||
def __init__(self, data, response, headers):
|
||||
"""Initialize the Forecast with data, HTTP response, and headers."""
|
||||
self.response = response
|
||||
self.http_headers = headers
|
||||
self.json = data
|
||||
|
||||
self._alerts = []
|
||||
for alertJSON in self.json.get("alerts", []):
|
||||
self._alerts.append(Alert(alertJSON))
|
||||
|
||||
def update(self):
|
||||
"""Update the forecast data by making a new request to the same URL."""
|
||||
r = requests.get(self.response.url)
|
||||
self.json = r.json()
|
||||
self.response = r
|
||||
|
||||
def currently(self):
|
||||
"""Return the current weather data block."""
|
||||
return self._pirateweather_data("currently")
|
||||
|
||||
def minutely(self):
|
||||
"""Return the minutely weather data block."""
|
||||
return self._pirateweather_data("minutely")
|
||||
|
||||
def hourly(self):
|
||||
"""Return the hourly weather data block."""
|
||||
return self._pirateweather_data("hourly")
|
||||
|
||||
def day_night(self):
|
||||
"""Return the day_night weather data block."""
|
||||
return self._pirateweather_data("day_night")
|
||||
|
||||
def daily(self):
|
||||
"""Return the daily weather data block."""
|
||||
return self._pirateweather_data("daily")
|
||||
|
||||
def flags(self):
|
||||
"""Return the flags data block."""
|
||||
return self._pirateweather_data("flags")
|
||||
|
||||
def offset(self):
|
||||
"""Return the time zone offset for the forecast location."""
|
||||
return self.json["offset"]
|
||||
|
||||
def alerts(self):
|
||||
"""Return the list of alerts issued for this forecast."""
|
||||
return self._alerts
|
||||
|
||||
def _pirateweather_data(self, key):
|
||||
"""Fetch and return specific weather data (currently, minutely, hourly, daily, flags and day_night)."""
|
||||
keys = ["minutely", "currently", "hourly", "daily", "flags", "day_night"]
|
||||
try:
|
||||
if key not in self.json:
|
||||
keys.remove(key)
|
||||
url = "{}&exclude={}{}".format(
|
||||
self.response.url.split("&")[0],
|
||||
",".join(keys),
|
||||
",alerts",
|
||||
)
|
||||
|
||||
response = requests.get(url).json()
|
||||
self.json[key] = response[key]
|
||||
|
||||
if key == "currently":
|
||||
return PirateWeatherDataPoint(self.json[key])
|
||||
if key == "flags":
|
||||
return PirateWeatherFlagsBlock(self.json[key])
|
||||
return PirateWeatherDataBlock(self.json[key])
|
||||
except KeyError:
|
||||
if key == "currently":
|
||||
return PirateWeatherDataPoint()
|
||||
return PirateWeatherDataBlock()
|
||||
|
||||
|
||||
class PirateWeatherDataBlock(UnicodeMixin):
|
||||
"""Represent a block of weather data such as minutely, hourly, or daily summaries."""
|
||||
|
||||
def __init__(self, d=None):
|
||||
"""Initialize the data block with summary and icon information."""
|
||||
d = d or {}
|
||||
self.summary = d.get("summary")
|
||||
self.icon = d.get("icon")
|
||||
self.data = [
|
||||
PirateWeatherDataPoint(datapoint) for datapoint in d.get("data", [])
|
||||
]
|
||||
|
||||
def __unicode__(self):
|
||||
"""Return a string representation of the data block."""
|
||||
return f"<PirateWeatherDataBlock instance: {self.summary} with {len(self.data)} PirateWeatherDataPoints>"
|
||||
|
||||
|
||||
class PirateWeatherFlagsBlock(UnicodeMixin):
|
||||
"""Represent a block of flags data."""
|
||||
|
||||
def __init__(self, d=None):
|
||||
"""Initialize the data block with flags information."""
|
||||
d = d or {}
|
||||
self.units = d.get("units")
|
||||
self.version = d.get("version")
|
||||
self.nearestStation = d.get("nearest-station")
|
||||
self.sources = list(d.get("sources"))
|
||||
self.sourceTimes = d.get("sourceTimes")
|
||||
self.processTime = d.get("processTime")
|
||||
self.ingestVersion = d.get("ingestVersion")
|
||||
self.nearestCity = d.get("nearestCity")
|
||||
self.nearestCountry = d.get("nearestCountry")
|
||||
self.nearestSubNational = d.get("nearestSubNational")
|
||||
|
||||
def __unicode__(self):
|
||||
"""Return a string representation of the data block."""
|
||||
return f"<PirateWeatherFlagsDataBlock instance: {self.version}>"
|
||||
|
||||
|
||||
class PirateWeatherDataPoint(UnicodeMixin):
|
||||
"""Represent a single data point in a weather forecast, such as an hourly or daily data point."""
|
||||
|
||||
def __init__(self, d={}):
|
||||
"""Initialize the data point with timestamp and weather information."""
|
||||
self.d = d
|
||||
|
||||
try:
|
||||
self.time = datetime.datetime.fromtimestamp(int(d["time"]))
|
||||
self.utime = d["time"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
sr_time = int(d["sunriseTime"])
|
||||
self.sunriseTime = datetime.datetime.fromtimestamp(sr_time)
|
||||
except KeyError:
|
||||
self.sunriseTime = None
|
||||
|
||||
try:
|
||||
ss_time = int(d["sunsetTime"])
|
||||
self.sunsetTime = datetime.datetime.fromtimestamp(ss_time)
|
||||
except KeyError:
|
||||
self.sunsetTime = None
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Return the weather property dynamically or return None if missing."""
|
||||
try:
|
||||
return self.d[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def __unicode__(self):
|
||||
"""Return a string representation of the data point."""
|
||||
return f"<PirateWeatherDataPoint instance: {self.summary} at {self.time}>"
|
||||
|
||||
|
||||
class Alert(UnicodeMixin):
|
||||
"""Represent a weather alert, such as a storm warning or flood alert."""
|
||||
|
||||
def __init__(self, json):
|
||||
"""Initialize the alert with the raw JSON data."""
|
||||
self.json = json
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Return the alert property dynamically or return None if missing."""
|
||||
try:
|
||||
return self.json[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def __unicode__(self):
|
||||
"""Return a string representation of the alert."""
|
||||
return f"<Alert instance: {self.title} at {self.time}>"
|
||||
Reference in New Issue
Block a user