miso-client 0.1.0__tar.gz → 0.2.0__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.

Potentially problematic release.


This version of miso-client might be problematic. Click here for more details.

Files changed (35) hide show
  1. {miso_client-0.1.0 → miso_client-0.2.0}/CHANGELOG.md +38 -0
  2. {miso_client-0.1.0/miso_client.egg-info → miso_client-0.2.0}/PKG-INFO +37 -1
  3. {miso_client-0.1.0 → miso_client-0.2.0}/README.md +36 -0
  4. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/__init__.py +83 -81
  5. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/errors.py +9 -4
  6. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/models/config.py +56 -35
  7. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/__init__.py +5 -5
  8. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/auth.py +65 -48
  9. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/cache.py +42 -41
  10. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/encryption.py +18 -17
  11. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/logger.py +109 -95
  12. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/permission.py +27 -36
  13. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/redis.py +17 -15
  14. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/services/role.py +25 -36
  15. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/utils/__init__.py +3 -3
  16. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/utils/config_loader.py +24 -16
  17. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/utils/data_masker.py +27 -28
  18. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/utils/http_client.py +91 -81
  19. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/utils/jwt_tools.py +14 -17
  20. {miso_client-0.1.0 → miso_client-0.2.0/miso_client.egg-info}/PKG-INFO +37 -1
  21. {miso_client-0.1.0 → miso_client-0.2.0}/pyproject.toml +1 -1
  22. {miso_client-0.1.0 → miso_client-0.2.0}/setup.py +1 -1
  23. {miso_client-0.1.0 → miso_client-0.2.0}/LICENSE +0 -0
  24. {miso_client-0.1.0 → miso_client-0.2.0}/MANIFEST.in +0 -0
  25. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/models/__init__.py +0 -0
  26. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client/py.typed +0 -0
  27. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client.egg-info/SOURCES.txt +0 -0
  28. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client.egg-info/dependency_links.txt +0 -0
  29. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client.egg-info/not-zip-safe +0 -0
  30. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client.egg-info/requires.txt +0 -0
  31. {miso_client-0.1.0 → miso_client-0.2.0}/miso_client.egg-info/top_level.txt +0 -0
  32. {miso_client-0.1.0 → miso_client-0.2.0}/pytest.ini +0 -0
  33. {miso_client-0.1.0 → miso_client-0.2.0}/requirements-test.txt +0 -0
  34. {miso_client-0.1.0 → miso_client-0.2.0}/requirements.txt +0 -0
  35. {miso_client-0.1.0 → miso_client-0.2.0}/setup.cfg +0 -0
@@ -5,6 +5,44 @@ All notable changes to the MisoClient SDK will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] - 2025-10-31
9
+
10
+ ### Added
11
+
12
+ - **API_KEY Support for Testing**: Added optional `API_KEY` environment variable that allows bypassing OAuth2 authentication for testing purposes
13
+ - When `API_KEY` is set in environment, bearer tokens matching the key will automatically validate without OAuth2
14
+ - `validate_token()` returns `True` for matching API_KEY tokens without calling controller
15
+ - `get_user()` and `get_user_info()` return `None` when using API_KEY (by design for testing scenarios)
16
+ - Configuration supports `api_key` field in `MisoClientConfig`
17
+ - Comprehensive test coverage for API_KEY authentication flows
18
+ - Useful for testing without requiring Keycloak setup
19
+
20
+ - **PowerShell Makefile**: Added `Makefile.ps1` with all development commands for Windows PowerShell users
21
+ - Replaces `dev.bat` and `dev.ps1` scripts with unified PowerShell Makefile
22
+ - Supports all standard development commands (install, test, lint, format, build, etc.)
23
+ - Consistent interface with Unix Makefile
24
+
25
+ - **Validate Command**: Added new `validate` target to both Makefile and Makefile.ps1
26
+ - Runs lint + format + test in sequence
27
+ - Useful for pre-commit validation and CI/CD pipelines
28
+ - Usage: `make validate` or `.\Makefile.ps1 validate`
29
+
30
+ ### Changed
31
+
32
+ - **Development Scripts**: Replaced `dev.bat` and `dev.ps1` with `Makefile.ps1` for better consistency
33
+ - All development commands now available through Makefile interface
34
+ - Improved cross-platform compatibility
35
+
36
+ ### Testing
37
+
38
+ - Added comprehensive test suite for API_KEY functionality
39
+ - Tests for `validate_token()` with API_KEY matching and non-matching scenarios
40
+ - Tests for `get_user()` and `get_user_info()` with API_KEY
41
+ - Tests for config loader API_KEY loading
42
+ - All tests verify OAuth2 fallback behavior when API_KEY doesn't match
43
+
44
+ ---
45
+
8
46
  ## [1.1.0] - 2025-10-30
9
47
 
10
48
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: miso-client
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python client SDK for AI Fabrix authentication, authorization, and logging
5
5
  Home-page: https://github.com/aifabrix/miso-client-python
6
6
  Author: AI Fabrix Team
@@ -366,6 +366,40 @@ ENCRYPTION_KEY=your-32-byte-encryption-key
366
366
 
367
367
  ---
368
368
 
369
+ ### Testing with API Key
370
+
371
+ **What happens:** When `API_KEY` is set in your `.env` file, you can authenticate requests using the API key as a bearer token, bypassing OAuth2 authentication. This is useful for testing without setting up Keycloak.
372
+
373
+ ```python
374
+ from miso_client import MisoClient, load_config
375
+
376
+ client = MisoClient(load_config())
377
+ await client.initialize()
378
+
379
+ # Use API_KEY as bearer token (for testing only)
380
+ api_key_token = "your-api-key-from-env"
381
+ is_valid = await client.validate_token(api_key_token)
382
+ # Returns True if token matches API_KEY from .env
383
+
384
+ user = await client.get_user(api_key_token)
385
+ # Returns None (API key auth doesn't provide user info)
386
+ ```
387
+
388
+ **Configuration:**
389
+
390
+ ```bash
391
+ # Add to .env for testing
392
+ API_KEY=your-test-api-key-here
393
+ ```
394
+
395
+ **Important:**
396
+ - API_KEY authentication bypasses OAuth2 validation completely
397
+ - User information methods (`get_user()`, `get_user_info()`) return `None` when using API_KEY
398
+ - Token validation returns `True` if the bearer token matches the configured `API_KEY`
399
+ - This feature is intended for testing and development only
400
+
401
+ ---
402
+
369
403
  ## 🔧 Configuration
370
404
 
371
405
  ```python
@@ -380,6 +414,7 @@ config = MisoClientConfig(
380
414
  port=6379,
381
415
  ),
382
416
  log_level="info", # Optional: 'debug' | 'info' | 'warn' | 'error'
417
+ api_key="your-test-api-key", # Optional: API key for testing (bypasses OAuth2)
383
418
  cache={ # Optional: Cache TTL settings
384
419
  "role_ttl": 900, # Role cache TTL (default: 900s)
385
420
  "permission_ttl": 900, # Permission cache TTL (default: 900s)
@@ -490,6 +525,7 @@ MISO_CONTROLLER_URL=http://localhost:3000
490
525
  REDIS_HOST=localhost
491
526
  REDIS_PORT=6379
492
527
  MISO_LOG_LEVEL=info
528
+ API_KEY=your-test-api-key # Optional: For testing (bypasses OAuth2)
493
529
  ```
494
530
 
495
531
  ---
@@ -317,6 +317,40 @@ ENCRYPTION_KEY=your-32-byte-encryption-key
317
317
 
318
318
  ---
319
319
 
320
+ ### Testing with API Key
321
+
322
+ **What happens:** When `API_KEY` is set in your `.env` file, you can authenticate requests using the API key as a bearer token, bypassing OAuth2 authentication. This is useful for testing without setting up Keycloak.
323
+
324
+ ```python
325
+ from miso_client import MisoClient, load_config
326
+
327
+ client = MisoClient(load_config())
328
+ await client.initialize()
329
+
330
+ # Use API_KEY as bearer token (for testing only)
331
+ api_key_token = "your-api-key-from-env"
332
+ is_valid = await client.validate_token(api_key_token)
333
+ # Returns True if token matches API_KEY from .env
334
+
335
+ user = await client.get_user(api_key_token)
336
+ # Returns None (API key auth doesn't provide user info)
337
+ ```
338
+
339
+ **Configuration:**
340
+
341
+ ```bash
342
+ # Add to .env for testing
343
+ API_KEY=your-test-api-key-here
344
+ ```
345
+
346
+ **Important:**
347
+ - API_KEY authentication bypasses OAuth2 validation completely
348
+ - User information methods (`get_user()`, `get_user_info()`) return `None` when using API_KEY
349
+ - Token validation returns `True` if the bearer token matches the configured `API_KEY`
350
+ - This feature is intended for testing and development only
351
+
352
+ ---
353
+
320
354
  ## 🔧 Configuration
321
355
 
322
356
  ```python
@@ -331,6 +365,7 @@ config = MisoClientConfig(
331
365
  port=6379,
332
366
  ),
333
367
  log_level="info", # Optional: 'debug' | 'info' | 'warn' | 'error'
368
+ api_key="your-test-api-key", # Optional: API key for testing (bypasses OAuth2)
334
369
  cache={ # Optional: Cache TTL settings
335
370
  "role_ttl": 900, # Role cache TTL (default: 900s)
336
371
  "permission_ttl": 900, # Permission cache TTL (default: 900s)
@@ -441,6 +476,7 @@ MISO_CONTROLLER_URL=http://localhost:3000
441
476
  REDIS_HOST=localhost
442
477
  REDIS_PORT=6379
443
478
  MISO_LOG_LEVEL=info
479
+ API_KEY=your-test-api-key # Optional: For testing (bypasses OAuth2)
444
480
  ```
445
481
 
446
482
  ---
@@ -7,34 +7,34 @@ for authentication, role-based access control, permission management, and loggin
7
7
 
8
8
  from typing import Any, Optional
9
9
 
10
+ from .errors import (
11
+ AuthenticationError,
12
+ AuthorizationError,
13
+ ConfigurationError,
14
+ ConnectionError,
15
+ MisoClientError,
16
+ )
10
17
  from .models.config import (
11
- RedisConfig,
12
- MisoClientConfig,
13
- UserInfo,
14
18
  AuthResult,
15
- LogEntry,
16
- RoleResult,
17
- PermissionResult,
19
+ ClientLoggingOptions,
18
20
  ClientTokenResponse,
21
+ LogEntry,
22
+ MisoClientConfig,
19
23
  PerformanceMetrics,
20
- ClientLoggingOptions,
24
+ PermissionResult,
25
+ RedisConfig,
26
+ RoleResult,
27
+ UserInfo,
21
28
  )
22
29
  from .services.auth import AuthService
23
- from .services.role import RoleService
30
+ from .services.cache import CacheService
31
+ from .services.encryption import EncryptionService
32
+ from .services.logger import LoggerChain, LoggerService
24
33
  from .services.permission import PermissionService
25
- from .services.logger import LoggerService, LoggerChain
26
34
  from .services.redis import RedisService
27
- from .services.encryption import EncryptionService
28
- from .services.cache import CacheService
29
- from .utils.http_client import HttpClient
35
+ from .services.role import RoleService
30
36
  from .utils.config_loader import load_config
31
- from .errors import (
32
- MisoClientError,
33
- AuthenticationError,
34
- AuthorizationError,
35
- ConnectionError,
36
- ConfigurationError,
37
- )
37
+ from .utils.http_client import HttpClient
38
38
 
39
39
  __version__ = "0.1.0"
40
40
  __author__ = "AI Fabrix Team"
@@ -44,18 +44,18 @@ __license__ = "MIT"
44
44
  class MisoClient:
45
45
  """
46
46
  Main MisoClient SDK class for authentication, authorization, and logging.
47
-
47
+
48
48
  This client provides a unified interface for:
49
49
  - Token validation and user management
50
50
  - Role-based access control
51
51
  - Permission management
52
52
  - Application logging with Redis caching
53
53
  """
54
-
54
+
55
55
  def __init__(self, config: MisoClientConfig):
56
56
  """
57
57
  Initialize MisoClient with configuration.
58
-
58
+
59
59
  Args:
60
60
  config: MisoClient configuration including controller URL, client credentials, etc.
61
61
  """
@@ -75,7 +75,7 @@ class MisoClient:
75
75
  async def initialize(self) -> None:
76
76
  """
77
77
  Initialize the client (connect to Redis if configured).
78
-
78
+
79
79
  This method should be called before using the client. It will attempt
80
80
  to connect to Redis if configured, but will gracefully fall back to
81
81
  controller-only mode if Redis is unavailable.
@@ -105,16 +105,18 @@ class MisoClient:
105
105
  def get_token(self, req: dict) -> str | None:
106
106
  """
107
107
  Extract Bearer token from request headers.
108
-
108
+
109
109
  Supports common request object patterns (dict with headers).
110
-
110
+
111
111
  Args:
112
112
  req: Request object with headers dict containing 'authorization' key
113
-
113
+
114
114
  Returns:
115
115
  Bearer token string or None if not found
116
116
  """
117
- headers_obj = req.get("headers", {}) if isinstance(req, dict) else getattr(req, "headers", {})
117
+ headers_obj = (
118
+ req.get("headers", {}) if isinstance(req, dict) else getattr(req, "headers", {})
119
+ )
118
120
  headers: dict[str, Any] = headers_obj if isinstance(headers_obj, dict) else {}
119
121
  auth_value = headers.get("authorization") or headers.get("Authorization")
120
122
  if not isinstance(auth_value, str):
@@ -123,16 +125,16 @@ class MisoClient:
123
125
  # Support "Bearer <token>" format
124
126
  if auth_value.startswith("Bearer "):
125
127
  return auth_value[7:]
126
-
128
+
127
129
  # If no Bearer prefix, assume the whole header is the token
128
130
  return auth_value
129
131
 
130
132
  async def get_environment_token(self) -> str:
131
133
  """
132
134
  Get environment token using client credentials.
133
-
135
+
134
136
  This is called automatically by HttpClient but can be called manually.
135
-
137
+
136
138
  Returns:
137
139
  Client token string
138
140
  """
@@ -141,12 +143,12 @@ class MisoClient:
141
143
  def login(self, redirect_uri: str) -> str:
142
144
  """
143
145
  Initiate login flow by redirecting to controller.
144
-
146
+
145
147
  Returns the login URL for browser redirect or manual navigation.
146
-
148
+
147
149
  Args:
148
150
  redirect_uri: URI to redirect to after successful login
149
-
151
+
150
152
  Returns:
151
153
  Login URL string
152
154
  """
@@ -155,10 +157,10 @@ class MisoClient:
155
157
  async def validate_token(self, token: str) -> bool:
156
158
  """
157
159
  Validate token with controller.
158
-
160
+
159
161
  Args:
160
162
  token: JWT token to validate
161
-
163
+
162
164
  Returns:
163
165
  True if token is valid, False otherwise
164
166
  """
@@ -167,10 +169,10 @@ class MisoClient:
167
169
  async def get_user(self, token: str) -> UserInfo | None:
168
170
  """
169
171
  Get user information from token.
170
-
172
+
171
173
  Args:
172
174
  token: JWT token
173
-
175
+
174
176
  Returns:
175
177
  UserInfo if token is valid, None otherwise
176
178
  """
@@ -179,10 +181,10 @@ class MisoClient:
179
181
  async def get_user_info(self, token: str) -> UserInfo | None:
180
182
  """
181
183
  Get user information from GET /api/auth/user endpoint.
182
-
184
+
183
185
  Args:
184
186
  token: JWT token
185
-
187
+
186
188
  Returns:
187
189
  UserInfo if token is valid, None otherwise
188
190
  """
@@ -191,10 +193,10 @@ class MisoClient:
191
193
  async def is_authenticated(self, token: str) -> bool:
192
194
  """
193
195
  Check if user is authenticated.
194
-
196
+
195
197
  Args:
196
198
  token: JWT token
197
-
199
+
198
200
  Returns:
199
201
  True if user is authenticated, False otherwise
200
202
  """
@@ -209,10 +211,10 @@ class MisoClient:
209
211
  async def get_roles(self, token: str) -> list[str]:
210
212
  """
211
213
  Get user roles (cached in Redis if available).
212
-
214
+
213
215
  Args:
214
216
  token: JWT token
215
-
217
+
216
218
  Returns:
217
219
  List of user roles
218
220
  """
@@ -221,11 +223,11 @@ class MisoClient:
221
223
  async def has_role(self, token: str, role: str) -> bool:
222
224
  """
223
225
  Check if user has specific role.
224
-
226
+
225
227
  Args:
226
228
  token: JWT token
227
229
  role: Role to check
228
-
230
+
229
231
  Returns:
230
232
  True if user has the role, False otherwise
231
233
  """
@@ -234,11 +236,11 @@ class MisoClient:
234
236
  async def has_any_role(self, token: str, roles: list[str]) -> bool:
235
237
  """
236
238
  Check if user has any of the specified roles.
237
-
239
+
238
240
  Args:
239
241
  token: JWT token
240
242
  roles: List of roles to check
241
-
243
+
242
244
  Returns:
243
245
  True if user has any of the roles, False otherwise
244
246
  """
@@ -247,11 +249,11 @@ class MisoClient:
247
249
  async def has_all_roles(self, token: str, roles: list[str]) -> bool:
248
250
  """
249
251
  Check if user has all of the specified roles.
250
-
252
+
251
253
  Args:
252
254
  token: JWT token
253
255
  roles: List of roles to check
254
-
256
+
255
257
  Returns:
256
258
  True if user has all roles, False otherwise
257
259
  """
@@ -260,10 +262,10 @@ class MisoClient:
260
262
  async def refresh_roles(self, token: str) -> list[str]:
261
263
  """
262
264
  Force refresh roles from controller (bypass cache).
263
-
265
+
264
266
  Args:
265
267
  token: JWT token
266
-
268
+
267
269
  Returns:
268
270
  Fresh list of user roles
269
271
  """
@@ -272,10 +274,10 @@ class MisoClient:
272
274
  async def get_permissions(self, token: str) -> list[str]:
273
275
  """
274
276
  Get user permissions (cached in Redis if available).
275
-
277
+
276
278
  Args:
277
279
  token: JWT token
278
-
280
+
279
281
  Returns:
280
282
  List of user permissions
281
283
  """
@@ -284,11 +286,11 @@ class MisoClient:
284
286
  async def has_permission(self, token: str, permission: str) -> bool:
285
287
  """
286
288
  Check if user has specific permission.
287
-
289
+
288
290
  Args:
289
291
  token: JWT token
290
292
  permission: Permission to check
291
-
293
+
292
294
  Returns:
293
295
  True if user has the permission, False otherwise
294
296
  """
@@ -297,11 +299,11 @@ class MisoClient:
297
299
  async def has_any_permission(self, token: str, permissions: list[str]) -> bool:
298
300
  """
299
301
  Check if user has any of the specified permissions.
300
-
302
+
301
303
  Args:
302
304
  token: JWT token
303
305
  permissions: List of permissions to check
304
-
306
+
305
307
  Returns:
306
308
  True if user has any of the permissions, False otherwise
307
309
  """
@@ -310,11 +312,11 @@ class MisoClient:
310
312
  async def has_all_permissions(self, token: str, permissions: list[str]) -> bool:
311
313
  """
312
314
  Check if user has all of the specified permissions.
313
-
315
+
314
316
  Args:
315
317
  token: JWT token
316
318
  permissions: List of permissions to check
317
-
319
+
318
320
  Returns:
319
321
  True if user has all permissions, False otherwise
320
322
  """
@@ -323,10 +325,10 @@ class MisoClient:
323
325
  async def refresh_permissions(self, token: str) -> list[str]:
324
326
  """
325
327
  Force refresh permissions from controller (bypass cache).
326
-
328
+
327
329
  Args:
328
330
  token: JWT token
329
-
331
+
330
332
  Returns:
331
333
  Fresh list of user permissions
332
334
  """
@@ -335,7 +337,7 @@ class MisoClient:
335
337
  async def clear_permissions_cache(self, token: str) -> None:
336
338
  """
337
339
  Clear cached permissions for a user.
338
-
340
+
339
341
  Args:
340
342
  token: JWT token
341
343
  """
@@ -347,7 +349,7 @@ class MisoClient:
347
349
  def log(self) -> LoggerService:
348
350
  """
349
351
  Get logger service for application logging.
350
-
352
+
351
353
  Returns:
352
354
  LoggerService instance
353
355
  """
@@ -358,12 +360,12 @@ class MisoClient:
358
360
  def encrypt(self, plaintext: str) -> str:
359
361
  """
360
362
  Encrypt sensitive data.
361
-
363
+
362
364
  Convenience method that delegates to encryption service.
363
-
365
+
364
366
  Args:
365
367
  plaintext: Plain text string to encrypt
366
-
368
+
367
369
  Returns:
368
370
  Base64-encoded encrypted string
369
371
  """
@@ -372,12 +374,12 @@ class MisoClient:
372
374
  def decrypt(self, encrypted_text: str) -> str:
373
375
  """
374
376
  Decrypt sensitive data.
375
-
377
+
376
378
  Convenience method that delegates to encryption service.
377
-
379
+
378
380
  Args:
379
381
  encrypted_text: Base64-encoded encrypted string
380
-
382
+
381
383
  Returns:
382
384
  Decrypted plain text string
383
385
  """
@@ -388,12 +390,12 @@ class MisoClient:
388
390
  async def cache_get(self, key: str) -> Optional[Any]:
389
391
  """
390
392
  Get cached value.
391
-
393
+
392
394
  Convenience method that delegates to cache service.
393
-
395
+
394
396
  Args:
395
397
  key: Cache key
396
-
398
+
397
399
  Returns:
398
400
  Cached value if found, None otherwise
399
401
  """
@@ -402,14 +404,14 @@ class MisoClient:
402
404
  async def cache_set(self, key: str, value: Any, ttl: int) -> bool:
403
405
  """
404
406
  Set cached value with TTL.
405
-
407
+
406
408
  Convenience method that delegates to cache service.
407
-
409
+
408
410
  Args:
409
411
  key: Cache key
410
412
  value: Value to cache
411
413
  ttl: Time to live in seconds
412
-
414
+
413
415
  Returns:
414
416
  True if successful, False otherwise
415
417
  """
@@ -418,12 +420,12 @@ class MisoClient:
418
420
  async def cache_delete(self, key: str) -> bool:
419
421
  """
420
422
  Delete cached value.
421
-
423
+
422
424
  Convenience method that delegates to cache service.
423
-
425
+
424
426
  Args:
425
427
  key: Cache key
426
-
428
+
427
429
  Returns:
428
430
  True if deleted, False otherwise
429
431
  """
@@ -432,7 +434,7 @@ class MisoClient:
432
434
  async def cache_clear(self) -> None:
433
435
  """
434
436
  Clear all cached values.
435
-
437
+
436
438
  Convenience method that delegates to cache service.
437
439
  """
438
440
  await self.cache.clear()
@@ -442,7 +444,7 @@ class MisoClient:
442
444
  def get_config(self) -> MisoClientConfig:
443
445
  """
444
446
  Get current configuration.
445
-
447
+
446
448
  Returns:
447
449
  Copy of current configuration
448
450
  """
@@ -451,7 +453,7 @@ class MisoClient:
451
453
  def is_redis_connected(self) -> bool:
452
454
  """
453
455
  Check if Redis is connected.
454
-
456
+
455
457
  Returns:
456
458
  True if Redis is connected, False otherwise
457
459
  """
@@ -7,11 +7,13 @@ This module defines custom exceptions for the MisoClient SDK.
7
7
 
8
8
  class MisoClientError(Exception):
9
9
  """Base exception for MisoClient SDK errors."""
10
-
11
- def __init__(self, message: str, status_code: int | None = None, error_body: dict | None = None):
10
+
11
+ def __init__(
12
+ self, message: str, status_code: int | None = None, error_body: dict | None = None
13
+ ):
12
14
  """
13
15
  Initialize MisoClient error.
14
-
16
+
15
17
  Args:
16
18
  message: Error message
17
19
  status_code: HTTP status code if applicable
@@ -25,20 +27,23 @@ class MisoClientError(Exception):
25
27
 
26
28
  class AuthenticationError(MisoClientError):
27
29
  """Raised when authentication fails."""
30
+
28
31
  pass
29
32
 
30
33
 
31
34
  class AuthorizationError(MisoClientError):
32
35
  """Raised when authorization check fails."""
36
+
33
37
  pass
34
38
 
35
39
 
36
40
  class ConnectionError(MisoClientError):
37
41
  """Raised when connection to controller or Redis fails."""
42
+
38
43
  pass
39
44
 
40
45
 
41
46
  class ConfigurationError(MisoClientError):
42
47
  """Raised when configuration is invalid."""
43
- pass
44
48
 
49
+ pass