weathergrabber 0.0.7a3__tar.gz → 0.0.8a5__tar.gz

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.
Files changed (81) hide show
  1. {weathergrabber-0.0.7a3/weathergrabber.egg-info → weathergrabber-0.0.8a5}/PKG-INFO +1 -1
  2. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/pyproject.toml +1 -1
  3. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/__init__.py +1 -1
  4. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/adapter/tty/console_tty.py +41 -10
  5. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/adapter/tty/waybar_tty.py +40 -11
  6. weathergrabber-0.0.8a5/weathergrabber/domain/city_location.py +71 -0
  7. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/moon_phase_enum.py +3 -3
  8. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/weather_icon_enum.py +4 -0
  9. weathergrabber-0.0.8a5/weathergrabber/service/extract_current_conditions_service.py +42 -0
  10. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5/weathergrabber.egg-info}/PKG-INFO +1 -1
  11. weathergrabber-0.0.7a3/weathergrabber/domain/city_location.py +0 -37
  12. weathergrabber-0.0.7a3/weathergrabber/service/extract_current_conditions_service.py +0 -47
  13. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/LICENSE +0 -0
  14. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/README.md +0 -0
  15. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/setup.cfg +0 -0
  16. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/tests/test_cli.py +0 -0
  17. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/tests/test_core.py +0 -0
  18. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/__main__.py +0 -0
  19. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/adapter/client/weather_api.py +0 -0
  20. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/adapter/client/weather_search_api.py +0 -0
  21. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/adapter/tty/json_tty.py +0 -0
  22. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/cli.py +0 -0
  23. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/core.py +0 -0
  24. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/icon_enum.py +0 -0
  25. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/air_quality_index_mapper.py +0 -0
  26. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/city_location_mapper.py +0 -0
  27. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/color_mapper.py +0 -0
  28. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/current_conditions_mapper.py +0 -0
  29. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/daily_predictions_mapper.py +0 -0
  30. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/day_night_mapper.py +0 -0
  31. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/forecast_mapper.py +0 -0
  32. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/health_activities_mapper.py +0 -0
  33. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/hourly_predictions_mapper.py +0 -0
  34. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/label_value_mapper.py +0 -0
  35. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/moon_phase_mapper.py +0 -0
  36. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/precipitation_mapper.py +0 -0
  37. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/search_mapper.py +0 -0
  38. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/sunrise_sunset_mapper.py +0 -0
  39. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/temperature_high_low_mapper.py +0 -0
  40. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/timestamp_mapper.py +0 -0
  41. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/today_details_mapper.py +0 -0
  42. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/uv_index_mapper.py +0 -0
  43. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/weather_icon_enum_mapper.py +0 -0
  44. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/mapper/wind_mapper.py +0 -0
  45. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/output_enum.py +0 -0
  46. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/adapter/params.py +0 -0
  47. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/air_quality_index.py +0 -0
  48. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/color.py +0 -0
  49. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/current_conditions.py +0 -0
  50. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/daily_predictions.py +0 -0
  51. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/day_night.py +0 -0
  52. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/forecast.py +0 -0
  53. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/health_activities.py +0 -0
  54. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/hourly_predictions.py +0 -0
  55. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/label_value.py +0 -0
  56. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/moon_phase.py +0 -0
  57. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/precipitation.py +0 -0
  58. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/search.py +0 -0
  59. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/sunrise_sunset.py +0 -0
  60. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/temperature_hight_low.py +0 -0
  61. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/timestamp.py +0 -0
  62. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/today_details.py +0 -0
  63. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/uv_index.py +0 -0
  64. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/domain/wind.py +0 -0
  65. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_aqi_service.py +0 -0
  66. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_daily_forecast_oldstyle_service.py +0 -0
  67. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_daily_forecast_service.py +0 -0
  68. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_health_activities_service.py +0 -0
  69. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_hourly_forecast_oldstyle_service.py +0 -0
  70. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_hourly_forecast_service.py +0 -0
  71. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_temperature_service.py +0 -0
  72. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/extract_today_details_service.py +0 -0
  73. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/read_weather_service.py +0 -0
  74. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/service/search_location_service.py +0 -0
  75. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/usecase/use_case.py +0 -0
  76. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber/weathergrabber_application.py +0 -0
  77. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber.egg-info/SOURCES.txt +0 -0
  78. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber.egg-info/dependency_links.txt +0 -0
  79. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber.egg-info/entry_points.txt +0 -0
  80. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber.egg-info/requires.txt +0 -0
  81. {weathergrabber-0.0.7a3 → weathergrabber-0.0.8a5}/weathergrabber.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weathergrabber
3
- Version: 0.0.7a3
3
+ Version: 0.0.8a5
4
4
  Summary: A grabber for weather.com data with various output formats.
5
5
  Author-email: Carlos Anselmo Mendes Junior <cjuniorfox@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "weathergrabber"
3
- version = "0.0.7a3"
3
+ version = "0.0.8a5"
4
4
  description = "A grabber for weather.com data with various output formats."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -4,4 +4,4 @@ from .core import main
4
4
  from .cli import main_cli
5
5
 
6
6
  __all__ = ["main", "main_cli"]
7
- __version__ = "0.1.0"
7
+ __version__ = "0.0.8a5"
@@ -21,8 +21,7 @@ class ConsoleTTY:
21
21
 
22
22
  rain_icon = WeatherIconEnum.RAIN.fa_icon if is_fa else WeatherIconEnum.RAIN.emoji_icon
23
23
 
24
- city = forecast.current_conditions.location.city
25
- state_province = forecast.current_conditions.location.state_province
24
+ city_location = forecast.current_conditions.location
26
25
  icon = forecast.current_conditions.icon.fa_icon if is_fa else forecast.current_conditions.icon.emoji_icon
27
26
  temperature = forecast.current_conditions.temperature
28
27
 
@@ -62,18 +61,48 @@ class ConsoleTTY:
62
61
  aqi_acronym = forecast.air_quality_index.acronym
63
62
  aqi_value = forecast.air_quality_index.value
64
63
 
64
+ hourly_predictions_format = [
65
+ {
66
+ 'title': h.title if len(h.title) < 8 else h.title[:6] + '.',
67
+ 'temperature' : h.temperature,
68
+ 'icon': h.icon.fa_icon if is_fa else h.icon.emoji_icon,
69
+ 'precipitation': f"{h.precipitation.percentage if h.precipitation.percentage else ''}"
70
+ } for h in forecast.hourly_predictions
71
+ ]
72
+
73
+ daily_predictions_format = [
74
+ {
75
+ 'title': d.title if len(d.title) < 8 else d.title[:6] + '.',
76
+ 'high_low': f"{d.high_low}",
77
+ 'icon': d.icon.fa_icon if is_fa else d.icon.emoji_icon,
78
+ 'precipitation': f"{d.precipitation.percentage}"
79
+ } for d in forecast.daily_predictions
80
+ ]
81
+
82
+ # Hourly predictions and daily predictions
65
83
  hourly_predictions = [
66
- f"{h.title}\t{h.temperature}\t{h.icon.fa_icon if is_fa else h.icon.emoji_icon}\t{rain_icon if h.precipitation.percentage else ''} {h.precipitation.percentage}"
67
- for h in forecast.hourly_predictions
84
+ f"{h['title']}"
85
+ f"{'\t' if len(h['title']) < 3 else ''}\t"
86
+ f"{h['temperature']}"
87
+ "\t"
88
+ f"{h['icon']}\t"
89
+ f"{rain_icon} {h['precipitation']}"
90
+ for h in hourly_predictions_format
68
91
  ]
92
+
69
93
  daily_predictions = [
70
- f"{d.title}\t{d.high_low}\t{d.icon.fa_icon if is_fa else d.icon.emoji_icon}\t{rain_icon} {d.precipitation.percentage}"
71
- for d in forecast.daily_predictions
94
+ f"{d['title']}"
95
+ f"{'\t' if len(d['title']) < 3 else ''}\t"
96
+ f"{d['high_low']}"
97
+ f"\t"
98
+ f"{d['icon']}\t"
99
+ f"{rain_icon} {d['precipitation']}"
100
+ for d in daily_predictions_format
72
101
  ]
73
102
 
74
103
  print_value = (
75
104
  "\n"
76
- f"{city}, {state_province}\n"
105
+ f"{city_location}\n"
77
106
  "\n"
78
107
  f"{icon} {temperature}\n"
79
108
  "\n"
@@ -84,9 +113,11 @@ class ConsoleTTY:
84
113
  "\n"
85
114
  f"{moon_icon} {moon_phase}\n"
86
115
  "\n"
87
- f"{wind_icon} {wind}\t {uv_index}\n"
88
- f"{humidity_icon} {humidity}\t\t {pressure}\n"
89
- f"{visibility_icon} {visibility}\t {aqi_acronym} {aqi_category} {aqi_value}\n"
116
+ f"{wind_icon} {wind}\t{uv_index}\n"
117
+ f"{humidity_icon} {humidity}\t\t{pressure}\n"
118
+ f"{visibility_icon} {visibility}"
119
+ f"\t{'\t' if len(visibility) < 6 else ''}"
120
+ f"{aqi_acronym} {aqi_category} {aqi_value}\n"
90
121
  "\n"
91
122
  f"{'\n'.join(hourly_predictions)}\n"
92
123
  "\n"
@@ -21,10 +21,11 @@ class WaybarTTY:
21
21
  # Forecast icon and temperature
22
22
  icon = forecast.current_conditions.icon.fa_icon if is_fa else forecast.current_conditions.icon.emoji_icon
23
23
  temperature = forecast.current_conditions.temperature
24
+ rain_icon = WeatherIconEnum.RAIN.fa_icon if is_fa else WeatherIconEnum.RAIN.emoji_icon
25
+
24
26
 
25
27
  # City and state/province
26
- city = forecast.current_conditions.location.city
27
- state_province = forecast.current_conditions.location.state_province
28
+ city_location = forecast.current_conditions.location
28
29
 
29
30
  # Summary
30
31
  summary = forecast.current_conditions.summary
@@ -65,19 +66,45 @@ class WaybarTTY:
65
66
  aqi_acronym = forecast.air_quality_index.acronym
66
67
  aqi_value = forecast.air_quality_index.value
67
68
 
69
+ hourly_predictions_format = [{
70
+ 'title': h.title if len(h.title) < 10 else h.title[:9] + '.',
71
+ 'temperature' : h.temperature,
72
+ 'icon': h.icon.fa_icon if is_fa else h.icon.emoji_icon,
73
+ 'precipitation': f"{h.precipitation.percentage if h.precipitation.percentage else ''}"
74
+ } for h in forecast.hourly_predictions]
75
+
76
+ daily_predictions_format = [
77
+ {
78
+ 'title': d.title if len(d.title) < 10 else d.title[:9] + '.',
79
+ 'high_low': f"{d.high_low.high}/<span size='small'>{d.high_low.low}</span>",
80
+ 'icon': d.icon.fa_icon if is_fa else d.icon.emoji_icon,
81
+ 'precipitation': f"{d.precipitation.percentage}"
82
+ } for d in forecast.daily_predictions
83
+ ]
84
+
68
85
  # Hourly predictions and daily predictions
69
- rain_icon = WeatherIconEnum.RAIN.fa_icon if is_fa else WeatherIconEnum.RAIN.emoji_icon
70
86
  hourly_predictions = [
71
- f"{h.title}{'\t' if len(h.title) < 5 else ''}\t{h.temperature}\t\t{h.icon.fa_icon if is_fa else h.icon.emoji_icon}\t{rain_icon if h.precipitation.percentage else ''} {h.precipitation.percentage}"
72
- for h in forecast.hourly_predictions
87
+ f"{h['title']}"
88
+ f"{'\t\t' if len(h['title']) < 4 else '\t'}"
89
+ f"{h['temperature']}"
90
+ "\t\t"
91
+ f"{h['icon']}\t"
92
+ f"{rain_icon} {h['precipitation']}"
93
+ for h in hourly_predictions_format
73
94
  ]
95
+
74
96
  daily_predictions = [
75
- f"{d.title}{'\t' if len(d.title) < 5 else ''}\t{d.high_low.high}/<span size='small'>{d.high_low.low}</span>\t{'\t' if len(d.title) < 5 else ''}{d.icon.fa_icon if is_fa else d.icon.emoji_icon}\t{rain_icon} {d.precipitation.percentage}"
76
- for d in forecast.daily_predictions
97
+ f"{d['title']}"
98
+ f"\t{'\t' if len(d['title']) < 6 else ' '}"
99
+ f"{d['high_low']}"
100
+ f"\t{'\t' if len(d['high_low']) < 33 else ''}"
101
+ f"{d['icon']}\t"
102
+ f"{rain_icon} {d['precipitation']}"
103
+ for d in daily_predictions_format
77
104
  ]
78
105
 
79
106
  tooltip = (
80
- f"{city}, {state_province}\n"
107
+ f"{city_location}\n"
81
108
  "\n"
82
109
  f"<span size='xx-large'>{icon}\t\t{temperature}</span>\n"
83
110
  "\n"
@@ -89,9 +116,11 @@ class WaybarTTY:
89
116
  "\n"
90
117
  f"{moon_icon} {moon_phase}\n"
91
118
  "\n"
92
- f"{wind_icon} {wind}\t {uv_index}\n"
93
- f"{humidity_icon} {humidity}\t\t {pressure}\n"
94
- f"{visibility_icon} {visibility}\t {aqi_acronym} {aqi_category} {aqi_value}\n"
119
+ f"{wind_icon} {wind}\t"
120
+ f"{'\t' if len(wind) < 6 else ''}"
121
+ f"{uv_index}\n"
122
+ f"{humidity_icon} {humidity}\t\t{pressure}\n"
123
+ f"{visibility_icon} {visibility}\t{aqi_acronym} {aqi_category} {aqi_value}\n"
95
124
  "\n"
96
125
  f"{'\n'.join(hourly_predictions)}\n"
97
126
  "\n"
@@ -0,0 +1,71 @@
1
+ class CityLocation:
2
+
3
+ def __init__(self, city: str, state_province: str = None, country: str = None, location = None):
4
+ self._city = city
5
+ self._state_province = state_province
6
+ self._country = country
7
+ self._location = location
8
+
9
+ @property
10
+ def city(self) -> str:
11
+ return self._city
12
+
13
+ @property
14
+ def state_province(self) -> str:
15
+ return self._state_province
16
+
17
+ @property
18
+ def country(self) -> str:
19
+ return self._country
20
+
21
+ @property
22
+ def location(self):
23
+ return self._location
24
+
25
+ def __repr__(self):
26
+ return f"CityLocation(city={self.city}, state_province={self.state_province}, country={self.country}, location={self.location})"
27
+
28
+ def __str__(self):
29
+ parts = []
30
+ if self.location:
31
+ parts.append(self.location)
32
+ if self.city:
33
+ parts.append(self.city)
34
+ if self.state_province:
35
+ parts.append(self.state_province)
36
+ if self.country:
37
+ parts.append(self.country)
38
+ return ", ".join(parts) if parts else "Unknown Location"
39
+
40
+ @classmethod
41
+ def from_string(cls, data: str) -> "CityLocation":
42
+ #'Nova Friburgo, Rio de Janeiro, Brazil'
43
+ #'Macuco, Santos, São Paulo, Brésil'
44
+ #'New York, NY, USA'
45
+ #'Tokyo, Tokyo Prefecture, Japan'
46
+ country, state_province, city, location = None, None, None, None
47
+ parts = data.split(", ")
48
+
49
+ if len(parts) > 2:
50
+ i = len(parts) - 1
51
+ while i > 0:
52
+ if not country:
53
+ country = parts[i]
54
+ elif not state_province:
55
+ state_province = parts[i]
56
+ elif not city:
57
+ city = parts[i]
58
+ i -= 1
59
+ # Location is the first registry. If it's different from city, use it.
60
+ if city != parts[0]:
61
+ location = parts[0]
62
+ return cls(city=city, state_province=state_province, country=country, location=location)
63
+
64
+ if len(parts) == 2:
65
+ city, state_province = parts
66
+ return cls(city=city, state_province=state_province)
67
+ elif len(parts) == 1:
68
+ city = parts[0]
69
+ return cls(city=city)
70
+ else:
71
+ raise ValueError("Invalid city location string format")
@@ -18,12 +18,12 @@ class MoonPhaseEnum(Enum):
18
18
  PHASE_10 = ("phase-10", "\uf186", "🌔")
19
19
  PHASE_11 = ("phase-11", "\uf186", "🌔")
20
20
  PHASE_12 = ("phase-12", "\uf186", "🌔")
21
- PHASE_13 = ("phase-13", "\uf186", "🌔")
21
+ PHASE_13 = ("phase-13", "\uf186", "🌕")
22
22
  # Full Moon
23
23
  PHASE_14 = ("phase-14", "\uf186", "🌕")
24
24
  # Waning Gibbous
25
- PHASE_15 = ("phase-15", "\uf186", "🌖")
26
- PHASE_16 = ("phase-16", "\uf186", "🌖")
25
+ PHASE_15 = ("phase-15", "\uf186", "🌕")
26
+ PHASE_16 = ("phase-16", "\uf186", "🌕")
27
27
  PHASE_17 = ("phase-17", "\uf186", "🌖")
28
28
  PHASE_18 = ("phase-18", "\uf186", "🌖")
29
29
  PHASE_19 = ("phase-19", "\uf186", "🌖")
@@ -11,6 +11,7 @@ class WeatherIconEnum(Enum):
11
11
  FEEL = ('feel', '\uf2c9', '🥵')
12
12
  FOGGY = ('foggy', '\uf74e', '🌫️')
13
13
  HUMIDITY = ('humidity', '\uf043', '💧')
14
+ ISOLATED_THUNDERSTORMS = ('isolated-thunderstorms', chr(0x26C8), '⛈️')
14
15
  MOSTLY_CLEAR_DAY = ('mostly-clear-day', chr(0xF0599), '☀️')
15
16
  MOSTLY_CLEAR_NIGHT = ('mostly-clear-night', chr(0xF0594), '🌙')
16
17
  MOSTLY_CLOUDY_DAY = ('mostly-cloudy-day', chr(0xf013), '☁️')
@@ -19,8 +20,10 @@ class WeatherIconEnum(Enum):
19
20
  PARTLY_CLOUDY_DAY = ('partly-cloudy-day', chr(0xF0595), '⛅')
20
21
  PARTLY_CLOUDY_NIGHT = ('partly-cloudy-night', chr(0xF0F31), '☁️')
21
22
  RAIN = ('rain', '\uf0e9', '🌧️')
23
+ RAIN_SHOW_WINTERY_MIX = ('rain-snow-wintery-mix', '\u26c6', '🌨️')
22
24
  RAINY_DAY = ('rainy-day', chr(0x1F326), '🌧️')
23
25
  RAINY_NIGHT = ('rainy-night', chr(0x1F326), '🌧️')
26
+ SCATTERED_SNOW_SHOWERS_NIGHT = ('scattered-snow-showers-night', '\u26c6', '🌨️')
24
27
  SCATTERED_SHOWERS_DAY = ('scattered-showers-day', chr(0x1F326), '🌦️')
25
28
  SCATTERED_SHOWERS_NIGHT = ('scattered-showers-night', chr(0x1F326), '🌦️')
26
29
  SCATTERED_THUNDERSTORMS_DAY = ('scattered-thunderstorms-day', chr(0x26C8), '⛈️')
@@ -30,6 +33,7 @@ class WeatherIconEnum(Enum):
30
33
  SNOW = ('snow', '\uf2dc', '❄️')
31
34
  SNOWY_ICY_DAY = ('snowy-icy-day', '\uf2dc', '❄️')
32
35
  SNOWY_ICY_NIGHT = ('snowy-icy-night', '\uf2dc', '❄️')
36
+ SNOW_SHOWERS = ('snow-showers', '\u26c6', '🌨️')
33
37
  SUNNY = ('sunny', chr(0xF0599), '☀️')
34
38
  SUNRISE = ('sunrise', '\ue34c', '🌅')
35
39
  SUNSET = ('sunset', '\ue34d', '🌇')
@@ -0,0 +1,42 @@
1
+ import logging
2
+ from pyquery import PyQuery
3
+ from weathergrabber.domain.weather_icon_enum import WeatherIconEnum
4
+ from weathergrabber.domain.city_location import CityLocation
5
+ from weathergrabber.domain.timestamp import Timestamp
6
+ from weathergrabber.domain.day_night import DayNight
7
+ from weathergrabber.domain.current_conditions import CurrentConditions
8
+
9
+ class ExtractCurrentConditionsService:
10
+ def __init__(self):
11
+ self.logger = logging.getLogger(__name__)
12
+ pass
13
+
14
+ def execute(self, weather_data: PyQuery) -> dict:
15
+ self.logger.debug("Extracting Current Conditions")
16
+
17
+ data = PyQuery(weather_data('div[data-testid="CurrentConditionsContainer"]'))
18
+
19
+ city_location_data = data.find('h1').text() #'Nova Friburgo, Rio de Janeiro, Brazil'
20
+ timestamp_data = data.find('span[class*="timestamp"]').text() # 'As of 8:01 pm GMT-03:00'
21
+ icon_data = data.find('svg[class*="wxIcon"]').attr('name') # 'partly-cloudy-night'
22
+ temp_day_night = data.find('div[class*="tempHiLoValue"]').text() #'Day\xa063°\xa0•\xa0Night\xa046°'
23
+
24
+ city_location = CityLocation.from_string(city_location_data)
25
+ timestamp = Timestamp.from_string(timestamp_data)
26
+ temperature = data.find('span[class*="tempValue"]').text() # '48°'
27
+ icon = WeatherIconEnum.from_name(icon_data)
28
+ phrase = data.find('div[data-testid*="wxPhrase"]').text() # 'Partly Cloudy'
29
+ day_night = DayNight.from_string(temp_day_night)
30
+
31
+ current_conditions = CurrentConditions(
32
+ location=city_location,
33
+ timestamp=timestamp,
34
+ temperature=temperature,
35
+ icon=icon,
36
+ summary=phrase,
37
+ day_night=day_night
38
+ )
39
+
40
+ self.logger.debug(f"Extracted current conditions: {current_conditions}")
41
+
42
+ return current_conditions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weathergrabber
3
- Version: 0.0.7a3
3
+ Version: 0.0.8a5
4
4
  Summary: A grabber for weather.com data with various output formats.
5
5
  Author-email: Carlos Anselmo Mendes Junior <cjuniorfox@gmail.com>
6
6
  License: MIT
@@ -1,37 +0,0 @@
1
- class CityLocation:
2
-
3
- def __init__(self, city: str, state_province: str = None, country: str = None):
4
- self._city = city
5
- self._state_province = state_province
6
- self._country = country
7
-
8
- @property
9
- def city(self) -> str:
10
- return self._city
11
-
12
- @property
13
- def state_province(self) -> str:
14
- return self._state_province
15
-
16
- @property
17
- def country(self) -> str:
18
- return self._country
19
-
20
- def __repr__(self):
21
- return f"CityLocation(city={self.city}, state_province={self.state_province}, country={self.country})"
22
-
23
- @classmethod
24
- def from_string(cls, data: str) -> "CityLocation":
25
- #'Nova Friburgo, Rio de Janeiro, Brazil'
26
- parts = data.split(", ")
27
- if len(parts) == 3:
28
- city, state_province, country = parts
29
- return cls(city=city, state_province=state_province, country=country)
30
- if len(parts) == 2:
31
- city, state_province = parts
32
- return cls(city=city, state_province=state_province)
33
- elif len(parts) == 1:
34
- city = parts[0]
35
- return cls(city=city)
36
- else:
37
- raise ValueError("Invalid city location string format")
@@ -1,47 +0,0 @@
1
- import logging
2
- from pyquery import PyQuery
3
- from weathergrabber.domain.weather_icon_enum import WeatherIconEnum
4
- from weathergrabber.domain.city_location import CityLocation
5
- from weathergrabber.domain.timestamp import Timestamp
6
- from weathergrabber.domain.day_night import DayNight
7
- from weathergrabber.domain.current_conditions import CurrentConditions
8
-
9
- class ExtractCurrentConditionsService:
10
- def __init__(self):
11
- self.logger = logging.getLogger(__name__)
12
- pass
13
-
14
- def execute(self, weather_data: PyQuery) -> dict:
15
- try:
16
- self.logger.debug("Extracting Current Conditions")
17
-
18
- data = PyQuery(weather_data('div[data-testid="CurrentConditionsContainer"]'))
19
-
20
- city_location_data = data.find('h1').text() #'Nova Friburgo, Rio de Janeiro, Brazil'
21
- timestamp_data = data.find('span[class*="timestamp"]').text() # 'As of 8:01 pm GMT-03:00'
22
- icon_data = data.find('svg[class*="wxIcon"]').attr('name') # 'partly-cloudy-night'
23
- temp_day_night = data.find('div[class*="tempHiLoValue"]').text() #'Day\xa063°\xa0•\xa0Night\xa046°'
24
-
25
- city_location = CityLocation.from_string(city_location_data)
26
- timestamp = Timestamp.from_string(timestamp_data)
27
- temperature = data.find('span[class*="tempValue"]').text() # '48°'
28
- icon = WeatherIconEnum.from_name(icon_data)
29
- phrase = data.find('div[data-testid*="wxPhrase"]').text() # 'Partly Cloudy'
30
- day_night = DayNight.from_string(temp_day_night)
31
-
32
- current_conditions = CurrentConditions(
33
- location=city_location,
34
- timestamp=timestamp,
35
- temperature=temperature,
36
- icon=icon,
37
- summary=phrase,
38
- day_night=day_night
39
- )
40
-
41
- self.logger.debug(f"Extracted current conditions: {current_conditions}")
42
-
43
- return current_conditions
44
-
45
- except Exception as e:
46
- self.logger.error(f"Error extracting current conditions: {e}")
47
- raise ValueError("Could not extract current conditions") from e