hakai-api 2.0.0__tar.gz → 2.0.2__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 (25) hide show
  1. {hakai_api-2.0.0 → hakai_api-2.0.2}/.github/workflows/release.yaml +2 -0
  2. {hakai_api-2.0.0 → hakai_api-2.0.2}/.github/workflows/test.yaml +2 -2
  3. {hakai_api-2.0.0 → hakai_api-2.0.2}/PKG-INFO +8 -7
  4. {hakai_api-2.0.0 → hakai_api-2.0.2}/README.md +5 -4
  5. {hakai_api-2.0.0 → hakai_api-2.0.2}/pyproject.toml +3 -3
  6. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/auth/base.py +1 -1
  7. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/auth/desktop.py +1 -1
  8. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/auth/web.py +1 -1
  9. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/client.py +5 -5
  10. {hakai_api-2.0.0 → hakai_api-2.0.2}/tests/test_auth_strategies.py +8 -7
  11. {hakai_api-2.0.0 → hakai_api-2.0.2}/tests/test_client.py +19 -19
  12. hakai_api-2.0.2/uv.lock +470 -0
  13. hakai_api-2.0.0/uv.lock +0 -758
  14. {hakai_api-2.0.0 → hakai_api-2.0.2}/.github/workflows/lint.yaml +0 -0
  15. {hakai_api-2.0.0 → hakai_api-2.0.2}/.gitignore +0 -0
  16. {hakai_api-2.0.0 → hakai_api-2.0.2}/.pre-commit-config.yaml +0 -0
  17. {hakai_api-2.0.0 → hakai_api-2.0.2}/CODEOWNERS +0 -0
  18. {hakai_api-2.0.0 → hakai_api-2.0.2}/CONTRIBUTING.md +0 -0
  19. {hakai_api-2.0.0 → hakai_api-2.0.2}/LICENSE +0 -0
  20. {hakai_api-2.0.0 → hakai_api-2.0.2}/example.py +0 -0
  21. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/__init__.py +0 -0
  22. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/auth/__init__.py +0 -0
  23. {hakai_api-2.0.0 → hakai_api-2.0.2}/src/hakai_api/auth/desktop_callback.html +0 -0
  24. {hakai_api-2.0.0 → hakai_api-2.0.2}/tests/__init__.py +0 -0
  25. {hakai_api-2.0.0 → hakai_api-2.0.2}/tests/test_backwards_compatability.py +0 -0
@@ -7,6 +7,8 @@ on:
7
7
  tags:
8
8
  - 'v[0-9]+.[0-9]+.[0-9]+'
9
9
  - 'v[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
10
+ paths-ignore:
11
+ - 'README.md'
10
12
 
11
13
  jobs:
12
14
  publish:
@@ -24,11 +24,11 @@ jobs:
24
24
  - Windows
25
25
  - MacOs
26
26
  py:
27
+ - "3.15"
28
+ - "3.14"
27
29
  - "3.13"
28
30
  - "3.12"
29
31
  - "3.11"
30
- - "3.10"
31
- - "3.9"
32
32
  steps:
33
33
  - uses: actions/checkout@v4
34
34
  - name: Install uv
@@ -1,12 +1,12 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: hakai_api
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Get Hakai database resources using http calls
5
5
  Author-email: Taylor Denouden <taylor.denouden@hakai.org>, Chris Davis <chris.davis@hakai.org>, Nate Rosenstock <nate.rosenstock@hakai.org>, Sam Albers <sam.albers@hakai.org>
6
6
  Maintainer-email: Taylor Denouden <taylor.denouden@hakai.org>, Sam Albers <sam.albers@hakai.org>
7
7
  License-Expression: MIT
8
8
  License-File: LICENSE
9
- Requires-Python: >=3.8
9
+ Requires-Python: >=3.11
10
10
  Requires-Dist: loguru>=0.7.3
11
11
  Requires-Dist: pkce>=1.0.3
12
12
  Requires-Dist: pytz>=2025.2
@@ -22,7 +22,7 @@ The exported `Client` class extends the functionality of the
22
22
  Python [requests library](https://docs.python-requests.org/en/master/) to supply Hakai
23
23
  OAuth2 credentials with url requests.
24
24
 
25
- ![PyPI](https://img.shields.io/pypi/v/hakai-api) [![tests](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml/badge.svg)](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml) [![License: MIT](https://img.shields.io/badge/License-MIT-black.svg)](https://opensource.org/licenses/MIT)
25
+ [![PyPI](https://img.shields.io/pypi/v/hakai-api)](https://pypi.org/project/hakai_api/) [![tests](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml/badge.svg)](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml) [![License: MIT](https://img.shields.io/badge/License-MIT-black.svg)](https://opensource.org/licenses/MIT)
26
26
 
27
27
  <details>
28
28
 
@@ -49,7 +49,7 @@ OAuth2 credentials with url requests.
49
49
 
50
50
  # Installation
51
51
 
52
- Python 3.8 or higher is required. Install with pip:
52
+ Python 3.11 or higher is required. Install with pip:
53
53
 
54
54
  ```bash
55
55
  pip install hakai-api
@@ -102,6 +102,7 @@ client = Client(user_agent="MyApp/1.0 (contact@example.com)")
102
102
  # Or set via environment variable
103
103
  os.environ['HAKAI_API_USER_AGENT'] = "MyApp/1.0 (contact@example.com)"
104
104
  client = Client()
105
+ ```
105
106
 
106
107
  # Methods
107
108
 
@@ -126,7 +127,7 @@ from, see the [Hakai API documentation](https://github.com/HakaiInstitute/hakai-
126
127
  ## Custom API Endpoints
127
128
 
128
129
  You can specify which API to access when instantiating the Client. By default, the API
129
- uses `https://hecate.hakai.org/api` as the API root. It may be useful to use this
130
+ uses `https://portal.hakai.org/api` as the API root. It may be useful to use this
130
131
  library to access a locally running API instance or to access the Goose API for testing
131
132
  purposes. If you are always going to be accessing data from a locally running API
132
133
  instance, you are better off using the requests.py library directly since Authorization
@@ -151,7 +152,7 @@ client = Client()
151
152
 
152
153
  # These are equivalent:
153
154
  response1 = client.get('/eims/views/output/stations')
154
- response2 = client.get('https://hecate.hakai.org/api/eims/views/output/stations')
155
+ response2 = client.get('https://portal.hakai.org/api/eims/views/output/stations')
155
156
  ```
156
157
 
157
158
  ## Credentials Configuration
@@ -6,7 +6,7 @@ The exported `Client` class extends the functionality of the
6
6
  Python [requests library](https://docs.python-requests.org/en/master/) to supply Hakai
7
7
  OAuth2 credentials with url requests.
8
8
 
9
- ![PyPI](https://img.shields.io/pypi/v/hakai-api) [![tests](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml/badge.svg)](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml) [![License: MIT](https://img.shields.io/badge/License-MIT-black.svg)](https://opensource.org/licenses/MIT)
9
+ [![PyPI](https://img.shields.io/pypi/v/hakai-api)](https://pypi.org/project/hakai_api/) [![tests](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml/badge.svg)](https://github.com/HakaiInstitute/hakai-api-client-py/actions/workflows/test.yaml) [![License: MIT](https://img.shields.io/badge/License-MIT-black.svg)](https://opensource.org/licenses/MIT)
10
10
 
11
11
  <details>
12
12
 
@@ -33,7 +33,7 @@ OAuth2 credentials with url requests.
33
33
 
34
34
  # Installation
35
35
 
36
- Python 3.8 or higher is required. Install with pip:
36
+ Python 3.11 or higher is required. Install with pip:
37
37
 
38
38
  ```bash
39
39
  pip install hakai-api
@@ -86,6 +86,7 @@ client = Client(user_agent="MyApp/1.0 (contact@example.com)")
86
86
  # Or set via environment variable
87
87
  os.environ['HAKAI_API_USER_AGENT'] = "MyApp/1.0 (contact@example.com)"
88
88
  client = Client()
89
+ ```
89
90
 
90
91
  # Methods
91
92
 
@@ -110,7 +111,7 @@ from, see the [Hakai API documentation](https://github.com/HakaiInstitute/hakai-
110
111
  ## Custom API Endpoints
111
112
 
112
113
  You can specify which API to access when instantiating the Client. By default, the API
113
- uses `https://hecate.hakai.org/api` as the API root. It may be useful to use this
114
+ uses `https://portal.hakai.org/api` as the API root. It may be useful to use this
114
115
  library to access a locally running API instance or to access the Goose API for testing
115
116
  purposes. If you are always going to be accessing data from a locally running API
116
117
  instance, you are better off using the requests.py library directly since Authorization
@@ -135,7 +136,7 @@ client = Client()
135
136
 
136
137
  # These are equivalent:
137
138
  response1 = client.get('/eims/views/output/stations')
138
- response2 = client.get('https://hecate.hakai.org/api/eims/views/output/stations')
139
+ response2 = client.get('https://portal.hakai.org/api/eims/views/output/stations')
139
140
  ```
140
141
 
141
142
  ## Credentials Configuration
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hakai_api"
3
- version = "2.0.0"
3
+ version = "2.0.2"
4
4
  description = "Get Hakai database resources using http calls"
5
5
  authors = [
6
6
  { name = "Taylor Denouden", email = "taylor.denouden@hakai.org" },
@@ -15,7 +15,7 @@ maintainers = [
15
15
  repository = "https://github.com/HakaiInstitute/hakai-api-client-py"
16
16
  license = "MIT"
17
17
  readme = "README.md"
18
- requires-python = ">=3.8"
18
+ requires-python = ">=3.11"
19
19
 
20
20
  dependencies = [
21
21
  "loguru>=0.7.3",
@@ -75,7 +75,7 @@ convention = "google"
75
75
  combine-as-imports = true
76
76
 
77
77
  [tool.mypy]
78
- python_version = "3.10"
78
+ python_version = "3.11"
79
79
  warn_return_any = false
80
80
  warn_unused_configs = true
81
81
  strict = true
@@ -45,7 +45,7 @@ class AuthStrategy(ABC):
45
45
  @property
46
46
  @abstractmethod
47
47
  def client_type(self) -> str:
48
- """Get the client type for this authentication strategy.
48
+ """The client type for this authentication strategy.
49
49
 
50
50
  Returns:
51
51
  The client type string (e.g., 'web', 'desktop').
@@ -257,7 +257,7 @@ class DesktopAuthStrategy(AuthStrategy):
257
257
 
258
258
  @property
259
259
  def client_type(self) -> str:
260
- """Get the client type for desktop authentication strategy."""
260
+ """The client type for the desktop authentication strategy."""
261
261
  return "desktop"
262
262
 
263
263
  # refresh_token method is now inherited from AuthStrategy base class
@@ -88,7 +88,7 @@ class WebAuthStrategy(AuthStrategy):
88
88
 
89
89
  @property
90
90
  def client_type(self) -> str:
91
- """Get the client type for web authentication strategy."""
91
+ """The client type for the web authentication strategy."""
92
92
  return "web"
93
93
 
94
94
  # refresh_token method is now inherited from AuthStrategy base class
@@ -52,8 +52,8 @@ class Client(OAuth2Session):
52
52
  >>> response = client.get("/custom/endpoint")
53
53
  """
54
54
 
55
- DEFAULT_API_ROOT = "https://hecate.hakai.org/api"
56
- DEFAULT_LOGIN_PAGE = "https://hecate.hakai.org/api-client-login"
55
+ DEFAULT_API_ROOT = "https://portal.hakai.org/api"
56
+ DEFAULT_LOGIN_PAGE = "https://portal.hakai.org/api-client-login"
57
57
  CREDENTIALS_ENV_VAR = "HAKAI_API_CREDENTIALS"
58
58
  USER_AGENT_ENV_VAR = "HAKAI_API_USER_AGENT"
59
59
 
@@ -151,7 +151,7 @@ class Client(OAuth2Session):
151
151
 
152
152
  @property
153
153
  def api_root(self) -> str:
154
- """Return the api base url.
154
+ """The API base URL.
155
155
 
156
156
  Returns:
157
157
  The base URL of the Hakai API.
@@ -160,7 +160,7 @@ class Client(OAuth2Session):
160
160
 
161
161
  @property
162
162
  def login_page(self) -> str:
163
- """Return the login page url.
163
+ """The login page URL.
164
164
 
165
165
  Returns:
166
166
  The URL of the login page.
@@ -169,7 +169,7 @@ class Client(OAuth2Session):
169
169
 
170
170
  @property
171
171
  def credentials(self) -> dict:
172
- """Return the credentials object.
172
+ """The credentials object.
173
173
 
174
174
  Returns:
175
175
  Credentials object.
@@ -3,10 +3,11 @@
3
3
  import json
4
4
  import os
5
5
  import tempfile
6
- from datetime import datetime, timezone
6
+ from collections.abc import Generator
7
+ from datetime import UTC, datetime
7
8
  from pathlib import Path
8
9
  from time import mktime
9
- from typing import Any, Generator
10
+ from typing import Any
10
11
  from unittest.mock import Mock, patch
11
12
 
12
13
  import pytest
@@ -18,7 +19,7 @@ class ConcreteAuthStrategy(AuthStrategy):
18
19
  """Concrete implementation for testing the abstract base class."""
19
20
 
20
21
  def get_credentials(self) -> dict:
21
- now_utc = datetime.now(timezone.utc)
22
+ now_utc = datetime.now(UTC)
22
23
  return {
23
24
  "access_token": "test_token",
24
25
  "token_type": "bearer",
@@ -58,7 +59,7 @@ def valid_credentials() -> dict:
58
59
  Returns:
59
60
  dict: Dictionary containing valid test credentials.
60
61
  """
61
- now_utc = datetime.now(timezone.utc)
62
+ now_utc = datetime.now(UTC)
62
63
  future_timestamp = int(now_utc.timestamp() + 3600) # Use UTC timestamp
63
64
  return {
64
65
  "access_token": "test_access_token",
@@ -75,7 +76,7 @@ def expired_credentials() -> dict:
75
76
  Returns:
76
77
  dict: Dictionary containing expired test credentials.
77
78
  """
78
- now_utc = datetime.now(timezone.utc)
79
+ now_utc = datetime.now(UTC)
79
80
  past_timestamp = int(now_utc.timestamp() - 3600) # Use UTC timestamp
80
81
  return {
81
82
  "access_token": "expired_access_token",
@@ -216,7 +217,7 @@ class TestWebAuthStrategy:
216
217
  def test_get_credentials_from_env(self) -> None:
217
218
  """Test getting credentials from environment variable."""
218
219
  # Use a future timestamp to ensure credentials aren't expired
219
- future_timestamp = int(mktime(datetime.now(timezone.utc).timetuple()) + 3600)
220
+ future_timestamp = int(mktime(datetime.now(UTC).timetuple()) + 3600)
220
221
  env_value = f"access_token=env_token&token_type=bearer&expires_at={future_timestamp}&expires_in=3600"
221
222
 
222
223
  with patch.dict(os.environ, {"HAKAI_API_CREDENTIALS": env_value}):
@@ -303,7 +304,7 @@ class TestDesktopAuthStrategy:
303
304
  def test_get_credentials_from_env(self) -> None:
304
305
  """Test getting credentials from environment variable."""
305
306
  # Use a future timestamp to ensure credentials aren't expired
306
- future_timestamp = int(mktime(datetime.now(timezone.utc).timetuple()) + 3600)
307
+ future_timestamp = int(mktime(datetime.now(UTC).timetuple()) + 3600)
307
308
  env_value = f"access_token=env_token&token_type=bearer&expires_at={future_timestamp}&expires_in=3600"
308
309
 
309
310
  with patch.dict(os.environ, {"HAKAI_API_CREDENTIALS": env_value}):
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  import tempfile
5
- from datetime import datetime, timezone
5
+ from datetime import UTC, datetime
6
6
  from time import mktime
7
7
  from typing import Any, NoReturn
8
8
  from unittest.mock import Mock, patch
@@ -15,7 +15,7 @@ from hakai_api import Client
15
15
  def test_get_valid_credentials_from_file(temp_credentials_file):
16
16
  """Test that credentials can be read from a file."""
17
17
  # Create a client object with a temporary credentials file
18
- now = datetime.now(timezone.utc)
18
+ now = datetime.now(UTC)
19
19
  client = Client(
20
20
  credentials={
21
21
  "token_type": "Bearer",
@@ -45,7 +45,7 @@ def test_get_valid_credentials_from_file(temp_credentials_file):
45
45
  def test_expired_credentials_are_handled(temp_credentials_file):
46
46
  """Test that expired credentials are removed properly."""
47
47
  # Create a client object with expired credentials and a temporary credentials file
48
- now = datetime.now(timezone.utc)
48
+ now = datetime.now(UTC)
49
49
  client = Client(
50
50
  credentials={
51
51
  "token_type": "Bearer",
@@ -69,7 +69,7 @@ def test_expired_credentials_are_handled(temp_credentials_file):
69
69
  def test_custom_api_root(temp_credentials_file):
70
70
  """Test that a customized api root can be set."""
71
71
  # Create a client object with temporary credentials file
72
- now = datetime.now(timezone.utc)
72
+ now = datetime.now(UTC)
73
73
  client = Client(
74
74
  credentials={
75
75
  "token_type": "Bearer",
@@ -88,7 +88,7 @@ def test_custom_api_root(temp_credentials_file):
88
88
  def test_custom_login_page(temp_credentials_file):
89
89
  """Test that a customized login page can be set."""
90
90
  # Create a client object with temporary credentials file
91
- now = datetime.now(timezone.utc)
91
+ now = datetime.now(UTC)
92
92
  client = Client(
93
93
  credentials={
94
94
  "token_type": "Bearer",
@@ -107,7 +107,7 @@ def test_custom_login_page(temp_credentials_file):
107
107
  def test_credentials_from_env_variable(temp_credentials_file):
108
108
  """Test setting credentials with HAKAI_API_CREDENTIALS environment variable."""
109
109
  # Create a client object with temporary credentials file
110
- now = datetime.now(timezone.utc)
110
+ now = datetime.now(UTC)
111
111
  os.environ["HAKAI_API_CREDENTIALS"] = "&".join([
112
112
  "token_type=Bearer",
113
113
  "access_token=test_access_token",
@@ -145,7 +145,7 @@ def test_user_agent_header(tmp_path):
145
145
  del os.environ[Client.USER_AGENT_ENV_VAR]
146
146
 
147
147
  # Create a client object with default User-Agent
148
- now = datetime.now(timezone.utc)
148
+ now = datetime.now(UTC)
149
149
  client = Client(
150
150
  credentials={
151
151
  "token_type": "Bearer",
@@ -201,7 +201,7 @@ def temp_credentials_file():
201
201
  @pytest.fixture
202
202
  def valid_credentials():
203
203
  """Sample valid credentials for testing."""
204
- future_timestamp = int(mktime(datetime.now(timezone.utc).timetuple()) + 3600)
204
+ future_timestamp = int(mktime(datetime.now(UTC).timetuple()) + 3600)
205
205
  return {
206
206
  "access_token": "valid_token",
207
207
  "token_type": "Bearer",
@@ -213,7 +213,7 @@ def valid_credentials():
213
213
  @pytest.fixture
214
214
  def expired_credentials():
215
215
  """Sample expired credentials for testing."""
216
- now_utc = datetime.now(timezone.utc)
216
+ now_utc = datetime.now(UTC)
217
217
  past_timestamp = int(now_utc.timestamp() - 3600) # Use UTC timestamp
218
218
  return {
219
219
  "access_token": "expired_token",
@@ -226,7 +226,7 @@ def expired_credentials():
226
226
  @pytest.fixture
227
227
  def credentials_with_refresh():
228
228
  """Sample credentials with refresh token."""
229
- future_timestamp = int(mktime(datetime.now(timezone.utc).timetuple()) + 3600)
229
+ future_timestamp = int(mktime(datetime.now(UTC).timetuple()) + 3600)
230
230
  return {
231
231
  "access_token": "token_with_refresh",
232
232
  "token_type": "Bearer",
@@ -325,7 +325,7 @@ class TestClientCredentialScenarios:
325
325
  return {
326
326
  "access_token": "new_token",
327
327
  "token_type": "Bearer",
328
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
328
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
329
329
  "expires_in": 3600,
330
330
  }
331
331
 
@@ -367,7 +367,7 @@ class TestClientCredentialScenarios:
367
367
  return {
368
368
  "access_token": "new_token",
369
369
  "token_type": "Bearer",
370
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
370
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
371
371
  "expires_in": 3600,
372
372
  }
373
373
 
@@ -414,7 +414,7 @@ class TestClientCredentialScenarios:
414
414
  def test_expired_env_credentials_are_rejected(self, tmp_path):
415
415
  """Test that expired environment credentials are rejected."""
416
416
  # Set expired credentials in environment
417
- now_utc = datetime.now(timezone.utc)
417
+ now_utc = datetime.now(UTC)
418
418
  past_timestamp = int(now_utc.timestamp() - 3600) # Use UTC timestamp
419
419
  expired_env_creds = (
420
420
  f"access_token=expired_env_token&token_type=Bearer&expires_at={past_timestamp}&expires_in=3600"
@@ -473,7 +473,7 @@ class TestClientCredentialScenarios:
473
473
  return {
474
474
  "access_token": "new_token",
475
475
  "token_type": "Bearer",
476
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
476
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
477
477
  "expires_in": 3600,
478
478
  }
479
479
 
@@ -514,7 +514,7 @@ class TestClientRefreshTokenScenarios:
514
514
  credentials_with_refresh = {
515
515
  "access_token": "old_token",
516
516
  "token_type": "Bearer",
517
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
517
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
518
518
  "expires_in": 3600,
519
519
  "refresh_token": "refresh123",
520
520
  }
@@ -524,7 +524,7 @@ class TestClientRefreshTokenScenarios:
524
524
  return {
525
525
  "access_token": "refreshed_token",
526
526
  "token_type": "Bearer",
527
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 7200),
527
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 7200),
528
528
  "expires_in": 7200,
529
529
  "refresh_token": "refresh123",
530
530
  }
@@ -544,7 +544,7 @@ class TestClientRefreshTokenScenarios:
544
544
  credentials_with_refresh = {
545
545
  "access_token": "old_token",
546
546
  "token_type": "Bearer",
547
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
547
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
548
548
  "expires_in": 3600,
549
549
  "refresh_token": "refresh123",
550
550
  }
@@ -554,7 +554,7 @@ class TestClientRefreshTokenScenarios:
554
554
  mock_response.status_code = 200
555
555
  mock_response.json.return_value = {
556
556
  "access_token": "refreshed_web_token",
557
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 7200),
557
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 7200),
558
558
  "expires_in": 7200,
559
559
  }
560
560
  return mock_response
@@ -581,7 +581,7 @@ class TestClientRefreshTokenScenarios:
581
581
  credentials_with_refresh = {
582
582
  "access_token": "old_token",
583
583
  "token_type": "Bearer",
584
- "expires_at": int(mktime(datetime.now(timezone.utc).timetuple()) + 3600),
584
+ "expires_at": int(mktime(datetime.now(UTC).timetuple()) + 3600),
585
585
  "expires_in": 3600,
586
586
  "refresh_token": "invalid_refresh",
587
587
  }