snap-python 0.1.3__tar.gz → 0.1.4__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.
Files changed (25) hide show
  1. {snap_python-0.1.3 → snap_python-0.1.4}/PKG-INFO +1 -1
  2. {snap_python-0.1.3 → snap_python-0.1.4}/pyproject.toml +1 -1
  3. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/components/store.py +98 -0
  4. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/search.py +33 -1
  5. {snap_python-0.1.3 → snap_python-0.1.4}/LICENSE +0 -0
  6. {snap_python-0.1.3 → snap_python-0.1.4}/README.md +0 -0
  7. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/__init__.py +0 -0
  8. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/client.py +0 -0
  9. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/components/__init__.py +0 -0
  10. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/components/config.py +0 -0
  11. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/components/snaps.py +0 -0
  12. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/changes.py +0 -0
  13. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/common.py +0 -0
  14. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/config.py +0 -0
  15. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/snaps.py +0 -0
  16. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/__init__.py +0 -0
  17. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/categories.py +0 -0
  18. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/info.py +0 -0
  19. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/json/category_by_name_schema.json +0 -0
  20. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/json/category_schema.json +0 -0
  21. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/json/snaps_find_schema.json +0 -0
  22. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/json/snaps_info_schema.json +0 -0
  23. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/schemas/store/refresh.py +0 -0
  24. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/scrape.py +0 -0
  25. {snap_python-0.1.3 → snap_python-0.1.4}/src/snap_python/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: snap-python
3
- Version: 0.1.3
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "snap-python"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  description = "Interact with snapd and snapstore(s) from Python"
5
5
  authors = ["Alexander Lukens <alexdlukens@gmail.com>"]
6
6
  license = "MIT"
@@ -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)
@@ -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
+ )
File without changes
File without changes