currentsapi 0.1.0__tar.gz → 0.1.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: currentsapi
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Official Python client for the Currents API
5
5
  Home-page: https://github.com/currentslab/currentsapi-python
6
6
  Author: Currents Dev
@@ -1,7 +1,7 @@
1
1
  import sys
2
2
 
3
3
  __project__ = "currentsapi"
4
- __version__ = "0.1.0"
4
+ __version__ = "0.1.1"
5
5
  __repo__ = "https://github.com/currentslab/currentsapi-python"
6
6
 
7
7
  from .client import CurrentsAPI
@@ -11,19 +11,25 @@ class CurrentsAPIError(Exception):
11
11
 
12
12
  def __init__(self, response):
13
13
  self.response = response
14
- super().__init__(str(response))
14
+ self._status = response.get("status")
15
+ self._code = response.get("code")
16
+ self._message = response.get("message") or response.get("msg")
17
+ super().__init__(self._message or str(response))
15
18
 
16
19
  @property
17
20
  def status(self):
18
- return self.response.get("status")
21
+ try:
22
+ return int(self._status)
23
+ except (TypeError, ValueError):
24
+ return self._status
19
25
 
20
26
  @property
21
27
  def code(self):
22
- return self.response.get("code")
28
+ return self._code
23
29
 
24
30
  @property
25
31
  def message(self):
26
- return self.response.get("message")
32
+ return self._message
27
33
 
28
34
 
29
35
  class CurrentsAPI:
@@ -95,11 +101,11 @@ class CurrentsAPI:
95
101
  params["category"] = category
96
102
 
97
103
  if start_date:
98
- date = self._parse_date(start_date, "start_date")
104
+ date = self._normalize_date(self._parse_date(start_date, "start_date"))
99
105
  params["start_date"] = date.strftime("%Y-%m-%dT%H:%M:%SZ")
100
106
 
101
107
  if end_date:
102
- date = self._parse_date(end_date, "end_date")
108
+ date = self._normalize_date(self._parse_date(end_date, "end_date"))
103
109
  params["end_date"] = date.strftime("%Y-%m-%dT%H:%M:%SZ")
104
110
 
105
111
  return self._get(self.search_endpoint, params)
@@ -116,7 +122,12 @@ class CurrentsAPI:
116
122
  @staticmethod
117
123
  def _parse_date(date_value, param_name):
118
124
  if isinstance(date_value, str):
119
- return parser.parse(date_value)
125
+ try:
126
+ return parser.parse(date_value)
127
+ except (parser.ParserError, OverflowError, ValueError) as exc:
128
+ raise ValueError(
129
+ "{} is not a parsable date: {}".format(param_name, exc)
130
+ ) from exc
120
131
  elif isinstance(date_value, datetime.date):
121
132
  return date_value
122
133
  else:
@@ -125,3 +136,9 @@ class CurrentsAPI:
125
136
  param_name
126
137
  )
127
138
  )
139
+
140
+ @staticmethod
141
+ def _normalize_date(date_value):
142
+ if isinstance(date_value, datetime.datetime) and date_value.tzinfo is not None:
143
+ return date_value.astimezone(datetime.timezone.utc)
144
+ return date_value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: currentsapi
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Official Python client for the Currents API
5
5
  Home-page: https://github.com/currentslab/currentsapi-python
6
6
  Author: Currents Dev
@@ -160,6 +160,54 @@ class TestClient(unittest.TestCase):
160
160
  with self.assertRaises(ValueError):
161
161
  api.search(start_date=123)
162
162
 
163
+ @patch("currentsapi.client.requests.get")
164
+ def test_api_error_uses_msg_key(self, mock_get):
165
+ mock_get.return_value = Mock(
166
+ status_code=401,
167
+ json=Mock(return_value={"status": "401", "msg": "Invalid token"}),
168
+ )
169
+ api = CurrentsAPI("key")
170
+ with self.assertRaises(CurrentsAPIError) as ctx:
171
+ api.latest_news()
172
+ self.assertEqual(ctx.exception.status, 401)
173
+ self.assertIsNone(ctx.exception.code)
174
+ self.assertEqual(ctx.exception.message, "Invalid token")
175
+ self.assertEqual(str(ctx.exception), "Invalid token")
176
+
177
+ @patch("currentsapi.client.requests.get")
178
+ def test_api_error_prefers_message_over_msg(self, mock_get):
179
+ mock_get.return_value = Mock(
180
+ status_code=400,
181
+ json=Mock(
182
+ return_value={
183
+ "status": "400",
184
+ "msg": "Bad request",
185
+ "code": "INVALID_QUERY",
186
+ "message": "Invalid parameters",
187
+ }
188
+ ),
189
+ )
190
+ api = CurrentsAPI("key")
191
+ with self.assertRaises(CurrentsAPIError) as ctx:
192
+ api.search(keywords="x", category="nope")
193
+ self.assertEqual(ctx.exception.status, 400)
194
+ self.assertEqual(ctx.exception.code, "INVALID_QUERY")
195
+ self.assertEqual(ctx.exception.message, "Invalid parameters")
196
+ self.assertEqual(str(ctx.exception), "Invalid parameters")
197
+
198
+ @patch("currentsapi.client.requests.get")
199
+ def test_tz_aware_datetime_converted_to_utc(self, mock_get):
200
+ mock_get.return_value = Mock(status_code=200, json=Mock(return_value={"status": "ok"}))
201
+ api = CurrentsAPI("key")
202
+ tz = datetime.timezone(datetime.timedelta(hours=8))
203
+ api.search(start_date=datetime.datetime(2024, 6, 1, 12, 0, tzinfo=tz))
204
+ kwargs = mock_get.call_args.kwargs
205
+ self.assertEqual(kwargs["params"]["start_date"], "2024-06-01T04:00:00Z")
206
+
207
+ def test_impossible_date_string_raises_valueerror(self):
208
+ api = CurrentsAPI("key")
209
+ with self.assertRaises(ValueError):
210
+ api.search(start_date="2026-13-45")
163
211
 
164
212
  if __name__ == "__main__":
165
213
  unittest.main()
File without changes
File without changes
File without changes
File without changes