weathergrabber 0.0.9a0__tar.gz → 0.0.10__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 (89) hide show
  1. {weathergrabber-0.0.9a0/weathergrabber.egg-info → weathergrabber-0.0.10}/PKG-INFO +1 -1
  2. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/pyproject.toml +1 -1
  3. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/tests/test_core.py +31 -0
  4. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/__init__.py +1 -1
  5. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/search_location_service.py +3 -7
  6. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/usecases/weather_forecast_uc.py +2 -2
  7. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/cli.py +2 -2
  8. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/core.py +9 -1
  9. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/weather_icon_enum.py +1 -0
  10. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10/weathergrabber.egg-info}/PKG-INFO +1 -1
  11. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/LICENSE +0 -0
  12. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/README.md +0 -0
  13. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/setup.cfg +0 -0
  14. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/tests/test_cli.py +0 -0
  15. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/tests/test_cli_version.py +0 -0
  16. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/tests/test_main.py +0 -0
  17. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/__main__.py +0 -0
  18. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/client/weather_api.py +0 -0
  19. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/client/weather_search_api.py +0 -0
  20. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/repository/forecast_repository.py +0 -0
  21. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/tty/console_tty.py +0 -0
  22. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/tty/json_tty.py +0 -0
  23. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/tty/statistics_tty.py +0 -0
  24. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/adapter/tty/waybar_tty.py +0 -0
  25. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_aqi_service.py +0 -0
  26. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_current_conditions_service.py +0 -0
  27. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_daily_forecast_oldstyle_service.py +0 -0
  28. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_daily_forecast_service.py +0 -0
  29. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_health_activities_service.py +0 -0
  30. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_hourly_forecast_oldstyle_service.py +0 -0
  31. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_hourly_forecast_service.py +0 -0
  32. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_temperature_service.py +0 -0
  33. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/extract_today_details_service.py +0 -0
  34. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/read_weather_service.py +0 -0
  35. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/retrieve_forecast_from_cache_service.py +0 -0
  36. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/retrieve_statistics_service.py +0 -0
  37. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/services/save_forecast_to_cache_service.py +0 -0
  38. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/usecases/statistics_uc.py +0 -0
  39. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/application/weathergrabber_application.py +0 -0
  40. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/icon_enum.py +0 -0
  41. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/air_quality_index_mapper.py +0 -0
  42. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/city_location_mapper.py +0 -0
  43. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/color_mapper.py +0 -0
  44. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/current_conditions_mapper.py +0 -0
  45. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/daily_predictions_mapper.py +0 -0
  46. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/day_night_mapper.py +0 -0
  47. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/forecast_mapper.py +0 -0
  48. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/health_activities_mapper.py +0 -0
  49. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/hourly_predictions_mapper.py +0 -0
  50. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/label_value_mapper.py +0 -0
  51. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/moon_phase_mapper.py +0 -0
  52. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/precipitation_mapper.py +0 -0
  53. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/search_mapper.py +0 -0
  54. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/statistics_mapper.py +0 -0
  55. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/sunrise_sunset_mapper.py +0 -0
  56. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/temperature_high_low_mapper.py +0 -0
  57. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/timestamp_mapper.py +0 -0
  58. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/today_details_mapper.py +0 -0
  59. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/uv_index_mapper.py +0 -0
  60. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/weather_icon_enum_mapper.py +0 -0
  61. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/mappers/wind_mapper.py +0 -0
  62. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/output_enum.py +0 -0
  63. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/adapter/params.py +0 -0
  64. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/air_quality_index.py +0 -0
  65. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/city_location.py +0 -0
  66. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/color.py +0 -0
  67. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/current_conditions.py +0 -0
  68. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/daily_predictions.py +0 -0
  69. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/day_night.py +0 -0
  70. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/forecast.py +0 -0
  71. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/health_activities.py +0 -0
  72. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/hourly_predictions.py +0 -0
  73. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/label_value.py +0 -0
  74. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/moon_phase.py +0 -0
  75. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/moon_phase_enum.py +0 -0
  76. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/precipitation.py +0 -0
  77. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/search.py +0 -0
  78. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/statistics.py +0 -0
  79. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/sunrise_sunset.py +0 -0
  80. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/temperature_hight_low.py +0 -0
  81. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/timestamp.py +0 -0
  82. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/today_details.py +0 -0
  83. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/uv_index.py +0 -0
  84. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber/domain/entities/wind.py +0 -0
  85. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber.egg-info/SOURCES.txt +0 -0
  86. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber.egg-info/dependency_links.txt +0 -0
  87. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber.egg-info/entry_points.txt +0 -0
  88. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/weathergrabber.egg-info/requires.txt +0 -0
  89. {weathergrabber-0.0.9a0 → weathergrabber-0.0.10}/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.9a0
3
+ Version: 0.0.10
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.9a"
3
+ version = "0.0.10"
4
4
  description = "A grabber for weather.com data with various output formats."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -45,3 +45,34 @@ def test_main_sets_log_level(mock_app):
45
45
  cache_statistics=False,
46
46
  )
47
47
  assert logging.getLogger().level == logging.DEBUG
48
+
49
+
50
+ @pytest.mark.parametrize("log_level, expect_trace", [
51
+ ("debug", True),
52
+ ("info", False),
53
+ ])
54
+ @patch('weathergrabber.core.WeatherGrabberApplication')
55
+ def test_main_logs_stack_trace_conditionally(mock_app, caplog, log_level, expect_trace):
56
+ mock_app.side_effect = RuntimeError("boom")
57
+ from weathergrabber.core import main
58
+
59
+ caplog.set_level(logging.DEBUG)
60
+
61
+ with pytest.raises(SystemExit) as excinfo:
62
+ main(
63
+ log_level=log_level,
64
+ location_name='Berlin',
65
+ location_id='789',
66
+ lang='de-DE',
67
+ output='console',
68
+ keep_open=False,
69
+ icons='emoji',
70
+ force_cache=False,
71
+ cache_statistics=False,
72
+ )
73
+
74
+ assert excinfo.value.code == 1
75
+
76
+ error_records = [r for r in caplog.records if r.levelno >= logging.ERROR]
77
+ assert error_records, "Expected at least one error log record"
78
+ assert any(rec.exc_info for rec in error_records) == expect_trace
@@ -4,7 +4,7 @@ from .core import main
4
4
  from .cli import main_cli
5
5
 
6
6
  __all__ = ["main", "main_cli"]
7
- __version__ = "0.0.9a"
7
+ __version__ = "0.0.10"
8
8
 
9
9
  def get_version():
10
10
  return __version__
@@ -13,13 +13,9 @@ class SearchLocationService:
13
13
  if not location_name:
14
14
  self.logger.debug("No location name provided. Bypassing search.")
15
15
  return None
16
+ data = self.api.search(location_name, lang)
16
17
 
17
18
  try:
18
- data = self.api.search(location_name, lang)
19
- if not data:
20
- self.logger.error(f"No data found for location: {location_name}")
21
- raise ValueError(f"Location '{location_name}' not found.")
22
-
23
19
  dal = data["dal"]["getSunV3LocationSearchUrlConfig"]
24
20
 
25
21
  # Pick the first (arbitrary) key, then get the value
@@ -29,7 +25,7 @@ class SearchLocationService:
29
25
  self.logger.debug(f"Found location ID: {location_id} for location name: {location_name}")
30
26
 
31
27
  return location_id
32
- except Exception as e:
33
- self.logger.error(f"Error searching for location '{location_name}': {e}")
28
+ except KeyError as e:
29
+ self.logger.debug(f"Error searching for location '{location_name}': {e}")
34
30
  raise ValueError(f"Could not find location '{location_name}'.")
35
31
 
@@ -68,10 +68,10 @@ class WeatherForecastUC:
68
68
 
69
69
  try:
70
70
  location_id = self._resolve_location_id(params)
71
+ weather_data = self.read_weather_service.execute(params.language, location_id)
71
72
  except ConnectionError as e:
73
+ self.logger.debug("A connection error occurred while fetching weather data. Trying to retrieve from cache.")
72
74
  return self.retrieve_forecast_from_cache_service.execute(params)
73
-
74
- weather_data = self.read_weather_service.execute(params.language, location_id)
75
75
 
76
76
  current_conditions = self.extract_current_conditions_service.execute(weather_data)
77
77
  today_details = self.extract_today_details_service.execute(weather_data)
@@ -16,9 +16,9 @@ def main_cli():
16
16
  parser.add_argument("--version", "-v", action='version', version=f'Weathergrabber {weathergrabber.get_version()}', help="Show version and exit")
17
17
  parser.add_argument(
18
18
  "--log",
19
- default="critical",
19
+ default="ERROR",
20
20
  choices=["debug", "info", "warning", "error", "critical", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
21
- help="Set the logging level (default: CRITICAL)"
21
+ help="Set the logging level (default: ERROR)"
22
22
  )
23
23
  args = parser.parse_args()
24
24
 
@@ -32,4 +32,12 @@ def main(log_level: str, location_name: str, location_id: str, lang: str, output
32
32
  cache_statistics=cache_statistics,
33
33
  )
34
34
 
35
- app = WeatherGrabberApplication(params)
35
+ try:
36
+ app = WeatherGrabberApplication(params)
37
+ except Exception as e:
38
+ logger = logging.getLogger()
39
+ if logger.level == logging.DEBUG:
40
+ logger.error(f"{e}", exc_info=True)
41
+ else:
42
+ logger.error(f"{e}")
43
+ raise SystemExit(1)
@@ -47,6 +47,7 @@ class WeatherIconEnum(Enum):
47
47
  # Suggestions from Copilot
48
48
  BLIZZARD = ('blizzard', '\u2744', '🌨️')
49
49
  DUST = ('dust', '\uf063', '🌪️')
50
+ BLOWING_DUST_SANDSTORM = ('blowing-dust-sandstorm', '\uf063', '🌪️')
50
51
  FLURRIES = ('flurries', '\u2744', '🌨️')
51
52
  FREEZING_DRIZZLE = ('freezing-drizzle', '\uf0e9', '🌧️')
52
53
  FREEZING_DRIZZLE_RAIN = ('freezing-drizzle-rain', '\uf0e9', '🌧️')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weathergrabber
3
- Version: 0.0.9a0
3
+ Version: 0.0.10
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