snap-python 0.0.3__tar.gz → 0.0.5__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.0.3 → snap_python-0.0.5}/PKG-INFO +11 -1
  2. {snap_python-0.0.3 → snap_python-0.0.5}/README.md +9 -0
  3. {snap_python-0.0.3 → snap_python-0.0.5}/pyproject.toml +1 -1
  4. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/client.py +8 -2
  5. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/components/snaps.py +15 -6
  6. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/common.py +36 -0
  7. snap_python-0.0.5/src/snap_python/schemas/snaps.py +100 -0
  8. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/info.py +2 -2
  9. snap_python-0.0.5/src/snap_python/schemas/store/search.py +122 -0
  10. snap_python-0.0.3/src/snap_python/schemas/snaps.py +0 -70
  11. snap_python-0.0.3/src/snap_python/schemas/store/search.py +0 -160
  12. {snap_python-0.0.3 → snap_python-0.0.5}/LICENSE +0 -0
  13. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/__init__.py +0 -0
  14. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/components/__init__.py +0 -0
  15. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/components/config.py +0 -0
  16. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/components/store.py +0 -0
  17. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/changes.py +0 -0
  18. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/config.py +0 -0
  19. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/__init__.py +0 -0
  20. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/categories.py +0 -0
  21. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/json/category_by_name_schema.json +0 -0
  22. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/json/category_schema.json +0 -0
  23. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/json/snaps_find_schema.json +0 -0
  24. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/schemas/store/json/snaps_info_schema.json +0 -0
  25. {snap_python-0.0.3 → snap_python-0.0.5}/src/snap_python/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: snap-python
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: An api to interact with snapd and snap stores
5
5
  Home-page: https://github.com/alexlukens/snap-python
6
6
  License: MIT
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
15
16
  Requires-Dist: httpx (>=0.27.2,<0.28.0)
16
17
  Requires-Dist: pydantic (>=2.9.2,<3.0.0)
17
18
  Requires-Dist: retry (>=0.9.2,<0.10.0)
@@ -38,6 +39,15 @@ Here is a simple example of how to use snap_python:
38
39
  # TODO
39
40
  ```
40
41
 
42
+ ## Create a Release
43
+
44
+ ```bash
45
+ git tag -a v0.x.x -m "Release v0.x.x"
46
+ gh release create v0.x.x --title "Release v0.x.x"
47
+ ```
48
+
49
+ The automation will build a wheel and push it to pypi
50
+
41
51
  ## License
42
52
 
43
53
  This project is licensed under the MIT License. See the LICENSE file for more details.
@@ -18,6 +18,15 @@ Here is a simple example of how to use snap_python:
18
18
  # TODO
19
19
  ```
20
20
 
21
+ ## Create a Release
22
+
23
+ ```bash
24
+ git tag -a v0.x.x -m "Release v0.x.x"
25
+ gh release create v0.x.x --title "Release v0.x.x"
26
+ ```
27
+
28
+ The automation will build a wheel and push it to pypi
29
+
21
30
  ## License
22
31
 
23
32
  This project is licensed under the MIT License. See the LICENSE file for more details.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "snap-python"
3
- version = "0.0.3"
3
+ version = "0.0.5"
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,6 +27,7 @@ class SnapClient(AbstractSnapsClient):
27
27
  tcp_location: str = None,
28
28
  store_base_url: str = "https://api.snapcraft.io",
29
29
  store_headers: dict[str, str] = None,
30
+ prompt_for_authentication: bool = False,
30
31
  ):
31
32
  if tcp_location and snapd_socket_location:
32
33
  raise ValueError(
@@ -40,14 +41,19 @@ class SnapClient(AbstractSnapsClient):
40
41
  self._transport = httpx.AsyncHTTPTransport(
41
42
  uds=snapd_socket_location or SNAPD_SOCKET
42
43
  )
43
-
44
44
  if store_headers is None:
45
45
  store_headers = {"Snap-Device-Series": "16", "X-Ubuntu-Series": "16"}
46
46
 
47
+ snapd_headers = {}
48
+ if prompt_for_authentication:
49
+ snapd_headers = {"X-Allow-Interaction": "true"}
50
+
47
51
  self.version = version
48
52
  self.store_base_url = store_base_url
49
53
  self.store_headers = store_headers
50
- self.snapd_client = httpx.AsyncClient(transport=self._transport)
54
+ self.snapd_client = httpx.AsyncClient(
55
+ transport=self._transport, headers=snapd_headers
56
+ )
51
57
  self.snaps = SnapsEndpoints(self)
52
58
  self.store = StoreEndpoints(
53
59
  base_url=self.store_base_url,
@@ -6,7 +6,10 @@ import httpx
6
6
 
7
7
  from snap_python.schemas.changes import ChangesResponse
8
8
  from snap_python.schemas.common import AsyncResponse
9
- from snap_python.schemas.snaps import SingleSnapResponse, SnapListResponse
9
+ from snap_python.schemas.snaps import (
10
+ InstalledSnapListResponse,
11
+ SingleInstalledSnapResponse,
12
+ )
10
13
  from snap_python.utils import AbstractSnapsClient, going_to_reload_daemon
11
14
 
12
15
  logger = logging.getLogger("snap_python.components.snaps")
@@ -17,12 +20,12 @@ class SnapsEndpoints:
17
20
  self._client = client
18
21
  self.common_endpoint = "snaps"
19
22
 
20
- async def list_installed_snaps(self) -> SnapListResponse:
23
+ async def list_installed_snaps(self) -> InstalledSnapListResponse:
21
24
  response: httpx.Response = await self._client.request(
22
25
  "GET", self.common_endpoint
23
26
  )
24
27
 
25
- response = SnapListResponse.model_validate_json(response.content)
28
+ response = InstalledSnapListResponse.model_validate_json(response.content)
26
29
  if response.status_code > 299:
27
30
  raise httpx.HTTPStatusError(
28
31
  request=response.request,
@@ -31,7 +34,7 @@ class SnapsEndpoints:
31
34
  )
32
35
  return response
33
36
 
34
- async def get_snap_info(self, snap: str) -> SingleSnapResponse:
37
+ async def get_snap_info(self, snap: str) -> SingleInstalledSnapResponse:
35
38
  try:
36
39
  response: httpx.Response = await self._client.request(
37
40
  "GET", f"{self.common_endpoint}/{snap}"
@@ -44,7 +47,7 @@ class SnapsEndpoints:
44
47
  )
45
48
  response = e.response
46
49
 
47
- return SingleSnapResponse.model_validate_json(response.content)
50
+ return SingleInstalledSnapResponse.model_validate_json(response.content)
48
51
 
49
52
  async def is_snap_installed(self, snap: str) -> bool:
50
53
  snap_info = await self.get_snap_info(snap)
@@ -57,6 +60,7 @@ class SnapsEndpoints:
57
60
  snap: str,
58
61
  channel: str = "stable",
59
62
  classic: bool = False,
63
+ dangerous: bool = False,
60
64
  devmode: bool = False,
61
65
  ignore_validation: bool = False,
62
66
  jailmode: bool = False,
@@ -73,6 +77,7 @@ class SnapsEndpoints:
73
77
  snap (str): name of the snap to install
74
78
  channel (str, optional): Channel to install. Defaults to "stable".
75
79
  classic (bool, optional): Install with classic confinement. Defaults to False.
80
+ 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.
76
81
  devmode (bool, optional): Install with devmode. Defaults to False.
77
82
  ignore_validation (bool, optional): _description_. Defaults to False.
78
83
  jailmode (bool, optional): Install snap with jailmode. Defaults to False.
@@ -90,6 +95,7 @@ class SnapsEndpoints:
90
95
  "action": "install",
91
96
  "channel": channel,
92
97
  "classic": classic,
98
+ "dangerous": dangerous,
93
99
  "devmode": devmode,
94
100
  "ignore_validation": ignore_validation,
95
101
  "jailmode": jailmode,
@@ -100,7 +106,10 @@ class SnapsEndpoints:
100
106
  # sideload
101
107
  if not Path(filename).exists():
102
108
  raise FileNotFoundError(f"File {filename} does not exist")
103
- request_data["dangerous"] = True
109
+ if request_data.get("dangerous") is not True:
110
+ raise ValueError(
111
+ "Cannot sideload snap without dangerous flag set to True"
112
+ )
104
113
  raw_response: httpx.Response = await self._client.request(
105
114
  "POST",
106
115
  f"{self.common_endpoint}",
@@ -62,3 +62,39 @@ class Media(BaseModel):
62
62
 
63
63
  class AsyncResponse(BaseResponse):
64
64
  change: str
65
+
66
+
67
+ class Download(BaseModel):
68
+ model_config = ConfigDict(extra="forbid", exclude_unset=True)
69
+
70
+ size: float
71
+
72
+
73
+ class Revision(BaseModel):
74
+ model_config = ConfigDict(extra="forbid", exclude_unset=True)
75
+
76
+ base: Optional[SnapBaseVersion] = None
77
+ channel: Optional[str] = None
78
+ common_ids: Optional[list[str]] = Field(
79
+ None, validation_alias=AliasChoices("common-ids", "common_ids")
80
+ )
81
+ confinement: Optional[SnapConfinement] = None
82
+ download: Optional[Download] = None
83
+ revision: Optional[int | str] = None
84
+ type: Optional[str] = None
85
+ version: Optional[str] = None
86
+
87
+
88
+ class Publisher(BaseModel):
89
+ model_config = ConfigDict(extra="forbid", exclude_unset=True)
90
+
91
+ display_name: str = Field(
92
+ ...,
93
+ validation_alias=AliasChoices("display-name", "display_name"),
94
+ description="Display name corresponding to the publisher.",
95
+ )
96
+ id: str = Field(..., description="The publisher id.")
97
+ username: str = Field(..., description="Username belonging to the publisher.")
98
+ validation: Optional[str] = Field(
99
+ None, description="Indicates if the account has been validated."
100
+ )
@@ -0,0 +1,100 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AliasChoices, AwareDatetime, BaseModel, ConfigDict, Field
4
+
5
+ from snap_python.schemas.common import (
6
+ BaseErrorResult,
7
+ BaseResponse,
8
+ Media,
9
+ Publisher,
10
+ Revision,
11
+ SnapApp,
12
+ )
13
+ from snap_python.schemas.store.categories import Category
14
+
15
+
16
+ class SnapHealth(BaseModel):
17
+ status: str
18
+ revision: str
19
+ timestamp: AwareDatetime
20
+
21
+
22
+ class InstalledSnapFields(Revision):
23
+ apps: list[SnapApp] = Field(default_factory=list)
24
+ developer: Optional[str] = None
25
+ devmode: Optional[bool] = None
26
+ health: Optional[SnapHealth] = None
27
+ icon: Optional[str] = None
28
+ id: Optional[str] = Field(
29
+ None, validation_alias=AliasChoices("id", "snap-id"), serialization_alias="id"
30
+ )
31
+ ignore_validation: bool = Field(
32
+ validation_alias=AliasChoices("ignore-validation", "ignore_validation"),
33
+ serialization_alias="ignore-validation",
34
+ )
35
+ install_date: AwareDatetime = Field(
36
+ validation_alias=AliasChoices("install-date", "install_date"),
37
+ serialization_alias="install-date",
38
+ )
39
+ installed_size: int = Field(
40
+ validation_alias=AliasChoices("installed-size", "installed_size"),
41
+ serialization_alias="installed-size",
42
+ )
43
+ jailmode: bool
44
+ mounted_from: str = Field(
45
+ validation_alias=AliasChoices("mounted-from", "mounted_from"),
46
+ serialization_alias="mounted-from",
47
+ )
48
+ status: str
49
+ tracking_channel: Optional[str] = Field(
50
+ validation_alias=AliasChoices("tracking-channel", "tracking_channel"),
51
+ serialization_alias="tracking-channel",
52
+ default=None,
53
+ )
54
+
55
+
56
+ class StoreSnapFields(BaseModel):
57
+ gated_snap_ids: Optional[list[str]] = Field(
58
+ None, alias=AliasChoices("gated-snap-ids", "gated_snap_ids")
59
+ )
60
+ categories: Optional[list[Category]] = None
61
+ prices: Optional[dict[str, str]] = None
62
+ snap_id: Optional[str] = Field(None, alias=AliasChoices("snap-id", "snap_id"))
63
+ store_url: Optional[str] = Field(None, alias=AliasChoices("store-url", "store_url"))
64
+ trending: Optional[bool] = None
65
+
66
+
67
+ class Snap(BaseModel):
68
+ model_config = ConfigDict(extra="forbid")
69
+
70
+ contact: Optional[str] = None
71
+ description: Optional[str] = None
72
+ license: str = "unset"
73
+ links: Optional[dict[str, list[str]]] = None
74
+ media: Optional[list[Media]] = None
75
+ name: Optional[str] = None
76
+ private: Optional[bool] = None
77
+ publisher: Optional[Publisher] = Field(None, description="The publisher.")
78
+ summary: Optional[str] = None
79
+ title: Optional[str] = None
80
+ unlisted: Optional[bool] = None
81
+ website: Optional[str] = None
82
+
83
+
84
+ class StoreSnap(Snap, StoreSnapFields):
85
+ pass
86
+
87
+
88
+ class InstalledSnap(Snap, InstalledSnapFields):
89
+ pass
90
+
91
+
92
+ class SingleInstalledSnapResponse(BaseResponse):
93
+ result: InstalledSnap | BaseErrorResult
94
+
95
+
96
+ class InstalledSnapListResponse(BaseResponse):
97
+ result: list[InstalledSnap]
98
+
99
+ def __len__(self):
100
+ return len(self.result)
@@ -6,7 +6,7 @@ from typing import List, Optional
6
6
 
7
7
  from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
8
8
 
9
- from snap_python.schemas.store.search import Snap
9
+ from snap_python.schemas.snaps import StoreSnap
10
10
 
11
11
  VALID_SNAP_INFO_FIELDS = [
12
12
  "architectures",
@@ -130,5 +130,5 @@ class InfoResponse(BaseModel):
130
130
  default_track: Optional[str] = Field(None, alias="default-track")
131
131
  error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
132
132
  name: str
133
- snap: Snap
133
+ snap: StoreSnap
134
134
  snap_id: str = Field(..., alias="snap-id")
@@ -0,0 +1,122 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from pydantic import AliasChoices, AwareDatetime, BaseModel, ConfigDict, Field
4
+
5
+ from snap_python.schemas.common import Revision
6
+ from snap_python.schemas.snaps import InstalledSnap, Snap, StoreSnap, StoreSnapFields
7
+
8
+ VALID_SEARCH_CATEGORY_FIELDS = [
9
+ "base",
10
+ "categories",
11
+ "channel",
12
+ "common-ids",
13
+ "confinement",
14
+ "contact",
15
+ "description",
16
+ "download",
17
+ "license",
18
+ "media",
19
+ "prices",
20
+ "private",
21
+ "publisher",
22
+ "revision",
23
+ "store-url",
24
+ "summary",
25
+ "title",
26
+ "type",
27
+ "version",
28
+ "website",
29
+ ]
30
+
31
+
32
+ class ErrorListItem(BaseModel):
33
+ model_config = ConfigDict(extra="forbid", exclude_unset=True)
34
+
35
+ code: str
36
+ message: str
37
+
38
+
39
+ class SnapDetails(BaseModel):
40
+ aliases: Optional[List[Dict]] = None
41
+ anon_download_url: str
42
+ apps: Optional[List[str]] = None
43
+ architecture: List[str]
44
+ base: Optional[str] = None
45
+ binary_filesize: int
46
+ channel: str
47
+ common_ids: List[str]
48
+ confinement: str
49
+ contact: Optional[str] = None
50
+ content: Optional[str] = None
51
+ date_published: AwareDatetime
52
+ deltas: Optional[List[str]] = None
53
+ description: str
54
+ developer_id: str
55
+ developer_name: str
56
+ developer_validation: str
57
+ download_sha3_384: Optional[str] = None
58
+ download_sha512: Optional[str] = None
59
+ download_url: str
60
+ epoch: str
61
+ gated_snap_ids: Optional[List[str]] = None
62
+ icon_url: str
63
+ last_updated: AwareDatetime
64
+ license: str
65
+ links: Dict[str, Any]
66
+ name: str
67
+ origin: str
68
+ package_name: str
69
+ prices: Dict[str, Any]
70
+ private: bool
71
+ publisher: str
72
+ raitings_average: float = 0.0
73
+ release: List[str]
74
+ revision: int
75
+ screenshot_urls: List[str]
76
+ snap_id: Optional[str] = None
77
+ summary: Optional[str] = None
78
+ support_url: Optional[str] = None
79
+ title: Optional[str] = None
80
+ version: Optional[str] = None
81
+ website: Optional[str] = None
82
+
83
+
84
+ class SearchResult(BaseModel):
85
+ model_config = ConfigDict(extra="forbid")
86
+
87
+ name: str
88
+ revision: Optional[Revision] = None
89
+ snap: StoreSnap
90
+ snap_id: str = Field(alias=AliasChoices("snap-id", "snap_id"))
91
+
92
+ @classmethod
93
+ def from_installed_snap(cls, installed_snap: InstalledSnap):
94
+ snap_info: dict = installed_snap.model_dump(mode="json")
95
+ revision_snap_fields = Revision.model_fields.keys()
96
+ revision_info = {}
97
+ for field in revision_snap_fields:
98
+ if field in snap_info:
99
+ revision_info[field] = snap_info.pop(field)
100
+
101
+ snap_id = snap_info.pop("id")
102
+ snap_name = snap_info.get("name")
103
+
104
+ # get set of acceptable fields for StoreSnap
105
+ store_snap_fields = set(StoreSnapFields.model_fields.keys()).union(
106
+ Snap.model_fields.keys()
107
+ )
108
+ store_snap_info = {
109
+ key: value for key, value in snap_info.items() if key in store_snap_fields
110
+ }
111
+
112
+ snap_info = {"snap": store_snap_info, "snap-id": snap_id, "name": snap_name}
113
+ snap_info["revision"] = revision_info
114
+
115
+ return cls.model_validate(snap_info)
116
+
117
+
118
+ class SearchResponse(BaseModel):
119
+ model_config = ConfigDict(extra="forbid")
120
+
121
+ error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
122
+ results: List[SearchResult]
@@ -1,70 +0,0 @@
1
- from pydantic import AliasChoices, AwareDatetime, BaseModel, ConfigDict, Field
2
-
3
- from snap_python.schemas.common import (
4
- BaseErrorResult,
5
- BaseResponse,
6
- Media,
7
- SnapApp,
8
- SnapBaseVersion,
9
- SnapConfinement,
10
- )
11
-
12
-
13
- class Snap(BaseModel):
14
- model_config = ConfigDict(extra="allow")
15
- apps: list[SnapApp] = Field(default_factory=list)
16
- base: SnapBaseVersion | None = None
17
- channel: str
18
- confinement: SnapConfinement
19
- contact: str
20
- description: str
21
- developer: str
22
- devmode: bool
23
- icon: str | None = None
24
- id: str
25
- ignore_validation: bool = Field(
26
- validation_alias=AliasChoices("ignore-validation", "ignore_validation"),
27
- serialization_alias="ignore-validation",
28
- )
29
- install_date: AwareDatetime = Field(
30
- validation_alias=AliasChoices("install-date", "install_date"),
31
- serialization_alias="install-date",
32
- )
33
- installed_size: int = Field(
34
- validation_alias=AliasChoices("installed-size", "installed_size"),
35
- serialization_alias="installed-size",
36
- )
37
- jailmode: bool
38
- license: str = "unset"
39
- links: dict[str, list[str]] | None = None
40
- media: list[Media] = Field(default_factory=list)
41
- mounted_from: str = Field(
42
- validation_alias=AliasChoices("mounted-from", "mounted_from"),
43
- serialization_alias="mounted-from",
44
- )
45
- name: str
46
- private: bool
47
- publisher: dict[str, str] | None = None
48
- revision: str
49
- status: str
50
- summary: str
51
- title: str | None = None
52
- tracking_channel: str | None = Field(
53
- validation_alias=AliasChoices("tracking-channel", "tracking_channel"),
54
- serialization_alias="tracking-channel",
55
- default=None,
56
- )
57
- type: str
58
- version: str
59
- website: str | None = None
60
-
61
-
62
- class SingleSnapResponse(BaseResponse):
63
- result: Snap | BaseErrorResult
64
-
65
-
66
- class SnapListResponse(BaseResponse):
67
- result: list[Snap]
68
-
69
- def __len__(self):
70
- return len(self.result)
@@ -1,160 +0,0 @@
1
- # generated by datamodel-codegen:
2
- # filename: snaps_find_schema.json
3
- # timestamp: 2024-09-17T01:18:24+00:00
4
-
5
-
6
- from typing import Any, Dict, List, Optional
7
-
8
- from pydantic import AliasChoices, AwareDatetime, BaseModel, ConfigDict, Field
9
-
10
- from snap_python.schemas.store.categories import Category, Media
11
-
12
- VALID_SEARCH_CATEGORY_FIELDS = [
13
- "base",
14
- "categories",
15
- "channel",
16
- "common-ids",
17
- "confinement",
18
- "contact",
19
- "description",
20
- "download",
21
- "license",
22
- "media",
23
- "prices",
24
- "private",
25
- "publisher",
26
- "revision",
27
- "store-url",
28
- "summary",
29
- "title",
30
- "type",
31
- "version",
32
- "website",
33
- ]
34
-
35
-
36
- class ErrorListItem(BaseModel):
37
- model_config = ConfigDict(extra="forbid", exclude_unset=True)
38
-
39
- code: str
40
- message: str
41
-
42
-
43
- class Download(BaseModel):
44
- model_config = ConfigDict(extra="forbid", exclude_unset=True)
45
-
46
- size: float
47
-
48
-
49
- class Revision(BaseModel):
50
- model_config = ConfigDict(extra="forbid", exclude_unset=True)
51
-
52
- base: Optional[str] = None
53
- channel: Optional[str] = None
54
- common_ids: Optional[List[str]] = Field(None, alias="common-ids")
55
- confinement: Optional[str] = None
56
- download: Optional[Download] = None
57
- revision: Optional[float] = None
58
- type: Optional[str] = None
59
- version: Optional[str] = None
60
-
61
-
62
- class Publisher(BaseModel):
63
- model_config = ConfigDict(extra="forbid", exclude_unset=True)
64
-
65
- display_name: str = Field(
66
- ...,
67
- alias="display-name",
68
- description="Display name corresponding to the publisher.",
69
- )
70
- id: str = Field(..., description="The publisher id.")
71
- username: str = Field(..., description="Username belonging to the publisher.")
72
- validation: Optional[str] = Field(
73
- None, description="Indicates if the account has been validated."
74
- )
75
-
76
-
77
- class Snap(BaseModel):
78
- model_config = ConfigDict(extra="forbid", exclude_unset=True)
79
-
80
- categories: Optional[List[Category]] = None
81
- contact: Optional[str] = None
82
- description: Optional[str] = ""
83
- gated_snap_ids: Optional[List[str]] = Field(
84
- None, alias=AliasChoices("gated-snap-ids", "gated_snap_ids")
85
- )
86
- license: Optional[str] = None
87
- links: Optional[Dict[str, Any]] = None
88
- media: Optional[List[Media]] = None
89
- name: Optional[str] = None
90
- prices: Optional[Dict[str, Any]] = None
91
- private: Optional[bool] = None
92
- publisher: Optional[Publisher] = Field(None, description="The publisher.")
93
- snap_id: Optional[str] = Field(None, alias=AliasChoices("snap-id", "snap_id"))
94
- store_url: Optional[str] = Field(None, alias=AliasChoices("store-url", "store_url"))
95
- summary: Optional[str] = None
96
- title: Optional[str] = None
97
- trending: Optional[bool] = None
98
- unlisted: Optional[bool] = None
99
- website: Optional[str] = None
100
-
101
-
102
- class SnapDetails(BaseModel):
103
- aliases: Optional[List[Dict]] = None
104
- anon_download_url: str
105
- apps: Optional[List[str]] = None
106
- architecture: List[str]
107
- base: Optional[str] = None
108
- binary_filesize: int
109
- channel: str
110
- common_ids: List[str]
111
- confinement: str
112
- contact: Optional[str] = None
113
- content: Optional[str] = None
114
- date_published: AwareDatetime
115
- deltas: Optional[List[str]] = None
116
- description: str
117
- developer_id: str
118
- developer_name: str
119
- developer_validation: str
120
- download_sha3_384: Optional[str] = None
121
- download_sha512: Optional[str] = None
122
- download_url: str
123
- epoch: str
124
- gated_snap_ids: Optional[List[str]] = None
125
- icon_url: str
126
- last_updated: AwareDatetime
127
- license: str
128
- links: Dict[str, Any]
129
- name: str
130
- origin: str
131
- package_name: str
132
- prices: Dict[str, Any]
133
- private: bool
134
- publisher: str
135
- raitings_average: float = 0.0
136
- release: List[str]
137
- revision: int
138
- screenshot_urls: List[str]
139
- snap_id: Optional[str] = None
140
- summary: Optional[str] = None
141
- support_url: Optional[str] = None
142
- title: Optional[str] = None
143
- version: Optional[str] = None
144
- website: Optional[str] = None
145
-
146
-
147
- class SearchResult(BaseModel):
148
- model_config = ConfigDict(extra="forbid", exclude_unset=True, exclude_none=True)
149
-
150
- name: str
151
- revision: Optional[Revision] = None
152
- snap: Snap
153
- snap_id: str = Field(alias=AliasChoices("snap-id", "snap_id"))
154
-
155
-
156
- class SearchResponse(BaseModel):
157
- model_config = ConfigDict(extra="forbid", exclude_unset=True, exclude_none=True)
158
-
159
- error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
160
- results: List[SearchResult]
File without changes