python-google-weather-api 0.0.6__tar.gz → 0.0.7__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 (18) hide show
  1. {python_google_weather_api-0.0.6/src/python_google_weather_api.egg-info → python_google_weather_api-0.0.7}/PKG-INFO +3 -1
  2. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/pyproject.toml +11 -1
  3. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/google_weather_api/api.py +28 -5
  4. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/google_weather_api/exceptions.py +17 -17
  5. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/google_weather_api/model.py +641 -605
  6. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7/src/python_google_weather_api.egg-info}/PKG-INFO +3 -1
  7. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/python_google_weather_api.egg-info/SOURCES.txt +2 -1
  8. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/python_google_weather_api.egg-info/requires.txt +2 -0
  9. python_google_weather_api-0.0.7/tests/test_api.py +269 -0
  10. python_google_weather_api-0.0.7/tests/test_model.py +143 -0
  11. python_google_weather_api-0.0.6/tests/test_api.py +0 -6
  12. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/LICENSE +0 -0
  13. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/README.md +0 -0
  14. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/setup.cfg +0 -0
  15. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/google_weather_api/__init__.py +0 -0
  16. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/google_weather_api/py.typed +0 -0
  17. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/python_google_weather_api.egg-info/dependency_links.txt +0 -0
  18. {python_google_weather_api-0.0.6 → python_google_weather_api-0.0.7}/src/python_google_weather_api.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-google-weather-api
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: A python client library for Google Weather API
5
5
  Author-email: tronikos <tronikos@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -13,6 +13,8 @@ Requires-Dist: aiohttp>=3.8
13
13
  Requires-Dist: mashumaro
14
14
  Provides-Extra: test
15
15
  Requires-Dist: pytest; extra == "test"
16
+ Requires-Dist: pytest-asyncio; extra == "test"
17
+ Requires-Dist: pytest-cov; extra == "test"
16
18
  Dynamic: license-file
17
19
 
18
20
  # python-google-weather-api
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-google-weather-api"
3
- version = "0.0.6"
3
+ version = "0.0.7"
4
4
  license = "Apache-2.0"
5
5
  authors = [
6
6
  { name="tronikos", email="tronikos@gmail.com" },
@@ -16,6 +16,8 @@ dependencies = [
16
16
  [project.optional-dependencies]
17
17
  test = [
18
18
  "pytest",
19
+ "pytest-asyncio",
20
+ "pytest-cov",
19
21
  ]
20
22
 
21
23
 
@@ -27,6 +29,13 @@ test = [
27
29
  requires = ["setuptools"]
28
30
  build-backend = "setuptools.build_meta"
29
31
 
32
+ [tool.pytest.ini_options]
33
+ asyncio_mode = "auto"
34
+ addopts = "--cov=google_weather_api --cov-report=term-missing --cov-fail-under=90"
35
+
36
+ [tool.coverage.run]
37
+ branch = true
38
+
30
39
  [tool.ruff]
31
40
  target-version = "py311"
32
41
  line-length = 127
@@ -64,6 +73,7 @@ ignore = [
64
73
  "D203", # 1 blank line required before class docstring
65
74
  "D213", # Multi-line docstring summary should start at the second line
66
75
  "PLR0913", # Too many arguments in function definition
76
+ "PLR0917", # Too many positional arguments in function definition
67
77
  "PLR1714", # Consider merging multiple comparisons
68
78
  "PLR2004", # Magic value used in comparison
69
79
  "TRY003", # Avoid specifying long messages outside the exception class
@@ -53,11 +53,12 @@ class GoogleWeatherApi:
53
53
  headers[aiohttp.hdrs.REFERER] = self.referrer
54
54
  params = {
55
55
  **params,
56
- "key": self.api_key,
57
56
  "language_code": self.language_code,
58
57
  "units_system": self.units_system,
59
58
  }
59
+ # Log before adding the API key so it doesn't end up in debug logs.
60
60
  _LOGGER.debug("GET %s with params: %s", url, params)
61
+ params["key"] = self.api_key
61
62
  try:
62
63
  async with self.session.get(
63
64
  url,
@@ -87,6 +88,26 @@ class GoogleWeatherApi:
87
88
  except aiohttp.ClientError as err:
88
89
  raise GoogleWeatherApiConnectionError(err) from err
89
90
 
91
+ async def _async_get_all_pages(
92
+ self, endpoint: str, params: dict[str, Any], records_key: str, limit: int
93
+ ) -> dict[str, Any]:
94
+ """Perform a GET request, following pagination until `limit` records are collected.
95
+
96
+ The API caps the number of records it returns per page (24 for hourly forecasts),
97
+ regardless of the requested page size, so a single request is not enough.
98
+ """
99
+ params = {**params, "page_size": limit}
100
+ data = await self._async_get(endpoint, params)
101
+ records: list[Any] = data.get(records_key, [])
102
+ while len(records) < limit and (page_token := data.get("nextPageToken")):
103
+ data = await self._async_get(endpoint, {**params, "page_token": page_token})
104
+ page_records: list[Any] = data.get(records_key, [])
105
+ if not page_records:
106
+ break
107
+ records.extend(page_records)
108
+ data[records_key] = records[:limit]
109
+ return data
110
+
90
111
  async def async_get_current_conditions(self, latitude: float, longitude: float) -> CurrentConditionsResponse:
91
112
  """Fetch current weather conditions.
92
113
 
@@ -106,14 +127,15 @@ class GoogleWeatherApi:
106
127
 
107
128
  See https://developers.google.com/maps/documentation/weather/reference/rest/v1/forecast.hours/lookup
108
129
  """
109
- data = await self._async_get(
130
+ data = await self._async_get_all_pages(
110
131
  "forecast/hours:lookup",
111
132
  {
112
133
  "location.latitude": latitude,
113
134
  "location.longitude": longitude,
114
135
  "hours": hours,
115
- "page_size": hours,
116
136
  },
137
+ "forecastHours",
138
+ hours,
117
139
  )
118
140
  return HourlyForecastResponse.from_dict(data)
119
141
 
@@ -122,13 +144,14 @@ class GoogleWeatherApi:
122
144
 
123
145
  See https://developers.google.com/maps/documentation/weather/reference/rest/v1/forecast.days/lookup
124
146
  """
125
- data = await self._async_get(
147
+ data = await self._async_get_all_pages(
126
148
  "forecast/days:lookup",
127
149
  {
128
150
  "location.latitude": latitude,
129
151
  "location.longitude": longitude,
130
152
  "days": days,
131
- "page_size": days,
132
153
  },
154
+ "forecastDays",
155
+ days,
133
156
  )
134
157
  return DailyForecastResponse.from_dict(data)
@@ -1,17 +1,17 @@
1
- """Exceptions for Google Weather API."""
2
-
3
-
4
- class GoogleWeatherApiError(Exception):
5
- """Exception talking to the Google Weather API."""
6
-
7
-
8
- class GoogleWeatherApiConnectionError(GoogleWeatherApiError):
9
- """Exception connecting to the Google Weather API."""
10
-
11
-
12
- class GoogleWeatherApiAuthError(GoogleWeatherApiError):
13
- """Exception raised for authentication errors in the Google Weather API."""
14
-
15
-
16
- class GoogleWeatherApiResponseError(GoogleWeatherApiError):
17
- """Exception raised for errors in the Google Weather API response."""
1
+ """Exceptions for Google Weather API."""
2
+
3
+
4
+ class GoogleWeatherApiError(Exception):
5
+ """Exception talking to the Google Weather API."""
6
+
7
+
8
+ class GoogleWeatherApiConnectionError(GoogleWeatherApiError):
9
+ """Exception connecting to the Google Weather API."""
10
+
11
+
12
+ class GoogleWeatherApiAuthError(GoogleWeatherApiError):
13
+ """Exception raised for authentication errors in the Google Weather API."""
14
+
15
+
16
+ class GoogleWeatherApiResponseError(GoogleWeatherApiError):
17
+ """Exception raised for errors in the Google Weather API response."""