simple-dwd-weatherforecast 2.0.31__py3-none-any.whl → 2.0.33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,22 +1,23 @@
1
+ import csv
2
+ import importlib
3
+ import json
4
+ import math
1
5
  from collections import OrderedDict, defaultdict
2
- import requests
6
+ from datetime import datetime, timedelta, timezone
7
+ from enum import Enum
3
8
  from io import BytesIO
4
9
  from zipfile import ZipFile
5
- from enum import Enum
6
- from lxml import etree
7
- from datetime import datetime, timedelta, timezone
10
+
8
11
  import arrow
9
- import math
10
- import json
11
- import csv
12
- import importlib
12
+ import requests
13
+ from lxml import etree
13
14
 
14
- with importlib.resources.files("simple_dwd_weatherforecast").joinpath(
15
+ with importlib.resources.files("simple_dwd_weatherforecast").joinpath( # type: ignore
15
16
  "stations.json"
16
17
  ).open("r", encoding="utf-8") as file:
17
18
  stations = json.load(file)
18
19
 
19
- with importlib.resources.files("simple_dwd_weatherforecast").joinpath(
20
+ with importlib.resources.files("simple_dwd_weatherforecast").joinpath( # type: ignore
20
21
  "uv_stations.json"
21
22
  ).open("r", encoding="utf-8") as file:
22
23
  uv_stations = json.load(file)
@@ -32,6 +33,7 @@ def get_station_by_name(station_name: str):
32
33
  for station in stations.items():
33
34
  if station[1]["name"] == station_name:
34
35
  return station
36
+ return None
35
37
 
36
38
 
37
39
  def get_nearest_station_id(lat: float, lon: float):
@@ -40,14 +42,21 @@ def get_nearest_station_id(lat: float, lon: float):
40
42
 
41
43
  def get_stations_sorted_by_distance(lat: float, lon: float):
42
44
  """
43
- Given a latitude and longitude, this function returns a list of stations sorted by their distance from the provided location.
45
+ Return stations sort by distance.
46
+
47
+ Given a latitude and longitude, this function returns a list of stations sorted by
48
+ their distance from the provided location.
44
49
 
45
- Parameters:
46
- lat (float): The latitude of the location.
47
- lon (float): The longitude of the location.
50
+ Args:
51
+ ----
52
+ lat: The latitude of the location.
53
+ lon: The longitude of the location.
48
54
 
49
55
  Returns:
50
- list: A list of stations sorted by distance, where each element is a list containing the station ID and its distance from the location.
56
+ -------
57
+ list: A list of stations sorted by distance, where each element is a list
58
+ containing the station ID and its distance from the location.
59
+
51
60
  """
52
61
  result = []
53
62
  for station in stations.items():
@@ -70,40 +79,40 @@ def get_distance(lat, lon, _lat, _lon):
70
79
 
71
80
  def get_region(station_id: str):
72
81
  if (
73
- station_id in stations.keys()
74
- and stations[station_id]["bundesland"] in Weather.region_codes.keys()
82
+ station_id in stations
83
+ and stations[station_id]["bundesland"] in Weather.region_codes
75
84
  ):
76
85
  return stations[station_id]["bundesland"]
77
86
  return None
78
87
 
79
88
 
80
89
  class WeatherDataType(Enum):
81
- CONDITION = ["condition", "present_weather"]
82
- TEMPERATURE = ["TTT", "dry_bulb_temperature_at_2_meter_above_ground"] # Unit: K
83
- DEWPOINT = ["Td", "dew_point_temperature_at_2_meter_above_ground"] # Unit: K
84
- PRESSURE = ["PPPP", "pressure_reduced_to_mean_sea_level"] # Unit: Pa
85
- WIND_SPEED = [
90
+ CONDITION = ("condition", "present_weather")
91
+ TEMPERATURE = ("TTT", "dry_bulb_temperature_at_2_meter_above_ground") # Unit: K
92
+ DEWPOINT = ("Td", "dew_point_temperature_at_2_meter_above_ground") # Unit: K
93
+ PRESSURE = ("PPPP", "pressure_reduced_to_mean_sea_level") # Unit: Pa
94
+ WIND_SPEED = (
86
95
  "FF",
87
96
  "maximum_wind_speed_as_10_minutes_mean_during_last_hour",
88
- ] # Unit: m/s
89
- WIND_DIRECTION = [
97
+ ) # Unit: m/s
98
+ WIND_DIRECTION = (
90
99
  "DD",
91
100
  "mean_wind_direction_during_last_10 min_at_10_meters_above_ground",
92
- ] # Unit: Degrees
93
- WIND_GUSTS = ["FX1", "maximum_wind_speed_last_hour"] # Unit: m/s
94
- PRECIPITATION = ["RR1c", "precipitation_amount_last_hour"] # Unit: kg/m^2
95
- PRECIPITATION_PROBABILITY = ["wwP", ""] # Unit: % (0..100)
96
- PRECIPITATION_DURATION = ["DRR1", ""] # Unit: s
97
- CLOUD_COVERAGE = ["N", "cloud_cover_total"] # Unit: % (0..100)
98
- VISIBILITY = ["VV", "horizontal_visibility"] # Unit: m
99
- SUN_DURATION = ["SunD1", ""] # Unit: s
100
- SUN_IRRADIANCE = ["Rad1h", "global_radiation_last_hour"] # Unit: kJ/m^2
101
- FOG_PROBABILITY = ["wwM", ""] # Unit: % (0..100)
102
- HUMIDITY = ["humidity", "relative_humidity"] # Unit: %
101
+ ) # Unit: Degrees
102
+ WIND_GUSTS = ("FX1", "maximum_wind_speed_last_hour") # Unit: m/s
103
+ PRECIPITATION = ("RR1c", "precipitation_amount_last_hour") # Unit: kg/m^2
104
+ PRECIPITATION_PROBABILITY = ("wwP", "") # Unit: % (0..100)
105
+ PRECIPITATION_DURATION = ("DRR1", "") # Unit: s
106
+ CLOUD_COVERAGE = ("N", "cloud_cover_total") # Unit: % (0..100)
107
+ VISIBILITY = ("VV", "horizontal_visibility") # Unit: m
108
+ SUN_DURATION = ("SunD1", "") # Unit: s
109
+ SUN_IRRADIANCE = ("Rad1h", "global_radiation_last_hour") # Unit: kJ/m^2
110
+ FOG_PROBABILITY = ("wwM", "") # Unit: % (0..100)
111
+ HUMIDITY = ("humidity", "relative_humidity") # Unit: %
103
112
 
104
113
 
105
114
  class Weather:
106
- """A class for interacting with weather data from dwd.de"""
115
+ """A class for interacting with weather data from dwd.de."""
107
116
 
108
117
  NOT_AVAILABLE = "---"
109
118
 
@@ -254,15 +263,17 @@ class Weather:
254
263
  self.region = get_region(station_id)
255
264
  self.nearest_uv_index_station = self.get_nearest_station_id_with_uv()
256
265
  else:
257
- raise ValueError("Not a valid station_id")
266
+ msg = "Not a valid station_id"
267
+ raise ValueError(msg)
258
268
 
259
269
  def get_nearest_station_id_with_uv(self):
260
270
  nearest_distance = float("inf")
261
271
  nearest_station_id = None
272
+ _station = self.station
262
273
  for station in uv_stations.items():
263
274
  distance = get_distance(
264
- self.station["lat"],
265
- self.station["lon"],
275
+ self.station["lat"], # type: ignore
276
+ self.station["lon"], # type: ignore
266
277
  station[1]["lat"],
267
278
  station[1]["lon"],
268
279
  )
@@ -274,17 +285,32 @@ class Weather:
274
285
  return nearest_station_id
275
286
 
276
287
  def get_station_name(self):
277
- return self.station["name"]
288
+ return self.station["name"] # type: ignore
278
289
 
279
290
  def is_in_timerange(self, timestamp: datetime):
280
291
  return (
281
- list(self.forecast_data.keys())[0]
292
+ list(self.forecast_data.keys())[0] # type: ignore
282
293
  <= self.strip_to_hour_str(timestamp)
283
- <= list(self.forecast_data.keys())[-1]
294
+ <= list(self.forecast_data.keys())[-1] # type: ignore
284
295
  )
285
296
 
286
- def is_valid_timeframe(_, timeframe: int) -> bool:
287
- if 24 < timeframe or timeframe <= 0:
297
+ def is_in_timerange_day(self, timestamp: datetime):
298
+ return (
299
+ self.strip_to_day(
300
+ arrow.get(
301
+ list(self.forecast_data.keys())[0], "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
302
+ ).datetime
303
+ )
304
+ <= self.strip_to_day(timestamp)
305
+ <= self.strip_to_day(
306
+ arrow.get(
307
+ list(self.forecast_data.keys())[-1], "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
308
+ ).datetime
309
+ )
310
+ )
311
+
312
+ def is_valid_timeframe(self, timeframe: int) -> bool:
313
+ if timeframe > 24 or timeframe <= 0:
288
314
  return False
289
315
  return 24 % timeframe == 0
290
316
 
@@ -299,7 +325,7 @@ class Weather:
299
325
  if shouldUpdate:
300
326
  self.update()
301
327
  if self.is_in_timerange(timestamp):
302
- return self.forecast_data[self.strip_to_hour_str(timestamp)][
328
+ return self.forecast_data[self.strip_to_hour_str(timestamp)][ # type: ignore
303
329
  weatherDataType.value[0]
304
330
  ]
305
331
  return None
@@ -311,7 +337,7 @@ class Weather:
311
337
  if self.is_in_timerange(timestamp):
312
338
  return str(
313
339
  self.weather_codes[
314
- self.forecast_data[self.strip_to_hour_str(timestamp)][
340
+ self.forecast_data[self.strip_to_hour_str(timestamp)][ # type: ignore
315
341
  WeatherDataType.CONDITION.value[0]
316
342
  ]
317
343
  ][0]
@@ -400,7 +426,7 @@ class Weather:
400
426
  else:
401
427
  print("no report for this station available. Have you updated first?")
402
428
 
403
- def get_uv_index(self, days_from_today: int, shouldUpdate=True) -> int:
429
+ def get_uv_index(self, days_from_today: int, shouldUpdate=True) -> int | None:
404
430
  if not self.uv_reports and shouldUpdate:
405
431
  self.update(
406
432
  force_hourly=False,
@@ -444,11 +470,11 @@ class Weather:
444
470
  ):
445
471
  if shouldUpdate:
446
472
  self.update()
447
- if self.is_in_timerange(timestamp):
473
+ if self.is_in_timerange_day(timestamp):
448
474
  return self.get_max(self.get_day_values(timestamp), weatherDataType)
449
475
  return None
450
476
 
451
- def get_max(_, weather_data, weatherDataType: WeatherDataType):
477
+ def get_max(self, weather_data, weatherDataType: WeatherDataType):
452
478
  value = None
453
479
  for item in weather_data:
454
480
  value_new = item[weatherDataType.value[0]]
@@ -481,11 +507,11 @@ class Weather:
481
507
  ):
482
508
  if shouldUpdate:
483
509
  self.update()
484
- if self.is_in_timerange(timestamp):
510
+ if self.is_in_timerange_day(timestamp):
485
511
  return self.get_min(self.get_day_values(timestamp), weatherDataType)
486
512
  return None
487
513
 
488
- def get_min(_, weather_data, weatherDataType: WeatherDataType):
514
+ def get_min(self, weather_data, weatherDataType: WeatherDataType):
489
515
  value = None
490
516
  for item in weather_data:
491
517
  value_new = item[weatherDataType.value[0]]
@@ -519,11 +545,11 @@ class Weather:
519
545
  ):
520
546
  if shouldUpdate:
521
547
  self.update()
522
- if self.is_in_timerange(timestamp):
548
+ if self.is_in_timerange_day(timestamp):
523
549
  return self.get_sum(self.get_day_values(timestamp), weatherDataType)
524
550
  return None
525
551
 
526
- def get_sum(_, weather_data, weatherDataType):
552
+ def get_sum(self, weather_data, weatherDataType):
527
553
  value_sum = 0.0
528
554
  for item in weather_data:
529
555
  value = item[weatherDataType.value[0]]
@@ -546,7 +572,16 @@ class Weather:
546
572
  )
547
573
  return None
548
574
 
549
- def get_avg(_, weather_data, weatherDataType):
575
+ def get_daily_avg(
576
+ self, weatherDataType: WeatherDataType, timestamp: datetime, shouldUpdate=True
577
+ ):
578
+ if shouldUpdate:
579
+ self.update()
580
+ if self.is_in_timerange_day(timestamp):
581
+ return self.get_avg(self.get_day_values(timestamp), weatherDataType)
582
+ return None
583
+
584
+ def get_avg(self, weather_data, weatherDataType):
550
585
  value_sum = 0.0
551
586
  count = len(weather_data)
552
587
  if count != 0:
@@ -565,54 +600,50 @@ class Weather:
565
600
  for _ in range(timeframe):
566
601
  hour_str = self.strip_to_hour_str(time_step)
567
602
  time_step += timedelta(hours=1)
568
- if hour_str not in self.forecast_data:
603
+ if hour_str not in self.forecast_data: # type: ignore
569
604
  continue
570
- result.append(self.forecast_data[hour_str])
605
+ result.append(self.forecast_data[hour_str]) # type: ignore
571
606
  return result
572
607
 
573
608
  def get_day_values(self, timestamp: datetime):
574
609
  "timestamp has to be checked prior to be in timerange"
575
610
  result = []
576
611
  first_entry_date = arrow.get(
577
- next(iter(self.forecast_data)), "YYYY-MM-DDTHH:mm:ss.SSSZ"
578
- ).datetime
612
+ next(iter(self.forecast_data)), "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
613
+ ).datetime # type: ignore
579
614
  if timestamp.day != first_entry_date.day:
580
615
  time_step = self.strip_to_day(timestamp)
581
616
  for _ in range(24):
582
617
  hour_str = self.strip_to_hour_str(time_step)
583
- if hour_str not in self.forecast_data:
618
+ if hour_str not in self.forecast_data: # type: ignore
584
619
  break
585
- result.append(self.forecast_data[hour_str])
620
+ result.append(self.forecast_data[hour_str]) # type: ignore
586
621
  time_step += timedelta(hours=1)
587
622
  else:
588
623
  time_step = first_entry_date
589
- endtime = (
590
- datetime(
591
- time_step.year,
592
- time_step.month,
593
- time_step.day,
594
- 0,
595
- 0,
596
- 0,
597
- 0,
598
- timezone.utc,
599
- )
600
- + timedelta(days=1)
601
- + timedelta(hours=-1)
602
- )
624
+ endtime = datetime(
625
+ time_step.year,
626
+ time_step.month,
627
+ time_step.day,
628
+ 0,
629
+ 0,
630
+ 0,
631
+ 0,
632
+ timezone.utc,
633
+ ) + timedelta(days=1)
603
634
  timediff = endtime - time_step
604
635
  for _ in range(round(timediff.total_seconds() / 3600)):
605
- result.append(self.forecast_data[self.strip_to_hour_str(time_step)])
636
+ result.append(self.forecast_data[self.strip_to_hour_str(time_step)]) # type: ignore
606
637
  time_step += timedelta(hours=1)
607
638
  return result
608
639
 
609
- def strip_to_hour_str(_, timestamp: datetime):
640
+ def strip_to_hour_str(self, timestamp: datetime):
610
641
  return timestamp.strftime("%Y-%m-%dT%H:00:00.000Z")
611
642
 
612
- def strip_to_hour(_, timestamp: datetime):
643
+ def strip_to_hour(self, timestamp: datetime):
613
644
  return datetime(timestamp.year, timestamp.month, timestamp.day, timestamp.hour)
614
645
 
615
- def strip_to_day(_, timestamp: datetime):
646
+ def strip_to_day(self, timestamp: datetime):
616
647
  return datetime(timestamp.year, timestamp.month, timestamp.day)
617
648
 
618
649
  def update(
@@ -672,7 +703,8 @@ class Weather:
672
703
 
673
704
  self.loaded_station_name = self.parse_station_name(tree)
674
705
 
675
- value = lambda wdt: self.get_weather_type(tree, wdt)
706
+ def value(wdt):
707
+ return self.get_weather_type(tree, wdt)
676
708
 
677
709
  values = [
678
710
  (wdt, value(wdt))
@@ -720,9 +752,9 @@ class Weather:
720
752
  ):
721
753
  item = placemark.find(".//kml:name", namespaces=self.namespaces)
722
754
 
723
- if item.text == self.station_id:
755
+ if item is not None and item.text == self.station_id:
724
756
  return placemark
725
- placemark.clear()
757
+ # placemark.clear()
726
758
 
727
759
  def parse_issue_time(self, tree):
728
760
  issue_time_new = arrow.get(
@@ -755,7 +787,9 @@ class Weather:
755
787
  if None in (temperature, dewpoint):
756
788
  return
757
789
 
758
- celsius = lambda t: t - 273.1
790
+ def celsius(t):
791
+ return t - 273.1
792
+
759
793
  T = celsius(temperature)
760
794
  TD = celsius(dewpoint)
761
795
 
@@ -868,7 +902,7 @@ class Weather:
868
902
  headers = {
869
903
  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.116 Safari/537.36"
870
904
  }
871
- headers["If-None-Match"] = self.etags[url] if url in self.etags else ""
905
+ headers["If-None-Match"] = self.etags[url] if url in self.etags else "" # type: ignore
872
906
  try:
873
907
  request = requests.get(url, headers=headers, timeout=30)
874
908
  # If resource has not been modified, return
@@ -876,7 +910,7 @@ class Weather:
876
910
  return
877
911
  elif request.status_code != 200:
878
912
  raise Exception(f"Unexpected status code {request.status_code}")
879
- self.etags[url] = request.headers["ETag"]
913
+ self.etags[url] = request.headers["ETag"] # type: ignore
880
914
  uv_reports = json.loads(request.text)["content"]
881
915
  # Match with existing stations
882
916
  for uv_report in uv_reports:
@@ -884,22 +918,22 @@ class Weather:
884
918
  self.uv_index_stations_reference_names[uv_report["city"]]
885
919
  )
886
920
  # uv_report.update({"lat": station[1]["lat"], "lon": station[1]["lon"]})
887
- self.uv_reports[station[0]] = uv_report
921
+ self.uv_reports[station[0]] = uv_report # type: ignore
888
922
  except Exception as error:
889
- print(f"Error in download_weather_report: {type(error)} args: {error.args}")
923
+ print(f"Error in download_uv_index: {type(error)} args: {error.args}")
890
924
 
891
925
  def download_weather_report(self, region_code):
892
926
  url = f"https://www.dwd.de/DWD/wetter/wv_allg/deutschland/text/vhdl13_{region_code}.html"
893
927
  headers = {
894
928
  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.116 Safari/537.36"
895
929
  }
896
- headers["If-None-Match"] = self.etags[url] if url in self.etags else ""
930
+ headers["If-None-Match"] = self.etags[url] if url in self.etags else "" # type: ignore
897
931
  try:
898
932
  request = requests.get(url, headers=headers, timeout=30)
899
933
  # If resource has not been modified, return
900
934
  if request.status_code == 304:
901
935
  return
902
- self.etags[url] = request.headers["ETag"]
936
+ self.etags[url] = request.headers["ETag"] # type: ignore
903
937
  weather_report = request.text
904
938
  a = weather_report.find(">")
905
939
  if a != -1:
@@ -910,22 +944,22 @@ class Weather:
910
944
 
911
945
  def download_latest_kml(self, stationid, force_hourly=False):
912
946
  if force_hourly:
913
- url = f"https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_S/all_stations/kml/MOSMIX_S_LATEST_240.kmz"
947
+ url = "https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_S/all_stations/kml/MOSMIX_S_LATEST_240.kmz"
914
948
  else:
915
949
  url = f"https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/{stationid}/kml/MOSMIX_L_LATEST_{stationid}.kmz"
916
- headers = {"If-None-Match": self.etags[url] if url in self.etags else ""}
950
+ headers = {"If-None-Match": self.etags[url] if url in self.etags else ""} # type: ignore
917
951
  try:
918
952
  request = requests.get(url, headers=headers, timeout=30)
919
953
  # If resource has not been modified, return
920
954
  if request.status_code == 304:
921
955
  return
922
- self.etags[url] = request.headers["ETag"]
956
+ self.etags[url] = request.headers["ETag"] # type: ignore
923
957
  with ZipFile(BytesIO(request.content), "r") as kmz:
924
958
  # large RAM allocation
925
959
  with kmz.open(kmz.namelist()[0], "r") as kml:
926
960
  self.parse_kml(kml, force_hourly)
927
961
  except Exception as error:
928
- print(f"Error in download_weather_report: {type(error)} args: {error.args}")
962
+ print(f"Error in download_latest_kml: {type(error)} args: {error.args}")
929
963
 
930
964
  def download_latest_report(self):
931
965
  station_id = self.station_id
@@ -934,7 +968,7 @@ class Weather:
934
968
  url = (
935
969
  f"https://opendata.dwd.de/weather/weather_reports/poi/{station_id}-BEOB.csv"
936
970
  )
937
- headers = {"If-None-Match": self.etags[url] if url in self.etags else ""}
971
+ headers = {"If-None-Match": self.etags[url] if url in self.etags else ""} # type: ignore
938
972
  try:
939
973
  response = requests.get(url, headers=headers, timeout=30)
940
974
  if response.status_code == 200:
@@ -974,4 +1008,4 @@ class Weather:
974
1008
  # Handle other status codes
975
1009
  print(f"Failed to download report. Status code: {response.status_code}")
976
1010
  except Exception as error:
977
- print(f"Error in download_weather_report: {type(error)} args: {error.args}")
1011
+ print(f"Error in download_latest_report: {type(error)} args: {error.args}")
@@ -6,7 +6,7 @@ from enum import Enum
6
6
 
7
7
 
8
8
  class WeatherMapType(Enum):
9
- NIEDERSCHLAGSRADAR = "dwd:Niederschlagsradar"
9
+ NIEDERSCHLAGSRADAR = "dwd:Niederschlagsradar,dwd:NCEW_EU"
10
10
  MAXTEMP = "dwd:GefuehlteTempMax"
11
11
  UVINDEX = "dwd:UVI_CS"
12
12
  POLLENFLUG = "dwd:Pollenflug"
@@ -15,6 +15,7 @@ class WeatherMapType(Enum):
15
15
  WARNUNGEN_GEMEINDEN = "dwd:Warnungen_Gemeinden"
16
16
  WARNUNGEN_KREISE = "dwd:Warnungen_Landkreise"
17
17
 
18
+
18
19
  class WeatherBackgroundMapType(Enum):
19
20
  LAENDER = "dwd:Laender"
20
21
  BUNDESLAENDER = "dwd:Warngebiete_Bundeslaender"
@@ -23,7 +24,16 @@ class WeatherBackgroundMapType(Enum):
23
24
  SATELLIT = "dwd:bluemarble"
24
25
  GEWAESSER = "dwd:Gewaesser"
25
26
 
26
- def get_from_location(longitude, latitude, radius_km, map_type: WeatherMapType, background_type: WeatherBackgroundMapType = WeatherBackgroundMapType.BUNDESLAENDER, image_width=520, image_height=580):
27
+
28
+ def get_from_location(
29
+ longitude,
30
+ latitude,
31
+ radius_km,
32
+ map_type: WeatherMapType,
33
+ background_type: WeatherBackgroundMapType = WeatherBackgroundMapType.BUNDESLAENDER,
34
+ image_width=520,
35
+ image_height=580,
36
+ ):
27
37
  if radius_km <= 0:
28
38
  raise ValueError("Radius must be greater than 0")
29
39
  if latitude < -90 or latitude > 90:
@@ -31,17 +41,45 @@ def get_from_location(longitude, latitude, radius_km, map_type: WeatherMapType,
31
41
  if longitude < -180 or longitude > 180:
32
42
  raise ValueError("Longitude must be between -180 and 180")
33
43
  radius = math.fabs(radius_km / (111.3 * math.cos(latitude)))
34
- return get_map(latitude-radius, longitude-radius, latitude+radius, longitude+radius, map_type, background_type, image_width, image_height)
44
+ return get_map(
45
+ latitude - radius,
46
+ longitude - radius,
47
+ latitude + radius,
48
+ longitude + radius,
49
+ map_type,
50
+ background_type,
51
+ image_width,
52
+ image_height,
53
+ )
35
54
 
36
- def get_germany(map_type: WeatherMapType, background_type: WeatherBackgroundMapType = WeatherBackgroundMapType.BUNDESLAENDER, image_width=520, image_height=580):
37
- return get_map(4.4, 46.4, 16.1, 55.6, map_type, background_type, image_width, image_height)
38
55
 
39
- def get_map(minx,miny,maxx,maxy, map_type: WeatherMapType, background_type: WeatherBackgroundMapType, image_width=520, image_height=580):
40
- if image_width > 1200 or image_height > 1400:
41
- raise ValueError("Width and height must not exceed 1200 and 1400 respectively. Please be kind to the DWD servers.")
56
+ def get_germany(
57
+ map_type: WeatherMapType,
58
+ background_type: WeatherBackgroundMapType = WeatherBackgroundMapType.BUNDESLAENDER,
59
+ image_width=520,
60
+ image_height=580,
61
+ ):
62
+ return get_map(
63
+ 4.4, 46.4, 16.1, 55.6, map_type, background_type, image_width, image_height
64
+ )
42
65
 
43
- url = f"https://maps.dwd.de/geoserver/dwd/wms?service=WMS&version=1.1.0&request=GetMap&layers={background_type.value},{map_type.value}&bbox={minx},{miny},{maxx},{maxy}&width={image_width}&height={image_height}&srs=EPSG:4326&styles=&format=image/png"
66
+
67
+ def get_map(
68
+ minx,
69
+ miny,
70
+ maxx,
71
+ maxy,
72
+ map_type: WeatherMapType,
73
+ background_type: WeatherBackgroundMapType,
74
+ image_width=520,
75
+ image_height=580,
76
+ ):
77
+ if image_width > 1200 or image_height > 1400:
78
+ raise ValueError(
79
+ "Width and height must not exceed 1200 and 1400 respectively. Please be kind to the DWD servers."
80
+ )
81
+ url = f"https://maps.dwd.de/geoserver/dwd/wms?service=WMS&version=1.1.0&request=GetMap&layers={map_type.value},{background_type.value}&bbox={minx},{miny},{maxx},{maxy}&width={image_width}&height={image_height}&srs=EPSG:4326&styles=&format=image/png"
44
82
  request = requests.get(url, stream=True)
45
83
  if request.status_code == 200:
46
84
  image = Image.open(BytesIO(request.content))
47
- return image
85
+ return image
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simple_dwd_weatherforecast
3
- Version: 2.0.31
3
+ Version: 2.0.33
4
4
  Summary: A simple tool to retrieve a weather forecast from DWD OpenData
5
5
  Home-page: https://github.com/FL550/simple_dwd_weatherforecast.git
6
6
  Author: Max Fermor
@@ -127,6 +127,8 @@ class Weather:
127
127
 
128
128
  get_timeframe_sum(weatherDataType: see WeatherDataType, datetime, timeframe: hours after datetime as int, optional bool shouldUpdate) # Returns the sum of that value within the time frame
129
129
 
130
+ get_daily_avg(weatherDataType: see WeatherDataType, datetime, optional bool shouldUpdate) # Returns the daily average of that value
131
+
130
132
  get_timeframe_avg(weatherDataType: see WeatherDataType, datetime, timeframe: hours after datetime as int, optional bool shouldUpdate) # Returns the average of that value within the time frame
131
133
 
132
134
  get_forecast_condition(datetime, optional bool shouldUpdate) # Result is condition as text
@@ -0,0 +1,42 @@
1
+ simple_dwd_weatherforecast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ simple_dwd_weatherforecast/dwdforecast.py,sha256=4ZqQweWyXCMJ8NajdKV_Ca0WkbxrsJXKX7RD0lQayXU,36587
3
+ simple_dwd_weatherforecast/dwdmap.py,sha256=fZMi3nk4MwzZm0dJ8TUwCgOuTw6t8kZmnOkoHGKpXx4,2695
4
+ simple_dwd_weatherforecast/stations.json,sha256=1u8qc2CT_rVy49SAlOicGixzHln6Y0FXevuFAz2maBw,838948
5
+ simple_dwd_weatherforecast/uv_stations.json,sha256=ADenYo-aR6qbf0UFkfYr72kkFzL9HyUKe4VQ23POGF8,2292
6
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ tests/dummy_data.py,sha256=sF8pXxq8innSpRc4lW0XxGcr34dESSAoBdAf2F2D4AI,63395
8
+ tests/dummy_data_full.py,sha256=IwYoeqVX8cpfn_gE-7arXaWV9btRm_HHqka_LfKqW-E,64053
9
+ tests/dummy_uv.py,sha256=TM1TwvNq_ea4WgIJyYsNAEXZJTx1dXH1ZVrW_LfLBLg,4548
10
+ tests/test_get_daily_avg.py,sha256=MNd7u9Y7_E6SIyxg59EKfdKx4QJ7R_WT5wvRgm7Gzks,2315
11
+ tests/test_get_daily_condition.py,sha256=foRgUO0W4ctWuer04RvUi2JqcFpiDBhFoLg9OdQSFj8,2004
12
+ tests/test_get_daily_max.py,sha256=schjGJDflg1YEQSdfRndw2NT4AvrVheSDveyVZrFySM,2220
13
+ tests/test_get_daily_min.py,sha256=GzqlOfLdwLqGLYVeAJ0fbK1JRq-_fT7z6Gea74lSY7E,2224
14
+ tests/test_get_daily_sum.py,sha256=UEntbPwGSleHocu0587WnuC5ijptQtzVNreR1d6yoM0,2221
15
+ tests/test_get_day_values.py,sha256=KOMkp_bh_nqZIufP8F3PNmF3WqXnPLOn6LKHrSi3SMA,29310
16
+ tests/test_get_forecast_condition.py,sha256=YVapxXH5Svq5P7XvWn48n19hriQ1-7CSezuGc6DswJQ,2866
17
+ tests/test_get_forecast_data.py,sha256=E1pIsgcWfQLgiVBMJ4URao3rBJgXebDWcPlV6FYZF-U,3394
18
+ tests/test_get_station_name.py,sha256=S18TZCUrLSRUgAz7sJ66igC0X-9JX_7O3Yh9Z6-QHnQ,423
19
+ tests/test_get_timeframe_avg.py,sha256=2XQU8posZWJ54fqcOTq2Ci0EE_KG38mtZ5Qi2emDL20,2425
20
+ tests/test_get_timeframe_condition.py,sha256=9ED_Uyx6v4Gq6qQ5SQyWtS_fOkbbhExKzfGGM18M38k,3237
21
+ tests/test_get_timeframe_max.py,sha256=gas73o1Ferkk87M4Y3k4LZ-fXKehI2ulsxcQfIviDTs,2407
22
+ tests/test_get_timeframe_min.py,sha256=WnFO36U_E-55TW7jR598lyLS4u-TOtXmufadJF7IWQs,2407
23
+ tests/test_get_timeframe_sum.py,sha256=hjHY9fvJUqi4o8AdFLPSDwi8GpXtjzLqsRzVMoUVjn4,2424
24
+ tests/test_get_timeframe_values.py,sha256=z8ozpWlyilw8-zjbk2gDExhTobNbgmcVTbZ6ZHjxAW4,6891
25
+ tests/test_is_in_timerange.py,sha256=3y88L3N73NxSTJ-_edx6OCnxHWKJWWFma98gjZvJDGg,1338
26
+ tests/test_is_valid_timeframe.py,sha256=mXjeu3lUyixiBUEljirTf6qDM_FZFQGWa-Rk0NBMUDU,891
27
+ tests/test_location_tools.py,sha256=wto_XzVnARJQ-Qc83YAn0ahfMBSaOHpfzqAeKRDsNm8,1208
28
+ tests/test_map.py,sha256=Bnf7XSap7xAfozE5U9aB0GjjMiHmXrpyJPE79VmEvFg,830
29
+ tests/test_parsekml.py,sha256=Y0EHJi5e8lqFUS8N9yfA5ByQkKV4-iyrwUaIipQpM7w,1065
30
+ tests/test_region.py,sha256=ReUB9Cy9roBemkpEkTjZZav-Mu3Ha7ADOAfa9J-gi80,877
31
+ tests/test_reported_weather.py,sha256=ULg4ogZRxus01p2rdxiSFL75AisqtcvnLDOc7uJMBH0,767
32
+ tests/test_station.py,sha256=Zjx-q0yxKVxVI_L1yB_bqY5pjZPoa1L94uC8Gx6shdY,1026
33
+ tests/test_stationsfile.py,sha256=slRH5N4Gznr6tkN2oMFWJbVCw3Xrma7Hvzn1lG5E-Qg,1401
34
+ tests/test_update.py,sha256=r763R-MfqFqQQy43PcmE9yWAiQU6T2rQ1u55ujlwMt8,7216
35
+ tests/test_update_hourly.py,sha256=mUc66JHndgIMdZ0DD_KXQTbPPg1g86F6CPUwJYjBV5U,1619
36
+ tests/test_uv_index.py,sha256=tr6wnOyHlXT1S3yp1oeHc4-Brmc-EMEdM4mtyrdpcHg,579
37
+ tests/test_weather.py,sha256=ZyX4ldUoJpJp7YpiNQwU6Od-nYRay-3qcaDJdNq8fhY,780
38
+ simple_dwd_weatherforecast-2.0.33.dist-info/LICENCE,sha256=27UG7gteqvSWuZlsbIq2_OAbh7VyifGGl-1zpuUoBcw,1072
39
+ simple_dwd_weatherforecast-2.0.33.dist-info/METADATA,sha256=OoVmEQpJwfD2ThO8I7DcKwD2Xcv0sm5izDTWFaJkOTs,10937
40
+ simple_dwd_weatherforecast-2.0.33.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
41
+ simple_dwd_weatherforecast-2.0.33.dist-info/top_level.txt,sha256=iyEobUh14Tzitx39Oi8qm0NhBrnZovl_dNKtvLUkLEM,33
42
+ simple_dwd_weatherforecast-2.0.33.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,56 @@
1
+ from simple_dwd_weatherforecast.dwdforecast import WeatherDataType
2
+ import unittest
3
+ from unittest.mock import patch
4
+ from datetime import datetime
5
+ from simple_dwd_weatherforecast import dwdforecast
6
+ from dummy_data import parsed_data
7
+
8
+
9
+ class Weather_get_daily_avg(unittest.TestCase):
10
+ def setUp(self):
11
+ self.dwd_weather = dwdforecast.Weather("H889")
12
+ self.dwd_weather.forecast_data = parsed_data
13
+ self.dwd_weather.station_name = "BAD HOMBURG"
14
+
15
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
+ def test_shouldupdate(self, mock_update):
17
+ test_time = datetime(2020, 11, 7, 3, 30)
18
+ self.dwd_weather.get_daily_avg(WeatherDataType.PRECIPITATION, test_time, True)
19
+ mock_update.assert_called()
20
+
21
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
22
+ def test_shouldupdate_not(self, mock_update):
23
+ test_time = datetime(2020, 11, 7, 3, 30)
24
+ self.dwd_weather.get_daily_avg(WeatherDataType.PRECIPITATION, test_time, False)
25
+ mock_update.assert_not_called()
26
+
27
+ def test_not_in_timerange(self):
28
+ test_time = datetime(2000, 11, 7, 3, 30)
29
+ self.assertIsNone(
30
+ self.dwd_weather.get_daily_avg(WeatherDataType.PRECIPITATION, test_time)
31
+ )
32
+
33
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
34
+ def test_precipitation(self, mock_update):
35
+ test_time = datetime(2020, 11, 6, 12, 0)
36
+ print(self.dwd_weather.get_day_values(test_time))
37
+ self.assertEqual(
38
+ self.dwd_weather.get_daily_avg(WeatherDataType.PRECIPITATION, test_time),
39
+ 1.8,
40
+ )
41
+
42
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
43
+ def test_temperature(self, mock_update):
44
+ test_time = datetime(2020, 11, 6, 23, 0)
45
+ self.assertEqual(
46
+ self.dwd_weather.get_daily_avg(WeatherDataType.TEMPERATURE, test_time),
47
+ 278.09,
48
+ )
49
+
50
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
51
+ def test_midnight(self, mock_update):
52
+ test_time = datetime(2020, 11, 6, 0, 0)
53
+ self.assertEqual(
54
+ self.dwd_weather.get_daily_avg(WeatherDataType.TEMPERATURE, test_time),
55
+ 278.09,
56
+ )
@@ -8,8 +8,7 @@ from dummy_data import parsed_data
8
8
  class Weather_get_daily_condition(unittest.TestCase):
9
9
  def setUp(self):
10
10
  self.dwd_weather = dwdforecast.Weather("H889")
11
- self.dwd_weather.forecast_data = parsed_data
12
- self.dwd_weather.station_name = "BAD HOMBURG"
11
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
13
12
 
14
13
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
15
14
  def test_shouldupdate(self, mock_update):
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_daily_max(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -45,3 +44,11 @@ class Weather_get_daily_max(unittest.TestCase):
45
44
  self.dwd_weather.get_daily_max(WeatherDataType.TEMPERATURE, test_time),
46
45
  283.05,
47
46
  )
47
+
48
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
49
+ def test_midnight(self, mock_update):
50
+ test_time = datetime(2020, 11, 6, 0, 0)
51
+ self.assertEqual(
52
+ self.dwd_weather.get_daily_max(WeatherDataType.TEMPERATURE, test_time),
53
+ 283.05,
54
+ )
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_daily_min(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -45,3 +44,11 @@ class Weather_get_daily_min(unittest.TestCase):
45
44
  self.dwd_weather.get_daily_min(WeatherDataType.TEMPERATURE, test_time),
46
45
  272.95,
47
46
  )
47
+
48
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
49
+ def test_midnight(self, mock_update):
50
+ test_time = datetime(2020, 11, 6, 0, 0)
51
+ self.assertEqual(
52
+ self.dwd_weather.get_daily_min(WeatherDataType.TEMPERATURE, test_time),
53
+ 272.95,
54
+ )
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_daily_sum(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -35,7 +34,7 @@ class Weather_get_daily_sum(unittest.TestCase):
35
34
  test_time = datetime(2020, 11, 6, 10, 0)
36
35
  self.assertEqual(
37
36
  self.dwd_weather.get_daily_sum(WeatherDataType.PRECIPITATION, test_time),
38
- 27.25,
37
+ 36.01,
39
38
  )
40
39
 
41
40
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
@@ -43,5 +42,13 @@ class Weather_get_daily_sum(unittest.TestCase):
43
42
  test_time = datetime(2020, 11, 6, 10, 0)
44
43
  self.assertEqual(
45
44
  self.dwd_weather.get_daily_sum(WeatherDataType.TEMPERATURE, test_time),
46
- 5286.25,
45
+ 5561.8,
46
+ )
47
+
48
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
49
+ def test_midnight(self, mock_update):
50
+ test_time = datetime(2020, 11, 6, 0, 0)
51
+ self.assertEqual(
52
+ self.dwd_weather.get_daily_sum(WeatherDataType.TEMPERATURE, test_time),
53
+ 5561.8,
47
54
  )
@@ -7,8 +7,7 @@ from dummy_data import parsed_data
7
7
  class Weather_get_day_values(unittest.TestCase):
8
8
  def setUp(self):
9
9
  self.dwd_weather = dwdforecast.Weather("H889")
10
- self.dwd_weather.forecast_data = parsed_data
11
- self.dwd_weather.station_name = "BAD HOMBURG"
10
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
12
11
 
13
12
  def test_day_not_current_day(self):
14
13
  test_time = datetime(2020, 11, 7, 10, 0)
@@ -451,6 +450,7 @@ class Weather_get_day_values(unittest.TestCase):
451
450
  self.dwd_weather.get_day_values(test_time),
452
451
  test_data,
453
452
  )
453
+ self.assertEqual(len(self.dwd_weather.get_day_values(test_time)), 24)
454
454
 
455
455
  def test_day_not_last_day(self):
456
456
  test_time = datetime(2020, 11, 16, 1, 0)
@@ -1004,8 +1004,27 @@ class Weather_get_day_values(unittest.TestCase):
1004
1004
  "wwM": 3.0,
1005
1005
  "humidity": 81.3,
1006
1006
  },
1007
+ {
1008
+ "TTT": 275.55,
1009
+ "Td": 273.45,
1010
+ "condition": "51",
1011
+ "PPPP": 103060.0,
1012
+ "DD": 52.0,
1013
+ "FF": 1.54,
1014
+ "FX1": 3.09,
1015
+ "RR1c": 8.76,
1016
+ "wwP": 2.0,
1017
+ "DRR1": 0.0,
1018
+ "N": 22.0,
1019
+ "VV": 15500.0,
1020
+ "SunD1": 0.0,
1021
+ "Rad1h": None,
1022
+ "wwM": 2.0,
1023
+ "humidity": 86.0,
1024
+ },
1007
1025
  ]
1008
1026
  self.assertEqual(
1009
1027
  self.dwd_weather.get_day_values(test_time),
1010
1028
  test_data,
1011
1029
  )
1030
+ self.assertEqual(len(self.dwd_weather.get_day_values(test_time)), 20)
@@ -8,8 +8,7 @@ from dummy_data import parsed_data
8
8
  class Weather_get_forecast_condition(unittest.TestCase):
9
9
  def setUp(self):
10
10
  self.dwd_weather = dwdforecast.Weather("H889")
11
- self.dwd_weather.forecast_data = parsed_data
12
- self.dwd_weather.station_name = "BAD HOMBURG"
11
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
13
12
 
14
13
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
15
14
  def test_shouldupdate(self, mock_update):
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_forecast_data(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -1,5 +1,4 @@
1
1
  import unittest
2
- from unittest.mock import patch
3
2
  from simple_dwd_weatherforecast import dwdforecast
4
3
  from dummy_data import parsed_data
5
4
 
@@ -7,7 +6,7 @@ from dummy_data import parsed_data
7
6
  class Weather_get_station_name(unittest.TestCase):
8
7
  def setUp(self):
9
8
  self.dwd_weather = dwdforecast.Weather("H889")
10
- self.dwd_weather.forecast_data = parsed_data
9
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
11
10
 
12
11
  def test_get_station_name(self):
13
12
  self.assertEqual(self.dwd_weather.get_station_name(), "Burbach-Wuergendorf")
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_timeframe_avg(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -8,8 +8,7 @@ from dummy_data import parsed_data
8
8
  class Weather_get_timeframe_condition(unittest.TestCase):
9
9
  def setUp(self):
10
10
  self.dwd_weather = dwdforecast.Weather("H889")
11
- self.dwd_weather.forecast_data = parsed_data
12
- self.dwd_weather.station_name = "BAD HOMBURG"
11
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
13
12
 
14
13
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
15
14
  def test_shouldupdate(self, mock_update):
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_timeframe_max(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_timeframe_min(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -9,8 +9,7 @@ from dummy_data import parsed_data
9
9
  class Weather_get_timeframe_sum(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
16
15
  def test_shouldupdate(self, mock_update):
@@ -7,8 +7,7 @@ from dummy_data import parsed_data
7
7
  class Weather_get_timeframe_values(unittest.TestCase):
8
8
  def setUp(self):
9
9
  self.dwd_weather = dwdforecast.Weather("H889")
10
- self.dwd_weather.forecast_data = parsed_data
11
- self.dwd_weather.station_name = "BAD HOMBURG"
10
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
12
11
 
13
12
  def test_timeframe_6(self):
14
13
  test_time = datetime(2020, 11, 7, 1, 0)
@@ -7,8 +7,7 @@ from dummy_data import parsed_data
7
7
  class Weather_is_in_timerange(unittest.TestCase):
8
8
  def setUp(self):
9
9
  self.dwd_weather = dwdforecast.Weather("H889")
10
- self.dwd_weather.forecast_data = parsed_data
11
- self.dwd_weather.station_name = "BAD HOMBURG"
10
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
12
11
 
13
12
  def test_is_in_timerange(self):
14
13
  test_time = datetime(2020, 11, 7, 3, 30)
@@ -21,3 +20,15 @@ class Weather_is_in_timerange(unittest.TestCase):
21
20
  def test_is_in_timerange_future(self):
22
21
  test_time = datetime(2102, 11, 5, 7, 30)
23
22
  self.assertFalse(self.dwd_weather.is_in_timerange(test_time))
23
+
24
+ def test_is_in_timerange_day(self):
25
+ test_time = datetime(2020, 11, 6, 0, 0)
26
+ self.assertTrue(self.dwd_weather.is_in_timerange_day(test_time))
27
+
28
+ def test_is_in_timerange_day_past(self):
29
+ test_time = datetime(2000, 11, 5, 17, 30)
30
+ self.assertFalse(self.dwd_weather.is_in_timerange(test_time))
31
+
32
+ def test_is_in_timerange_day_future(self):
33
+ test_time = datetime(2102, 11, 5, 7, 30)
34
+ self.assertFalse(self.dwd_weather.is_in_timerange(test_time))
@@ -6,8 +6,7 @@ from dummy_data import parsed_data
6
6
  class Weather_is_valid_timeframe(unittest.TestCase):
7
7
  def setUp(self):
8
8
  self.dwd_weather = dwdforecast.Weather("H889")
9
- self.dwd_weather.forecast_data = parsed_data
10
- self.dwd_weather.station_name = "BAD HOMBURG"
9
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
11
10
 
12
11
  def test_is_day(self):
13
12
  self.assertTrue(self.dwd_weather.is_valid_timeframe(24))
@@ -25,4 +24,4 @@ class Weather_is_valid_timeframe(unittest.TestCase):
25
24
  self.assertFalse(self.dwd_weather.is_valid_timeframe(0))
26
25
 
27
26
  def test_is_negative(self):
28
- self.assertFalse(self.dwd_weather.is_valid_timeframe(-5))
27
+ self.assertFalse(self.dwd_weather.is_valid_timeframe(-5))
tests/test_station.py CHANGED
@@ -17,7 +17,7 @@ class StationTestCase(unittest.TestCase):
17
17
 
18
18
  def test_is_valid_station_id_empty_string(self):
19
19
  self.assertFalse(dwdforecast.load_station_id(""))
20
- self.assertFalse(dwdforecast.load_station_id(1))
20
+ self.assertFalse(dwdforecast.load_station_id("1"))
21
21
 
22
22
  def test_get_station_by_name(self):
23
- self.assertEqual(dwdforecast.get_station_by_name("Ulm")[0], "10838")
23
+ self.assertEqual(dwdforecast.get_station_by_name("Ulm")[0], "10838") # type: ignore
tests/test_update.py CHANGED
@@ -9,8 +9,7 @@ import time
9
9
  class WeatherUpdate(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  @patch(
16
15
  "simple_dwd_weatherforecast.dwdforecast.Weather.download_latest_report",
@@ -2,15 +2,14 @@ import unittest
2
2
  from unittest.mock import patch
3
3
  from simple_dwd_weatherforecast import dwdforecast
4
4
  from dummy_data import parsed_data
5
- from datetime import datetime, timezone, timedelta
5
+ from datetime import datetime, timezone
6
6
  import time
7
7
 
8
8
 
9
9
  class WeatherUpdate(unittest.TestCase):
10
10
  def setUp(self):
11
11
  self.dwd_weather = dwdforecast.Weather("H889")
12
- self.dwd_weather.forecast_data = parsed_data
13
- self.dwd_weather.station_name = "BAD HOMBURG"
12
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
14
13
 
15
14
  def test_download(self):
16
15
  self.dwd_weather.update(force_hourly=True)
tests/test_weather.py CHANGED
@@ -6,8 +6,7 @@ from dummy_data import parsed_data
6
6
  class WeatherInit(unittest.TestCase):
7
7
  def setUp(self):
8
8
  self.dwd_weather = dwdforecast.Weather("L821")
9
- self.dwd_weather.forecast_data = parsed_data
10
- self.dwd_weather.station_name = "BAD HOMBURG"
9
+ self.dwd_weather.forecast_data = parsed_data # type: ignore
11
10
 
12
11
  def test_init_with_wrong_id(self):
13
12
  with self.assertRaises(ValueError) as _:
@@ -19,7 +18,7 @@ class WeatherInit(unittest.TestCase):
19
18
 
20
19
  def test_init_with_no_id(self):
21
20
  with self.assertRaises(TypeError) as _:
22
- dwdforecast.Weather()
21
+ dwdforecast.Weather() # type: ignore
23
22
 
24
23
  def test_uv_index(self):
25
24
  self.assertEqual(self.dwd_weather.nearest_uv_index_station, "10637")
@@ -1,41 +0,0 @@
1
- simple_dwd_weatherforecast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- simple_dwd_weatherforecast/dwdforecast.py,sha256=ZTKS32lRedjzNucZHZ0w9bBuzJd3--EibU9wG6Au_M4,35282
3
- simple_dwd_weatherforecast/dwdmap.py,sha256=bFAZfYjUryZkErJ3aDNRm9ZhNwKGMcy4pEl8TnWJKzA,2476
4
- simple_dwd_weatherforecast/stations.json,sha256=1u8qc2CT_rVy49SAlOicGixzHln6Y0FXevuFAz2maBw,838948
5
- simple_dwd_weatherforecast/uv_stations.json,sha256=ADenYo-aR6qbf0UFkfYr72kkFzL9HyUKe4VQ23POGF8,2292
6
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- tests/dummy_data.py,sha256=sF8pXxq8innSpRc4lW0XxGcr34dESSAoBdAf2F2D4AI,63395
8
- tests/dummy_data_full.py,sha256=IwYoeqVX8cpfn_gE-7arXaWV9btRm_HHqka_LfKqW-E,64053
9
- tests/dummy_uv.py,sha256=TM1TwvNq_ea4WgIJyYsNAEXZJTx1dXH1ZVrW_LfLBLg,4548
10
- tests/test_get_daily_condition.py,sha256=J_0gg9fejPqESP7Np5wl5kr7wwcm04a-G1Txx4JH02g,2043
11
- tests/test_get_daily_max.py,sha256=vC873a1Uuw01a61fkvV0XKwTnkxJWkrOycTOSLrOp9Q,1940
12
- tests/test_get_daily_min.py,sha256=jYgPK-dK7P_QRBe1oNlSSZlnd-BrTDXGt5AfS-sEThw,1944
13
- tests/test_get_daily_sum.py,sha256=WeOVXl905X-n5gnPuNM6ut-q9VeBM2j2f6heBDol3Ok,1942
14
- tests/test_get_day_values.py,sha256=zn9GaLnsLA_rvk6pNApmR9ZHD_OsElU01T6oFJiqL7I,28680
15
- tests/test_get_forecast_condition.py,sha256=mawVIJ7xQgH9Xbz_nLnAHNS5Ib-mp-A3zLbkEllw2hw,2904
16
- tests/test_get_forecast_data.py,sha256=dsKtfGTlQbhB7tteBuB6d_RHEOtM7ikfVWh_Fk-CtyU,3432
17
- tests/test_get_station_name.py,sha256=58fBETHAgDaTAsAFP9xOcYfipNO-AqUf_n_bMj5FwWc,439
18
- tests/test_get_timeframe_avg.py,sha256=Ye22DDmNBQB1uDUHz3r92zA-9ItTZiPxNwsLHoNfc0g,2463
19
- tests/test_get_timeframe_condition.py,sha256=scalL3W4Ts1epuqsdyBDoN0NG85dj2wYH8zzr2T7ld8,3276
20
- tests/test_get_timeframe_max.py,sha256=AM4arB06XRymq3cSCUPeT9f-MtejuMjZkgzM0NCVfrs,2445
21
- tests/test_get_timeframe_min.py,sha256=dLkPfOSfQaEXiw1AAmXTjhaqTEu7-s1Gj_KI5Jmqvbo,2445
22
- tests/test_get_timeframe_sum.py,sha256=3jzxUwFvqkEmVRCZc_3_5Piu05pDbxDdcCNTZWD8x0Y,2462
23
- tests/test_get_timeframe_values.py,sha256=qcS-gWD4D3zF3lYBuhULlM28NfAISnHFSYjdVVhNBq8,6929
24
- tests/test_is_in_timerange.py,sha256=Zy8YwO_O272IwjdrGKfqARw5EPnIdhZM5e648bBXaWQ,870
25
- tests/test_is_valid_timeframe.py,sha256=lmQTapM6BztqFEgei-JTuuETq5ZhscPzxqT2Y2_u3Ak,928
26
- tests/test_location_tools.py,sha256=wto_XzVnARJQ-Qc83YAn0ahfMBSaOHpfzqAeKRDsNm8,1208
27
- tests/test_map.py,sha256=Bnf7XSap7xAfozE5U9aB0GjjMiHmXrpyJPE79VmEvFg,830
28
- tests/test_parsekml.py,sha256=Y0EHJi5e8lqFUS8N9yfA5ByQkKV4-iyrwUaIipQpM7w,1065
29
- tests/test_region.py,sha256=ReUB9Cy9roBemkpEkTjZZav-Mu3Ha7ADOAfa9J-gi80,877
30
- tests/test_reported_weather.py,sha256=ULg4ogZRxus01p2rdxiSFL75AisqtcvnLDOc7uJMBH0,767
31
- tests/test_station.py,sha256=Ug5honzk2WuVjOJsfatan-3UDDrAxbsM72nFm3rmCdQ,1008
32
- tests/test_stationsfile.py,sha256=slRH5N4Gznr6tkN2oMFWJbVCw3Xrma7Hvzn1lG5E-Qg,1401
33
- tests/test_update.py,sha256=JMdlN_lc9Zb58yU4GNrO_sOaKN9pZEx8nt4E2UeKBi0,7254
34
- tests/test_update_hourly.py,sha256=Zx0e_E2n2Wi1yGMDN6TURzIbk_xVYaMc-7IDK1sC5UY,1668
35
- tests/test_uv_index.py,sha256=tr6wnOyHlXT1S3yp1oeHc4-Brmc-EMEdM4mtyrdpcHg,579
36
- tests/test_weather.py,sha256=U4FkTtqLcLs8k-xy6YKNM_4HVscITymURCEIUShk6iE,802
37
- simple_dwd_weatherforecast-2.0.31.dist-info/LICENCE,sha256=27UG7gteqvSWuZlsbIq2_OAbh7VyifGGl-1zpuUoBcw,1072
38
- simple_dwd_weatherforecast-2.0.31.dist-info/METADATA,sha256=qVASoG2VqxxpKIKQ7-6m1yYBVL1nQYu7CqBO_7SgdO4,10800
39
- simple_dwd_weatherforecast-2.0.31.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
40
- simple_dwd_weatherforecast-2.0.31.dist-info/top_level.txt,sha256=iyEobUh14Tzitx39Oi8qm0NhBrnZovl_dNKtvLUkLEM,33
41
- simple_dwd_weatherforecast-2.0.31.dist-info/RECORD,,