kroger-api 0.2.0__tar.gz → 0.3.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.
Files changed (44) hide show
  1. {kroger_api-0.2.0 → kroger_api-0.3.1}/MANIFEST.in +2 -2
  2. {kroger_api-0.2.0/kroger_api.egg-info → kroger_api-0.3.1}/PKG-INFO +10 -7
  3. {kroger_api-0.2.0 → kroger_api-0.3.1}/README.md +9 -1
  4. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/__init__.py +2 -1
  5. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/authorization.py +3 -2
  6. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/client.py +12 -10
  7. kroger_api-0.3.1/kroger_api/tests/test_auth.py +0 -0
  8. kroger_api-0.3.1/kroger_api/tests/test_client.py +36 -0
  9. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/token_storage.py +45 -3
  10. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/utils/env.py +1 -1
  11. {kroger_api-0.2.0 → kroger_api-0.3.1/kroger_api.egg-info}/PKG-INFO +10 -7
  12. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api.egg-info/SOURCES.txt +2 -5
  13. {kroger_api-0.2.0 → kroger_api-0.3.1}/pyproject.toml +2 -3
  14. kroger_api-0.2.0/CHANGELOG.md +0 -34
  15. kroger_api-0.2.0/assets/kroger-api-python-add-to-cart-demo.mp4 +0 -0
  16. kroger_api-0.2.0/assets/product_api_script.gif +0 -0
  17. kroger_api-0.2.0/kroger_api.egg-info/not-zip-safe +0 -1
  18. kroger_api-0.2.0/setup.py +0 -75
  19. {kroger_api-0.2.0 → kroger_api-0.3.1}/LICENSE +0 -0
  20. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/authorization_api_examples.py +0 -0
  21. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/cart_api_examples.py +0 -0
  22. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/clear_tokens.py +0 -0
  23. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/identity_api_examples.py +0 -0
  24. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/location_api_examples.py +0 -0
  25. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/oauth_flow.py +0 -0
  26. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/oauth_pkce_flow.py +0 -0
  27. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/product_api_examples.py +0 -0
  28. {kroger_api-0.2.0 → kroger_api-0.3.1}/examples/token_refresh_example.py +0 -0
  29. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/__init__.py +0 -0
  30. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/cart.py +0 -0
  31. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/identity.py +0 -0
  32. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/location.py +0 -0
  33. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/api/product.py +0 -0
  34. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/auth/__init__.py +0 -0
  35. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/auth/interactive.py +0 -0
  36. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/kroger_api.py +0 -0
  37. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/utils/__init__.py +0 -0
  38. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/utils/oauth.py +0 -0
  39. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api/utils/pkce.py +0 -0
  40. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api.egg-info/dependency_links.txt +0 -0
  41. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api.egg-info/requires.txt +0 -0
  42. {kroger_api-0.2.0 → kroger_api-0.3.1}/kroger_api.egg-info/top_level.txt +0 -0
  43. {kroger_api-0.2.0 → kroger_api-0.3.1}/requirements.txt +0 -0
  44. {kroger_api-0.2.0 → kroger_api-0.3.1}/setup.cfg +0 -0
@@ -7,8 +7,8 @@ include LICENSE
7
7
  # Include requirements
8
8
  include requirements.txt
9
9
 
10
- # Include assets (demo videos, images, etc.)
11
- recursive-include assets *.mp4 *.gif *.png *.jpg *.jpeg
10
+ # Media assets stay on GitHub; don't ship them in the sdist
11
+ recursive-exclude assets *
12
12
 
13
13
  # Include examples directory but don't package them in the main distribution
14
14
  recursive-include examples *.py
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kroger-api
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: A Python client library for the Kroger Public API
5
- Home-page: https://github.com/CupOfOwls/kroger-api
6
- Author: Stephen Thoemmes
7
5
  Author-email: Stephen Thoemmes <thoemmes.stephen@gmail.com>
8
6
  License: MIT License
9
7
 
@@ -61,10 +59,7 @@ Requires-Dist: flake8; extra == "dev"
61
59
  Requires-Dist: mypy; extra == "dev"
62
60
  Provides-Extra: examples
63
61
  Requires-Dist: tabulate>=0.8.0; extra == "examples"
64
- Dynamic: author
65
- Dynamic: home-page
66
62
  Dynamic: license-file
67
- Dynamic: requires-python
68
63
 
69
64
  # 🛒 Kroger Public API 🛍️ -- with Examples in Python 🐍
70
65
 
@@ -76,6 +71,8 @@ Adding an item to your cart via an interactive Python script, and checking that
76
71
 
77
72
  https://github.com/user-attachments/assets/0079cbc7-5af0-473b-909a-d43508fe43d5
78
73
 
74
+ You can also check out [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp), which is an implementation of the Model Context Protocol leveraging this kroger-api package!
75
+
79
76
  ## 🚀 Quick Start
80
77
 
81
78
  ### Installation
@@ -175,9 +172,15 @@ This library implements robust, automatic token management:
175
172
  2. On 401 Unauthorized errors, attempts token refresh
176
173
  3. Retries original request with new token
177
174
 
178
- Token files (automatically managed, stored in project root):
175
+ Token files (automatically managed):
179
176
  - `.kroger_token_client_product.compact.json` - Client credentials tokens
180
177
  - `.kroger_token_user.json` - User authorization tokens
178
+ These tokens are stored in the first matching location:
179
+ 1. `$KROGER_TOKEN_DIR` — set this environment variable to choose the directory yourself
180
+ 2. `$XDG_DATA_HOME/kroger-mcp/` (defaults to `~/.local/share/kroger-mcp/`) on Unix-like machines (macOS, Linux)
181
+ 3. `%APPDATA%\kroger-mcp\` on Windows
182
+
183
+ The directory is shared with the [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp) package so both reuse the same tokens, and it is always writable even when the process is launched with a read-only working directory (e.g. MCP servers under Claude Desktop on Windows).
181
184
 
182
185
  ### 🔒 Enhanced Security with PKCE
183
186
 
@@ -8,6 +8,8 @@ Adding an item to your cart via an interactive Python script, and checking that
8
8
 
9
9
  https://github.com/user-attachments/assets/0079cbc7-5af0-473b-909a-d43508fe43d5
10
10
 
11
+ You can also check out [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp), which is an implementation of the Model Context Protocol leveraging this kroger-api package!
12
+
11
13
  ## 🚀 Quick Start
12
14
 
13
15
  ### Installation
@@ -107,9 +109,15 @@ This library implements robust, automatic token management:
107
109
  2. On 401 Unauthorized errors, attempts token refresh
108
110
  3. Retries original request with new token
109
111
 
110
- Token files (automatically managed, stored in project root):
112
+ Token files (automatically managed):
111
113
  - `.kroger_token_client_product.compact.json` - Client credentials tokens
112
114
  - `.kroger_token_user.json` - User authorization tokens
115
+ These tokens are stored in the first matching location:
116
+ 1. `$KROGER_TOKEN_DIR` — set this environment variable to choose the directory yourself
117
+ 2. `$XDG_DATA_HOME/kroger-mcp/` (defaults to `~/.local/share/kroger-mcp/`) on Unix-like machines (macOS, Linux)
118
+ 3. `%APPDATA%\kroger-mcp\` on Windows
119
+
120
+ The directory is shared with the [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp) package so both reuse the same tokens, and it is always writable even when the process is launched with a read-only working directory (e.g. MCP servers under Claude Desktop on Windows).
113
121
 
114
122
  ### 🔒 Enhanced Security with PKCE
115
123
 
@@ -2,5 +2,6 @@
2
2
  from kroger_api.kroger_api import KrogerAPI
3
3
  from . import auth
4
4
  from . import utils
5
+ from .client import KrogerClient
5
6
 
6
- __all__ = ['KrogerAPI', 'auth', 'utils']
7
+ __all__ = ['KrogerAPI', 'auth', 'utils', 'KrogerClient'] # Optional but recommended
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  from typing import Dict, Optional, Any
2
3
 
3
4
  from kroger_api.client import KrogerClient
@@ -7,7 +8,7 @@ from kroger_api.token_storage import get_refresh_token, load_token
7
8
  class AuthorizationAPI:
8
9
  """
9
10
  Provides access to the Kroger Authorization API endpoints.
10
- """
11
+ """
11
12
 
12
13
  def __init__(self, client: KrogerClient):
13
14
  """
@@ -104,7 +105,7 @@ class AuthorizationAPI:
104
105
  try:
105
106
  return self.refresh_token(refresh_token)
106
107
  except Exception as e:
107
- print(f"Failed to refresh token: {e}")
108
+ print(f"Failed to refresh token: {e}", file=sys.stderr)
108
109
 
109
110
  # If we couldn't refresh or there was no token, return None
110
111
  return None
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  import os
2
3
  import base64
3
4
  import requests
@@ -21,7 +22,7 @@ class KrogerClient:
21
22
  Base client for interacting with the Kroger API
22
23
  """
23
24
  BASE_URL = "https://api.kroger.com"
24
-
25
+
25
26
  def __init__(self, client_id: str = None, client_secret: str = None, redirect_uri: str = None):
26
27
  """
27
28
  Initialize the Kroger API client
@@ -91,7 +92,8 @@ class KrogerClient:
91
92
  Returns:
92
93
  The token information
93
94
  """
94
- # Set the token file for this scope
95
+ # Set the token file for this scope (resolved to a writable
96
+ # directory by token_storage.get_token_file_path)
95
97
  self.token_file = f".kroger_token_client_{scope.replace(':', '_')}.json"
96
98
 
97
99
  # Try to load an existing token first
@@ -103,7 +105,7 @@ class KrogerClient:
103
105
  return token_info
104
106
 
105
107
  # If token is invalid, get a new one
106
- print("Token appears invalid, requesting a new one")
108
+ print("Token appears invalid, requesting a new one", file=sys.stderr)
107
109
 
108
110
  # If no valid token exists, get a new one
109
111
  token_info = self._get_token(grant_type="client_credentials", scope=scope)
@@ -174,7 +176,7 @@ class KrogerClient:
174
176
  except requests.exceptions.HTTPError as e:
175
177
  if e.response.status_code == 400:
176
178
  # Invalid refresh token
177
- print("Invalid refresh token. Please re-authenticate.")
179
+ print("Invalid refresh token. Please re-authenticate.", file=sys.stderr)
178
180
  raise
179
181
 
180
182
  def test_token(self, token_info: Dict[str, Any]) -> bool:
@@ -210,22 +212,22 @@ class KrogerClient:
210
212
 
211
213
  # If token is invalid and we have a refresh token, try to refresh
212
214
  try:
213
- print("Token validation failed, attempting to refresh")
215
+ print("Token validation failed, attempting to refresh", file=sys.stderr)
214
216
  new_token_info = self.refresh_token(token_info["refresh_token"])
215
217
  self.token_info = new_token_info
216
218
  return True
217
219
  except Exception as e:
218
- print(f"Failed to refresh token: {e}")
220
+ print(f"Failed to refresh token: {e}", file=sys.stderr)
219
221
  return False
220
222
  except Exception:
221
223
  # If the validation request failed, try the refresh token
222
224
  try:
223
- print("Token validation request failed, attempting to refresh")
225
+ print("Token validation request failed, attempting to refresh", file=sys.stderr)
224
226
  new_token_info = self.refresh_token(token_info["refresh_token"])
225
227
  self.token_info = new_token_info
226
228
  return True
227
229
  except Exception as e:
228
- print(f"Failed to refresh token: {e}")
230
+ print(f"Failed to refresh token: {e}", file=sys.stderr)
229
231
  return False
230
232
  else:
231
233
  # If we don't have a refresh token, just validate the token directly
@@ -353,7 +355,7 @@ class KrogerClient:
353
355
 
354
356
  # Check if the error is due to an expired or invalid token
355
357
  if error_data.get("error") == "invalid_token":
356
- print("Token is invalid or has expired, attempting to refresh")
358
+ print("Token is invalid or has expired, attempting to refresh", file=sys.stderr)
357
359
 
358
360
  # Try to refresh the token if we have a refresh token
359
361
  if self.token_file:
@@ -384,7 +386,7 @@ class KrogerClient:
384
386
 
385
387
  return response.json()
386
388
  except Exception as refresh_error:
387
- print(f"Failed to refresh token: {refresh_error}")
389
+ print(f"Failed to refresh token: {refresh_error}", file=sys.stderr)
388
390
  # Re-raise the original error if we couldn't refresh
389
391
 
390
392
  # If we couldn't handle the error, re-raise it
File without changes
@@ -0,0 +1,36 @@
1
+ import unittest
2
+ from unittest.mock import patch, MagicMock
3
+ from kroger_api.client import KrogerClient
4
+
5
+ class TestKrogerClient(unittest.TestCase):
6
+
7
+ def setUp(self):
8
+ self.client = KrogerClient(client_id="fake_id", client_secret="fake_secret", redirect_uri="http://redirect.uri")
9
+
10
+ def test_get_authorization_url_basic(self):
11
+ url = self.client.get_authorization_url(scope="openid profile")
12
+ self.assertIn("scope=openid profile", url)
13
+ self.assertIn("client_id=fake_id", url)
14
+ self.assertIn("redirect_uri=http://redirect.uri", url)
15
+
16
+ @patch('kroger_api.client.load_token')
17
+ @patch('kroger_api.client.save_token')
18
+ @patch('kroger_api.client.requests.post')
19
+
20
+ def test_get_token_with_client_credentials(self, mock_post, mock_save_token, mock_load_token):
21
+ #mock load_token to return None
22
+ mock_load_token.return_value = None
23
+
24
+ #mock response from requests.post
25
+ mock_response = MagicMock()
26
+ mock_response.json.return_value = {"access_token": "abc123", "expires_in": 3600}
27
+ mock_response.raise_for_status = lambda: None
28
+ mock_post.return_value = mock_response
29
+
30
+ token_info = self.client.get_token_with_client_credentials("scope1")
31
+
32
+ self.assertEqual(token_info["access_token"], "abc123")
33
+ mock_save_token.assert_called_once()
34
+
35
+ if __name__ == '__main__':
36
+ unittest.main()
@@ -3,13 +3,41 @@ Token storage utility for Kroger API client.
3
3
  This module provides functions to save and load OAuth tokens to avoid repeated logins.
4
4
  """
5
5
 
6
+ import sys
6
7
  import os
7
8
  import json
9
+ from pathlib import Path
8
10
  from typing import Dict, Any, Optional
9
11
 
10
12
  # Default token file location
11
13
  TOKEN_FILE = ".kroger_tokens.json"
12
14
 
15
+ def get_token_file_path(token_name) -> str:
16
+ """Get the appropriate path for storing the token file.
17
+
18
+ Resolution order:
19
+ 1. If token_name is already an absolute path, use it as-is.
20
+ 2. If KROGER_TOKEN_DIR is set, store the file there.
21
+ 3. Otherwise use the platform data directory (XDG spec on Unix,
22
+ APPDATA on Windows) under a 'kroger-mcp' subdirectory, which is
23
+ shared with the kroger-mcp package so both reuse the same tokens.
24
+ """
25
+ if os.path.isabs(token_name):
26
+ return token_name
27
+
28
+ env_dir = os.environ.get('KROGER_TOKEN_DIR')
29
+ if env_dir:
30
+ token_dir = Path(env_dir).expanduser()
31
+ elif os.name == 'nt': # Windows
32
+ token_dir = Path(os.environ.get('APPDATA', Path.home())) / 'kroger-mcp'
33
+ else: # Unix-like
34
+ token_dir = Path(os.environ.get('XDG_DATA_HOME', Path.home() / '.local' / 'share')) / 'kroger-mcp'
35
+
36
+ token_dir.mkdir(parents=True, exist_ok=True)
37
+ return str(token_dir / token_name)
38
+
39
+
40
+
13
41
 
14
42
  def save_token(token_info: Dict[str, Any], token_file: str = TOKEN_FILE) -> None:
15
43
  """
@@ -19,6 +47,10 @@ def save_token(token_info: Dict[str, Any], token_file: str = TOKEN_FILE) -> None
19
47
  token_info: The token information returned from the API
20
48
  token_file: The file path to save the token to
21
49
  """
50
+
51
+
52
+ token_file = get_token_file_path(token_file)
53
+
22
54
  # Save to file
23
55
  with open(token_file, "w") as f:
24
56
  json.dump(token_info, f, indent=2)
@@ -37,6 +69,9 @@ def load_token(token_file: str = TOKEN_FILE) -> Optional[Dict[str, Any]]:
37
69
  Returns:
38
70
  The token information or None if not available
39
71
  """
72
+
73
+ token_file = get_token_file_path(token_file)
74
+
40
75
  if not os.path.exists(token_file):
41
76
  return None
42
77
 
@@ -44,10 +79,10 @@ def load_token(token_file: str = TOKEN_FILE) -> Optional[Dict[str, Any]]:
44
79
  with open(token_file, "r") as f:
45
80
  token_info = json.load(f)
46
81
 
47
- print(f"Found saved token, will test if it's still valid...")
82
+ print(f"Found saved token, will test if it's still valid...", file=sys.stderr)
48
83
  return token_info
49
84
  except (json.JSONDecodeError, IOError) as e:
50
- print(f"Error loading token: {e}")
85
+ print(f"Error loading token: {e}", file=sys.stderr)
51
86
  return None
52
87
 
53
88
 
@@ -58,9 +93,13 @@ def clear_token(token_file: str = TOKEN_FILE) -> None:
58
93
  Args:
59
94
  token_file: The file path to delete
60
95
  """
96
+
97
+ token_file = get_token_file_path(token_file)
98
+
99
+
61
100
  if os.path.exists(token_file):
62
101
  os.remove(token_file)
63
- print("Token file deleted.")
102
+ print("Token file deleted.", file=sys.stderr)
64
103
 
65
104
 
66
105
  def get_refresh_token(token_file: str = TOKEN_FILE) -> Optional[str]:
@@ -73,6 +112,9 @@ def get_refresh_token(token_file: str = TOKEN_FILE) -> Optional[str]:
73
112
  Returns:
74
113
  The refresh token or None if not available
75
114
  """
115
+
116
+ token_file = get_token_file_path(token_file)
117
+
76
118
  token_info = load_token(token_file)
77
119
 
78
120
  if token_info and "refresh_token" in token_info:
@@ -71,6 +71,6 @@ def get_zip_code(default: str = "00000") -> str:
71
71
  """
72
72
  zip_code = os.getenv("KROGER_USER_ZIP_CODE")
73
73
  if not zip_code:
74
- print(f"KROGER_USER_ZIP_CODE environment variable is not set. Using default: {default}")
74
+ print(f"KROGER_USER_ZIP_CODE environment variable is not set. Using default: {default}", file=sys.stderr)
75
75
  return default
76
76
  return zip_code
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kroger-api
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: A Python client library for the Kroger Public API
5
- Home-page: https://github.com/CupOfOwls/kroger-api
6
- Author: Stephen Thoemmes
7
5
  Author-email: Stephen Thoemmes <thoemmes.stephen@gmail.com>
8
6
  License: MIT License
9
7
 
@@ -61,10 +59,7 @@ Requires-Dist: flake8; extra == "dev"
61
59
  Requires-Dist: mypy; extra == "dev"
62
60
  Provides-Extra: examples
63
61
  Requires-Dist: tabulate>=0.8.0; extra == "examples"
64
- Dynamic: author
65
- Dynamic: home-page
66
62
  Dynamic: license-file
67
- Dynamic: requires-python
68
63
 
69
64
  # 🛒 Kroger Public API 🛍️ -- with Examples in Python 🐍
70
65
 
@@ -76,6 +71,8 @@ Adding an item to your cart via an interactive Python script, and checking that
76
71
 
77
72
  https://github.com/user-attachments/assets/0079cbc7-5af0-473b-909a-d43508fe43d5
78
73
 
74
+ You can also check out [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp), which is an implementation of the Model Context Protocol leveraging this kroger-api package!
75
+
79
76
  ## 🚀 Quick Start
80
77
 
81
78
  ### Installation
@@ -175,9 +172,15 @@ This library implements robust, automatic token management:
175
172
  2. On 401 Unauthorized errors, attempts token refresh
176
173
  3. Retries original request with new token
177
174
 
178
- Token files (automatically managed, stored in project root):
175
+ Token files (automatically managed):
179
176
  - `.kroger_token_client_product.compact.json` - Client credentials tokens
180
177
  - `.kroger_token_user.json` - User authorization tokens
178
+ These tokens are stored in the first matching location:
179
+ 1. `$KROGER_TOKEN_DIR` — set this environment variable to choose the directory yourself
180
+ 2. `$XDG_DATA_HOME/kroger-mcp/` (defaults to `~/.local/share/kroger-mcp/`) on Unix-like machines (macOS, Linux)
181
+ 3. `%APPDATA%\kroger-mcp\` on Windows
182
+
183
+ The directory is shared with the [kroger-mcp](https://github.com/CupOfOwls/kroger-mcp) package so both reuse the same tokens, and it is always writable even when the process is launched with a read-only working directory (e.g. MCP servers under Claude Desktop on Windows).
181
184
 
182
185
  ### 🔒 Enhanced Security with PKCE
183
186
 
@@ -1,12 +1,8 @@
1
- CHANGELOG.md
2
1
  LICENSE
3
2
  MANIFEST.in
4
3
  README.md
5
4
  pyproject.toml
6
5
  requirements.txt
7
- setup.py
8
- assets/kroger-api-python-add-to-cart-demo.mp4
9
- assets/product_api_script.gif
10
6
  examples/authorization_api_examples.py
11
7
  examples/cart_api_examples.py
12
8
  examples/clear_tokens.py
@@ -23,7 +19,6 @@ kroger_api/token_storage.py
23
19
  kroger_api.egg-info/PKG-INFO
24
20
  kroger_api.egg-info/SOURCES.txt
25
21
  kroger_api.egg-info/dependency_links.txt
26
- kroger_api.egg-info/not-zip-safe
27
22
  kroger_api.egg-info/requires.txt
28
23
  kroger_api.egg-info/top_level.txt
29
24
  kroger_api/api/__init__.py
@@ -34,6 +29,8 @@ kroger_api/api/location.py
34
29
  kroger_api/api/product.py
35
30
  kroger_api/auth/__init__.py
36
31
  kroger_api/auth/interactive.py
32
+ kroger_api/tests/test_auth.py
33
+ kroger_api/tests/test_client.py
37
34
  kroger_api/utils/__init__.py
38
35
  kroger_api/utils/env.py
39
36
  kroger_api/utils/oauth.py
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"]
2
+ requires = ["setuptools>=61"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
@@ -33,7 +33,7 @@ dependencies = [
33
33
  "certifi>=2021.0.0",
34
34
  "urllib3>=1.26.0",
35
35
  ]
36
- dynamic = ["version"]
36
+ version = "0.3.1"
37
37
 
38
38
  [project.optional-dependencies]
39
39
  dev = [
@@ -58,4 +58,3 @@ Documentation = "https://developer.kroger.com/documentation/public/"
58
58
  [tool.setuptools.packages.find]
59
59
  exclude = ["tests*", "docs_kroger_api*", "venv*", "examples*", "assets*"]
60
60
 
61
- [tool.setuptools_scm]
@@ -1,34 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to the `kroger-api` package will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [0.2.0] - 2025-05-28
9
-
10
- ### Added
11
-
12
- - **PKCE Support**: Added Proof Key for Code Exchange (PKCE) support for enhanced security in the OAuth flow
13
- - New `code_challenge` and `code_challenge_method` parameters in `get_authorization_url()`
14
- - New `code_verifier` parameter in `get_token_with_authorization_code()`
15
- - New utility module `pkce.py` with helper functions:
16
- - `generate_code_verifier()`: Generate a random code verifier
17
- - `generate_code_challenge()`: Generate a code challenge from a code verifier
18
- - `generate_pkce_parameters()`: Generate all PKCE parameters in one call
19
-
20
- ### Security
21
-
22
- - Enhanced OAuth security with PKCE support, mitigating authorization code interception attacks
23
- - Improved token exchange with better error handling for PKCE flows
24
-
25
- ## [0.1.0] - 2025-05-23
26
-
27
- ### Added
28
-
29
- - Initial release of the Kroger API client library
30
- - Support for OAuth 2.0 authorization code flow and client credentials flow
31
- - API access for products, locations, cart, identity, and more
32
- - Token storage and automatic refresh
33
- - Flexible token management with custom file paths
34
- - Example scripts for common use cases
kroger_api-0.2.0/setup.py DELETED
@@ -1,75 +0,0 @@
1
- from setuptools import setup, find_packages
2
- import os
3
-
4
- # Read the contents of README file
5
- this_directory = os.path.abspath(os.path.dirname(__file__))
6
- with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
7
- long_description = f.read()
8
-
9
- setup(
10
- name="kroger-api",
11
- version="0.2.0",
12
- packages=find_packages(exclude=['tests*', 'docs_kroger_api*', 'venv*', 'examples*', 'assets*']),
13
-
14
- # Dependencies
15
- install_requires=[
16
- "requests>=2.25.0",
17
- "python-dotenv>=0.15.0",
18
- "certifi>=2021.0.0",
19
- "urllib3>=1.26.0",
20
- ],
21
-
22
- # Optional dependencies for development/examples
23
- extras_require={
24
- 'dev': [
25
- 'pytest>=7.0.0',
26
- 'pytest-mock>=3.0.0',
27
- 'requests-mock>=1.9.0',
28
- 'black',
29
- 'flake8',
30
- 'mypy',
31
- ],
32
- 'examples': [
33
- 'tabulate>=0.8.0',
34
- ],
35
- },
36
-
37
- # Metadata
38
- author="Stephen Thoemmes",
39
- author_email="thoemmes.stephen@gmail.com",
40
- description="A Python client library for the Kroger Public API",
41
- long_description=long_description,
42
- long_description_content_type="text/markdown",
43
- keywords="kroger, api, grocery, shopping, retail",
44
- url="https://github.com/CupOfOwls/kroger-api",
45
- project_urls={
46
- "Bug Reports": "https://github.com/CupOfOwls/kroger-api/issues",
47
- "Source": "https://github.com/CupOfOwls/kroger-api",
48
- "Kroger API Documentation": "https://developer.kroger.com/documentation/public/",
49
- "Demo Video": "https://github.com/CupOfOwls/kroger-api/blob/main/assets/kroger-api-python-add-to-cart-demo.mp4",
50
- },
51
-
52
- # Classifiers for PyPI
53
- classifiers=[
54
- "Development Status :: 4 - Beta",
55
- "Intended Audience :: Developers",
56
- "License :: OSI Approved :: MIT License",
57
- "Operating System :: OS Independent",
58
- "Programming Language :: Python :: 3",
59
- "Programming Language :: Python :: 3.8",
60
- "Programming Language :: Python :: 3.9",
61
- "Programming Language :: Python :: 3.10",
62
- "Programming Language :: Python :: 3.11",
63
- "Programming Language :: Python :: 3.12",
64
- "Topic :: Software Development :: Libraries :: Python Modules",
65
- "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
66
- "Topic :: Office/Business",
67
- ],
68
-
69
- # Python version requirement
70
- python_requires=">=3.8",
71
-
72
- # Include additional files (controlled by MANIFEST.in)
73
- include_package_data=True,
74
- zip_safe=False,
75
- )
File without changes
File without changes
File without changes