canonicalwebteam.store-api 7.1.0__tar.gz → 7.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 canonicalwebteam.store-api might be problematic. Click here for more details.

Files changed (14) hide show
  1. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/PKG-INFO +1 -1
  2. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/stores_web_redis/utility.py +36 -14
  3. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/pyproject.toml +1 -1
  4. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/LICENSE +0 -0
  5. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/README.md +0 -0
  6. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/__init__.py +0 -0
  7. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/exceptions.py +0 -0
  8. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/retry_utils.py +0 -0
  9. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/store_api/__init__.py +0 -0
  10. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/store_api/base.py +0 -0
  11. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/store_api/dashboard.py +0 -0
  12. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/store_api/devicegw.py +0 -0
  13. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/store_api/publishergw.py +0 -0
  14. {canonicalwebteam_store_api-7.1.0 → canonicalwebteam_store_api-7.2.0}/canonicalwebteam/stores_web_redis/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: canonicalwebteam.store-api
3
- Version: 7.1.0
3
+ Version: 7.2.0
4
4
  Summary:
5
5
  License: LGPL-3.0
6
6
  Author: Canonical Web Team
@@ -3,7 +3,7 @@ from cachetools import TTLCache
3
3
  import redis
4
4
  import json
5
5
  import logging
6
- from typing import Optional, Any
6
+ from typing import Optional, Any, Union
7
7
 
8
8
  logger = logging.getLogger(__name__)
9
9
 
@@ -12,6 +12,16 @@ port = os.getenv("REDIS_DB_PORT", "6379")
12
12
  password = os.getenv("REDIS_DB_PASSWORD", None)
13
13
 
14
14
 
15
+ class SafeJSONEncoder(json.JSONEncoder):
16
+ def default(self, obj):
17
+ if isinstance(obj, bytes):
18
+ try:
19
+ return obj.decode("utf-8")
20
+ except UnicodeDecodeError:
21
+ return f"<<non-decodable-bytes ({len(obj)} bytes)>>"
22
+ return super().default(obj)
23
+
24
+
15
25
  class RedisCache:
16
26
  def __init__(self, namespace: str, maxsize: int, ttl: int = 300):
17
27
  self.namespace = namespace
@@ -29,20 +39,23 @@ class RedisCache:
29
39
  logger.warning("Redis unavailable: %s", e)
30
40
  self.redis_available = False
31
41
 
32
- def _build_key(self, base_key: str, **parts) -> str:
42
+ def _build_key(
43
+ self, key: Union[str, tuple[str, Optional[dict[str, Any]]]]
44
+ ) -> str:
45
+ base_key, parts = key if isinstance(key, tuple) else (key, {})
33
46
  key_parts = ":".join(f"{k}-{v}" for k, v in parts.items() if v)
34
- key = (
47
+ full_key = (
35
48
  f"{self.namespace}:{base_key}:{key_parts}"
36
49
  if key_parts
37
50
  else f"{self.namespace}:{base_key}"
38
51
  )
39
- return key
52
+ return full_key
40
53
 
41
54
  def _serialize(self, value: Any) -> str:
42
55
  if isinstance(value, str):
43
56
  return value
44
57
  try:
45
- return json.dumps(value)
58
+ return json.dumps(value, cls=SafeJSONEncoder)
46
59
  except (TypeError, ValueError) as e:
47
60
  logger.error("Serialization error: %s", e)
48
61
  raise
@@ -60,34 +73,43 @@ class RedisCache:
60
73
  logger.error("Deserialization error: %s", e)
61
74
  raise
62
75
 
63
- def get(self, key: str, expected_type: type = str) -> Any:
76
+ def get(
77
+ self,
78
+ key: Union[str, tuple[str, Optional[dict[str, Any]]]],
79
+ expected_type: type = str,
80
+ ) -> Any:
81
+ full_key = self._build_key(key)
64
82
  if self.redis_available:
65
- full_key = self._build_key(key)
66
83
  try:
67
84
  value = self.client.get(full_key)
68
85
  return self._deserialize(value, expected_type)
69
86
  except redis.RedisError as e:
70
87
  logger.error("Redis get error: %s", e)
71
- value = self.fallback.get(key)
88
+ value = self.fallback.get(full_key)
72
89
  return value
73
90
 
74
- def set(self, key: str, value: Any, ttl=300):
91
+ def set(
92
+ self,
93
+ key: Union[str, tuple[str, Optional[dict[str, Any]]]],
94
+ value: Any,
95
+ ttl=300,
96
+ ):
97
+ full_key = self._build_key(key)
75
98
  if self.redis_available:
76
- full_key = self._build_key(key)
77
99
  try:
78
100
  serialized = self._serialize(value)
79
101
  self.client.setex(full_key, ttl, serialized)
80
102
  return
81
103
  except redis.RedisError as e:
82
104
  logger.error("Redis set error: %s", e)
83
- self.fallback[key] = value
105
+ self.fallback[full_key] = value
84
106
 
85
- def delete(self, key: str):
107
+ def delete(self, key: Union[str, tuple[str, Optional[dict[str, Any]]]]):
108
+ full_key = self._build_key(key)
86
109
  if self.redis_available:
87
- full_key = self._build_key(key)
88
110
  try:
89
111
  self.client.delete(full_key)
90
112
  except redis.RedisError as e:
91
113
  logger.error("Redis delete error: %s", e)
92
114
  else:
93
- self.fallback.pop(key, None)
115
+ self.fallback.pop(full_key, None)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = 'canonicalwebteam.store-api'
3
- version = '7.1.0'
3
+ version = '7.2.0'
4
4
  description = ''
5
5
  authors = ['Canonical Web Team <webteam@canonical.com>']
6
6
  license = 'LGPL-3.0'