snap-python 0.1.5__py3-none-any.whl → 0.1.7__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.
- snap_python/client.py +0 -1
- snap_python/components/store.py +53 -3
- snap_python/schemas/common.py +4 -4
- snap_python/schemas/snaps.py +1 -3
- snap_python/schemas/store/categories.py +4 -4
- snap_python/schemas/store/info.py +15 -13
- snap_python/schemas/store/refresh.py +1 -1
- snap_python/schemas/store/search.py +1 -7
- snap_python/schemas/store/track.py +138 -0
- {snap_python-0.1.5.dist-info → snap_python-0.1.7.dist-info}/METADATA +3 -3
- {snap_python-0.1.5.dist-info → snap_python-0.1.7.dist-info}/RECORD +13 -12
- {snap_python-0.1.5.dist-info → snap_python-0.1.7.dist-info}/LICENSE +0 -0
- {snap_python-0.1.5.dist-info → snap_python-0.1.7.dist-info}/WHEEL +0 -0
snap_python/client.py
CHANGED
|
@@ -61,7 +61,6 @@ 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)
|
|
65
64
|
|
|
66
65
|
@retry(httpx.HTTPError, tries=3, delay=1, backoff=1)
|
|
67
66
|
async def request(self, method: str, endpoint: str, **kwargs) -> httpx.Response:
|
snap_python/components/store.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import uuid
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
import retry
|
|
5
6
|
from httpx import AsyncClient, Response
|
|
@@ -23,6 +24,10 @@ from snap_python.schemas.store.search import (
|
|
|
23
24
|
PaginatedSnapSearchResponse,
|
|
24
25
|
SearchResponse,
|
|
25
26
|
)
|
|
27
|
+
from snap_python.schemas.store.track import (
|
|
28
|
+
TrackRiskMap,
|
|
29
|
+
channel_map_to_current_track_map,
|
|
30
|
+
)
|
|
26
31
|
|
|
27
32
|
|
|
28
33
|
class StoreEndpoints:
|
|
@@ -73,8 +78,19 @@ class StoreEndpoints:
|
|
|
73
78
|
response.raise_for_status()
|
|
74
79
|
return response.json()
|
|
75
80
|
|
|
81
|
+
async def get_snap_name_from_snap_id(self, snap_id: str) -> str | None:
|
|
82
|
+
response = await self.store_client.get(
|
|
83
|
+
f"https://api.snapcraft.io/v2/assertions/snap-declaration/16/{snap_id}"
|
|
84
|
+
)
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
response_json = response.json()
|
|
87
|
+
return response_json.get("headers", {}).get("snap-name", None)
|
|
88
|
+
|
|
76
89
|
async def get_snap_info(
|
|
77
|
-
self,
|
|
90
|
+
self,
|
|
91
|
+
snap_name: Optional[str] = None,
|
|
92
|
+
snap_id: Optional[str] = None,
|
|
93
|
+
fields: list[str] | None = None,
|
|
78
94
|
) -> InfoResponse:
|
|
79
95
|
"""
|
|
80
96
|
Get information about a snap.
|
|
@@ -89,6 +105,15 @@ class StoreEndpoints:
|
|
|
89
105
|
|
|
90
106
|
:raises ValueError: If invalid fields are provided.
|
|
91
107
|
"""
|
|
108
|
+
if snap_name is None and snap_id is None:
|
|
109
|
+
raise ValueError("Either snap_name or snap_id must be provided.")
|
|
110
|
+
if snap_name is not None and snap_id is not None:
|
|
111
|
+
raise ValueError("Only one of snap_name or snap_id must be provided.")
|
|
112
|
+
|
|
113
|
+
# get snap name from id, then proceed as usual
|
|
114
|
+
if snap_id is not None:
|
|
115
|
+
snap_name = await self.get_snap_name_from_snap_id(snap_id)
|
|
116
|
+
|
|
92
117
|
query = {}
|
|
93
118
|
if fields is not None:
|
|
94
119
|
if not all(field in VALID_SNAP_INFO_FIELDS for field in fields):
|
|
@@ -165,7 +190,7 @@ class StoreEndpoints:
|
|
|
165
190
|
async def find(
|
|
166
191
|
self,
|
|
167
192
|
query: str | None = None,
|
|
168
|
-
fields: str | None = None,
|
|
193
|
+
fields: list[str] | None = None,
|
|
169
194
|
name_startswith: str | None = None,
|
|
170
195
|
architecture: str | None = None,
|
|
171
196
|
common_id: str | None = None,
|
|
@@ -183,7 +208,7 @@ class StoreEndpoints:
|
|
|
183
208
|
:param query: The search query.
|
|
184
209
|
:type query: str, optional
|
|
185
210
|
:param fields: The fields to include in the response.
|
|
186
|
-
:type fields: str, optional
|
|
211
|
+
:type fields: list[str], optional
|
|
187
212
|
:param name_startswith: Filter snaps by name prefix.
|
|
188
213
|
:type name_startswith: str, optional
|
|
189
214
|
:param architecture: Filter snaps by architecture.
|
|
@@ -494,3 +519,28 @@ class StoreEndpoints:
|
|
|
494
519
|
response_json["limit"] = limit
|
|
495
520
|
|
|
496
521
|
return PaginatedSnapSearchResponse.model_validate(response_json)
|
|
522
|
+
|
|
523
|
+
async def get_track_risk_map(
|
|
524
|
+
self, snap_name: str
|
|
525
|
+
) -> dict[str, dict[str, TrackRiskMap]]:
|
|
526
|
+
"""Get the track risk map for a snap.
|
|
527
|
+
|
|
528
|
+
:param snap_name: The name of the snap.
|
|
529
|
+
:type snap_name: str
|
|
530
|
+
|
|
531
|
+
:returns: A dictionary mapping tracks to their risk maps.
|
|
532
|
+
:rtype: dict[str, TrackRiskMap]
|
|
533
|
+
"""
|
|
534
|
+
snap_info = await self.get_snap_info(
|
|
535
|
+
snap_name=snap_name,
|
|
536
|
+
fields=[
|
|
537
|
+
"channel-map",
|
|
538
|
+
"architectures",
|
|
539
|
+
"base",
|
|
540
|
+
"revision",
|
|
541
|
+
"confinement",
|
|
542
|
+
"version",
|
|
543
|
+
"created-at",
|
|
544
|
+
],
|
|
545
|
+
)
|
|
546
|
+
return channel_map_to_current_track_map(snap_info.channel_map)
|
snap_python/schemas/common.py
CHANGED
|
@@ -52,7 +52,7 @@ class SnapApp(BaseModel):
|
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class Media(BaseModel):
|
|
55
|
-
model_config = ConfigDict(
|
|
55
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
56
56
|
|
|
57
57
|
height: Optional[float] = None
|
|
58
58
|
type: str
|
|
@@ -65,13 +65,13 @@ class AsyncResponse(BaseResponse):
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
class Download(BaseModel):
|
|
68
|
-
model_config = ConfigDict(
|
|
68
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
69
69
|
|
|
70
70
|
size: float
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
class Revision(BaseModel):
|
|
74
|
-
model_config = ConfigDict(
|
|
74
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
75
75
|
|
|
76
76
|
base: Optional[SnapBaseVersion] = None
|
|
77
77
|
channel: Optional[str] = None
|
|
@@ -86,7 +86,7 @@ class Revision(BaseModel):
|
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
class Publisher(BaseModel):
|
|
89
|
-
model_config = ConfigDict(
|
|
89
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
90
90
|
|
|
91
91
|
display_name: str = Field(
|
|
92
92
|
...,
|
snap_python/schemas/snaps.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from pydantic import AliasChoices, AwareDatetime, BaseModel,
|
|
3
|
+
from pydantic import AliasChoices, AwareDatetime, BaseModel, Field
|
|
4
4
|
|
|
5
5
|
from snap_python.schemas.common import (
|
|
6
6
|
BaseErrorResult,
|
|
@@ -66,8 +66,6 @@ class StoreSnapFields(BaseModel):
|
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
class Snap(BaseModel):
|
|
69
|
-
model_config = ConfigDict(extra="forbid")
|
|
70
|
-
|
|
71
69
|
contact: Optional[str] = None
|
|
72
70
|
description: Optional[str] = None
|
|
73
71
|
license: str = "unset"
|
|
@@ -10,7 +10,7 @@ VALID_CATEGORY_FIELDS = ["name", "type", "title", "summary", "description", "med
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Media(BaseModel):
|
|
13
|
-
model_config = ConfigDict(
|
|
13
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
14
14
|
|
|
15
15
|
height: Optional[float] = None
|
|
16
16
|
type: str
|
|
@@ -19,7 +19,7 @@ class Media(BaseModel):
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class Category(BaseModel):
|
|
22
|
-
model_config = ConfigDict(
|
|
22
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
23
23
|
|
|
24
24
|
description: Optional[str] = None
|
|
25
25
|
media: Optional[Media] = None
|
|
@@ -31,12 +31,12 @@ class Category(BaseModel):
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class CategoryResponse(BaseModel):
|
|
34
|
-
model_config = ConfigDict(
|
|
34
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
35
35
|
|
|
36
36
|
categories: Optional[List[Category]] = None
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class SingleCategoryResponse(BaseModel):
|
|
40
|
-
model_config = ConfigDict(
|
|
40
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
41
41
|
|
|
42
42
|
category: Category
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# generated by datamodel-codegen:
|
|
2
|
-
# filename: snaps_info_schema.json
|
|
3
|
-
# timestamp: 2024-10-17T01:47:02+00:00
|
|
4
|
-
|
|
5
1
|
from typing import List, Optional
|
|
6
2
|
|
|
7
|
-
from pydantic import
|
|
3
|
+
from pydantic import (
|
|
4
|
+
AliasChoices,
|
|
5
|
+
AwareDatetime,
|
|
6
|
+
BaseModel,
|
|
7
|
+
ConfigDict,
|
|
8
|
+
Field,
|
|
9
|
+
)
|
|
8
10
|
|
|
9
11
|
from snap_python.schemas.snaps import StoreSnap
|
|
10
12
|
|
|
@@ -43,7 +45,7 @@ VALID_SNAP_INFO_FIELDS = [
|
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
class Channel(BaseModel):
|
|
46
|
-
model_config = ConfigDict(
|
|
48
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
47
49
|
|
|
48
50
|
architecture: str
|
|
49
51
|
name: str
|
|
@@ -57,7 +59,7 @@ class Channel(BaseModel):
|
|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
class Delta(BaseModel):
|
|
60
|
-
model_config = ConfigDict(
|
|
62
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
61
63
|
|
|
62
64
|
format: str
|
|
63
65
|
sha3_384: Optional[str] = Field(
|
|
@@ -70,7 +72,7 @@ class Delta(BaseModel):
|
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
class Download(BaseModel):
|
|
73
|
-
model_config = ConfigDict(
|
|
75
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
74
76
|
|
|
75
77
|
deltas: List[Delta]
|
|
76
78
|
sha3_384: Optional[str] = Field(
|
|
@@ -81,7 +83,7 @@ class Download(BaseModel):
|
|
|
81
83
|
|
|
82
84
|
|
|
83
85
|
class Epoch(BaseModel):
|
|
84
|
-
model_config = ConfigDict(
|
|
86
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
85
87
|
|
|
86
88
|
read: List[float]
|
|
87
89
|
write: List[float]
|
|
@@ -96,7 +98,7 @@ class Download1(BaseModel):
|
|
|
96
98
|
|
|
97
99
|
|
|
98
100
|
class Resource(BaseModel):
|
|
99
|
-
model_config = ConfigDict(
|
|
101
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
100
102
|
|
|
101
103
|
architectures: Optional[List[str]] = None
|
|
102
104
|
created_at: Optional[str] = Field(
|
|
@@ -113,7 +115,7 @@ class Resource(BaseModel):
|
|
|
113
115
|
|
|
114
116
|
|
|
115
117
|
class ChannelMapItem(BaseModel):
|
|
116
|
-
model_config = ConfigDict(
|
|
118
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
117
119
|
|
|
118
120
|
architectures: Optional[List[str]] = None
|
|
119
121
|
base: Optional[str] = None
|
|
@@ -143,14 +145,14 @@ class ChannelMapItem(BaseModel):
|
|
|
143
145
|
|
|
144
146
|
|
|
145
147
|
class ErrorListItem(BaseModel):
|
|
146
|
-
model_config = ConfigDict(
|
|
148
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
147
149
|
|
|
148
150
|
code: str
|
|
149
151
|
message: str
|
|
150
152
|
|
|
151
153
|
|
|
152
154
|
class InfoResponse(BaseModel):
|
|
153
|
-
model_config = ConfigDict(
|
|
155
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
154
156
|
|
|
155
157
|
channel_map: List[ChannelMapItem] = Field(
|
|
156
158
|
...,
|
|
@@ -38,7 +38,7 @@ VALID_SEARCH_CATEGORY_FIELDS = [
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class ErrorListItem(BaseModel):
|
|
41
|
-
model_config = ConfigDict(
|
|
41
|
+
model_config = ConfigDict(exclude_unset=True)
|
|
42
42
|
|
|
43
43
|
code: str
|
|
44
44
|
message: str
|
|
@@ -90,8 +90,6 @@ class SnapDetails(BaseModel):
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
class SearchResult(BaseModel):
|
|
93
|
-
model_config = ConfigDict(extra="forbid")
|
|
94
|
-
|
|
95
93
|
name: str
|
|
96
94
|
revision: Optional[Revision] = None
|
|
97
95
|
snap: StoreSnap
|
|
@@ -124,15 +122,11 @@ class SearchResult(BaseModel):
|
|
|
124
122
|
|
|
125
123
|
|
|
126
124
|
class SearchResponse(BaseModel):
|
|
127
|
-
model_config = ConfigDict(extra="forbid")
|
|
128
|
-
|
|
129
125
|
error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
|
|
130
126
|
results: List[SearchResult]
|
|
131
127
|
|
|
132
128
|
|
|
133
129
|
class ArchSearchItem(BaseModel):
|
|
134
|
-
model_config = ConfigDict(extra="ignore")
|
|
135
|
-
|
|
136
130
|
aliases: Optional[list[dict[str, str]]]
|
|
137
131
|
apps: list[str]
|
|
138
132
|
package_name: str
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import (
|
|
5
|
+
AwareDatetime,
|
|
6
|
+
BaseModel,
|
|
7
|
+
field_validator,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from snap_python.schemas.store.info import Channel, ChannelMapItem
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("snap_python.schemas.store.track")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TrackRevisionDetails(BaseModel):
|
|
16
|
+
"""Contains details for a specific track/risk/architecture
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Raises:
|
|
20
|
+
ValueError: If the architecture is invalid.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
arch: str
|
|
24
|
+
base: str
|
|
25
|
+
channel: Channel
|
|
26
|
+
confinement: str
|
|
27
|
+
created_at: AwareDatetime
|
|
28
|
+
released_at: AwareDatetime
|
|
29
|
+
revision: int
|
|
30
|
+
risk: str
|
|
31
|
+
track: str
|
|
32
|
+
version: str
|
|
33
|
+
|
|
34
|
+
@field_validator("arch")
|
|
35
|
+
@classmethod
|
|
36
|
+
def validate_arch(cls, value):
|
|
37
|
+
valid_architectures = {
|
|
38
|
+
"amd64",
|
|
39
|
+
"arm64",
|
|
40
|
+
"armhf",
|
|
41
|
+
"i386",
|
|
42
|
+
"ppc64el",
|
|
43
|
+
"s390x",
|
|
44
|
+
"riscv64",
|
|
45
|
+
}
|
|
46
|
+
if value not in valid_architectures:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"Invalid architecture: {value}. Must be one of {', '.join(valid_architectures)}."
|
|
49
|
+
)
|
|
50
|
+
return value
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TrackRiskMap(BaseModel):
|
|
54
|
+
"""Map of architectures to their revision details for a specific risk level."""
|
|
55
|
+
|
|
56
|
+
amd64: Optional[TrackRevisionDetails] = None
|
|
57
|
+
arm64: Optional[TrackRevisionDetails] = None
|
|
58
|
+
armhf: Optional[TrackRevisionDetails] = None
|
|
59
|
+
i386: Optional[TrackRevisionDetails] = None
|
|
60
|
+
ppc64el: Optional[TrackRevisionDetails] = None
|
|
61
|
+
s390x: Optional[TrackRevisionDetails] = None
|
|
62
|
+
riscv64: Optional[TrackRevisionDetails] = None
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def architectures(self) -> list[str]:
|
|
66
|
+
"""Return a list of architectures that have revisions."""
|
|
67
|
+
return [
|
|
68
|
+
arch for arch, details in self.model_dump().items() if details is not None
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def channel_map_to_current_track_map(
|
|
73
|
+
channel_map: list[ChannelMapItem],
|
|
74
|
+
) -> dict[str, dict[str, TrackRiskMap]]:
|
|
75
|
+
"""Convert a list of ChannelMapItem to a map of track -> risk -> TrackRiskMap."""
|
|
76
|
+
# track -> risk -> arch
|
|
77
|
+
current_track_map: dict[str, dict[str, TrackRiskMap]] = {}
|
|
78
|
+
|
|
79
|
+
all_tracks = set(item.channel.track for item in channel_map)
|
|
80
|
+
logger.debug(f"Found tracks: {', '.join(all_tracks)}")
|
|
81
|
+
|
|
82
|
+
for track in all_tracks:
|
|
83
|
+
current_track_map[track] = {}
|
|
84
|
+
|
|
85
|
+
for item in channel_map:
|
|
86
|
+
track = item.channel.track
|
|
87
|
+
risk = item.channel.risk
|
|
88
|
+
|
|
89
|
+
if not item.architectures:
|
|
90
|
+
logger.error(
|
|
91
|
+
f"Warning: Channel {item} has no architectures defined. Skipping."
|
|
92
|
+
)
|
|
93
|
+
continue
|
|
94
|
+
assert (
|
|
95
|
+
len(item.architectures) == 1
|
|
96
|
+
), "Channel must have exactly one architecture."
|
|
97
|
+
|
|
98
|
+
assert (
|
|
99
|
+
item.revision is not None
|
|
100
|
+
), f"Channel {item} must have a revision defined."
|
|
101
|
+
assert item.channel is not None, f"Channel {item} must have a channel defined."
|
|
102
|
+
assert item.base is not None, f"Channel {item} must have a base defined."
|
|
103
|
+
assert (
|
|
104
|
+
item.confinement is not None
|
|
105
|
+
), f"Channel {item} must have a confinement defined."
|
|
106
|
+
assert item.version is not None, f"Channel {item} must have a version defined."
|
|
107
|
+
assert (
|
|
108
|
+
item.created_at is not None
|
|
109
|
+
), f"Channel {item} must have a created_at defined."
|
|
110
|
+
assert (
|
|
111
|
+
item.channel.released_at is not None
|
|
112
|
+
), f"Channel {item} must have a released_at defined."
|
|
113
|
+
|
|
114
|
+
arch = item.architectures[0]
|
|
115
|
+
|
|
116
|
+
revision_details = TrackRevisionDetails(
|
|
117
|
+
arch=arch,
|
|
118
|
+
base=item.base,
|
|
119
|
+
channel=item.channel,
|
|
120
|
+
confinement=item.confinement,
|
|
121
|
+
created_at=item.created_at,
|
|
122
|
+
released_at=item.channel.released_at,
|
|
123
|
+
revision=item.revision,
|
|
124
|
+
risk=risk,
|
|
125
|
+
track=track,
|
|
126
|
+
version=item.version,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if risk not in current_track_map[track]:
|
|
130
|
+
current_track_map[track][risk] = TrackRiskMap()
|
|
131
|
+
setattr(current_track_map[track][risk], arch, revision_details)
|
|
132
|
+
|
|
133
|
+
# re validate the track map to ensure it has all required fields
|
|
134
|
+
for track, risk_map in current_track_map.items():
|
|
135
|
+
for risk in risk_map:
|
|
136
|
+
risk_map[risk] = TrackRiskMap.model_validate(risk_map[risk])
|
|
137
|
+
|
|
138
|
+
return current_track_map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: snap-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Interact with snapd and snapstore(s) from Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Alexander Lukens
|
|
@@ -12,8 +12,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Requires-Dist: httpx (
|
|
16
|
-
Requires-Dist: pydantic (
|
|
15
|
+
Requires-Dist: httpx (>0.27,<1)
|
|
16
|
+
Requires-Dist: pydantic (>2.9,<3)
|
|
17
17
|
Requires-Dist: retry (>=0.9.2,<0.10.0)
|
|
18
18
|
Project-URL: Documentation, https://alexdlukens.github.io/snap-python/
|
|
19
19
|
Project-URL: Repository, https://github.com/alexdlukens/snap-python
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
snap_python/__init__.py,sha256=gV43Nempk7HFKD1UCvxUhmP9x6dBmPjotcITREr81Vg,222
|
|
2
|
-
snap_python/client.py,sha256=
|
|
2
|
+
snap_python/client.py,sha256=HrgLu0ebhPci8cN3GmfOWc9-ccri80Pk4Oys2RVdoQY,6539
|
|
3
3
|
snap_python/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
snap_python/components/config.py,sha256=IO_gCrumphEZioINFmXxb8I5OVsKC9cgSa28sQbZ700,1775
|
|
5
5
|
snap_python/components/snaps.py,sha256=NfZAgoNvsvf-aJa-ZZJoJxS-KrwrG6gBe1ScN2WM5To,18003
|
|
6
|
-
snap_python/components/store.py,sha256=
|
|
6
|
+
snap_python/components/store.py,sha256=tN7LNsSpEjRLZBE1JTrUdQdcuWYZ6h7srZY7xQyZBf8,18735
|
|
7
7
|
snap_python/schemas/changes.py,sha256=7SYUFXAQq9arl7hAA3YQ0YubMurPJtknTOVxP8ryqew,1919
|
|
8
|
-
snap_python/schemas/common.py,sha256
|
|
8
|
+
snap_python/schemas/common.py,sha256=-_a9o45piK0jzwwrW96swAuaXvh_jh9WwlxKU_waCEA,2544
|
|
9
9
|
snap_python/schemas/config.py,sha256=xXTGhk6TpwI8RlR6_qnfWlBHrBnTwr3hRCO5qCnN-6U,107
|
|
10
|
-
snap_python/schemas/snaps.py,sha256=
|
|
10
|
+
snap_python/schemas/snaps.py,sha256=nh2LaqSVFJl6Enpo_SiPZllndRcSK-9bk4E4Q_CxI6w,3598
|
|
11
11
|
snap_python/schemas/store/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
snap_python/schemas/store/categories.py,sha256=
|
|
13
|
-
snap_python/schemas/store/info.py,sha256=
|
|
12
|
+
snap_python/schemas/store/categories.py,sha256=6NZyfi23zWpL2jEgoIKLrTzX9AIjq2APdiQEuCaUzEQ,1018
|
|
13
|
+
snap_python/schemas/store/info.py,sha256=6TqxAqFAXf_z1bkz9MjiNKYpbd87eXL20w4rkgJZQnM,4190
|
|
14
14
|
snap_python/schemas/store/json/category_by_name_schema.json,sha256=3-95m6V2WXaPCu_DZw-STa9YHPEbr7CI8fbhjaq881s,1674
|
|
15
15
|
snap_python/schemas/store/json/category_schema.json,sha256=c4h_eyyBbChOiNby3hYfjAh9i_1MDbPJnHHU4rGOGss,1898
|
|
16
16
|
snap_python/schemas/store/json/snaps_find_schema.json,sha256=TfKpnievs5QOc7ah97ATMCQTOEfKspONTZnwSwq_0fI,8866
|
|
17
17
|
snap_python/schemas/store/json/snaps_info_schema.json,sha256=udoOovb6Ea7EnE_R9RuZ1CpY1wOJ3-K8xP4-8zKHgrQ,15888
|
|
18
|
-
snap_python/schemas/store/refresh.py,sha256=
|
|
19
|
-
snap_python/schemas/store/search.py,sha256=
|
|
18
|
+
snap_python/schemas/store/refresh.py,sha256=fKYffBNki2-rLUk2oVnjAdQTO6P6kJTfcMtAZ1gouTo,3174
|
|
19
|
+
snap_python/schemas/store/search.py,sha256=pFdWXwscM36M9pRfHcpqpbQyNazAW0IOxy5iv4c_tWI,4404
|
|
20
|
+
snap_python/schemas/store/track.py,sha256=5x8UIXhLxDVCtG8H-JJaaaUe_5nFLOth9TkpZ51w474,4307
|
|
20
21
|
snap_python/scrape.py,sha256=ZDJAROp8jwossaAA78gBFTKQzrfnO11RgyyOZqevNd0,4576
|
|
21
22
|
snap_python/utils.py,sha256=cmUooPg5DzNL197Xxvu7LGD4Gwk3xxsT68wbVytRtV0,1240
|
|
22
|
-
snap_python-0.1.
|
|
23
|
-
snap_python-0.1.
|
|
24
|
-
snap_python-0.1.
|
|
25
|
-
snap_python-0.1.
|
|
23
|
+
snap_python-0.1.7.dist-info/LICENSE,sha256=lYXNZszxC_l2rlBvrHYs-esDegxWh8MKtjrdxA24uOk,1072
|
|
24
|
+
snap_python-0.1.7.dist-info/METADATA,sha256=aCfIUhlj5WgeIOQgwKMisa60GUSEPO6OM01JqrBySZ8,1868
|
|
25
|
+
snap_python-0.1.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
26
|
+
snap_python-0.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|