akebi 0.1.0__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.
- akebi-0.1.0/.github/workflows/release.yml +40 -0
- akebi-0.1.0/.gitignore +16 -0
- akebi-0.1.0/CHANGELOG.md +11 -0
- akebi-0.1.0/LICENSE.md +25 -0
- akebi-0.1.0/PKG-INFO +85 -0
- akebi-0.1.0/README.md +66 -0
- akebi-0.1.0/akebi/__init__.py +1 -0
- akebi-0.1.0/akebi/bun.py +217 -0
- akebi-0.1.0/akebi/utils.py +182 -0
- akebi-0.1.0/prek.toml +12 -0
- akebi-0.1.0/pyproject.toml +32 -0
- akebi-0.1.0/uv.lock +361 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- published
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build Package
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout Repository
|
|
14
|
+
uses: actions/checkout@v7
|
|
15
|
+
|
|
16
|
+
- name: Set Up uv
|
|
17
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
18
|
+
|
|
19
|
+
- name: Build Package
|
|
20
|
+
run: uv build
|
|
21
|
+
|
|
22
|
+
- name: Upload Artifact
|
|
23
|
+
uses: actions/upload-artifact@v7
|
|
24
|
+
with:
|
|
25
|
+
path: dist
|
|
26
|
+
|
|
27
|
+
publish:
|
|
28
|
+
name: Publish to PyPI
|
|
29
|
+
needs: build
|
|
30
|
+
permissions:
|
|
31
|
+
id-token: write
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- name: Download Artifact
|
|
35
|
+
uses: actions/download-artifact@v8
|
|
36
|
+
with:
|
|
37
|
+
path: dist
|
|
38
|
+
|
|
39
|
+
- name: Publish to PyPI
|
|
40
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
akebi-0.1.0/.gitignore
ADDED
akebi-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog[^1]
|
|
2
|
+
|
|
3
|
+
Notable changes to Akebi will be documented here.
|
|
4
|
+
|
|
5
|
+
Akebi follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## <a name="0.1.0">0.1.0 — 2026-06-23</a>
|
|
8
|
+
|
|
9
|
+
This is the initial release of Akebi.
|
|
10
|
+
|
|
11
|
+
[^1]: Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
akebi-0.1.0/LICENSE.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2026-present celsius narhwal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
|
6
|
+
obtaining a copy of this software and associated documentation
|
|
7
|
+
files (the “Software”), to deal in the Software without
|
|
8
|
+
restriction, including without limitation the rights to use,
|
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the
|
|
11
|
+
Software is furnished to do so, subject to the following
|
|
12
|
+
conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be
|
|
15
|
+
included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
25
|
+
|
akebi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: akebi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Manage Bun installations from Python
|
|
5
|
+
Author-email: celsius narhwal <hello@celsiusnarhwal.dev>
|
|
6
|
+
License-File: LICENSE.md
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Requires-Dist: httpx2>=2.4.0
|
|
9
|
+
Requires-Dist: kokomikke>=0.1.4
|
|
10
|
+
Requires-Dist: loguru>=0.7.3
|
|
11
|
+
Requires-Dist: platformdirs>=4.10.0
|
|
12
|
+
Requires-Dist: pydantic-extra-types>=2.11.1
|
|
13
|
+
Requires-Dist: pydantic-settings>=2.14.1
|
|
14
|
+
Requires-Dist: pydantic>=2.13.4
|
|
15
|
+
Requires-Dist: rich>=15.0.0
|
|
16
|
+
Requires-Dist: semver>=3.0.4
|
|
17
|
+
Requires-Dist: sqlitedict>=2.1.0
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# Akebi
|
|
21
|
+
|
|
22
|
+
Akebi allows Python programs to manage [Bun](https://bun.com) installations. It is intended for programs that need
|
|
23
|
+
to install or run Node.js packages but do not wish to depend on the end user having an appropriate runtime or package
|
|
24
|
+
manager installed.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```shell
|
|
29
|
+
pip install akebi
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
First, create an `akebi.Bun` object:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from akebi import Bun
|
|
38
|
+
|
|
39
|
+
bun = Bun()
|
|
40
|
+
bun = Bun(version="1.3.14") # use a specific version of Bun
|
|
41
|
+
bun = Bun(version="latest") # use the latest version of Bun
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can then invoke Bun by calling the `Bun` object you just created. A `Bun` object takes a `subprocess.run`-esque list or string
|
|
45
|
+
containing command-line arguments.
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from akebi import Bun
|
|
49
|
+
|
|
50
|
+
bun = Bun()
|
|
51
|
+
|
|
52
|
+
bun(["run", "./my-script.ts"])
|
|
53
|
+
bun(["add", "next"])
|
|
54
|
+
bun(["create", "docusaurus"])
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Akebi will automatically install Bun as necessary, but you can also install it manually with `Bun.setup`:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
bun.setup()
|
|
61
|
+
|
|
62
|
+
# or, to forcibly overwrite existing installations of the same version:
|
|
63
|
+
|
|
64
|
+
bun.setup(force=True)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Under the hood, Akebi uses `subprocess.run` to invoke Bun. Keyword arguments passed to `Bun` objects will be passed
|
|
68
|
+
through to `subprocess.run`, e.g.:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
bun("update tailwindcss", shell=True, capture_output=True, text=True)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Isolated installations
|
|
75
|
+
|
|
76
|
+
If you want to ensure the Bun installations used by your program aren't touched by anything else that uses
|
|
77
|
+
Akebi, you can set `Bun.app_name`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
bun = Bun(app_name="com.example.myapp")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Bun installations created by your program will be located under an `app_name` subdirectory. You should choose
|
|
84
|
+
an app name that's consistent within your program and not likely be taken by other programs that use
|
|
85
|
+
Akebi.
|
akebi-0.1.0/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Akebi
|
|
2
|
+
|
|
3
|
+
Akebi allows Python programs to manage [Bun](https://bun.com) installations. It is intended for programs that need
|
|
4
|
+
to install or run Node.js packages but do not wish to depend on the end user having an appropriate runtime or package
|
|
5
|
+
manager installed.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
pip install akebi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
First, create an `akebi.Bun` object:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from akebi import Bun
|
|
19
|
+
|
|
20
|
+
bun = Bun()
|
|
21
|
+
bun = Bun(version="1.3.14") # use a specific version of Bun
|
|
22
|
+
bun = Bun(version="latest") # use the latest version of Bun
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You can then invoke Bun by calling the `Bun` object you just created. A `Bun` object takes a `subprocess.run`-esque list or string
|
|
26
|
+
containing command-line arguments.
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from akebi import Bun
|
|
30
|
+
|
|
31
|
+
bun = Bun()
|
|
32
|
+
|
|
33
|
+
bun(["run", "./my-script.ts"])
|
|
34
|
+
bun(["add", "next"])
|
|
35
|
+
bun(["create", "docusaurus"])
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Akebi will automatically install Bun as necessary, but you can also install it manually with `Bun.setup`:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
bun.setup()
|
|
42
|
+
|
|
43
|
+
# or, to forcibly overwrite existing installations of the same version:
|
|
44
|
+
|
|
45
|
+
bun.setup(force=True)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Under the hood, Akebi uses `subprocess.run` to invoke Bun. Keyword arguments passed to `Bun` objects will be passed
|
|
49
|
+
through to `subprocess.run`, e.g.:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
bun("update tailwindcss", shell=True, capture_output=True, text=True)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Isolated installations
|
|
56
|
+
|
|
57
|
+
If you want to ensure the Bun installations used by your program aren't touched by anything else that uses
|
|
58
|
+
Akebi, you can set `Bun.app_name`:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
bun = Bun(app_name="com.example.myapp")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Bun installations created by your program will be located under an `app_name` subdirectory. You should choose
|
|
65
|
+
an app name that's consistent within your program and not likely be taken by other programs that use
|
|
66
|
+
Akebi.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from akebi.bun import Bun
|
akebi-0.1.0/akebi/bun.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import hashlib
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import shutil
|
|
6
|
+
import stat
|
|
7
|
+
import subprocess
|
|
8
|
+
import typing as t
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from tempfile import TemporaryDirectory
|
|
11
|
+
from zipfile import ZipFile
|
|
12
|
+
|
|
13
|
+
from pydantic import (
|
|
14
|
+
BaseModel,
|
|
15
|
+
ConfigDict,
|
|
16
|
+
Field,
|
|
17
|
+
TypeAdapter,
|
|
18
|
+
ValidationInfo,
|
|
19
|
+
field_validator,
|
|
20
|
+
validate_call,
|
|
21
|
+
)
|
|
22
|
+
from pydantic_extra_types.semantic_version import SemanticVersion
|
|
23
|
+
from rich.status import Status
|
|
24
|
+
|
|
25
|
+
from akebi import utils
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Bun(BaseModel):
|
|
29
|
+
model_config = ConfigDict(frozen=True)
|
|
30
|
+
|
|
31
|
+
app_name: str = None
|
|
32
|
+
"""
|
|
33
|
+
An identifier under which Bun installations created by this object are to be isolated.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# In practice, this will always be a `SemanticVersion` object.
|
|
37
|
+
version: SemanticVersion | t.Literal["latest"] = Field(None, validate_default=True)
|
|
38
|
+
"""
|
|
39
|
+
The version of Bun to use. Leave empty to use the latest version locally available. Pass "latest" to use the
|
|
40
|
+
latest version, period.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
@field_validator("version", mode="before")
|
|
44
|
+
@classmethod
|
|
45
|
+
def validate_version(cls, v, info: ValidationInfo) -> SemanticVersion | str:
|
|
46
|
+
if v is None:
|
|
47
|
+
installed_versions = []
|
|
48
|
+
|
|
49
|
+
for directory in utils.get_bun_dir(info.data.get("app_name")).glob("*/"):
|
|
50
|
+
try:
|
|
51
|
+
installed_versions.append(
|
|
52
|
+
TypeAdapter(SemanticVersion).validate_python(directory.name)
|
|
53
|
+
)
|
|
54
|
+
except ValueError:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
if installed_versions:
|
|
58
|
+
return max(installed_versions)
|
|
59
|
+
else:
|
|
60
|
+
v = "latest"
|
|
61
|
+
|
|
62
|
+
if isinstance(v, str) and v == "latest":
|
|
63
|
+
with utils.github_client(api=True) as gh:
|
|
64
|
+
releases = (
|
|
65
|
+
gh.get("/repos/oven-sh/bun/releases").raise_for_status().json()
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return releases[0]["tag_name"].split("-v")[-1]
|
|
69
|
+
|
|
70
|
+
return v
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def bin_path(self) -> Path:
|
|
74
|
+
"""
|
|
75
|
+
The absolute path to the Bun executable.
|
|
76
|
+
|
|
77
|
+
This only returns where the executable *should* be; it does not guarantee that it exists.
|
|
78
|
+
"""
|
|
79
|
+
return utils.get_bun_dir(self.app_name) / str(self.version) / "bin" / "bun"
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def checksum(self) -> str | None:
|
|
83
|
+
"""
|
|
84
|
+
The checksum of the file at the intended location of the Bun executable.
|
|
85
|
+
"""
|
|
86
|
+
if self.bin_path.is_file():
|
|
87
|
+
return hashlib.sha256(self.bin_path.read_bytes()).hexdigest()
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def stored_checksum(self) -> str | None:
|
|
91
|
+
"""
|
|
92
|
+
The checksum of the Bun executable at the time it was downloaded.
|
|
93
|
+
"""
|
|
94
|
+
with utils.state(table="bun") as bun_db:
|
|
95
|
+
return bun_db.get(str(self.bin_path))
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def is_installed(self) -> bool:
|
|
99
|
+
"""
|
|
100
|
+
Whether this Bun is installed.
|
|
101
|
+
"""
|
|
102
|
+
return self.bin_path.is_file() and self.checksum == self.stored_checksum
|
|
103
|
+
|
|
104
|
+
def setup(self, *, force: bool = False) -> t.Self:
|
|
105
|
+
"""
|
|
106
|
+
Install this Bun if it isn't installed already.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
force: bool, default=False
|
|
111
|
+
Install this Bun even if it's already installed.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
Bun
|
|
116
|
+
This object.
|
|
117
|
+
"""
|
|
118
|
+
if self.is_installed and not force:
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
with Status(f"Installing Bun v{self.version}..."):
|
|
122
|
+
target = {"host": platform.system().casefold()}
|
|
123
|
+
|
|
124
|
+
architecture = platform.machine().casefold()
|
|
125
|
+
|
|
126
|
+
match architecture:
|
|
127
|
+
case "x86_64" | "amd64":
|
|
128
|
+
target["architecture"] = "x64"
|
|
129
|
+
case "arm64":
|
|
130
|
+
target["architecture"] = "aarch64"
|
|
131
|
+
case _:
|
|
132
|
+
target["architecture"] = architecture
|
|
133
|
+
|
|
134
|
+
if target["host"] == "linux":
|
|
135
|
+
libc = utils.guess_libc()
|
|
136
|
+
|
|
137
|
+
if libc == "musl":
|
|
138
|
+
target["libc"] = libc
|
|
139
|
+
|
|
140
|
+
if utils.needs_baseline_build():
|
|
141
|
+
target["build"] = "baseline"
|
|
142
|
+
|
|
143
|
+
asset = f"bun-{'-'.join(target.values())}.zip"
|
|
144
|
+
|
|
145
|
+
with utils.github_client() as gh:
|
|
146
|
+
asset_resp = gh.get(
|
|
147
|
+
f"/oven-sh/bun/releases/download/bun-v{self.version}/{asset}",
|
|
148
|
+
follow_redirects=True,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if asset_resp.status_code == 404:
|
|
152
|
+
# noinspection PyArgumentList
|
|
153
|
+
raise Exception(
|
|
154
|
+
f"No Bun {self.version} release with name {asset} could be found"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
asset_resp.raise_for_status()
|
|
158
|
+
|
|
159
|
+
with TemporaryDirectory() as tmpdir:
|
|
160
|
+
with contextlib.chdir(tmpdir):
|
|
161
|
+
bun_zip = Path("bun.zip")
|
|
162
|
+
bun_zip.write_bytes(asset_resp.content)
|
|
163
|
+
|
|
164
|
+
ZipFile(bun_zip).extractall()
|
|
165
|
+
|
|
166
|
+
bun_bin = next(Path.cwd().glob("**/bun"))
|
|
167
|
+
bun_bin.chmod(bun_bin.stat().st_mode | stat.S_IEXEC)
|
|
168
|
+
|
|
169
|
+
self.bin_path.parent.mkdir(parents=True, exist_ok=True)
|
|
170
|
+
|
|
171
|
+
shutil.move(bun_bin, self.bin_path)
|
|
172
|
+
|
|
173
|
+
with utils.state(table="bun") as bun_db:
|
|
174
|
+
bun_db[str(self.bin_path)] = self.checksum
|
|
175
|
+
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
@validate_call()
|
|
179
|
+
def __call__(
|
|
180
|
+
self,
|
|
181
|
+
args: t.Annotated[list | str, Field(default_factory=list)],
|
|
182
|
+
/,
|
|
183
|
+
**kwargs,
|
|
184
|
+
) -> subprocess.CompletedProcess:
|
|
185
|
+
"""
|
|
186
|
+
Invoke this Bun.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
args: list or str, optional, default=[]
|
|
191
|
+
Command-line arguments to pass to the invocation.
|
|
192
|
+
|
|
193
|
+
kwargs: dict, default={}
|
|
194
|
+
Arbitrary keyword arguments to pass to ``subprocess.run``.
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
subprocess.CompletedProcess
|
|
199
|
+
The associated ``subprocess.CompletedProcess`` object.
|
|
200
|
+
"""
|
|
201
|
+
self.setup()
|
|
202
|
+
|
|
203
|
+
if isinstance(args, list):
|
|
204
|
+
args = [self.bin_path] + args
|
|
205
|
+
elif isinstance(args, str):
|
|
206
|
+
args = f"{self.bin_path} {args}"
|
|
207
|
+
|
|
208
|
+
env = kwargs.get("env", os.environ)
|
|
209
|
+
|
|
210
|
+
# If the Bun binary isn't on PATH then things like create-next-app will be displeased.
|
|
211
|
+
if isinstance(env, t.MutableMapping):
|
|
212
|
+
kwargs["env"] = {
|
|
213
|
+
**env,
|
|
214
|
+
"PATH": str(self.bin_path.parent) + os.pathsep + env.get("PATH", ""),
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return subprocess.run(args, **kwargs)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
import platform
|
|
3
|
+
import subprocess
|
|
4
|
+
import typing as t
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import httpx2 as httpx
|
|
9
|
+
import kokomikke
|
|
10
|
+
import platformdirs
|
|
11
|
+
from sqlitedict import SqliteDict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def github_client(*, api: bool = False, **kwargs) -> httpx.Client:
|
|
15
|
+
"""
|
|
16
|
+
Return an ``httpx.Client`` for GitHub.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
api: bool, default=False
|
|
21
|
+
If True, return an `httpx.Client` for the GitHub API.
|
|
22
|
+
|
|
23
|
+
kwargs: dict, default={}
|
|
24
|
+
Arbitrary keyword arguments to pass to ``httpx.Client``.
|
|
25
|
+
"""
|
|
26
|
+
return httpx.Client(
|
|
27
|
+
base_url="https://api.github.com" if api else "https://github.com",
|
|
28
|
+
event_hooks={
|
|
29
|
+
"request": [_github_client_request_token_hook],
|
|
30
|
+
"response": [_github_client_rate_limit_hook],
|
|
31
|
+
},
|
|
32
|
+
**kwargs,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_cache_dir() -> Path:
|
|
37
|
+
"""
|
|
38
|
+
Return Akebi's cache directory.
|
|
39
|
+
"""
|
|
40
|
+
path = platformdirs.user_cache_path("akebi", appauthor=False)
|
|
41
|
+
path.mkdir(exist_ok=True, parents=True)
|
|
42
|
+
|
|
43
|
+
return path
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_data_dir() -> Path:
|
|
47
|
+
"""
|
|
48
|
+
Return Akebi's data directory.
|
|
49
|
+
"""
|
|
50
|
+
path = platformdirs.user_data_path("akebi", appauthor=False)
|
|
51
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
return path
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_bun_dir(app_name: str = None) -> Path:
|
|
57
|
+
"""
|
|
58
|
+
Return the directory where Akebi-managed Bun installs are located.
|
|
59
|
+
"""
|
|
60
|
+
if app_name:
|
|
61
|
+
path = get_cache_dir() / "isolated" / app_name / "bun"
|
|
62
|
+
else:
|
|
63
|
+
path = get_cache_dir() / "shared" / "bun"
|
|
64
|
+
|
|
65
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
|
|
67
|
+
return path
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def guess_libc() -> t.Literal["gnu", "musl"] | None:
|
|
71
|
+
"""
|
|
72
|
+
Make a best-effort attempt at determining the C standard library implementation on a Linux system.
|
|
73
|
+
"""
|
|
74
|
+
if platform.system().lower() != "linux":
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
# Check os-release for known musl distributions
|
|
78
|
+
try:
|
|
79
|
+
os_release = platform.freedesktop_os_release()
|
|
80
|
+
except OSError:
|
|
81
|
+
pass
|
|
82
|
+
else:
|
|
83
|
+
identities = {os_release.get("ID")}.union(os_release.get("ID_LIKE", "").split())
|
|
84
|
+
|
|
85
|
+
if identities.intersection({"alpine", "postmarketos", "chimera"}):
|
|
86
|
+
return "musl"
|
|
87
|
+
|
|
88
|
+
# Read the output of `ldd --version`
|
|
89
|
+
try:
|
|
90
|
+
ldd_command = subprocess.run(
|
|
91
|
+
["ldd", "--version"], capture_output=True, text=True
|
|
92
|
+
)
|
|
93
|
+
except FileNotFoundError:
|
|
94
|
+
pass
|
|
95
|
+
else:
|
|
96
|
+
# `ldd --version` on musl systems exits nonzero and writes to stderr. why? you tell me
|
|
97
|
+
ldd_info = ldd_command.stdout + ldd_command.stderr
|
|
98
|
+
|
|
99
|
+
if "gnu" in ldd_info.casefold():
|
|
100
|
+
return "gnu"
|
|
101
|
+
elif "musl" in ldd_info.casefold():
|
|
102
|
+
return "musl"
|
|
103
|
+
|
|
104
|
+
# Check which libc the Python interpreter is linked against
|
|
105
|
+
match platform.libc_ver()[0]:
|
|
106
|
+
case "glibc":
|
|
107
|
+
return "gnu"
|
|
108
|
+
case "musl":
|
|
109
|
+
return "musl"
|
|
110
|
+
|
|
111
|
+
# Check /lib and /lib64 for files beginning with ld-linux- or ld-musl-
|
|
112
|
+
for directory in ["/lib", "/lib64"]:
|
|
113
|
+
for prefix, libc in zip(["ld-linux-", "ld-musl-"], ["gnu", "musl"]):
|
|
114
|
+
if next(Path(directory).glob(f"{prefix}*"), None):
|
|
115
|
+
return libc
|
|
116
|
+
|
|
117
|
+
# If all else fails, assume glibc and hope for the best
|
|
118
|
+
return "gnu"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def needs_baseline_build() -> bool:
|
|
122
|
+
"""
|
|
123
|
+
Determine whether the host machine requires a baseline build of Bun.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
if platform.machine() in ["arm64", "aarch64"]:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
match platform.system().lower():
|
|
130
|
+
case "darwin":
|
|
131
|
+
try:
|
|
132
|
+
sysctl = subprocess.check_output(["sysctl", "-a"], text=True)
|
|
133
|
+
except FileNotFoundError, subprocess.CalledProcessError:
|
|
134
|
+
return True
|
|
135
|
+
else:
|
|
136
|
+
return "avx2" not in sysctl.casefold()
|
|
137
|
+
|
|
138
|
+
case "linux":
|
|
139
|
+
cpu_info = Path("/proc/cpuinfo")
|
|
140
|
+
return not (
|
|
141
|
+
cpu_info.is_file() and "avx2" in cpu_info.read_text().casefold()
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
case "windows":
|
|
145
|
+
return not bool(ctypes.windll.kernel32.IsProcessorFeaturePresent(40))
|
|
146
|
+
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@contextmanager
|
|
151
|
+
def state(table: str = "unnamed") -> SqliteDict:
|
|
152
|
+
"""
|
|
153
|
+
Context manager for accessing Akebi's key-value store.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
table: str, default="unnamed"
|
|
158
|
+
The table to access.
|
|
159
|
+
"""
|
|
160
|
+
with SqliteDict(get_data_dir() / "akebi.db", tablename=table) as db:
|
|
161
|
+
yield db
|
|
162
|
+
db.commit()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _github_client_request_token_hook(request: httpx.Request) -> None:
|
|
166
|
+
"""
|
|
167
|
+
HTTPX event hook to attach a GitHub access token, if one can be found, to requests to GitHub.
|
|
168
|
+
"""
|
|
169
|
+
if token := kokomikke.search():
|
|
170
|
+
request.headers["Authorization"] = f"Bearer {token}"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _github_client_rate_limit_hook(response: httpx.Response) -> None:
|
|
174
|
+
"""
|
|
175
|
+
HTTPX event hook to handle HTTP 429 errors in responses from GitHub.
|
|
176
|
+
"""
|
|
177
|
+
if response.status_code == 429:
|
|
178
|
+
raise Exception(
|
|
179
|
+
"GitHub is rate limiting you. You can probably fix this by setting the "
|
|
180
|
+
"GITHUB_TOKEN environment variable or logging into the GitHub CLI (https://cli.github.com); your "
|
|
181
|
+
"credentials will automatically be attached to future GitHub requests."
|
|
182
|
+
)
|
akebi-0.1.0/prek.toml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "akebi"
|
|
3
|
+
description = "Manage Bun installations from Python"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
license-files = ["LICENSE.md"]
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "celsius narhwal", email = "hello@celsiusnarhwal.dev" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.14"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"httpx2>=2.4.0",
|
|
12
|
+
"kokomikke>=0.1.4",
|
|
13
|
+
"loguru>=0.7.3",
|
|
14
|
+
"platformdirs>=4.10.0",
|
|
15
|
+
"pydantic>=2.13.4",
|
|
16
|
+
"pydantic-extra-types>=2.11.1",
|
|
17
|
+
"pydantic-settings>=2.14.1",
|
|
18
|
+
"rich>=15.0.0",
|
|
19
|
+
"semver>=3.0.4",
|
|
20
|
+
"sqlitedict>=2.1.0",
|
|
21
|
+
]
|
|
22
|
+
dynamic = ["version"]
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
akebi = "akebi:main"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.version]
|
|
28
|
+
source = "vcs"
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
32
|
+
build-backend = "hatchling.build"
|
akebi-0.1.0/uv.lock
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.14"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "akebi"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
source = { editable = "." }
|
|
9
|
+
dependencies = [
|
|
10
|
+
{ name = "httpx2" },
|
|
11
|
+
{ name = "kokomikke" },
|
|
12
|
+
{ name = "loguru" },
|
|
13
|
+
{ name = "platformdirs" },
|
|
14
|
+
{ name = "pydantic" },
|
|
15
|
+
{ name = "pydantic-extra-types" },
|
|
16
|
+
{ name = "pydantic-settings" },
|
|
17
|
+
{ name = "rich" },
|
|
18
|
+
{ name = "semver" },
|
|
19
|
+
{ name = "sqlitedict" },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[package.metadata]
|
|
23
|
+
requires-dist = [
|
|
24
|
+
{ name = "httpx2", specifier = ">=2.4.0" },
|
|
25
|
+
{ name = "kokomikke", specifier = ">=0.1.4" },
|
|
26
|
+
{ name = "loguru", specifier = ">=0.7.3" },
|
|
27
|
+
{ name = "platformdirs", specifier = ">=4.10.0" },
|
|
28
|
+
{ name = "pydantic", specifier = ">=2.13.4" },
|
|
29
|
+
{ name = "pydantic-extra-types", specifier = ">=2.11.1" },
|
|
30
|
+
{ name = "pydantic-settings", specifier = ">=2.14.1" },
|
|
31
|
+
{ name = "rich", specifier = ">=15.0.0" },
|
|
32
|
+
{ name = "semver", specifier = ">=3.0.4" },
|
|
33
|
+
{ name = "sqlitedict", specifier = ">=2.1.0" },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "annotated-types"
|
|
38
|
+
version = "0.7.0"
|
|
39
|
+
source = { registry = "https://pypi.org/simple" }
|
|
40
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
|
41
|
+
wheels = [
|
|
42
|
+
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[[package]]
|
|
46
|
+
name = "anyio"
|
|
47
|
+
version = "4.13.0"
|
|
48
|
+
source = { registry = "https://pypi.org/simple" }
|
|
49
|
+
dependencies = [
|
|
50
|
+
{ name = "idna" },
|
|
51
|
+
]
|
|
52
|
+
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
|
53
|
+
wheels = [
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[[package]]
|
|
58
|
+
name = "colorama"
|
|
59
|
+
version = "0.4.6"
|
|
60
|
+
source = { registry = "https://pypi.org/simple" }
|
|
61
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
62
|
+
wheels = [
|
|
63
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[[package]]
|
|
67
|
+
name = "h11"
|
|
68
|
+
version = "0.16.0"
|
|
69
|
+
source = { registry = "https://pypi.org/simple" }
|
|
70
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
|
71
|
+
wheels = [
|
|
72
|
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[[package]]
|
|
76
|
+
name = "httpcore2"
|
|
77
|
+
version = "2.4.0"
|
|
78
|
+
source = { registry = "https://pypi.org/simple" }
|
|
79
|
+
dependencies = [
|
|
80
|
+
{ name = "h11" },
|
|
81
|
+
{ name = "truststore" },
|
|
82
|
+
]
|
|
83
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7b/9b/2b1d1833a58236d1f6ee755e027a3917da0db59cc9708554cefc440ee8b6/httpcore2-2.4.0.tar.gz", hash = "sha256:3093a8ab8980d9f910b9cb4351df9186a0ad2350a6284a9107ac9a362a584422", size = 64618, upload-time = "2026-06-11T06:35:53.425Z" }
|
|
84
|
+
wheels = [
|
|
85
|
+
{ url = "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl", hash = "sha256:5218779da5d6e3c2013ac706121abfb3815d450e0613495c0de50264dce58242", size = 80151, upload-time = "2026-06-11T06:35:50.89Z" },
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
[[package]]
|
|
89
|
+
name = "httpx2"
|
|
90
|
+
version = "2.4.0"
|
|
91
|
+
source = { registry = "https://pypi.org/simple" }
|
|
92
|
+
dependencies = [
|
|
93
|
+
{ name = "anyio" },
|
|
94
|
+
{ name = "httpcore2" },
|
|
95
|
+
{ name = "idna" },
|
|
96
|
+
{ name = "truststore" },
|
|
97
|
+
]
|
|
98
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fc/60/b43ced4ccf26e95b396dbf67051d3e5042b645917d4da0469dd82a3bdd4f/httpx2-2.4.0.tar.gz", hash = "sha256:32e0734b61eb0824b3f56a9e98d6d92d381a3ef12c0045aa917ee63df6c411ef", size = 81691, upload-time = "2026-06-11T06:35:54.538Z" }
|
|
99
|
+
wheels = [
|
|
100
|
+
{ url = "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl", hash = "sha256:425acd99297829599decf6701386dd84db3542597d36d3e2e4def930ecd57fd9", size = 74941, upload-time = "2026-06-11T06:35:52.235Z" },
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
[[package]]
|
|
104
|
+
name = "idna"
|
|
105
|
+
version = "3.18"
|
|
106
|
+
source = { registry = "https://pypi.org/simple" }
|
|
107
|
+
sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" }
|
|
108
|
+
wheels = [
|
|
109
|
+
{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" },
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
[[package]]
|
|
113
|
+
name = "kokomikke"
|
|
114
|
+
version = "0.1.4"
|
|
115
|
+
source = { registry = "https://pypi.org/simple" }
|
|
116
|
+
dependencies = [
|
|
117
|
+
{ name = "platformdirs" },
|
|
118
|
+
{ name = "pydantic" },
|
|
119
|
+
{ name = "pyyaml" },
|
|
120
|
+
]
|
|
121
|
+
sdist = { url = "https://files.pythonhosted.org/packages/4c/33/f8b7ea7cc90d1212b2ffc6dba9b0a4cbd42b0e4c582571ce08821af4307b/kokomikke-0.1.4.tar.gz", hash = "sha256:8131acfe6259aac10e343d3adb5a5b5debc1caa013c2b93385eeebeefaf2ea11", size = 24172, upload-time = "2026-06-16T13:49:03.814Z" }
|
|
122
|
+
wheels = [
|
|
123
|
+
{ url = "https://files.pythonhosted.org/packages/c3/2e/3d62491c7fbbaf9ee6cf27bb45f3fdaeef2f9c991228f7ef9801a8e3a03d/kokomikke-0.1.4-py3-none-any.whl", hash = "sha256:d8850feb49e6509a485068f651927a0a365af96f5159ee70daa37213904e5708", size = 4972, upload-time = "2026-06-16T13:49:02.592Z" },
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
[[package]]
|
|
127
|
+
name = "loguru"
|
|
128
|
+
version = "0.7.3"
|
|
129
|
+
source = { registry = "https://pypi.org/simple" }
|
|
130
|
+
dependencies = [
|
|
131
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
132
|
+
{ name = "win32-setctime", marker = "sys_platform == 'win32'" },
|
|
133
|
+
]
|
|
134
|
+
sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" }
|
|
135
|
+
wheels = [
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" },
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
[[package]]
|
|
140
|
+
name = "markdown-it-py"
|
|
141
|
+
version = "4.2.0"
|
|
142
|
+
source = { registry = "https://pypi.org/simple" }
|
|
143
|
+
dependencies = [
|
|
144
|
+
{ name = "mdurl" },
|
|
145
|
+
]
|
|
146
|
+
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
|
147
|
+
wheels = [
|
|
148
|
+
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
[[package]]
|
|
152
|
+
name = "mdurl"
|
|
153
|
+
version = "0.1.2"
|
|
154
|
+
source = { registry = "https://pypi.org/simple" }
|
|
155
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
|
156
|
+
wheels = [
|
|
157
|
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
[[package]]
|
|
161
|
+
name = "platformdirs"
|
|
162
|
+
version = "4.10.0"
|
|
163
|
+
source = { registry = "https://pypi.org/simple" }
|
|
164
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" }
|
|
165
|
+
wheels = [
|
|
166
|
+
{ url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" },
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
[[package]]
|
|
170
|
+
name = "pydantic"
|
|
171
|
+
version = "2.13.4"
|
|
172
|
+
source = { registry = "https://pypi.org/simple" }
|
|
173
|
+
dependencies = [
|
|
174
|
+
{ name = "annotated-types" },
|
|
175
|
+
{ name = "pydantic-core" },
|
|
176
|
+
{ name = "typing-extensions" },
|
|
177
|
+
{ name = "typing-inspection" },
|
|
178
|
+
]
|
|
179
|
+
sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
|
|
180
|
+
wheels = [
|
|
181
|
+
{ url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
[[package]]
|
|
185
|
+
name = "pydantic-core"
|
|
186
|
+
version = "2.46.4"
|
|
187
|
+
source = { registry = "https://pypi.org/simple" }
|
|
188
|
+
dependencies = [
|
|
189
|
+
{ name = "typing-extensions" },
|
|
190
|
+
]
|
|
191
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
|
|
192
|
+
wheels = [
|
|
193
|
+
{ url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" },
|
|
194
|
+
{ url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" },
|
|
195
|
+
{ url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" },
|
|
196
|
+
{ url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" },
|
|
197
|
+
{ url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" },
|
|
198
|
+
{ url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" },
|
|
199
|
+
{ url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" },
|
|
200
|
+
{ url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" },
|
|
201
|
+
{ url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" },
|
|
202
|
+
{ url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" },
|
|
203
|
+
{ url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" },
|
|
204
|
+
{ url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" },
|
|
205
|
+
{ url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" },
|
|
206
|
+
{ url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" },
|
|
207
|
+
{ url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" },
|
|
208
|
+
{ url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" },
|
|
209
|
+
{ url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" },
|
|
210
|
+
{ url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" },
|
|
211
|
+
{ url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" },
|
|
212
|
+
{ url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" },
|
|
213
|
+
{ url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" },
|
|
214
|
+
{ url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" },
|
|
215
|
+
{ url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" },
|
|
216
|
+
{ url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" },
|
|
217
|
+
{ url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" },
|
|
218
|
+
{ url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" },
|
|
219
|
+
{ url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" },
|
|
220
|
+
{ url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" },
|
|
221
|
+
{ url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" },
|
|
222
|
+
{ url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" },
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
[[package]]
|
|
226
|
+
name = "pydantic-extra-types"
|
|
227
|
+
version = "2.11.1"
|
|
228
|
+
source = { registry = "https://pypi.org/simple" }
|
|
229
|
+
dependencies = [
|
|
230
|
+
{ name = "pydantic" },
|
|
231
|
+
{ name = "typing-extensions" },
|
|
232
|
+
]
|
|
233
|
+
sdist = { url = "https://files.pythonhosted.org/packages/66/71/dba38ee2651f84f7842206adbd2233d8bbdb59fb85e9fa14232486a8c471/pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049", size = 172002, upload-time = "2026-03-16T08:08:03.92Z" }
|
|
234
|
+
wheels = [
|
|
235
|
+
{ url = "https://files.pythonhosted.org/packages/17/c1/3226e6d7f5a4f736f38ac11a6fbb262d701889802595cdb0f53a885ac2e0/pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1", size = 79526, upload-time = "2026-03-16T08:08:02.533Z" },
|
|
236
|
+
]
|
|
237
|
+
|
|
238
|
+
[[package]]
|
|
239
|
+
name = "pydantic-settings"
|
|
240
|
+
version = "2.14.1"
|
|
241
|
+
source = { registry = "https://pypi.org/simple" }
|
|
242
|
+
dependencies = [
|
|
243
|
+
{ name = "pydantic" },
|
|
244
|
+
{ name = "python-dotenv" },
|
|
245
|
+
{ name = "typing-inspection" },
|
|
246
|
+
]
|
|
247
|
+
sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" }
|
|
248
|
+
wheels = [
|
|
249
|
+
{ url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" },
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
[[package]]
|
|
253
|
+
name = "pygments"
|
|
254
|
+
version = "2.20.0"
|
|
255
|
+
source = { registry = "https://pypi.org/simple" }
|
|
256
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
|
257
|
+
wheels = [
|
|
258
|
+
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
[[package]]
|
|
262
|
+
name = "python-dotenv"
|
|
263
|
+
version = "1.2.2"
|
|
264
|
+
source = { registry = "https://pypi.org/simple" }
|
|
265
|
+
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
|
|
266
|
+
wheels = [
|
|
267
|
+
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
[[package]]
|
|
271
|
+
name = "pyyaml"
|
|
272
|
+
version = "6.0.3"
|
|
273
|
+
source = { registry = "https://pypi.org/simple" }
|
|
274
|
+
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
|
275
|
+
wheels = [
|
|
276
|
+
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
|
|
277
|
+
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
|
|
278
|
+
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
|
|
279
|
+
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
|
|
280
|
+
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
|
|
281
|
+
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
|
|
282
|
+
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
|
|
283
|
+
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
|
|
284
|
+
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
|
|
285
|
+
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
|
|
286
|
+
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
|
|
287
|
+
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
|
|
288
|
+
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
|
|
289
|
+
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
|
|
290
|
+
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
|
|
291
|
+
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
|
|
292
|
+
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
|
|
293
|
+
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
[[package]]
|
|
297
|
+
name = "rich"
|
|
298
|
+
version = "15.0.0"
|
|
299
|
+
source = { registry = "https://pypi.org/simple" }
|
|
300
|
+
dependencies = [
|
|
301
|
+
{ name = "markdown-it-py" },
|
|
302
|
+
{ name = "pygments" },
|
|
303
|
+
]
|
|
304
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
|
305
|
+
wheels = [
|
|
306
|
+
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
[[package]]
|
|
310
|
+
name = "semver"
|
|
311
|
+
version = "3.0.4"
|
|
312
|
+
source = { registry = "https://pypi.org/simple" }
|
|
313
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" }
|
|
314
|
+
wheels = [
|
|
315
|
+
{ url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" },
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
[[package]]
|
|
319
|
+
name = "sqlitedict"
|
|
320
|
+
version = "2.1.0"
|
|
321
|
+
source = { registry = "https://pypi.org/simple" }
|
|
322
|
+
sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" }
|
|
323
|
+
|
|
324
|
+
[[package]]
|
|
325
|
+
name = "truststore"
|
|
326
|
+
version = "0.10.4"
|
|
327
|
+
source = { registry = "https://pypi.org/simple" }
|
|
328
|
+
sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
|
|
329
|
+
wheels = [
|
|
330
|
+
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
[[package]]
|
|
334
|
+
name = "typing-extensions"
|
|
335
|
+
version = "4.15.0"
|
|
336
|
+
source = { registry = "https://pypi.org/simple" }
|
|
337
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
|
338
|
+
wheels = [
|
|
339
|
+
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
[[package]]
|
|
343
|
+
name = "typing-inspection"
|
|
344
|
+
version = "0.4.2"
|
|
345
|
+
source = { registry = "https://pypi.org/simple" }
|
|
346
|
+
dependencies = [
|
|
347
|
+
{ name = "typing-extensions" },
|
|
348
|
+
]
|
|
349
|
+
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
|
350
|
+
wheels = [
|
|
351
|
+
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
[[package]]
|
|
355
|
+
name = "win32-setctime"
|
|
356
|
+
version = "1.2.0"
|
|
357
|
+
source = { registry = "https://pypi.org/simple" }
|
|
358
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" }
|
|
359
|
+
wheels = [
|
|
360
|
+
{ url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" },
|
|
361
|
+
]
|