snap-python 0.0.3__tar.gz → 0.0.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.0.3 → snap_python-0.0.4}/PKG-INFO +1 -1
  2. {snap_python-0.0.3 → snap_python-0.0.4}/pyproject.toml +1 -1
  3. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/components/snaps.py +8 -5
  4. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/common.py +36 -0
  5. snap_python-0.0.4/src/snap_python/schemas/snaps.py +93 -0
  6. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/info.py +2 -2
  7. snap_python-0.0.4/src/snap_python/schemas/store/search.py +120 -0
  8. snap_python-0.0.3/src/snap_python/schemas/snaps.py +0 -70
  9. snap_python-0.0.3/src/snap_python/schemas/store/search.py +0 -160
  10. {snap_python-0.0.3 → snap_python-0.0.4}/LICENSE +0 -0
  11. {snap_python-0.0.3 → snap_python-0.0.4}/README.md +0 -0
  12. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/__init__.py +0 -0
  13. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/client.py +0 -0
  14. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/components/__init__.py +0 -0
  15. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/components/config.py +0 -0
  16. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/components/store.py +0 -0
  17. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/changes.py +0 -0
  18. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/config.py +0 -0
  19. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/__init__.py +0 -0
  20. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/categories.py +0 -0
  21. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/json/category_by_name_schema.json +0 -0
  22. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/json/category_schema.json +0 -0
  23. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/json/snaps_find_schema.json +0 -0
  24. {snap_python-0.0.3 → snap_python-0.0.4}/src/snap_python/schemas/store/json/snaps_info_schema.json +0 -0
  25. {snap_python-0.0.3 → snap_python-0.0.4}/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.4
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "snap-python"
3
- version = "0.0.3"
3
+ version = "0.0.4"
4
4
  description = "An api to interact with snapd and snap stores"
5
5
  authors = ["Alexander Lukens <alexdlukens@gmail.com>"]
6
6
  license = "MIT"
@@ -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)
@@ -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,93 @@
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 InstalledSnapFields(Revision):
17
+ apps: list[SnapApp] = Field(default_factory=list)
18
+ developer: Optional[str] = None
19
+ devmode: Optional[bool] = None
20
+ icon: Optional[str] = None
21
+ id: Optional[str] = Field(
22
+ None, validation_alias=AliasChoices("id", "snap-id"), serialization_alias="id"
23
+ )
24
+ ignore_validation: bool = Field(
25
+ validation_alias=AliasChoices("ignore-validation", "ignore_validation"),
26
+ serialization_alias="ignore-validation",
27
+ )
28
+ install_date: AwareDatetime = Field(
29
+ validation_alias=AliasChoices("install-date", "install_date"),
30
+ serialization_alias="install-date",
31
+ )
32
+ installed_size: int = Field(
33
+ validation_alias=AliasChoices("installed-size", "installed_size"),
34
+ serialization_alias="installed-size",
35
+ )
36
+ jailmode: bool
37
+ mounted_from: str = Field(
38
+ validation_alias=AliasChoices("mounted-from", "mounted_from"),
39
+ serialization_alias="mounted-from",
40
+ )
41
+ status: str
42
+ tracking_channel: Optional[str] = Field(
43
+ validation_alias=AliasChoices("tracking-channel", "tracking_channel"),
44
+ serialization_alias="tracking-channel",
45
+ default=None,
46
+ )
47
+
48
+
49
+ class StoreSnapFields(BaseModel):
50
+ gated_snap_ids: Optional[list[str]] = Field(
51
+ None, alias=AliasChoices("gated-snap-ids", "gated_snap_ids")
52
+ )
53
+ categories: Optional[list[Category]] = None
54
+ prices: Optional[dict[str, str]] = None
55
+ snap_id: Optional[str] = Field(None, alias=AliasChoices("snap-id", "snap_id"))
56
+ store_url: Optional[str] = Field(None, alias=AliasChoices("store-url", "store_url"))
57
+ trending: Optional[bool] = None
58
+
59
+
60
+ class Snap(BaseModel):
61
+ model_config = ConfigDict(extra="forbid")
62
+
63
+ contact: Optional[str] = None
64
+ description: Optional[str] = None
65
+ license: str = "unset"
66
+ links: Optional[dict[str, list[str]]] = None
67
+ media: Optional[list[Media]] = None
68
+ name: Optional[str] = None
69
+ private: Optional[bool] = None
70
+ publisher: Optional[Publisher] = Field(None, description="The publisher.")
71
+ summary: Optional[str] = None
72
+ title: Optional[str] = None
73
+ unlisted: Optional[bool] = None
74
+ website: Optional[str] = None
75
+
76
+
77
+ class StoreSnap(Snap, StoreSnapFields):
78
+ pass
79
+
80
+
81
+ class InstalledSnap(Snap, InstalledSnapFields):
82
+ pass
83
+
84
+
85
+ class SingleInstalledSnapResponse(BaseResponse):
86
+ result: InstalledSnap | BaseErrorResult
87
+
88
+
89
+ class InstalledSnapListResponse(BaseResponse):
90
+ result: list[InstalledSnap]
91
+
92
+ def __len__(self):
93
+ 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,120 @@
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, 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.pop("name")
103
+
104
+ # get set of acceptable fields for StoreSnap
105
+ store_snap_fields = StoreSnapFields.model_fields.keys()
106
+ snap_info = {
107
+ key: value for key, value in snap_info.items() if key in store_snap_fields
108
+ }
109
+
110
+ snap_info = {"snap": snap_info, "snap-id": snap_id, "name": snap_name}
111
+ snap_info["revision"] = revision_info
112
+
113
+ return cls.model_validate(snap_info)
114
+
115
+
116
+ class SearchResponse(BaseModel):
117
+ model_config = ConfigDict(extra="forbid")
118
+
119
+ error_list: Optional[List[ErrorListItem]] = Field(None, alias="error-list")
120
+ 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
File without changes