canonicalwebteam.store-api 6.8.1__py3-none-any.whl → 7.0.0__py3-none-any.whl

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.
@@ -132,7 +132,6 @@ class DeviceGW(Base):
132
132
  if featured:
133
133
  params["featured"] = featured
134
134
  response = self.session.get(url, params=params, headers=headers)
135
- # pprint(response.json())
136
135
  return self.process_response(response)
137
136
 
138
137
  def get_all_items(self, size: int, api_version: int = 1) -> dict:
@@ -229,6 +228,34 @@ class DeviceGW(Base):
229
228
  )
230
229
  return self.process_response(response)
231
230
 
231
+ def get_snap_details(
232
+ self,
233
+ name: str,
234
+ channel: Optional[str] = None,
235
+ fields: list = [],
236
+ ) -> dict:
237
+ """
238
+ Documentation: https://api.snapcraft.io/docs/details.html#snap_details
239
+ Endpoint: [GET]
240
+ https://api.snapcraft.io/api/v1/{name_space}/details/{package_name}
241
+ """
242
+ # this method is only available in API version 1
243
+ api_version = 1
244
+ url = self.get_endpoint_url("details/" + name, api_version=api_version)
245
+ params = {}
246
+ if fields:
247
+ params = {"fields": ",".join(fields)}
248
+ if channel:
249
+ params["channel"] = channel
250
+ headers = self.config[api_version].get("headers")
251
+
252
+ response = self.session.get(
253
+ url,
254
+ params=params,
255
+ headers=headers,
256
+ )
257
+ return self.process_response(response)
258
+
232
259
  def get_public_metrics(self, json: dict, api_version: int = 1) -> dict:
233
260
  """
234
261
  Documentation: https://api.snapcraft.io/docs/metrics.html
File without changes
@@ -0,0 +1,87 @@
1
+ import os
2
+ from cachetools import TTLCache
3
+ import redis
4
+ import json
5
+ import logging
6
+ from typing import Optional, Any
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ host = os.getenv("REDIS_DB_HOSTNAME", "localhost")
11
+ port = os.getenv("REDIS_DB_PORT", "6379")
12
+ password = os.getenv("REDIS_DB_PASSWORD", None)
13
+
14
+
15
+ class RedisCache:
16
+ def __init__(self, namespace: str, maxsize: int, ttl: int = 300):
17
+ self.namespace = namespace
18
+ self.fallback = TTLCache(maxsize=maxsize, ttl=ttl)
19
+ try:
20
+ self.client = redis.Redis(
21
+ host=host,
22
+ port=int(port),
23
+ password=password,
24
+ decode_responses=True,
25
+ )
26
+ self.client.ping()
27
+ self.redis_available = True
28
+ except redis.RedisError as e:
29
+ logger.warning("Redis unavailable: %s", e)
30
+ self.redis_available = False
31
+
32
+ def _build_key(self, key: str) -> str:
33
+ return f"{self.namespace}:{key}"
34
+
35
+ def _serialize(self, value: Any) -> str:
36
+ if isinstance(value, str):
37
+ return value
38
+ try:
39
+ return json.dumps(value)
40
+ except (TypeError, ValueError) as e:
41
+ logger.error("Serialization error: %s", e)
42
+ raise
43
+
44
+ def _deserialize(
45
+ self, value: Optional[str], expected_type: type = str
46
+ ) -> Any:
47
+ if value is None:
48
+ return None
49
+ if expected_type is str:
50
+ return value
51
+ try:
52
+ return json.loads(value)
53
+ except (TypeError, ValueError) as e:
54
+ logger.error("Deserialization error: %s", e)
55
+ raise
56
+
57
+ def get(self, key: str, expected_type: type = str) -> Any:
58
+ if self.redis_available:
59
+ full_key = self._build_key(key)
60
+ try:
61
+ value = self.client.get(full_key)
62
+ return self._deserialize(value, expected_type)
63
+ except redis.RedisError as e:
64
+ logger.error("Redis get error: %s", e)
65
+ value = self.fallback.get(key)
66
+ return value
67
+
68
+ def set(self, key: str, value: Any, ttl=300):
69
+ if self.redis_available:
70
+ full_key = self._build_key(key)
71
+ try:
72
+ serialized = self._serialize(value)
73
+ self.client.setex(full_key, ttl, serialized)
74
+ return
75
+ except redis.RedisError as e:
76
+ logger.error("Redis set error: %s", e)
77
+ self.fallback[key] = value
78
+
79
+ def delete(self, key: str):
80
+ if self.redis_available:
81
+ full_key = self._build_key(key)
82
+ try:
83
+ self.client.delete(full_key)
84
+ except redis.RedisError as e:
85
+ logger.error("Redis delete error: %s", e)
86
+ else:
87
+ self.fallback.pop(key, None)
@@ -1,22 +1,23 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: canonicalwebteam.store-api
3
- Version: 6.8.1
3
+ Version: 7.0.0
4
4
  Summary:
5
5
  License: LGPL-3.0
6
6
  Author: Canonical Web Team
7
7
  Author-email: webteam@canonical.com
8
- Requires-Python: >=3.8,<4.0
8
+ Requires-Python: >=3.9,<4.0
9
9
  Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.8
12
11
  Classifier: Programming Language :: Python :: 3.9
13
12
  Classifier: Programming Language :: Python :: 3.10
14
13
  Classifier: Programming Language :: Python :: 3.11
15
14
  Classifier: Programming Language :: Python :: 3.12
16
15
  Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: cachetools (>=6.2.0,<7.0.0)
17
17
  Requires-Dist: coverage (>=7.0,<8.0)
18
18
  Requires-Dist: mypy (>=1.14.1,<2.0.0)
19
19
  Requires-Dist: pymacaroons (==0.13.0)
20
+ Requires-Dist: redis (>=6.4.0,<7.0.0)
20
21
  Requires-Dist: requests (>=2.32.2,<3.0.0)
21
22
  Description-Content-Type: text/markdown
22
23
 
@@ -4,9 +4,11 @@ canonicalwebteam/retry_utils.py,sha256=zGGabWzHyoXPNdwXBS_gbz3W0Qpdg3wN1G6aNy_xe
4
4
  canonicalwebteam/store_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  canonicalwebteam/store_api/base.py,sha256=_kx3_hPQHJPUtdf3z4NXmcwHlswV1g1mw483fZXD5LM,3331
6
6
  canonicalwebteam/store_api/dashboard.py,sha256=M5JLjTTahN-bfiVz9SuP6ahLjqEvOalwmNim6X5Ky6o,22796
7
- canonicalwebteam/store_api/devicegw.py,sha256=YXmVXdHCZhukNHJq-eaFUCxa2VxqLT8qt19UrqgXGN0,9777
7
+ canonicalwebteam/store_api/devicegw.py,sha256=i42fnc29-CF3vM_tm7mwoOjQraDhu41EDkxILle1pQ4,10627
8
8
  canonicalwebteam/store_api/publishergw.py,sha256=u2D2Y76xC8ms16XTZcUe_KmRdcyzqOV2g0aN9HYZBrQ,29702
9
- canonicalwebteam_store_api-6.8.1.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
10
- canonicalwebteam_store_api-6.8.1.dist-info/METADATA,sha256=EwLBQ8u54hVJw3XFgYLribWqsubU_gNtAMdVMyj6VxA,2253
11
- canonicalwebteam_store_api-6.8.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
12
- canonicalwebteam_store_api-6.8.1.dist-info/RECORD,,
9
+ canonicalwebteam/stores_web_redis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ canonicalwebteam/stores_web_redis/utility.py,sha256=h-4AxoMM0TBYjgWgq6dlN1-c0VKzaB9ZDzSPe75CVdY,2787
11
+ canonicalwebteam_store_api-7.0.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
12
+ canonicalwebteam_store_api-7.0.0.dist-info/METADATA,sha256=-iatcvbkeNQnpOgKOaPyTkdfl4LM1ckmUk05XMa1svI,2284
13
+ canonicalwebteam_store_api-7.0.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
+ canonicalwebteam_store_api-7.0.0.dist-info/RECORD,,