snap-python 0.0.5__tar.gz → 0.1.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.
- {snap_python-0.0.5 → snap_python-0.1.0}/PKG-INFO +2 -3
- {snap_python-0.0.5 → snap_python-0.1.0}/pyproject.toml +7 -1
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/client.py +32 -7
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/components/snaps.py +106 -12
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/components/store.py +28 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/search.py +26 -1
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/utils.py +6 -2
- {snap_python-0.0.5 → snap_python-0.1.0}/LICENSE +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/README.md +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/__init__.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/components/__init__.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/components/config.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/changes.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/common.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/config.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/snaps.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/__init__.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/categories.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/info.py +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/category_by_name_schema.json +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/category_schema.json +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/snaps_find_schema.json +0 -0
- {snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/snaps_info_schema.json +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: snap-python
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: An api to interact with snapd and snap stores
|
|
5
|
-
Home-page: https://github.com/alexlukens/snap-python
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: Alexander Lukens
|
|
8
7
|
Author-email: alexdlukens@gmail.com
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "snap-python"
|
|
3
|
-
version = "0.0
|
|
3
|
+
version = "0.1.0"
|
|
4
4
|
description = "An api to interact with snapd and snap stores"
|
|
5
5
|
authors = ["Alexander Lukens <alexdlukens@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -27,3 +27,9 @@ sphinx-rtd-theme = "^3.0.2"
|
|
|
27
27
|
[build-system]
|
|
28
28
|
requires = ["poetry-core"]
|
|
29
29
|
build-backend = "poetry.core.masonry.api"
|
|
30
|
+
|
|
31
|
+
[tool.pytest.ini_options]
|
|
32
|
+
asyncio_mode = "auto"
|
|
33
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
34
|
+
addopts = "--cov=snap_python --cov-report=html"
|
|
35
|
+
testpaths = "tests"
|
|
@@ -44,15 +44,15 @@ class SnapClient(AbstractSnapsClient):
|
|
|
44
44
|
if store_headers is None:
|
|
45
45
|
store_headers = {"Snap-Device-Series": "16", "X-Ubuntu-Series": "16"}
|
|
46
46
|
|
|
47
|
-
snapd_headers = {}
|
|
47
|
+
self.snapd_headers = {}
|
|
48
48
|
if prompt_for_authentication:
|
|
49
|
-
snapd_headers = {"X-Allow-Interaction": "true"}
|
|
49
|
+
self.snapd_headers = {"X-Allow-Interaction": "true"}
|
|
50
50
|
|
|
51
51
|
self.version = version
|
|
52
52
|
self.store_base_url = store_base_url
|
|
53
53
|
self.store_headers = store_headers
|
|
54
54
|
self.snapd_client = httpx.AsyncClient(
|
|
55
|
-
transport=self._transport, headers=snapd_headers
|
|
55
|
+
transport=self._transport, headers=self.snapd_headers
|
|
56
56
|
)
|
|
57
57
|
self.snaps = SnapsEndpoints(self)
|
|
58
58
|
self.store = StoreEndpoints(
|
|
@@ -61,6 +61,7 @@ class SnapClient(AbstractSnapsClient):
|
|
|
61
61
|
headers=self.store_headers,
|
|
62
62
|
)
|
|
63
63
|
self.config = ConfigEndpoints(self)
|
|
64
|
+
self.snapd_client = httpx.AsyncClient(transport=self._transport)
|
|
64
65
|
|
|
65
66
|
@retry(httpx.HTTPError, tries=3, delay=1, backoff=1)
|
|
66
67
|
async def request(self, method: str, endpoint: str, **kwargs) -> httpx.Response:
|
|
@@ -111,30 +112,54 @@ class SnapClient(AbstractSnapsClient):
|
|
|
111
112
|
|
|
112
113
|
return response
|
|
113
114
|
|
|
115
|
+
@retry(httpx.HTTPError, tries=3, delay=0.5)
|
|
114
116
|
async def get_changes_by_id(self, change_id: str) -> ChangesResponse:
|
|
117
|
+
"""
|
|
118
|
+
Asynchronously retrieves changes by their ID.
|
|
119
|
+
Args:
|
|
120
|
+
change_id (str): The ID of the change to retrieve.
|
|
121
|
+
Returns:
|
|
122
|
+
ChangesResponse: The response object containing the changes.
|
|
123
|
+
Raises:
|
|
124
|
+
httpx.HTTPStatusError: If the request results in an HTTP error.
|
|
125
|
+
"""
|
|
126
|
+
|
|
115
127
|
try:
|
|
116
128
|
response = await self.request("GET", f"changes/{change_id}")
|
|
117
129
|
except httpx.HTTPStatusError as e:
|
|
118
130
|
logger.warning(
|
|
119
|
-
|
|
131
|
+
"Bad response status code for get_changes_by_id: %s",
|
|
132
|
+
e.response.status_code,
|
|
120
133
|
)
|
|
121
134
|
response = e.response
|
|
122
|
-
pass
|
|
123
135
|
|
|
124
136
|
return ChangesResponse.model_validate_json(response.content)
|
|
125
137
|
|
|
126
138
|
async def get_changes_by_id_generator(
|
|
127
139
|
self, change_id: str
|
|
128
140
|
) -> AsyncGenerator[ChangesResponse, None]:
|
|
141
|
+
"""
|
|
142
|
+
Asynchronous generator to fetch changes by change ID.
|
|
143
|
+
This generator continuously requests changes from the server using the provided
|
|
144
|
+
change ID and yields the response as a ChangesResponse object. It includes error
|
|
145
|
+
handling for HTTP status errors and adds a small delay between requests to avoid
|
|
146
|
+
overwhelming the server.
|
|
147
|
+
Args:
|
|
148
|
+
change_id (str): The ID of the change to fetch.
|
|
149
|
+
Yields:
|
|
150
|
+
ChangesResponse: The response object containing the changes.
|
|
151
|
+
Raises:
|
|
152
|
+
httpx.HTTPStatusError: If the request fails with an HTTP status error.
|
|
153
|
+
"""
|
|
129
154
|
while True:
|
|
130
155
|
try:
|
|
131
156
|
response = await self.request("GET", f"changes/{change_id}")
|
|
132
157
|
except httpx.HTTPStatusError as e:
|
|
133
158
|
logger.warning(
|
|
134
|
-
|
|
159
|
+
"Bad response status code for get_changes_by_id: %s",
|
|
160
|
+
e.response.status_code,
|
|
135
161
|
)
|
|
136
162
|
response = e.response
|
|
137
|
-
pass
|
|
138
163
|
|
|
139
164
|
change_response = ChangesResponse.model_validate_json(response.content)
|
|
140
165
|
yield change_response
|
|
@@ -10,7 +10,7 @@ from snap_python.schemas.snaps import (
|
|
|
10
10
|
InstalledSnapListResponse,
|
|
11
11
|
SingleInstalledSnapResponse,
|
|
12
12
|
)
|
|
13
|
-
from snap_python.utils import AbstractSnapsClient, going_to_reload_daemon
|
|
13
|
+
from snap_python.utils import AbstractSnapsClient, SnapdAPIError, going_to_reload_daemon
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger("snap_python.components.snaps")
|
|
16
16
|
|
|
@@ -62,7 +62,6 @@ class SnapsEndpoints:
|
|
|
62
62
|
classic: bool = False,
|
|
63
63
|
dangerous: bool = False,
|
|
64
64
|
devmode: bool = False,
|
|
65
|
-
ignore_validation: bool = False,
|
|
66
65
|
jailmode: bool = False,
|
|
67
66
|
revision: int = None,
|
|
68
67
|
filename: str = None,
|
|
@@ -79,14 +78,13 @@ class SnapsEndpoints:
|
|
|
79
78
|
classic (bool, optional): Install with classic confinement. Defaults to False.
|
|
80
79
|
dangerous (bool, optional): install the given snap files even if there are no pre-acknowledged signatures for them, meaning they are not verified and could be dangerous if true (optional, implied by devmode). Defaults to False.
|
|
81
80
|
devmode (bool, optional): Install with devmode. Defaults to False.
|
|
82
|
-
ignore_validation (bool, optional): _description_. Defaults to False.
|
|
83
81
|
jailmode (bool, optional): Install snap with jailmode. Defaults to False.
|
|
84
82
|
revision (int, optional): install a specific revision of the snap. Defaults to None.
|
|
85
83
|
filename (str, optional): Path to snap to sideload. Defaults to None.
|
|
86
84
|
wait (bool, optional): Whether to wait for snap to install. If not waiting, will return async response with change id. Defaults to False.
|
|
87
85
|
|
|
88
86
|
Raises:
|
|
89
|
-
|
|
87
|
+
SnapdAPIError: If error occurs during snap install
|
|
90
88
|
|
|
91
89
|
Returns:
|
|
92
90
|
AsyncResponse | ChangesResponse: If wait is True, will return ChangesResponse. Otherwise, will return AsyncResponse
|
|
@@ -97,7 +95,6 @@ class SnapsEndpoints:
|
|
|
97
95
|
"classic": classic,
|
|
98
96
|
"dangerous": dangerous,
|
|
99
97
|
"devmode": devmode,
|
|
100
|
-
"ignore_validation": ignore_validation,
|
|
101
98
|
"jailmode": jailmode,
|
|
102
99
|
}
|
|
103
100
|
if revision:
|
|
@@ -128,17 +125,16 @@ class SnapsEndpoints:
|
|
|
128
125
|
while True:
|
|
129
126
|
try:
|
|
130
127
|
changes = await self._client.get_changes_by_id(changes_id)
|
|
131
|
-
logger.debug(
|
|
132
|
-
except httpx.HTTPError
|
|
128
|
+
logger.debug("Progress: %s", changes.result.overall_progress)
|
|
129
|
+
except httpx.HTTPError:
|
|
133
130
|
if going_to_reload_daemon(previous_changes):
|
|
134
131
|
logger.debug("Waiting for daemon to reload")
|
|
135
|
-
|
|
136
|
-
continue
|
|
132
|
+
changes = previous_changes
|
|
137
133
|
|
|
138
134
|
if changes.ready:
|
|
139
135
|
break
|
|
140
136
|
if changes.result.err:
|
|
141
|
-
raise
|
|
137
|
+
raise SnapdAPIError(f"Error in snap install: {changes.result.err}")
|
|
142
138
|
await asyncio.sleep(0.1)
|
|
143
139
|
previous_changes = changes
|
|
144
140
|
return changes
|
|
@@ -151,6 +147,18 @@ class SnapsEndpoints:
|
|
|
151
147
|
terminate: bool = False,
|
|
152
148
|
wait: bool = False,
|
|
153
149
|
) -> AsyncResponse | ChangesResponse:
|
|
150
|
+
"""
|
|
151
|
+
Asynchronously removes a snap package.
|
|
152
|
+
Args:
|
|
153
|
+
snap (str): The name of the snap package to remove.
|
|
154
|
+
purge (bool, optional): If True, purges the snap package. Defaults to False.
|
|
155
|
+
terminate (bool, optional): If True, terminates the snap package. Defaults to False.
|
|
156
|
+
wait (bool, optional): If True, waits for the removal process to complete. Defaults to False.
|
|
157
|
+
Returns:
|
|
158
|
+
AsyncResponse | ChangesResponse: The response from the snapd API, either an asynchronous response or a changes response if waiting for completion.
|
|
159
|
+
Raises:
|
|
160
|
+
SnapdAPIError: If there is an error in the snap removal process.
|
|
161
|
+
"""
|
|
154
162
|
request_data = {
|
|
155
163
|
"action": "remove",
|
|
156
164
|
"purge": purge,
|
|
@@ -168,7 +176,7 @@ class SnapsEndpoints:
|
|
|
168
176
|
while True:
|
|
169
177
|
try:
|
|
170
178
|
changes = await self._client.get_changes_by_id(changes_id)
|
|
171
|
-
except httpx.HTTPError
|
|
179
|
+
except httpx.HTTPError:
|
|
172
180
|
if going_to_reload_daemon(previous_changes):
|
|
173
181
|
logger.debug("Waiting for daemon to reload")
|
|
174
182
|
await asyncio.sleep(0.1)
|
|
@@ -176,9 +184,95 @@ class SnapsEndpoints:
|
|
|
176
184
|
if changes.ready:
|
|
177
185
|
break
|
|
178
186
|
if changes.result.err:
|
|
179
|
-
raise
|
|
187
|
+
raise SnapdAPIError(f"Error in snap remove: {changes.result.err}")
|
|
180
188
|
await asyncio.sleep(0.1)
|
|
181
189
|
previous_changes = changes
|
|
182
190
|
return changes
|
|
183
191
|
|
|
184
192
|
return response
|
|
193
|
+
|
|
194
|
+
async def refresh_snap(
|
|
195
|
+
self,
|
|
196
|
+
snap: str,
|
|
197
|
+
channel: str = "stable",
|
|
198
|
+
classic: bool = False,
|
|
199
|
+
dangerous: bool = False,
|
|
200
|
+
devmode: bool = False,
|
|
201
|
+
ignore_validation: bool = False,
|
|
202
|
+
jailmode: bool = False,
|
|
203
|
+
revision: int = None,
|
|
204
|
+
filename: str = None,
|
|
205
|
+
wait: bool = False,
|
|
206
|
+
) -> AsyncResponse | ChangesResponse:
|
|
207
|
+
"""
|
|
208
|
+
Refreshes a snap package.
|
|
209
|
+
Args:
|
|
210
|
+
snap (str): The name of the snap package to refresh.
|
|
211
|
+
channel (str, optional): The channel to refresh the snap from. Defaults to "stable".
|
|
212
|
+
classic (bool, optional): Whether to use classic confinement. Defaults to False.
|
|
213
|
+
dangerous (bool, optional): Whether to allow installation of unasserted snaps. Defaults to False.
|
|
214
|
+
devmode (bool, optional): Whether to use development mode. Defaults to False.
|
|
215
|
+
ignore_validation (bool, optional): Whether to ignore validation. Defaults to False.
|
|
216
|
+
jailmode (bool, optional): Whether to use jail mode. Defaults to False.
|
|
217
|
+
revision (int, optional): The specific revision to refresh to. Defaults to None.
|
|
218
|
+
filename (str, optional): The path to the snap file for sideloading. Defaults to None.
|
|
219
|
+
wait (bool, optional): Whether to wait for the refresh operation to complete. Defaults to False.
|
|
220
|
+
Returns:
|
|
221
|
+
AsyncResponse | ChangesResponse: The response from the refresh operation.
|
|
222
|
+
Raises:
|
|
223
|
+
FileNotFoundError: If the specified snap file does not exist.
|
|
224
|
+
ValueError: If attempting to sideload without the dangerous flag set to True.
|
|
225
|
+
SnapdAPIError: If there is an error during the snap refresh.
|
|
226
|
+
"""
|
|
227
|
+
request_data = {
|
|
228
|
+
"action": "refresh",
|
|
229
|
+
"channel": channel,
|
|
230
|
+
"classic": classic,
|
|
231
|
+
"dangerous": dangerous,
|
|
232
|
+
"devmode": devmode,
|
|
233
|
+
"ignore_validation": ignore_validation,
|
|
234
|
+
"jailmode": jailmode,
|
|
235
|
+
}
|
|
236
|
+
if revision:
|
|
237
|
+
request_data["revision"] = revision
|
|
238
|
+
if filename:
|
|
239
|
+
# sideload
|
|
240
|
+
if not Path(filename).exists():
|
|
241
|
+
raise FileNotFoundError(f"File {filename} does not exist")
|
|
242
|
+
if request_data.get("dangerous") is not True:
|
|
243
|
+
raise ValueError(
|
|
244
|
+
"Cannot sideload snap without dangerous flag set to True"
|
|
245
|
+
)
|
|
246
|
+
raw_response: httpx.Response = await self._client.request(
|
|
247
|
+
"POST",
|
|
248
|
+
f"{self.common_endpoint}",
|
|
249
|
+
data=request_data,
|
|
250
|
+
files={"snap": open(filename, "rb")},
|
|
251
|
+
)
|
|
252
|
+
else:
|
|
253
|
+
# install from default snap store
|
|
254
|
+
raw_response: httpx.Response = await self._client.request(
|
|
255
|
+
"POST", f"{self.common_endpoint}/{snap}", json=request_data
|
|
256
|
+
)
|
|
257
|
+
response = AsyncResponse.model_validate_json(raw_response.content)
|
|
258
|
+
if wait:
|
|
259
|
+
changes_id = response.change
|
|
260
|
+
previous_changes = None
|
|
261
|
+
while True:
|
|
262
|
+
try:
|
|
263
|
+
changes = await self._client.get_changes_by_id(changes_id)
|
|
264
|
+
logger.debug("Progress: %s", changes.result.overall_progress)
|
|
265
|
+
except httpx.HTTPError:
|
|
266
|
+
if going_to_reload_daemon(previous_changes):
|
|
267
|
+
logger.debug("Waiting for daemon to reload")
|
|
268
|
+
await asyncio.sleep(0.1)
|
|
269
|
+
continue
|
|
270
|
+
|
|
271
|
+
if changes.ready:
|
|
272
|
+
break
|
|
273
|
+
if changes.result.err:
|
|
274
|
+
raise SnapdAPIError(f"Error in snap remove: {changes.result.err}")
|
|
275
|
+
await asyncio.sleep(0.1)
|
|
276
|
+
previous_changes = changes
|
|
277
|
+
return changes
|
|
278
|
+
return response
|
|
@@ -11,6 +11,7 @@ from snap_python.schemas.store.categories import (
|
|
|
11
11
|
from snap_python.schemas.store.info import VALID_SNAP_INFO_FIELDS, InfoResponse
|
|
12
12
|
from snap_python.schemas.store.search import (
|
|
13
13
|
VALID_SEARCH_CATEGORY_FIELDS,
|
|
14
|
+
ArchSearchResponse,
|
|
14
15
|
SearchResponse,
|
|
15
16
|
)
|
|
16
17
|
|
|
@@ -165,3 +166,30 @@ class StoreEndpoints:
|
|
|
165
166
|
return await self.find(
|
|
166
167
|
category=category, fields=["title", "store-url", "summary"]
|
|
167
168
|
)
|
|
169
|
+
|
|
170
|
+
async def get_all_snaps_for_arch(self, arch: str) -> ArchSearchResponse:
|
|
171
|
+
# use the old "/api/v1/snaps/names" to get all snaps for a given architecture
|
|
172
|
+
|
|
173
|
+
# ensure valid arch
|
|
174
|
+
if arch not in [
|
|
175
|
+
"amd64",
|
|
176
|
+
"arm64",
|
|
177
|
+
"armhf",
|
|
178
|
+
"i386",
|
|
179
|
+
"ppc64el",
|
|
180
|
+
"s390x",
|
|
181
|
+
"riscv64",
|
|
182
|
+
]:
|
|
183
|
+
raise ValueError(f"Invalid architecture: {arch}")
|
|
184
|
+
|
|
185
|
+
route = "/api/v1/snaps/names"
|
|
186
|
+
extra_headers = {"X-Ubuntu-Architecture": arch}
|
|
187
|
+
|
|
188
|
+
response = await self.store_client.get(
|
|
189
|
+
f"{self._raw_base_url}{route}", headers=extra_headers, timeout=60
|
|
190
|
+
)
|
|
191
|
+
response.raise_for_status()
|
|
192
|
+
|
|
193
|
+
response_json = response.json()
|
|
194
|
+
response_json["arch"] = arch
|
|
195
|
+
return ArchSearchResponse.model_validate(response_json)
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
|
-
from pydantic import
|
|
3
|
+
from pydantic import (
|
|
4
|
+
AliasChoices,
|
|
5
|
+
AliasPath,
|
|
6
|
+
AwareDatetime,
|
|
7
|
+
BaseModel,
|
|
8
|
+
ConfigDict,
|
|
9
|
+
Field,
|
|
10
|
+
)
|
|
4
11
|
|
|
5
12
|
from snap_python.schemas.common import Revision
|
|
6
13
|
from snap_python.schemas.snaps import InstalledSnap, Snap, StoreSnap, StoreSnapFields
|
|
@@ -120,3 +127,21 @@ class SearchResponse(BaseModel):
|
|
|
120
127
|
|
|
121
128
|
error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
|
|
122
129
|
results: List[SearchResult]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class ArchSearchItem(BaseModel):
|
|
133
|
+
model_config = ConfigDict(extra="ignore")
|
|
134
|
+
|
|
135
|
+
aliases: Optional[list[dict[str, str]]]
|
|
136
|
+
apps: list[str]
|
|
137
|
+
package_name: str
|
|
138
|
+
summary: str
|
|
139
|
+
title: str
|
|
140
|
+
version: str
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ArchSearchResponse(BaseModel):
|
|
144
|
+
results: list[ArchSearchItem] = Field(
|
|
145
|
+
alias=AliasPath("_embedded", "clickindex:package")
|
|
146
|
+
)
|
|
147
|
+
arch: str
|
|
@@ -5,13 +5,17 @@ import httpx
|
|
|
5
5
|
from snap_python.schemas.changes import ChangesResponse
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
class SnapdAPIError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
class AbstractSnapsClient(ABC): # pragma: no cover
|
|
9
13
|
@abstractmethod
|
|
10
|
-
async def request(self) -> httpx.Response:
|
|
14
|
+
async def request(self, method: str, endpoint: str, **kwargs) -> httpx.Response:
|
|
11
15
|
pass
|
|
12
16
|
|
|
13
17
|
@abstractmethod
|
|
14
|
-
async def request_raw(self) -> httpx.Response:
|
|
18
|
+
async def request_raw(self, method: str, endpoint: str, **kwargs) -> httpx.Response:
|
|
15
19
|
pass
|
|
16
20
|
|
|
17
21
|
@abstractmethod
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/category_schema.json
RENAMED
|
File without changes
|
{snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/snaps_find_schema.json
RENAMED
|
File without changes
|
{snap_python-0.0.5 → snap_python-0.1.0}/src/snap_python/schemas/store/json/snaps_info_schema.json
RENAMED
|
File without changes
|