canonicalwebteam.store-api 6.8.0__py3-none-any.whl → 6.9.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.
@@ -1,5 +1,5 @@
1
1
  from typing import Callable, Tuple, Type, TypeVar
2
- from random import random
2
+ from random import uniform
3
3
  from sys import maxsize as MAX_INT
4
4
  import functools
5
5
 
@@ -22,27 +22,45 @@ def retry(
22
22
  Decorator that implements retry logic for `func` when any of the
23
23
  Exceptions in `exceptions` happen.
24
24
 
25
- Arguments:
26
- func: function what will be retried
27
-
28
- Keyword arguments:
29
- limit: max number of retry attempts
30
- exceptions: tuple containing the types of exceptions we can catch and
31
- that trigger a retry
32
- callback_fn: function that takes as argument an exception caught a during
33
- the retry loop, it should return a bool indicating whether to abort
34
- the loop or not; it will be called every time a member of `exceptions`
35
- is caught
36
- logger_fn: function that logs errors caught and not propagated during
37
- the retry loop; it will be called every time a member of `exceptions`
38
- is caught
39
- delay_fn: function that takes the current attempt as an argument and
40
- returns a float indicating the delay in seconds before calling `func`
41
- again
42
- sleep_fn: function that takes a float indicating a delay in seconds and
43
- waits for this specified time before executing `func` again; it's
44
- user's responsibility to make sure the sleep function is appropriate
45
- for their usage (e.g. use an async sleep in and async environment)
25
+ Args:
26
+ func (Callable[P, R], optional): The function that will be retried.
27
+ Defaults to `None` when invoking the decorator using parameters,
28
+ e.g. `@retry(limit=3)`).
29
+ limit (int, optional): The maximum number of retry attempts.
30
+ Defaults to `sys.maxsize`, allowing for a very large number of
31
+ retries.
32
+ delay_fn (Callable[[int], float], optional): A function that accepts
33
+ the current attempt number (starting from 1) and returns a float
34
+ representing the delay in seconds before the next call to `func`.
35
+ Defaults to a function that always returns 0.0 (no delay).
36
+ sleep_fn (Callable[[float], None], optional): A function that takes
37
+ a float (delay in seconds) and pauses execution for that duration.
38
+ Users are responsible for ensuring this function is appropriate
39
+ for their environment (e.g., an async sleep for async contexts).
40
+ Defaults to a function that performs no actual sleep.
41
+ callback_fn (Callable[[Exception], bool], optional): A function that
42
+ is called every time an exception from `exceptions` is caught
43
+ during the retry loop. It receives the caught exception as an
44
+ argument and should return `True` to abort the retry loop, or
45
+ `False` to continue. Defaults to a function that always returns
46
+ `False`.
47
+ logger_fn (Callable[[str], None], optional): A function designed to
48
+ log errors that are caught and handled (not propagated) during
49
+ the retry loop. It's invoked each time an exception from
50
+ `exceptions` is caught. Defaults to a function that performs no
51
+ logging.
52
+ exceptions (Tuple[Type[Exception]], optional): A tuple containing the
53
+ types of exceptions that will trigger a retry. Defaults to
54
+ `(Exception)`, meaning any standard exception will cause a retry.
55
+
56
+ Returns:
57
+ Callable[P, R]: A decorated version of the input function `func`
58
+ that incorporates the defined retry logic. If `func` is initially
59
+ `None` (when used as `@retry(...)`), it returns a decorator
60
+ function ready to be applied to another callable.
61
+
62
+ Raises:
63
+ ValueError: if `limit` is less than 1
46
64
  """
47
65
 
48
66
  if func is None:
@@ -59,7 +77,7 @@ def retry(
59
77
  exceptions=exceptions,
60
78
  )
61
79
 
62
- if limit <= 0:
80
+ if limit < 1:
63
81
  raise ValueError("The limit must be at least 1")
64
82
 
65
83
  @functools.wraps(func)
@@ -94,30 +112,59 @@ def retry(
94
112
  return _retry
95
113
 
96
114
 
97
- def delay_constant(delay: float):
115
+ def delay_constant(d: float):
98
116
  """
99
- Returns a function that always returns `delay`
117
+ Create a constant delay function that always returns `d`.
118
+
119
+ Args:
120
+ d (float): The constant delay in seconds that the returned function
121
+ will always provide.
122
+
123
+ Returns:
124
+ Callable[[int], float]: A function that takes an integer
125
+ (representing the attempt number) and always returns the
126
+ specified `d` float.
127
+
128
+ Raises:
129
+ ValueError: if `d` is negative
100
130
  """
101
- if delay < 0:
131
+ if d < 0:
102
132
  raise ValueError("The delay must be at least 0")
103
133
 
104
134
  def _delay_constant(_: int):
105
- return delay
135
+ return d
106
136
 
107
137
  return _delay_constant
108
138
 
109
139
 
110
- def delay_random(min: float, max: float):
140
+ def delay_random(min_delay: float, max_delay: float):
111
141
  """
112
- Returns a function that picks a random delay between `min` and `max`
142
+ Create a random delay function that returns a random value between
143
+ `min_delay` and `max_delay`.
144
+
145
+ Args:
146
+ min_delay (float): The minimum delay in seconds that the returned
147
+ function will provide.
148
+ max_delay (float): The maximum delay in seconds that the returned
149
+ function will provide.
150
+
151
+ Returns:
152
+ Callable[[int], float]: A function that takes an integer
153
+ (representing the attempt number) and returns a random float
154
+ between `min_delay` and `max_delay`.
155
+
156
+ Raises:
157
+ ValueError: if `min` is negative
158
+ ValueError: if `max` is less than or equal to `min`
113
159
  """
114
- if min < 0:
160
+
161
+ if min_delay < 0:
115
162
  raise ValueError("The minimum delay must be at least 0")
116
- if max <= min:
163
+ if max_delay <= min_delay:
117
164
  raise ValueError("The maximum delay must be greater than the minimum")
118
165
 
119
166
  def _delay_random(_: int):
120
- return min + random() * (max - min)
167
+ return uniform(min_delay, max_delay)
121
168
 
122
169
  return _delay_random
123
170
 
@@ -126,10 +173,30 @@ def delay_exponential(
126
173
  delay_mult: float, exp_base: float, max_delay: float = float("inf")
127
174
  ):
128
175
  """
129
- Returns a function that implements an exponential backoff with an upper
130
- limit based on the number of attempts made `n`, according to the following
131
- formula:
132
- min(`max_delay`, `delay_mult` * `exp_base`^`n`)
176
+ Create a function that implements an exponential backoff with an upper
177
+ limit. The delay is calculated based on the number of attempts made `n`,
178
+ according to the following formula:
179
+ `min(max_delay, delay_mult * exp_base^n)`.
180
+
181
+ Args:
182
+ delay_mult (float): The multiplier for the exponential delay
183
+ calculation. This value scales the base exponential growth.
184
+ exp_base (float): The base of the exponent for the delay
185
+ calculation. This determines how quickly the delay increases
186
+ with each attempt.
187
+ max_delay (float, optional): The upper limit for the delay in
188
+ seconds. The calculated exponential delay will not exceed this
189
+ value. Defaults to positive infinity.
190
+
191
+ Returns:
192
+ Callable[[int], float]: A function that takes an integer
193
+ (representing the attempt number `n`) and returns a float
194
+ indicating the calculated exponential delay.
195
+
196
+ Raises:
197
+ ValueError: if `delay_mult` is negative or zero
198
+ ValueError: if `exp_base` is less than 1
199
+ ValueError: if `max_delay` is negative
133
200
  """
134
201
  if delay_mult <= 0:
135
202
  raise ValueError("The delay multiplier must be greater than 0")
@@ -229,6 +229,34 @@ class DeviceGW(Base):
229
229
  )
230
230
  return self.process_response(response)
231
231
 
232
+ def get_snap_details(
233
+ self,
234
+ name: str,
235
+ channel: Optional[str] = None,
236
+ fields: list = [],
237
+ ) -> dict:
238
+ """
239
+ Documentation: https://api.snapcraft.io/docs/details.html#snap_details
240
+ Endpoint: [GET]
241
+ https://api.snapcraft.io/api/v1/{name_space}/details/{package_name}
242
+ """
243
+ # this method is only available in API version 1
244
+ api_version = 1
245
+ url = self.get_endpoint_url("details/" + name, api_version=api_version)
246
+ params = {}
247
+ if fields:
248
+ params = {"fields": ",".join(fields)}
249
+ if channel:
250
+ params["channel"] = channel
251
+ headers = self.config[api_version].get("headers")
252
+
253
+ response = self.session.get(
254
+ url,
255
+ params=params,
256
+ headers=headers,
257
+ )
258
+ return self.process_response(response)
259
+
232
260
  def get_public_metrics(self, json: dict, api_version: int = 1) -> dict:
233
261
  """
234
262
  Documentation: https://api.snapcraft.io/docs/metrics.html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: canonicalwebteam.store-api
3
- Version: 6.8.0
3
+ Version: 6.9.0
4
4
  Summary:
5
5
  License: LGPL-3.0
6
6
  Author: Canonical Web Team
@@ -1,12 +1,12 @@
1
1
  canonicalwebteam/__init__.py,sha256=ED6jHcYiuYpr_0vjGz0zx2lrrmJT9sDJCzIljoDfmlM,65
2
2
  canonicalwebteam/exceptions.py,sha256=Uf9HxtLH5fAXPdDm6H14tA8jUxKQAWUmWIovzHLtdRw,2134
3
- canonicalwebteam/retry_utils.py,sha256=KcaWscyVbzhP4VNPWUnh-mlIKe5T09z4jdI1bJgtvfg,5422
3
+ canonicalwebteam/retry_utils.py,sha256=zGGabWzHyoXPNdwXBS_gbz3W0Qpdg3wN1G6aNy_xef8,8517
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=hRyAsX8ncuZBvmtndgDrqIF_Nbtv7H6MhaclyA7yeTY,10661
8
8
  canonicalwebteam/store_api/publishergw.py,sha256=u2D2Y76xC8ms16XTZcUe_KmRdcyzqOV2g0aN9HYZBrQ,29702
9
- canonicalwebteam_store_api-6.8.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
10
- canonicalwebteam_store_api-6.8.0.dist-info/METADATA,sha256=_u5GFZweT4nhOYTN9pSs0E3zLvJnFBgbtevUyjsByuQ,2253
11
- canonicalwebteam_store_api-6.8.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
12
- canonicalwebteam_store_api-6.8.0.dist-info/RECORD,,
9
+ canonicalwebteam_store_api-6.9.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
10
+ canonicalwebteam_store_api-6.9.0.dist-info/METADATA,sha256=s4r6eLl-i1URl04CpAHOQcyducvklHim4vjjfVrJyVY,2253
11
+ canonicalwebteam_store_api-6.9.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
12
+ canonicalwebteam_store_api-6.9.0.dist-info/RECORD,,