l10n-gr 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.
- l10n_gr-0.1.0/.gitignore +18 -0
- l10n_gr-0.1.0/PKG-INFO +31 -0
- l10n_gr-0.1.0/README.md +23 -0
- l10n_gr-0.1.0/pyproject.toml +21 -0
- l10n_gr-0.1.0/src/l10n_gr_cli/__init__.py +1 -0
- l10n_gr-0.1.0/src/l10n_gr_cli/main.py +251 -0
- l10n_gr-0.1.0/tests/test_tree.py +21 -0
- l10n_gr-0.1.0/uv.lock +174 -0
l10n_gr-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
dist/
|
|
6
|
+
.next/
|
|
7
|
+
.DS_Store
|
|
8
|
+
.idea/
|
|
9
|
+
.venv/
|
|
10
|
+
.output/
|
|
11
|
+
.nuxt/
|
|
12
|
+
__pycache__/
|
|
13
|
+
infra/site/.env
|
|
14
|
+
apps/site/dist
|
|
15
|
+
|
|
16
|
+
# Odoo Enterprise packages: proprietary, never in this repo (CLAUDE.md hard boundary 1 spirit)
|
|
17
|
+
odoo-deb/
|
|
18
|
+
*.deb
|
l10n_gr-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: l10n-gr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: l10n.gr command line: live development of your Odoo modules on a project's staging (l10n-gr dev)
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# l10n-gr
|
|
10
|
+
|
|
11
|
+
Command line for partners of [l10n.gr](https://l10n.gr). `l10n-gr dev` sends the modules of your local checkout to
|
|
12
|
+
your project's staging as you save, so you see the change in Odoo seconds later, without a push and a pipeline run.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
pip install l10n-gr
|
|
16
|
+
cd ~/code/acme-odoo # the repository your project's pipeline uses
|
|
17
|
+
l10n-gr dev --project acme
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Start a session first in console.l10n.gr: project → Staging → «Live development» → Start. The console shows a dev
|
|
21
|
+
token once; paste it when the CLI asks (or set `L10N_GR_TOKEN`). The token reaches only this project's staging.
|
|
22
|
+
|
|
23
|
+
Every save runs the pipeline's checks (static rules and the AI review). A blocking finding rejects the change and
|
|
24
|
+
staging keeps the last accepted state. Accepted changes install new modules and upgrade the changed ones. The staging
|
|
25
|
+
log follows in the same terminal.
|
|
26
|
+
|
|
27
|
+
`Ctrl+C`, «End» in the console, 8 hours without a change, or a deploy to staging end the session, and staging goes back
|
|
28
|
+
to the approved release. Code reaches production only through git and the pipeline.
|
|
29
|
+
|
|
30
|
+
In PyCharm, run it in the terminal or as a Run configuration (module `l10n_gr_cli.main`, parameters
|
|
31
|
+
`dev --project acme`, working directory your repository).
|
l10n_gr-0.1.0/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# l10n-gr
|
|
2
|
+
|
|
3
|
+
Command line for partners of [l10n.gr](https://l10n.gr). `l10n-gr dev` sends the modules of your local checkout to
|
|
4
|
+
your project's staging as you save, so you see the change in Odoo seconds later, without a push and a pipeline run.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
pip install l10n-gr
|
|
8
|
+
cd ~/code/acme-odoo # the repository your project's pipeline uses
|
|
9
|
+
l10n-gr dev --project acme
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Start a session first in console.l10n.gr: project → Staging → «Live development» → Start. The console shows a dev
|
|
13
|
+
token once; paste it when the CLI asks (or set `L10N_GR_TOKEN`). The token reaches only this project's staging.
|
|
14
|
+
|
|
15
|
+
Every save runs the pipeline's checks (static rules and the AI review). A blocking finding rejects the change and
|
|
16
|
+
staging keeps the last accepted state. Accepted changes install new modules and upgrade the changed ones. The staging
|
|
17
|
+
log follows in the same terminal.
|
|
18
|
+
|
|
19
|
+
`Ctrl+C`, «End» in the console, 8 hours without a change, or a deploy to staging end the session, and staging goes back
|
|
20
|
+
to the approved release. Code reaches production only through git and the pipeline.
|
|
21
|
+
|
|
22
|
+
In PyCharm, run it in the terminal or as a Run configuration (module `l10n_gr_cli.main`, parameters
|
|
23
|
+
`dev --project acme`, working directory your repository).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "l10n-gr"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "l10n.gr command line: live development of your Odoo modules on a project's staging (l10n-gr dev)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
dependencies = [] # standard library only
|
|
9
|
+
|
|
10
|
+
[project.scripts]
|
|
11
|
+
l10n-gr = "l10n_gr_cli.main:main"
|
|
12
|
+
|
|
13
|
+
[dependency-groups]
|
|
14
|
+
dev = ["pytest>=8.4"]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["hatchling"]
|
|
18
|
+
build-backend = "hatchling.build"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.wheel]
|
|
21
|
+
packages = ["src/l10n_gr_cli"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""l10n.gr command line."""
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""`l10n-gr dev`: live development on a project's staging (console spec §5.13, ADR-0010).
|
|
2
|
+
|
|
3
|
+
Watches the Odoo modules of the current repository (folders with a __manifest__.py at its root, as the pipeline builds
|
|
4
|
+
them), sends the whole tree on every save (paths and sha256, contents only when the console asks), prints each check's
|
|
5
|
+
result and follows the staging log. Standard library only."""
|
|
6
|
+
import argparse
|
|
7
|
+
import base64
|
|
8
|
+
import getpass
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import threading
|
|
14
|
+
import time
|
|
15
|
+
import urllib.error
|
|
16
|
+
import urllib.request
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
CONSOLE = "https://console.l10n.gr"
|
|
20
|
+
SKIP_DIRS = {"__pycache__", "node_modules"}
|
|
21
|
+
# what the console accepts (livedev.SUFFIXES): other files stay local, so a stray build artefact never blocks a save
|
|
22
|
+
SUFFIXES = {".py", ".xml", ".csv", ".js", ".json", ".txt", ".cfg", ".yml", ".yaml", ".ini", ".md", ".rst", ".po", ".pot",
|
|
23
|
+
".scss", ".css", ".less", ".html", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".woff", ".woff2",
|
|
24
|
+
".ttf", ".otf", ".eot", ".pdf", ".xlsx", ".docx", ".odt", ".mp3", ".mp4", ".wav"}
|
|
25
|
+
MAX_FILE = 5_000_000
|
|
26
|
+
DONE = {"applied", "rejected", "failed", "superseded"}
|
|
27
|
+
TOKENS = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "l10n-gr" / "dev-tokens.json"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ApiError(Exception):
|
|
31
|
+
def __init__(self, status: int, code: str):
|
|
32
|
+
super().__init__(code)
|
|
33
|
+
self.status, self.code = status, code
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Console:
|
|
37
|
+
def __init__(self, url: str, token: str):
|
|
38
|
+
self.url, self.token = url.rstrip("/"), token
|
|
39
|
+
|
|
40
|
+
def call(self, method: str, path: str, body: dict | None = None):
|
|
41
|
+
req = urllib.request.Request(f"{self.url}/api/dev{path}", method=method,
|
|
42
|
+
data=json.dumps(body).encode() if body is not None else None,
|
|
43
|
+
headers={"Authorization": f"Bearer {self.token}", "Content-Type": "application/json",
|
|
44
|
+
"User-Agent": "l10n-gr-cli/0.1"})
|
|
45
|
+
try:
|
|
46
|
+
with urllib.request.urlopen(req, timeout=120) as r:
|
|
47
|
+
return json.loads(r.read() or b"null")
|
|
48
|
+
except urllib.error.HTTPError as e:
|
|
49
|
+
try:
|
|
50
|
+
code = json.loads(e.read())["error"]["code"]
|
|
51
|
+
except (ValueError, KeyError, TypeError):
|
|
52
|
+
code = f"http.{e.code}"
|
|
53
|
+
raise ApiError(e.code, code) from None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# --- the local tree -----------------------------------------------------------------------------------------------------
|
|
57
|
+
def modules(root: Path) -> list[Path]:
|
|
58
|
+
return sorted(d for d in root.iterdir() if d.is_dir() and not d.name.startswith(".") and (d / "__manifest__.py").is_file())
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def snapshot(root: Path) -> dict[str, tuple[int, int]]:
|
|
62
|
+
"""path -> (mtime_ns, size) of every file of every module."""
|
|
63
|
+
out = {}
|
|
64
|
+
for mod in modules(root):
|
|
65
|
+
for dirpath, dirnames, filenames in os.walk(mod):
|
|
66
|
+
dirnames[:] = [d for d in dirnames if not d.startswith(".") and d not in SKIP_DIRS]
|
|
67
|
+
for name in filenames:
|
|
68
|
+
if name.startswith(".") or Path(name).suffix.lower() not in SUFFIXES or name.endswith("~"):
|
|
69
|
+
continue
|
|
70
|
+
f = Path(dirpath) / name
|
|
71
|
+
try:
|
|
72
|
+
st = f.stat()
|
|
73
|
+
except OSError: # removed while scanning
|
|
74
|
+
continue
|
|
75
|
+
out[f.relative_to(root).as_posix()] = (st.st_mtime_ns, st.st_size)
|
|
76
|
+
return out
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Tree:
|
|
80
|
+
"""The tree as the console sees it: sha256 per path, hashed again only when mtime or size changes."""
|
|
81
|
+
|
|
82
|
+
def __init__(self, root: Path):
|
|
83
|
+
self.root, self.cache = root, {}
|
|
84
|
+
|
|
85
|
+
def hashes(self, snap: dict) -> dict[str, str]:
|
|
86
|
+
out = {}
|
|
87
|
+
for path, stamp in snap.items():
|
|
88
|
+
if stamp[1] > MAX_FILE:
|
|
89
|
+
print(f" skipped {path}: larger than {MAX_FILE // 1_000_000} MB", file=sys.stderr)
|
|
90
|
+
continue
|
|
91
|
+
if self.cache.get(path, (None,))[0] != stamp:
|
|
92
|
+
try:
|
|
93
|
+
self.cache[path] = (stamp, hashlib.sha256((self.root / path).read_bytes()).hexdigest())
|
|
94
|
+
except OSError:
|
|
95
|
+
continue
|
|
96
|
+
out[path] = self.cache[path][1]
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
def blobs(self, paths: list[str], tree: dict[str, str]) -> dict[str, str]:
|
|
100
|
+
return {tree[p]: base64.b64encode((self.root / p).read_bytes()).decode() for p in paths}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# --- output -------------------------------------------------------------------------------------------------------------
|
|
104
|
+
def say(msg: str) -> None:
|
|
105
|
+
print(f"{time.strftime('%H:%M:%S')} {msg}", flush=True)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def report(ch: dict) -> None:
|
|
109
|
+
status = ch["status"]
|
|
110
|
+
if status == "applied":
|
|
111
|
+
parts = [f"installed {', '.join(ch['installed'])}" if ch["installed"] else "",
|
|
112
|
+
f"upgraded {', '.join(ch['upgraded'])}" if ch["upgraded"] else ""]
|
|
113
|
+
say(f"✓ applied on staging{': ' + '; '.join(x for x in parts if x) if any(parts) else ''}")
|
|
114
|
+
elif status == "rejected":
|
|
115
|
+
say("✗ rejected: staging keeps the last accepted state")
|
|
116
|
+
elif status == "failed":
|
|
117
|
+
say("✗ failed on staging: the previous state is back")
|
|
118
|
+
for line in ch.get("output", "").splitlines()[-30:]:
|
|
119
|
+
print(f" {line}")
|
|
120
|
+
for f in ch.get("findings", []):
|
|
121
|
+
print(f" {f['severity'].upper():5} {f['file']}:{f['line']} [{f['rule']}] {f['message']}")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def follow_log(api: Console, stop: threading.Event) -> None:
|
|
125
|
+
after = ""
|
|
126
|
+
while not stop.wait(2):
|
|
127
|
+
try:
|
|
128
|
+
entries = api.call("GET", f"/log?after={after}")["entries"]
|
|
129
|
+
except (ApiError, OSError, ValueError):
|
|
130
|
+
continue
|
|
131
|
+
for e in entries:
|
|
132
|
+
after = e["ts"]
|
|
133
|
+
print(f" log {e['level']:7} {e['logger']}: {e['message']}", flush=True)
|
|
134
|
+
for line in (e.get("trace") or "").splitlines():
|
|
135
|
+
print(f" {line}")
|
|
136
|
+
if e.get("collapsed"):
|
|
137
|
+
print(f" [{e['collapsed']['lines']} lines of an l10n.gr traceback hidden] {e['collapsed']['error']}")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# --- dev ----------------------------------------------------------------------------------------------------------------
|
|
141
|
+
def _saved() -> dict:
|
|
142
|
+
try:
|
|
143
|
+
return json.loads(TOKENS.read_text())
|
|
144
|
+
except (OSError, ValueError):
|
|
145
|
+
return {}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _save(project: str, token: str | None) -> None:
|
|
149
|
+
tokens = _saved()
|
|
150
|
+
if token:
|
|
151
|
+
tokens[project] = token
|
|
152
|
+
else:
|
|
153
|
+
tokens.pop(project, None)
|
|
154
|
+
TOKENS.parent.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
TOKENS.write_text(json.dumps(tokens))
|
|
156
|
+
TOKENS.chmod(0o600)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
ENDED = {"partner": "ended from the console", "cli": "ended", "idle": "ended after 8 hours without a change",
|
|
160
|
+
"deploy": "ended by a deploy to staging", "suite": "ended by an l10n.gr upgrade of staging",
|
|
161
|
+
"extraction": "ended: the change reads l10n.gr code"}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _ended(code: str) -> str:
|
|
165
|
+
return ENDED.get(code.removeprefix("live.ended."), "ended") if code.startswith("live.ended.") else code
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def sync(api: Console, tree: Tree, hashes: dict) -> dict | None:
|
|
169
|
+
r = api.call("POST", "/changes", {"tree": hashes})
|
|
170
|
+
if r["missing"]:
|
|
171
|
+
r = api.call("POST", "/changes", {"tree": hashes, "blobs": tree.blobs(r["missing"], hashes)})
|
|
172
|
+
return r.get("change")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def dev(args) -> int:
|
|
176
|
+
root = Path(args.path).resolve()
|
|
177
|
+
if not modules(root):
|
|
178
|
+
print(f"No Odoo modules in {root}: run l10n-gr dev at the root of your project's repository.", file=sys.stderr)
|
|
179
|
+
return 2
|
|
180
|
+
token = os.environ.get("L10N_GR_TOKEN") or _saved().get(args.project)
|
|
181
|
+
while True:
|
|
182
|
+
if not token:
|
|
183
|
+
print("Start a session in console.l10n.gr: project → Staging → Live development → Start.")
|
|
184
|
+
token = getpass.getpass("Dev token: ").strip()
|
|
185
|
+
api = Console(args.console, token)
|
|
186
|
+
try:
|
|
187
|
+
info = api.call("GET", "/session")
|
|
188
|
+
break
|
|
189
|
+
except ApiError as e:
|
|
190
|
+
_save(args.project, None)
|
|
191
|
+
if e.status == 401 or e.code.startswith("live.ended."):
|
|
192
|
+
print(f"This token is not valid ({_ended(e.code)}). Start a new session in the console.", file=sys.stderr)
|
|
193
|
+
token = None
|
|
194
|
+
if os.environ.get("L10N_GR_TOKEN"):
|
|
195
|
+
return 1
|
|
196
|
+
continue
|
|
197
|
+
print(f"The console refused: {e.code}", file=sys.stderr)
|
|
198
|
+
return 1
|
|
199
|
+
if info["project"] != args.project:
|
|
200
|
+
print(f"This token is for project {info['project']}, not {args.project}.", file=sys.stderr)
|
|
201
|
+
return 1
|
|
202
|
+
_save(args.project, token)
|
|
203
|
+
say(f"live session on {info['staging']} ({', '.join(p.name for p in modules(root))})")
|
|
204
|
+
stop = threading.Event()
|
|
205
|
+
threading.Thread(target=follow_log, args=(api, stop), daemon=True).start()
|
|
206
|
+
tree, last, pending = Tree(root), None, None
|
|
207
|
+
try:
|
|
208
|
+
while True:
|
|
209
|
+
snap = snapshot(root)
|
|
210
|
+
if snap != last:
|
|
211
|
+
time.sleep(0.4) # editors write in steps: send once the save settles
|
|
212
|
+
last = snapshot(root)
|
|
213
|
+
if change := sync(api, tree, tree.hashes(last)):
|
|
214
|
+
say(f"sent {len(change['files'])} changed file(s), checking…")
|
|
215
|
+
pending = change["id"]
|
|
216
|
+
if pending:
|
|
217
|
+
ch = api.call("GET", f"/changes/{pending}")
|
|
218
|
+
if ch["status"] in DONE:
|
|
219
|
+
if ch["status"] != "superseded":
|
|
220
|
+
report(ch)
|
|
221
|
+
pending = None
|
|
222
|
+
time.sleep(1)
|
|
223
|
+
except KeyboardInterrupt:
|
|
224
|
+
stop.set()
|
|
225
|
+
try:
|
|
226
|
+
api.call("POST", "/end")
|
|
227
|
+
say("session ended: staging goes back to the approved release")
|
|
228
|
+
except (ApiError, OSError):
|
|
229
|
+
pass
|
|
230
|
+
_save(args.project, None)
|
|
231
|
+
return 0
|
|
232
|
+
except ApiError as e:
|
|
233
|
+
stop.set()
|
|
234
|
+
_save(args.project, None)
|
|
235
|
+
say(f"session {_ended(e.code)}" if e.code.startswith("live.ended.") else f"the console refused: {e.code}")
|
|
236
|
+
return 1
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def main(argv: list[str] | None = None) -> int:
|
|
240
|
+
ap = argparse.ArgumentParser(prog="l10n-gr", description="l10n.gr command line")
|
|
241
|
+
sub = ap.add_subparsers(dest="command", required=True)
|
|
242
|
+
d = sub.add_parser("dev", help="live development on the project's staging")
|
|
243
|
+
d.add_argument("--project", required=True, help="the project's name in the console, e.g. acme")
|
|
244
|
+
d.add_argument("--path", default=".", help="your repository (default: the current folder)")
|
|
245
|
+
d.add_argument("--console", default=os.environ.get("L10N_GR_CONSOLE", CONSOLE), help=argparse.SUPPRESS)
|
|
246
|
+
args = ap.parse_args(argv)
|
|
247
|
+
return dev(args)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
if __name__ == "__main__":
|
|
251
|
+
sys.exit(main())
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""The tree the CLI sends: only module folders, no caches or editor files, hashes follow the contents."""
|
|
2
|
+
import hashlib
|
|
3
|
+
|
|
4
|
+
from l10n_gr_cli.main import Tree, modules, snapshot
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_tree(tmp_path):
|
|
8
|
+
(tmp_path / "acme" / "models" / "__pycache__").mkdir(parents=True)
|
|
9
|
+
(tmp_path / "acme" / "__manifest__.py").write_text("{'name': 'Acme'}")
|
|
10
|
+
(tmp_path / "acme" / "models" / "move.py").write_text("x = 1\n")
|
|
11
|
+
(tmp_path / "acme" / "models" / "__pycache__" / "move.cpython-312.pyc").write_bytes(b"\0")
|
|
12
|
+
(tmp_path / "acme" / ".move.py.swp").write_text("")
|
|
13
|
+
(tmp_path / "docs").mkdir()
|
|
14
|
+
(tmp_path / "docs" / "notes.md").write_text("not a module")
|
|
15
|
+
assert [m.name for m in modules(tmp_path)] == ["acme"]
|
|
16
|
+
snap = snapshot(tmp_path)
|
|
17
|
+
assert sorted(snap) == ["acme/__manifest__.py", "acme/models/move.py"]
|
|
18
|
+
tree = Tree(tmp_path)
|
|
19
|
+
assert tree.hashes(snap)["acme/models/move.py"] == hashlib.sha256(b"x = 1\n").hexdigest()
|
|
20
|
+
(tmp_path / "acme" / "models" / "move.py").write_text("x = 22\n")
|
|
21
|
+
assert tree.hashes(snapshot(tmp_path))["acme/models/move.py"] == hashlib.sha256(b"x = 22\n").hexdigest()
|
l10n_gr-0.1.0/uv.lock
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.10"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "colorama"
|
|
7
|
+
version = "0.4.6"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
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" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ 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" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "exceptiongroup"
|
|
16
|
+
version = "1.3.1"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
20
|
+
]
|
|
21
|
+
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
22
|
+
wheels = [
|
|
23
|
+
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "iniconfig"
|
|
28
|
+
version = "2.3.1"
|
|
29
|
+
source = { registry = "https://pypi.org/simple" }
|
|
30
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz", hash = "sha256:67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960", size = 21209, upload-time = "2026-10-06T22:48:38.076Z" }
|
|
31
|
+
wheels = [
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl", hash = "sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7", size = 7552, upload-time = "2026-10-06T22:48:36.959Z" },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[package]]
|
|
36
|
+
name = "l10n-gr"
|
|
37
|
+
version = "0.1.0"
|
|
38
|
+
source = { editable = "." }
|
|
39
|
+
|
|
40
|
+
[package.dev-dependencies]
|
|
41
|
+
dev = [
|
|
42
|
+
{ name = "pytest" },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[package.metadata]
|
|
46
|
+
|
|
47
|
+
[package.metadata.requires-dev]
|
|
48
|
+
dev = [{ name = "pytest", specifier = ">=8.4" }]
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "packaging"
|
|
52
|
+
version = "26.3"
|
|
53
|
+
source = { registry = "https://pypi.org/simple" }
|
|
54
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
|
55
|
+
wheels = [
|
|
56
|
+
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[[package]]
|
|
60
|
+
name = "pluggy"
|
|
61
|
+
version = "1.7.0"
|
|
62
|
+
source = { registry = "https://pypi.org/simple" }
|
|
63
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bf/db/7fc19e6f2dc92a966727031389fc2e08b558f0f25eb7403c1119ad4713cd/pluggy-1.7.0.tar.gz", hash = "sha256:d1eaa46ebb595891b860ab086b4d09c8588af65ebd4361b8e8f4bb8920b90ba8", size = 123304, upload-time = "2026-10-15T09:50:58.343Z" }
|
|
64
|
+
wheels = [
|
|
65
|
+
{ url = "https://files.pythonhosted.org/packages/40/9e/2b38731e0fc536806f16490e1a12d7f0dc2a1235aa8cc07bcc75416a7daa/pluggy-1.7.0-py3-none-any.whl", hash = "sha256:7dd7b0d8832ba3cb632c306926ded123429211b83641b35dc5c41ad2d34f9bec", size = 27082, upload-time = "2026-10-15T09:50:56.808Z" },
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[[package]]
|
|
69
|
+
name = "pygments"
|
|
70
|
+
version = "2.21.0"
|
|
71
|
+
source = { registry = "https://pypi.org/simple" }
|
|
72
|
+
sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" }
|
|
73
|
+
wheels = [
|
|
74
|
+
{ url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[[package]]
|
|
78
|
+
name = "pytest"
|
|
79
|
+
version = "9.2.0"
|
|
80
|
+
source = { registry = "https://pypi.org/simple" }
|
|
81
|
+
dependencies = [
|
|
82
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
83
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
84
|
+
{ name = "iniconfig" },
|
|
85
|
+
{ name = "packaging" },
|
|
86
|
+
{ name = "pluggy" },
|
|
87
|
+
{ name = "pygments" },
|
|
88
|
+
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
|
89
|
+
]
|
|
90
|
+
sdist = { url = "https://files.pythonhosted.org/packages/79/42/bb4641652e58dedeac2ec51abc1f8cae4fee4ec63899a0999016229a0f2a/pytest-9.2.0.tar.gz", hash = "sha256:97c4f3b1f3c7414aa36465e09b8220f1d03627993bd51b1282e193753c80557b", size = 1797555, upload-time = "2026-10-27T21:30:20.728Z" }
|
|
91
|
+
wheels = [
|
|
92
|
+
{ url = "https://files.pythonhosted.org/packages/51/39/1f5d8c8877a0fa327db959c19341d4be61660de1ab6b7391f9eb805bcd67/pytest-9.2.0-py3-none-any.whl", hash = "sha256:07acdcf88ec174f907dc01af70bf52d49b014bbab03faeeade31c96b18c2e588", size = 411776, upload-time = "2026-10-27T21:30:19.131Z" },
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "tomli"
|
|
97
|
+
version = "2.5.0"
|
|
98
|
+
source = { registry = "https://pypi.org/simple" }
|
|
99
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/78/9ad63712633ed3ab5cc1a648d863d7e7da371e9425e209555a0fe711b695/tomli-2.5.0.tar.gz", hash = "sha256:264507556cd8b8c8e7c6ee037cdf443a463f03f4c958e57195e3d369711b8ff6", size = 17662, upload-time = "2026-10-07T12:23:37.892Z" }
|
|
100
|
+
wheels = [
|
|
101
|
+
{ url = "https://files.pythonhosted.org/packages/22/a6/ab99b60ee52acd949684febabc3005d0045d0f66bebd9cdebd67372d26dd/tomli-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4dc1c1781f2f716de763d1e9a7b34c6a894e167e291c7c5d16c72f7a9538545", size = 163901, upload-time = "2026-10-07T12:22:15.601Z" },
|
|
102
|
+
{ url = "https://files.pythonhosted.org/packages/bc/00/ee01b7ed4579180fff07142d290257f25ba786f23f3ec6005f620933c2f5/tomli-2.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eff8babca5a7999bc137acbc7482a8b7e17ffca5075ab41f5d770ab408c7bfef", size = 163756, upload-time = "2026-10-07T12:22:16.957Z" },
|
|
103
|
+
{ url = "https://files.pythonhosted.org/packages/72/c2/4efebf65372f6583185f79799312109dddb61102d47e5c33dcfd1a297aca/tomli-2.5.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86665cee9c4835b7a7f1e8ec2c719b5258d4dc782887aded5a8ae7352a96843b", size = 268038, upload-time = "2026-10-07T12:22:18.135Z" },
|
|
104
|
+
{ url = "https://files.pythonhosted.org/packages/53/07/5850468e925d898abb36038666f9c333a94d2a223e802a8ba5b6d319d23f/tomli-2.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e369fd63331746182360977b1892bfc215476a30d61612d732425311639f56", size = 276422, upload-time = "2026-10-07T12:22:19.567Z" },
|
|
105
|
+
{ url = "https://files.pythonhosted.org/packages/b4/87/f293984cdcf83c054196d4fd3dad44fc68ae55b4b8c44bc76cef360c3150/tomli-2.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ad1ea345759240d6463efa0ed1c704402752e49aa21476620738d74d72d8aa1", size = 272616, upload-time = "2026-10-07T12:22:20.794Z" },
|
|
106
|
+
{ url = "https://files.pythonhosted.org/packages/ce/ce/db582886b3c1219d3fec93ebd669332482e5aee7a91e0f7838d84f2d1759/tomli-2.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96243987194634bd411066ce40c952e108f86af04db533ecd8ac3ff2a85b1885", size = 276593, upload-time = "2026-10-07T12:22:22.12Z" },
|
|
107
|
+
{ url = "https://files.pythonhosted.org/packages/bf/72/7619b87dea4261fc27dd7b54c4461c129c1f7d9bb7ba3aec89c797a431b8/tomli-2.5.0-cp311-cp311-win32.whl", hash = "sha256:610b27d99f28ec5f191c7064a48f3ddb179a1fe6ca73d571483ae859f57b605e", size = 101830, upload-time = "2026-10-07T12:22:23.651Z" },
|
|
108
|
+
{ url = "https://files.pythonhosted.org/packages/1e/74/220106da34502304b6751a2a9b8a9fbca6c3fd47e737a2e2e3da7c61c9db/tomli-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c804ae44fe7b4bab5da295e4f980a1ff04670bca9d23fe0a4e887e08ebd741a8", size = 112742, upload-time = "2026-10-07T12:22:24.972Z" },
|
|
109
|
+
{ url = "https://files.pythonhosted.org/packages/27/99/7d9c8b41837a7773613e169504147375c157a290167aa59ad74a085f521f/tomli-2.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:cfac177ebd6236003846ea339981f71457cb6eb748f23381eb257e45092e3980", size = 109332, upload-time = "2026-10-07T12:22:26.117Z" },
|
|
110
|
+
{ url = "https://files.pythonhosted.org/packages/52/ed/7baa86f87493646a594de388c7c1c40a39dd0461f7e9c0359cbeefc91fe8/tomli-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f4a40d03fb9f63424f0979855bdeaf44dd7696b8d59501822c10ed30ba532df", size = 164854, upload-time = "2026-10-07T12:22:27.444Z" },
|
|
111
|
+
{ url = "https://files.pythonhosted.org/packages/a5/b1/44c0341f2224397855723c7a8a39f718ea6fcbcc3dacc66e5aeca0f334e3/tomli-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ebf8d19b17bd0daeb7b7dec81a946a439b753942fd0210d6e96c532249eea6b", size = 164074, upload-time = "2026-10-07T12:22:28.679Z" },
|
|
112
|
+
{ url = "https://files.pythonhosted.org/packages/23/04/e2d5b7d3fba47adedb23de616c16d428ea076c79a3d8e1d95d649ffe197e/tomli-2.5.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf0b5e8e0f68ebb494356e577c06c139161efd8d3b9050f93b39b7c26cc54ff0", size = 274274, upload-time = "2026-10-07T12:22:29.804Z" },
|
|
113
|
+
{ url = "https://files.pythonhosted.org/packages/43/90/6090e706ff27a6f89f4a40578e3324b95c3cd8c4150868aabf33a8f414c3/tomli-2.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cf74416bdc94ae458b14e37286c1073081850ac8459a00d0c5efef5d44294c6", size = 286435, upload-time = "2026-10-07T12:22:31.297Z" },
|
|
114
|
+
{ url = "https://files.pythonhosted.org/packages/0a/9e/a2c40768df16c408f22430afb0a73e9d7e5f79c950884954649d1146b74d/tomli-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61ea1ebe1e55a34ea8199cc8dbff398d35027b82271c8ac4802fd3a1fd5b1bcc", size = 278119, upload-time = "2026-10-07T12:22:32.601Z" },
|
|
115
|
+
{ url = "https://files.pythonhosted.org/packages/12/25/3c0cb485b98e9cfac495629b1c93c87ccf0b72fbe9d2689fd8fe62c6d5a3/tomli-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed53f7e89bb04f6d9e8e7799112360b0c4d5cbff067de0814c98c37c39b920f7", size = 286177, upload-time = "2026-10-07T12:22:33.745Z" },
|
|
116
|
+
{ url = "https://files.pythonhosted.org/packages/77/8b/0144c65f0e37e51c18d04ae15c21b19431c165002d0131fe9aa8b0b8b1e8/tomli-2.5.0-cp312-cp312-win32.whl", hash = "sha256:e7ad033e27a516a233bea839cdb77b80146facb3b4f40bf02cd0cac165cdd5c2", size = 102760, upload-time = "2026-10-07T12:22:34.887Z" },
|
|
117
|
+
{ url = "https://files.pythonhosted.org/packages/de/32/5d6d8f42fc9a05fce69354e00ff256484192f5f2fc9a2165718fa0de61ec/tomli-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd05de8c1698f8413dd7d869492693a0bf2211543b787ac78cd5e7536af1a6d7", size = 112722, upload-time = "2026-10-07T12:22:36.162Z" },
|
|
118
|
+
{ url = "https://files.pythonhosted.org/packages/30/65/df18032218db0fb9b769fb23c8039a051f15c811993995ea04c350273a32/tomli-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:069435bd5480429b98c5e5afb02ab21c219b6f0064680671c6dc0d46817346ea", size = 109534, upload-time = "2026-10-07T12:22:37.296Z" },
|
|
119
|
+
{ url = "https://files.pythonhosted.org/packages/42/e5/51736d70da209350969e15aca5c5ab6e2ce1ea87a0a892a6c13aec172a86/tomli-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:943276cf269e0071948d9ff697159c1735e623c1151d88abb09b74659ef0cbea", size = 163328, upload-time = "2026-10-07T12:22:38.373Z" },
|
|
120
|
+
{ url = "https://files.pythonhosted.org/packages/ec/55/086f80dab4ab497602644274e6dea7ec5dd0b4e262e443a8ad3bb7edee2d/tomli-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:463b16086865b97facd8d0b3fb4cb7c544e3f58d2a69dc3113d6db9653fdb043", size = 162246, upload-time = "2026-10-07T12:22:39.673Z" },
|
|
121
|
+
{ url = "https://files.pythonhosted.org/packages/aa/eb/3ecc94459f3635c92321f4e7bde571323fdb2267c50e19e3188a281eae3b/tomli-2.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1245a6638fc4bb0a60af38a7d45413db34a13842027c77597c712c998c62fdf0", size = 272655, upload-time = "2026-10-07T12:22:41.08Z" },
|
|
122
|
+
{ url = "https://files.pythonhosted.org/packages/c0/d7/494fd1f0c37a621f1ad9975c2efadb523e8101f144ed6edb2e7fe64738f2/tomli-2.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d8bac3d603c97e6854424e5b2b5b741bdbde387e09f162fb0446812b4a8362b", size = 283595, upload-time = "2026-10-07T12:22:42.222Z" },
|
|
123
|
+
{ url = "https://files.pythonhosted.org/packages/70/51/bb8d62b1317e6640866f6949b2d5855e5300f2c99d46de1cd245570bba65/tomli-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:21e4cae4114aba25aa0d4f85cdf486d290fb35c0954d7bba536248da64d43066", size = 276253, upload-time = "2026-10-07T12:22:43.625Z" },
|
|
124
|
+
{ url = "https://files.pythonhosted.org/packages/66/f4/f46bd7f0763cd47de2db697dca9257c6a4adfd1a93b018cc75c8190ed5a8/tomli-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bbaefc84548d754be821bba7c4141c4787dda182f9e77f2f87b71213529efa7b", size = 283582, upload-time = "2026-10-07T12:22:44.983Z" },
|
|
125
|
+
{ url = "https://files.pythonhosted.org/packages/ac/03/70f2bcb2923a6db37818d917e124270a7f4cfd38ea576f5aa753a91c0ef5/tomli-2.5.0-cp313-cp313-win32.whl", hash = "sha256:abdbf6313b8d9efe157edeb7ab6eae4de064b1300ad31abf73755154b30abe68", size = 102628, upload-time = "2026-10-07T12:22:46.508Z" },
|
|
126
|
+
{ url = "https://files.pythonhosted.org/packages/dc/98/d52024bb5b0ff68b4f0d276d867f634c84a67319a7e9f6b7708a37742333/tomli-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd4dc129784e0c5335bd4e61dfcc4487499a013419e655cf2da1d091b7e0efdc", size = 113301, upload-time = "2026-10-07T12:22:47.647Z" },
|
|
127
|
+
{ url = "https://files.pythonhosted.org/packages/6f/f2/540db3a70572a8c23a28aba3e9c358ce0ffffbafc990905c1343aa265b31/tomli-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:69491c143d2fe063046e0301e62a810bed338fa4d1ce0fd870c27dc1e09b0d84", size = 109744, upload-time = "2026-10-07T12:22:48.925Z" },
|
|
128
|
+
{ url = "https://files.pythonhosted.org/packages/e4/49/caf6b307766eb9567664a8707e9d6be5fcc0e8903f18781c6677a60d80c7/tomli-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d3182ee2d887e507bd67319a0a61105d1dd33facc111329559a233b772c1a105", size = 162899, upload-time = "2026-10-07T12:22:50.088Z" },
|
|
129
|
+
{ url = "https://files.pythonhosted.org/packages/d3/c8/68cfce773a2733a49c74f99d627fb461bd990756860099eac25617889585/tomli-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:521345fd1f19d45b8df87657aaa38b6f2ca3800059fadf428e7ebf479a383646", size = 162080, upload-time = "2026-10-07T12:22:51.558Z" },
|
|
130
|
+
{ url = "https://files.pythonhosted.org/packages/7e/b2/e5bb8651fdad593f670501a7d718b1a7f73f064d44dea15e04c04dfef45d/tomli-2.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e95c7614e705bfe2b04b27aa124adec59752d15813df37e2156747cab3a006b", size = 273380, upload-time = "2026-10-07T12:22:52.918Z" },
|
|
131
|
+
{ url = "https://files.pythonhosted.org/packages/8d/d2/9e2d7f8b1dfe0e2b34c245986ebd55c4c553ea4ce6c47c443b332673253f/tomli-2.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ac2027d37c3afbdf4bdd377f2676f6f1d2122a5be1f1137b49dced590b37e75", size = 283228, upload-time = "2026-10-07T12:22:54.173Z" },
|
|
132
|
+
{ url = "https://files.pythonhosted.org/packages/ba/df/ec7b876b7b1a2718bd74a3743c076fff565b04029ba33e8f61fac262739f/tomli-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c414be4ed9d3cac80c42e348fa5a956117d1a48227f48026e31f59cb4a7671eb", size = 277189, upload-time = "2026-10-07T12:22:55.342Z" },
|
|
133
|
+
{ url = "https://files.pythonhosted.org/packages/7d/7b/e192d9eed0b9cb80da799f4d77052297fb9a2c3cc9b19f571f56ea88add6/tomli-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9b03d7dc168353b4132965bde20feceabaa470e570c6f59660dfae59b1f9eeb3", size = 283632, upload-time = "2026-10-07T12:22:56.735Z" },
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/84/50/ff94454e75461d75623e47401ed323d65c10aab8fe9033242c20cd2fdf32/tomli-2.5.0-cp314-cp314-win32.whl", hash = "sha256:6f041843c4d3a37245c0c056fd955b186bf8b1fb85690cbe40b81230891dc34b", size = 103535, upload-time = "2026-10-07T12:22:58.084Z" },
|
|
135
|
+
{ url = "https://files.pythonhosted.org/packages/54/0b/bdacf05f963bd6026ebf6eeb0beda847d1d60e03e440725c64a4e08a0afd/tomli-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:f4b653094e18f9031102d3a1da5c729c8f222d85225b18037dac621695e46e1a", size = 114621, upload-time = "2026-10-07T12:22:59.2Z" },
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/61/99/53f438fa6ae4f9d4ed0ddde3e7242b3bdc34b48c8f9948b72b9e9b127676/tomli-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3f89d10c1ff6a38d992c27fc8a4816af71a909e08a40ec66934240b1e74347c3", size = 111572, upload-time = "2026-10-07T12:23:00.479Z" },
|
|
137
|
+
{ url = "https://files.pythonhosted.org/packages/b9/20/1f88f19427d380a40e90a770e087489eaafe4aeee070ae88ed2bbec00acd/tomli-2.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e9e15b4a6c7dd6b85b5fbab29488a73f1f70de516942308daa266bf0e0aeb0d4", size = 171814, upload-time = "2026-10-07T12:23:01.914Z" },
|
|
138
|
+
{ url = "https://files.pythonhosted.org/packages/d0/56/cbe5079c9f9a54b9b3e27fc82f08f3cb36edee75561679f53d2380c801d6/tomli-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e12bbcd32897272fb05929110362ae9ff4c1b9bb26bd9e971e71dcd3275b4c3d", size = 171324, upload-time = "2026-10-07T12:23:03.18Z" },
|
|
139
|
+
{ url = "https://files.pythonhosted.org/packages/2b/30/1d53fd3b0f1cb3ba542e345ec32c26aefdddc4e829e4f3429af8a4f27782/tomli-2.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20aa36de8f2cf87237143bc1fa1aae8d6612c09118f4da21c6a684db5dd1f6f9", size = 297441, upload-time = "2026-10-07T12:23:04.345Z" },
|
|
140
|
+
{ url = "https://files.pythonhosted.org/packages/66/d9/0800acb6a111686f764c1b91ef15cc42a20a66a46013bb42220f1d2c61c1/tomli-2.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22185fad8a1e622f064e78008018a0dd3323550dcb479cb7a1d296888d74024f", size = 307476, upload-time = "2026-10-07T12:23:05.671Z" },
|
|
141
|
+
{ url = "https://files.pythonhosted.org/packages/e8/63/30a8f3cd51b5bec37f04744bad0b0dc6160df84aad4f27b0e9283d66f221/tomli-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:984012f71908165449a951de2050d52f276bfe3aa5d5f570f63ddad814370374", size = 296113, upload-time = "2026-10-07T12:23:07.202Z" },
|
|
142
|
+
{ url = "https://files.pythonhosted.org/packages/ab/18/0b9ffc597e69c5a1e20a7823cb60d54b39a9f54e91edcb8574f022186758/tomli-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f79203b3965b4000e91808aaa7c040206093f2b8bf86f455982f2274c9ccf442", size = 307725, upload-time = "2026-10-07T12:23:08.508Z" },
|
|
143
|
+
{ url = "https://files.pythonhosted.org/packages/ab/c7/18f8baae0b5607a60e8e19b4a7fedee43a8ff6458e3896dcbbadeeac9c22/tomli-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:91294a9fb94a75542f6e46e4a2ae709bd8d9b51134098cae5cf3bea5478b6d03", size = 108546, upload-time = "2026-10-07T12:23:09.956Z" },
|
|
144
|
+
{ url = "https://files.pythonhosted.org/packages/72/34/4cca9739254130627bde87500b3f2b512154fe2f278efa7e2a5e10ad4bcb/tomli-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f15e3e0b835a6d68b10c86bf80a3149780498d6911c93c3ffd1861d19f9200f1", size = 117814, upload-time = "2026-10-07T12:23:11.486Z" },
|
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/7d/fb/afa530d47dd80a78fce43beac6bc6e00f84558eafcffbc6f37b21e80d056/tomli-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6664b7ae7af7294256c53960a6103077f4914cec8ff98479c352f622c6f6b2f0", size = 115188, upload-time = "2026-10-07T12:23:12.728Z" },
|
|
146
|
+
{ url = "https://files.pythonhosted.org/packages/66/98/316fdc00f8c0939e6fe50461dd343c162d3ad51d1286eb25b7db54361d50/tomli-2.5.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:a525685c2f97da40762b8695eb7aa0af4c8344ca1905c73e4e29cb04d34607dc", size = 162775, upload-time = "2026-10-07T12:23:13.941Z" },
|
|
147
|
+
{ url = "https://files.pythonhosted.org/packages/c5/22/7b10fa5bb01c9539f53f69b619361b19350acc73657772ea7ac70ba309a8/tomli-2.5.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:9dbb18c1cfb2f6517942fc9314437f66aa06d94436ffb1f06102ef3572f35276", size = 161406, upload-time = "2026-10-07T12:23:15.215Z" },
|
|
148
|
+
{ url = "https://files.pythonhosted.org/packages/9c/e7/1a069d86dfd20f1f84f71c63faed9f83c1d890bc06c27d82dc7d888fb573/tomli-2.5.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:752e8b1aa6a4367ef8bf6a1a1e005540f7ed055ba36d7193796812ca5404eb52", size = 273855, upload-time = "2026-10-07T12:23:16.471Z" },
|
|
149
|
+
{ url = "https://files.pythonhosted.org/packages/ae/83/d1ef43d1687d092ab9c235455c76e6e709483b346b056f086095c7c263a5/tomli-2.5.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47300f9bf791808f77d82747691c4bb09cb14bdf3060cca99b42cdc4361d5a7", size = 284910, upload-time = "2026-10-07T12:23:18.166Z" },
|
|
150
|
+
{ url = "https://files.pythonhosted.org/packages/cc/05/f4d9cf7de61822ece0c3873f30d291e324911c71a378b8bfe5ced13fd9f5/tomli-2.5.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:19b0dd8749f4ea2f112c5fcfb3c5248390c899d7e2e173f1d91abee1fa0ff391", size = 277723, upload-time = "2026-10-07T12:23:19.355Z" },
|
|
151
|
+
{ url = "https://files.pythonhosted.org/packages/42/28/78262493141fa543151cf005760c3cb01d09fc28a11f993c05109902cb8c/tomli-2.5.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:57b1c3b01fab802e2899bc3d168dca320e14165e2fd9fd584760fb4ca5826859", size = 285115, upload-time = "2026-10-07T12:23:20.698Z" },
|
|
152
|
+
{ url = "https://files.pythonhosted.org/packages/1a/b9/e1dab9a30bcb677b5cc5cee810609cfd64f24306a3055767dd3fda00b1e0/tomli-2.5.0-cp315-cp315-win32.whl", hash = "sha256:667e521b37a6c5ccaa044202c235b530f90177ffe2cd4a64ecc213c7dd535feb", size = 103475, upload-time = "2026-10-07T12:23:21.941Z" },
|
|
153
|
+
{ url = "https://files.pythonhosted.org/packages/4c/bd/31a3790c11d6ea95fcf5e6022ac0f8d0543c9b61120b730fc481bd43d3b4/tomli-2.5.0-cp315-cp315-win_amd64.whl", hash = "sha256:d747252933c8a65ef6bd8da0fbb7ce28a90eb6119d8cd00772cd528aa07b68d5", size = 114589, upload-time = "2026-10-07T12:23:23.098Z" },
|
|
154
|
+
{ url = "https://files.pythonhosted.org/packages/47/a2/4f6310fa699364f0e3af7ee3af88dddd9af066d33e716a0265bbe2b3ea84/tomli-2.5.0-cp315-cp315-win_arm64.whl", hash = "sha256:75dbcde8751b0a960aa3de173aa5e894d590755c6d7758b7e774c06f1dc3cbdd", size = 111493, upload-time = "2026-10-07T12:23:24.233Z" },
|
|
155
|
+
{ url = "https://files.pythonhosted.org/packages/68/14/00853f0b396d8971107ae1921bb5b322fdee1650d2f16bf06c20adb532e5/tomli-2.5.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:2419c2a189551987b59d80e63ec355671283336f41c6b9b89462df679c7d0c57", size = 171380, upload-time = "2026-10-07T12:23:25.512Z" },
|
|
156
|
+
{ url = "https://files.pythonhosted.org/packages/89/ad/fa6949321dadee46b27363974fb197b94c911c3b0f7a5fd26d7dc18fc2a0/tomli-2.5.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:0dc598040da8d42cf20f0be588ed7004f46db12a0ac6c32e03a59dccedaaadcd", size = 170553, upload-time = "2026-10-07T12:23:26.855Z" },
|
|
157
|
+
{ url = "https://files.pythonhosted.org/packages/53/aa/3056c919eb3e084df3752b2cf5f865dcc04af0b27dba2f66d7b28af4633a/tomli-2.5.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49096930c8d886c9bbdab62d2d0d17ce823ddeea522309a190b36245d5b49e01", size = 294428, upload-time = "2026-10-07T12:23:28.132Z" },
|
|
158
|
+
{ url = "https://files.pythonhosted.org/packages/96/b2/faeeb5d8769ea3832021d73e892c8391eae7b4b4f8b55a789127bd8b18a9/tomli-2.5.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8ade5023067f99fe72b88accd30d0ea05a158e9e32a11f124e731ea9695313f", size = 304909, upload-time = "2026-10-07T12:23:29.381Z" },
|
|
159
|
+
{ url = "https://files.pythonhosted.org/packages/f6/52/f094c09e73fb654b621716d019acb5d29bdfd1be01df80c281d552bda48d/tomli-2.5.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b69564772b5c8f22ea5f498dff08cfa825045b4d4c4400529000bdf818aa3b2a", size = 293220, upload-time = "2026-10-07T12:23:30.608Z" },
|
|
160
|
+
{ url = "https://files.pythonhosted.org/packages/86/f5/0c30541078ca4b505ce3bd76ed931facbfec524dd018535d691d1af0a6d2/tomli-2.5.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8ff3a2ca028c7eee0c777f9a092038d0a594a9fa04e215f929a22c329e2cb142", size = 305705, upload-time = "2026-10-07T12:23:32.181Z" },
|
|
161
|
+
{ url = "https://files.pythonhosted.org/packages/05/74/590e7d19d6a118fc5cc5704ff358e21d95b8573f6b9443b1519f29ca8825/tomli-2.5.0-cp315-cp315t-win32.whl", hash = "sha256:62fc1bc8eb03e3a9cadfca713d65614ed8e09d974a283295ffe3a831976b4dc5", size = 108432, upload-time = "2026-10-07T12:23:33.496Z" },
|
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/1c/b8/63a75cfb27a17c38550e44025d3a6e7be64516fd8608a3b75703bf37d81b/tomli-2.5.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f3fcbc57b1791fa6cbe5d8434179d51de12be1a4811469529f47f6e7487a2571", size = 117281, upload-time = "2026-10-07T12:23:34.648Z" },
|
|
163
|
+
{ url = "https://files.pythonhosted.org/packages/72/01/e8c1debb2173973372934c68fc8e46170ab60ef23ed4592dff4dec6e8993/tomli-2.5.0-cp315-cp315t-win_arm64.whl", hash = "sha256:d2ba24db8a9376921b5e87b4762b9adb0f3f1deaea68f2b8b0bb2c11efb9c3e7", size = 115069, upload-time = "2026-10-07T12:23:35.77Z" },
|
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl", hash = "sha256:32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b", size = 14765, upload-time = "2026-10-07T12:23:36.875Z" },
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
[[package]]
|
|
168
|
+
name = "typing-extensions"
|
|
169
|
+
version = "4.16.0"
|
|
170
|
+
source = { registry = "https://pypi.org/simple" }
|
|
171
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
|
|
172
|
+
wheels = [
|
|
173
|
+
{ url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
|
|
174
|
+
]
|