snap-python 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -20,6 +20,7 @@ from snap_python.schemas.store.refresh import (
20
20
  from snap_python.schemas.store.search import (
21
21
  VALID_SEARCH_CATEGORY_FIELDS,
22
22
  ArchSearchResponse,
23
+ PaginatedSnapSearchResponse,
23
24
  SearchResponse,
24
25
  )
25
26
 
@@ -396,3 +397,100 @@ class StoreEndpoints:
396
397
  )
397
398
  response.raise_for_status()
398
399
  return RefreshRevisionResponse.model_validate_json(response.content)
400
+
401
+ async def get_many_snap_revision_info(
402
+ self,
403
+ snap_name: str,
404
+ from_revision: int,
405
+ to_revision: int,
406
+ arch: str,
407
+ fields=None,
408
+ ) -> RefreshRevisionResponse:
409
+ """Get information about a snap revision.
410
+
411
+ :param snap_name: The name of the snap.
412
+ :type snap_name: str
413
+ :param revision: The revision of the snap.
414
+ :type revision: int
415
+ :param arch: The architecture of the snap to retrieve details about (e.g. amd64, arm64, riscv64, etc).
416
+ :type arch: str
417
+
418
+ :returns: The snap revision information.
419
+ :rtype: RefreshRevisionResponse
420
+ """
421
+
422
+ # cast revision to int
423
+ from_revision = int(from_revision)
424
+ to_revision = int(to_revision)
425
+ extra_headers = {"Snap-Device-Architecture": arch}
426
+ snap_info = await self.get_snap_info(snap_name=snap_name)
427
+
428
+ # I don't think this matters for the "context" field, so using info from the first available
429
+ channel_map_item = snap_info.channel_map[0]
430
+
431
+ payload = {
432
+ "context": [
433
+ {
434
+ "tracking-channel": "stable",
435
+ "snap-id": snap_info.snap_id,
436
+ "revision": channel_map_item.revision,
437
+ "instance-key": str(uuid.uuid4()),
438
+ }
439
+ ],
440
+ "actions": [],
441
+ }
442
+ for revision in range(from_revision, to_revision + 1):
443
+ payload["actions"].append(
444
+ {
445
+ "action": "download",
446
+ "name": snap_name,
447
+ "revision": revision,
448
+ "instance-key": str(uuid.uuid4()),
449
+ }
450
+ )
451
+
452
+ if fields is not None:
453
+ if not all(field in VALID_SNAP_REFRESH_FIELDS for field in fields):
454
+ raise ValueError(
455
+ f"Invalid fields. Allowed fields: {VALID_SNAP_REFRESH_FIELDS}"
456
+ )
457
+ payload["fields"] = fields
458
+
459
+ response = await self.snap_refresh(
460
+ snap_name=snap_name,
461
+ payload=payload,
462
+ extra_headers=extra_headers,
463
+ )
464
+ response.raise_for_status()
465
+ return RefreshRevisionResponse.model_validate_json(response.content)
466
+
467
+ async def get_snap_search_paginated(
468
+ self,
469
+ q: str = "",
470
+ scope: str = "wide",
471
+ arch: str = "wide",
472
+ page: int = 1,
473
+ limit: int = 100,
474
+ confinement: str = "strict,classic",
475
+ ) -> PaginatedSnapSearchResponse:
476
+ payload = {
477
+ "scope": scope,
478
+ "arch": arch,
479
+ "page": page,
480
+ "size": limit,
481
+ "confinement": confinement,
482
+ }
483
+ if q:
484
+ payload["q"] = q
485
+
486
+ response = await self.store_client.get(
487
+ f"{self._raw_base_url}/api/v1/snaps/search",
488
+ params=payload,
489
+ )
490
+
491
+ response.raise_for_status()
492
+ response_json = response.json()
493
+ response_json["page"] = page
494
+ response_json["limit"] = limit
495
+
496
+ return PaginatedSnapSearchResponse.model_validate(response_json)
@@ -72,6 +72,12 @@ class StoreRefreshSnap(Snap, SnapRefreshFields):
72
72
  pass
73
73
 
74
74
 
75
+ class RefreshResultError(BaseModel):
76
+ code: str
77
+ message: str
78
+ extra: Optional[dict] = None
79
+
80
+
75
81
  class RefreshResultData(BaseModel):
76
82
  model_config = ConfigDict(extra="forbid", exclude_unset=True)
77
83
 
@@ -98,6 +104,13 @@ class RefreshResultData(BaseModel):
98
104
  snap_id: str = Field(
99
105
  ..., alias=AliasChoices("snap-id", "snap_id"), serialization_alias="snap-id"
100
106
  )
107
+ error: RefreshResultError | None = None
108
+
109
+ @property
110
+ def is_error(self) -> bool:
111
+ if self.error:
112
+ return True
113
+ return False
101
114
 
102
115
 
103
116
  class RefreshRevisionResponse(BaseModel):
@@ -7,6 +7,7 @@ from pydantic import (
7
7
  BaseModel,
8
8
  ConfigDict,
9
9
  Field,
10
+ computed_field,
10
11
  )
11
12
 
12
13
  from snap_python.schemas.common import Revision
@@ -144,4 +145,35 @@ class ArchSearchResponse(BaseModel):
144
145
  results: list[ArchSearchItem] = Field(
145
146
  alias=AliasChoices(AliasPath("_embedded", "clickindex:package"), "results")
146
147
  )
147
- arch: str
148
+ arch: str = "wide"
149
+
150
+
151
+ class PaginatedResponse(BaseModel):
152
+ total: int
153
+ page: int = Field(ge=0)
154
+ limit: int = Field(ge=1, le=100)
155
+
156
+ @computed_field
157
+ @property
158
+ def next_page(self) -> Optional[int]:
159
+ if self.page * self.limit + self.limit < self.total:
160
+ return self.page + 1
161
+ return None
162
+
163
+ @computed_field
164
+ @property
165
+ def previous_page(self) -> Optional[int]:
166
+ if self.page > 0:
167
+ return self.page - 1
168
+ return None
169
+
170
+ @computed_field
171
+ @property
172
+ def has_more(self) -> bool:
173
+ return self.page * self.limit + self.limit < self.total
174
+
175
+
176
+ class PaginatedSnapSearchResponse(PaginatedResponse):
177
+ results: list[ArchSearchItem] = Field(
178
+ alias=AliasChoices(AliasPath("_embedded", "clickindex:package"), "results")
179
+ )
snap_python/scrape.py CHANGED
@@ -25,7 +25,6 @@ def get_highest_revision(channel_map: list[ChannelMapItem]) -> ChannelMapItem:
25
25
 
26
26
  """
27
27
 
28
- print(channel_map)
29
28
  return max(channel_map, key=lambda x: x.revision)
30
29
 
31
30
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: snap-python
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Interact with snapd and snapstore(s) from Python
5
5
  License: MIT
6
6
  Author: Alexander Lukens
@@ -3,7 +3,7 @@ snap_python/client.py,sha256=rZAfzcQNhdtTyjQml1N-9-nAianFyEwOaI4H_0FMaFE,6612
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=FQ362L83jmhu3MLKszOU1w5jGP8l5-WNBlUTLnR6IW8,13176
6
- snap_python/components/store.py,sha256=8r1WUOBu2vPpDXGSSgK9f1HKU3Rfl6wAPu6siTnEcPU,13803
6
+ snap_python/components/store.py,sha256=lxN-6cVslAeen-yfZqMPQ2iNvDUNBCClWIvLn5PZi2Q,16971
7
7
  snap_python/schemas/changes.py,sha256=7SYUFXAQq9arl7hAA3YQ0YubMurPJtknTOVxP8ryqew,1919
8
8
  snap_python/schemas/common.py,sha256=GLtC9aBo3O8vLKX9PNvzE-_DKN02OGpwsS7Ik2WK9-8,2608
9
9
  snap_python/schemas/config.py,sha256=xXTGhk6TpwI8RlR6_qnfWlBHrBnTwr3hRCO5qCnN-6U,107
@@ -15,11 +15,11 @@ snap_python/schemas/store/json/category_by_name_schema.json,sha256=3-95m6V2WXaPC
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=EjzQurejMggHJUqALoJUpXt26nh_OClkd1qZYaibews,2928
19
- snap_python/schemas/store/search.py,sha256=-Fd1G821-V6JVxvbcgfnzXy8VQoWnS9MR1oLdRurqu0,3743
20
- snap_python/scrape.py,sha256=ZL-kaKdhkz2SfM0iDoJdRLH-lovRyONRNyOm-xivyII,4599
18
+ snap_python/schemas/store/refresh.py,sha256=HAlt-rKfy7vmZSCujMXtW9HHXlVYbHGFwy_BKfD1uCU,3190
19
+ snap_python/schemas/store/search.py,sha256=4ghZb8xY6IESxZuAvzSjM9RaEwZAH3zjiC06zLc0zvU,4561
20
+ snap_python/scrape.py,sha256=ZDJAROp8jwossaAA78gBFTKQzrfnO11RgyyOZqevNd0,4576
21
21
  snap_python/utils.py,sha256=cmUooPg5DzNL197Xxvu7LGD4Gwk3xxsT68wbVytRtV0,1240
22
- snap_python-0.1.2.dist-info/LICENSE,sha256=lYXNZszxC_l2rlBvrHYs-esDegxWh8MKtjrdxA24uOk,1072
23
- snap_python-0.1.2.dist-info/METADATA,sha256=mdz8xXB3SRa_3cnXmmJjYSlY7f4BuzYOIkw7Rw8chqw,1883
24
- snap_python-0.1.2.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
25
- snap_python-0.1.2.dist-info/RECORD,,
22
+ snap_python-0.1.4.dist-info/LICENSE,sha256=lYXNZszxC_l2rlBvrHYs-esDegxWh8MKtjrdxA24uOk,1072
23
+ snap_python-0.1.4.dist-info/METADATA,sha256=jT6zFn5qHbXNkM8oS4fZQbdGqgFytApIIL85IydP_6M,1883
24
+ snap_python-0.1.4.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
25
+ snap_python-0.1.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.1
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any