pytest-embedded-arduino-cli-ch32rv 0.0.1__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.
- pytest_embedded_arduino_cli_ch32rv-0.0.1/.github/workflows/release.yml +158 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/.github/workflows/test.yml +29 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/.gitignore +4 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/.python-version +1 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/CHANGELOG.md +7 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/LICENSE +21 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/PKG-INFO +46 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/README.ja.md +26 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/README.md +26 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/pyproject.toml +40 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/src/pytest_embedded_arduino_cli_ch32rv/__init__.py +3 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/src/pytest_embedded_arduino_cli_ch32rv/plugin.py +235 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/tests/test_plugin.py +72 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/tools/prepare_release.py +89 -0
- pytest_embedded_arduino_cli_ch32rv-0.0.1/uv.lock +337 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Release version (X.Y.Z, or X.Y.ZbN for a beta)"
|
|
8
|
+
required: true
|
|
9
|
+
publish_pypi:
|
|
10
|
+
description: "Publish package to PyPI"
|
|
11
|
+
required: true
|
|
12
|
+
type: boolean
|
|
13
|
+
default: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
prepare:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: write
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Setup Python
|
|
28
|
+
uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version-file: ".python-version"
|
|
31
|
+
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@v6
|
|
34
|
+
|
|
35
|
+
- name: Run release preparation
|
|
36
|
+
run: uv run python tools/prepare_release.py --version "${{ github.event.inputs.version }}"
|
|
37
|
+
|
|
38
|
+
- name: Run tests
|
|
39
|
+
run: uv run pytest tests
|
|
40
|
+
|
|
41
|
+
- name: Build package
|
|
42
|
+
run: uv build
|
|
43
|
+
|
|
44
|
+
- name: Commit release changes
|
|
45
|
+
run: |
|
|
46
|
+
git config user.name "github-actions[bot]"
|
|
47
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
48
|
+
git add pyproject.toml src/pytest_embedded_arduino_cli_ch32rv/__init__.py CHANGELOG.md
|
|
49
|
+
git commit -m "chore(release): v${{ github.event.inputs.version }}"
|
|
50
|
+
|
|
51
|
+
- name: Create tag
|
|
52
|
+
run: git tag "v${{ github.event.inputs.version }}"
|
|
53
|
+
|
|
54
|
+
- name: Push commit and tag
|
|
55
|
+
run: |
|
|
56
|
+
git push origin HEAD
|
|
57
|
+
git push origin "v${{ github.event.inputs.version }}"
|
|
58
|
+
|
|
59
|
+
create_github_release:
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
needs: prepare
|
|
62
|
+
permissions:
|
|
63
|
+
contents: write
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout tag
|
|
67
|
+
uses: actions/checkout@v4
|
|
68
|
+
with:
|
|
69
|
+
ref: "v${{ github.event.inputs.version }}"
|
|
70
|
+
fetch-depth: 0
|
|
71
|
+
|
|
72
|
+
- name: Build release body from CHANGELOG
|
|
73
|
+
run: |
|
|
74
|
+
VERSION="${{ github.event.inputs.version }}" python - <<'PY'
|
|
75
|
+
import os
|
|
76
|
+
import subprocess
|
|
77
|
+
from pathlib import Path
|
|
78
|
+
|
|
79
|
+
version = os.environ["VERSION"]
|
|
80
|
+
current_tag = f"v{version}"
|
|
81
|
+
|
|
82
|
+
changelog = Path("CHANGELOG.md").read_text(encoding="utf-8").splitlines()
|
|
83
|
+
section_header = f"## {version}"
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
start = changelog.index(section_header)
|
|
87
|
+
except ValueError as exc:
|
|
88
|
+
raise SystemExit(f"Version section {section_header} not found in CHANGELOG.md") from exc
|
|
89
|
+
|
|
90
|
+
end = len(changelog)
|
|
91
|
+
for i in range(start + 1, len(changelog)):
|
|
92
|
+
if changelog[i].startswith("## "):
|
|
93
|
+
end = i
|
|
94
|
+
break
|
|
95
|
+
|
|
96
|
+
section = "\n".join(changelog[start:end]).strip()
|
|
97
|
+
body = section + "\n\nRepository: https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv"
|
|
98
|
+
|
|
99
|
+
tags = (
|
|
100
|
+
subprocess.check_output(
|
|
101
|
+
["git", "tag", "--list", "v*", "--sort=v:refname"],
|
|
102
|
+
text=True,
|
|
103
|
+
)
|
|
104
|
+
.strip()
|
|
105
|
+
.splitlines()
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
prev_tag = ""
|
|
109
|
+
for i, tag in enumerate(tags):
|
|
110
|
+
if tag == current_tag and i > 0:
|
|
111
|
+
prev_tag = tags[i - 1]
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
if prev_tag:
|
|
115
|
+
body += (
|
|
116
|
+
"\n\nFull Changelog: "
|
|
117
|
+
"https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv/compare/"
|
|
118
|
+
f"{prev_tag}...{current_tag}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
Path("release_body.md").write_text(body + "\n", encoding="utf-8")
|
|
122
|
+
PY
|
|
123
|
+
|
|
124
|
+
- name: Create GitHub Release
|
|
125
|
+
uses: softprops/action-gh-release@v2
|
|
126
|
+
with:
|
|
127
|
+
tag_name: "v${{ github.event.inputs.version }}"
|
|
128
|
+
body_path: release_body.md
|
|
129
|
+
generate_release_notes: false
|
|
130
|
+
prerelease: ${{ contains(github.event.inputs.version, 'a') || contains(github.event.inputs.version, 'b') || contains(github.event.inputs.version, 'rc') }}
|
|
131
|
+
|
|
132
|
+
publish_pypi:
|
|
133
|
+
runs-on: ubuntu-latest
|
|
134
|
+
needs: prepare
|
|
135
|
+
if: ${{ github.event.inputs.publish_pypi == 'true' }}
|
|
136
|
+
permissions:
|
|
137
|
+
id-token: write
|
|
138
|
+
contents: read
|
|
139
|
+
|
|
140
|
+
steps:
|
|
141
|
+
- name: Checkout tag
|
|
142
|
+
uses: actions/checkout@v4
|
|
143
|
+
with:
|
|
144
|
+
ref: "v${{ github.event.inputs.version }}"
|
|
145
|
+
|
|
146
|
+
- name: Setup Python
|
|
147
|
+
uses: actions/setup-python@v5
|
|
148
|
+
with:
|
|
149
|
+
python-version-file: ".python-version"
|
|
150
|
+
|
|
151
|
+
- name: Install uv
|
|
152
|
+
uses: astral-sh/setup-uv@v6
|
|
153
|
+
|
|
154
|
+
- name: Build package
|
|
155
|
+
run: uv build
|
|
156
|
+
|
|
157
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
158
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version-file: ".python-version"
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v6
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: uv run pytest tests
|
|
27
|
+
|
|
28
|
+
- name: Build package
|
|
29
|
+
run: uv build
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Changelog / 変更履歴
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.0.1
|
|
6
|
+
- (EN) First beta. Three fixtures for pytest-embedded-arduino-cli tests on CH32 boards flashed by ch32rv: `ch32rv` (the platform's ch32rv, from `runtime.tools.ch32rv.path`), `oep_host` (an oep-client-python session on the OEP probe behind the test's port, through ch32rv's broker, with a 60 s lease refreshed on use), and `ch32_uart` (the DUT's UART as the probe sees it - a WCH-Link's UART bridge or an OEP probe's fixture UART - opened with `open(baud)` and read with `expect` / `expect_exact` / `write`, like `dut`).
|
|
7
|
+
- (JA) 最初のβ版。ch32rv で書く CH32 の板の pytest-embedded-arduino-cli の試験のための 3 つの fixture: `ch32rv`(platform の ch32rv、`runtime.tools.ch32rv.path` から)、`oep_host`(試験の port の先の OEP の probe への oep-client-python の session。ch32rv のブローカー経由、60 秒の lease を使うたびに延ばす)、`ch32_uart`(probe から見た DUT の UART。WCH-Link の UART bridge か OEP の probe の fixture UART を `open(baud)` で開き、`dut` と同じ `expect` / `expect_exact` / `write` で扱う)。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CH32 RISC-V User Group
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytest-embedded-arduino-cli-ch32rv
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: pytest-embedded-arduino-cli plugin for CH32 boards flashed by ch32rv: the ch32rv path, the OEP probe host, and the DUT's UART on the probe
|
|
5
|
+
Project-URL: Homepage, https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv
|
|
6
|
+
Project-URL: Repository, https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv
|
|
7
|
+
Author: TANAKA Masayuki
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Framework :: Pytest
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Testing
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: oep-client-python>=0.0.4
|
|
16
|
+
Requires-Dist: pyserial>=3.5
|
|
17
|
+
Requires-Dist: pytest-embedded-arduino-cli>=1.7.1
|
|
18
|
+
Requires-Dist: pytest>=8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# pytest-embedded-arduino-cli-ch32rv
|
|
22
|
+
|
|
23
|
+
[Japanese](README.ja.md)
|
|
24
|
+
|
|
25
|
+
A [pytest-embedded-arduino-cli](https://github.com/tanakamasayuki/pytest-embedded-arduino-cli) plugin for CH32 boards
|
|
26
|
+
flashed by [ch32rv](https://github.com/ch32-riscv-ug/ch32rv) (the uploader the
|
|
27
|
+
[ArduinoCore-CH32](https://github.com/ch32-riscv-ug/ArduinoCore-CH32) platform bundles).
|
|
28
|
+
|
|
29
|
+
pytest-embedded-arduino-cli already uploads with ch32rv and gives the test a `dut` read through ch32rv's monitor (pick
|
|
30
|
+
its `source` - `uart`, `dmseq`, ... - with the profile's `port_config` in `sketch.yaml`). This plugin adds:
|
|
31
|
+
|
|
32
|
+
| fixture | what it is |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `ch32rv` | the ch32rv the platform installed (`runtime.tools.ch32rv.path`), as a path |
|
|
35
|
+
| `oep_host` | an [oep-client-python](https://pypi.org/project/oep-client-python/) session on the OEP probe behind the port, through ch32rv's broker (`.host` is the Host) |
|
|
36
|
+
| `ch32_uart` | the DUT's UART as the probe sees it: `ch32_uart.open(baud)` returns a channel with `expect` / `expect_exact` / `write`, like `dut` |
|
|
37
|
+
|
|
38
|
+
`ch32_uart` opens a WCH-Link's UART bridge (the CDC serial port of the Link behind the port), or on an OEP probe the
|
|
39
|
+
`oep.fixture.uart` whose pins the probe's saved plan assigns (`oep config plan <probe> oep.fixture.uart#<n> rx=<ch>
|
|
40
|
+
tx=<ch> --save`). Which DUT USART and route are wired to the probe is the test's business, not the plugin's.
|
|
41
|
+
|
|
42
|
+
The OEP session holds a 60 s lease, refreshed whenever the test uses it; a test that stays quiet for longer loses it.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
pip install pytest-embedded-arduino-cli-ch32rv
|
|
46
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# pytest-embedded-arduino-cli-ch32rv
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
[ch32rv](https://github.com/ch32-riscv-ug/ch32rv)([ArduinoCore-CH32](https://github.com/ch32-riscv-ug/ArduinoCore-CH32)
|
|
6
|
+
が同梱する書き込みツール)で書く CH32 の板のための、[pytest-embedded-arduino-cli](https://github.com/tanakamasayuki/pytest-embedded-arduino-cli)
|
|
7
|
+
のプラグイン。
|
|
8
|
+
|
|
9
|
+
pytest-embedded-arduino-cli は ch32rv で書き込み、ch32rv の monitor で読む `dut` を出す(`source` の `uart` / `dmseq` などは
|
|
10
|
+
`sketch.yaml` の profile の `port_config` で選ぶ)。このプラグインが足すもの:
|
|
11
|
+
|
|
12
|
+
| fixture | 中身 |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `ch32rv` | platform が入れた ch32rv(`runtime.tools.ch32rv.path`)の path |
|
|
15
|
+
| `oep_host` | port の先の OEP の probe への [oep-client-python](https://pypi.org/project/oep-client-python/) の session。ch32rv のブローカー経由(`.host` が Host) |
|
|
16
|
+
| `ch32_uart` | probe から見た DUT の UART。`ch32_uart.open(baud)` が `dut` と同じ `expect` / `expect_exact` / `write` を持つ口を返す |
|
|
17
|
+
|
|
18
|
+
`ch32_uart` は、WCH-Link なら port の先の Link の UART bridge(CDC の serial port)を、OEP の probe なら、probe に保存した plan
|
|
19
|
+
がピンを割り当てた `oep.fixture.uart` を開く(`oep config plan <probe> oep.fixture.uart#<n> rx=<ch> tx=<ch> --save`)。DUT のどの
|
|
20
|
+
USART と route が probe につながっているかは試験の側が知っていることで、プラグインは知らない。
|
|
21
|
+
|
|
22
|
+
OEP の session は 60 秒の lease を持ち、試験が使うたびに延ばす。それより長く黙っている試験では session が切れる。
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pip install pytest-embedded-arduino-cli-ch32rv
|
|
26
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# pytest-embedded-arduino-cli-ch32rv
|
|
2
|
+
|
|
3
|
+
[Japanese](README.ja.md)
|
|
4
|
+
|
|
5
|
+
A [pytest-embedded-arduino-cli](https://github.com/tanakamasayuki/pytest-embedded-arduino-cli) plugin for CH32 boards
|
|
6
|
+
flashed by [ch32rv](https://github.com/ch32-riscv-ug/ch32rv) (the uploader the
|
|
7
|
+
[ArduinoCore-CH32](https://github.com/ch32-riscv-ug/ArduinoCore-CH32) platform bundles).
|
|
8
|
+
|
|
9
|
+
pytest-embedded-arduino-cli already uploads with ch32rv and gives the test a `dut` read through ch32rv's monitor (pick
|
|
10
|
+
its `source` - `uart`, `dmseq`, ... - with the profile's `port_config` in `sketch.yaml`). This plugin adds:
|
|
11
|
+
|
|
12
|
+
| fixture | what it is |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `ch32rv` | the ch32rv the platform installed (`runtime.tools.ch32rv.path`), as a path |
|
|
15
|
+
| `oep_host` | an [oep-client-python](https://pypi.org/project/oep-client-python/) session on the OEP probe behind the port, through ch32rv's broker (`.host` is the Host) |
|
|
16
|
+
| `ch32_uart` | the DUT's UART as the probe sees it: `ch32_uart.open(baud)` returns a channel with `expect` / `expect_exact` / `write`, like `dut` |
|
|
17
|
+
|
|
18
|
+
`ch32_uart` opens a WCH-Link's UART bridge (the CDC serial port of the Link behind the port), or on an OEP probe the
|
|
19
|
+
`oep.fixture.uart` whose pins the probe's saved plan assigns (`oep config plan <probe> oep.fixture.uart#<n> rx=<ch>
|
|
20
|
+
tx=<ch> --save`). Which DUT USART and route are wired to the probe is the test's business, not the plugin's.
|
|
21
|
+
|
|
22
|
+
The OEP session holds a 60 s lease, refreshed whenever the test uses it; a test that stays quiet for longer loses it.
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pip install pytest-embedded-arduino-cli-ch32rv
|
|
26
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pytest-embedded-arduino-cli-ch32rv"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "pytest-embedded-arduino-cli plugin for CH32 boards flashed by ch32rv: the ch32rv path, the OEP probe host, and the DUT's UART on the probe"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "TANAKA Masayuki" },
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Framework :: Pytest",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Software Development :: Testing",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"pytest>=8",
|
|
23
|
+
"pytest-embedded-arduino-cli>=1.7.1",
|
|
24
|
+
"oep-client-python>=0.0.4",
|
|
25
|
+
"pyserial>=3.5",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.entry-points.pytest11]
|
|
29
|
+
embedded-arduino-cli-ch32rv = "pytest_embedded_arduino_cli_ch32rv.plugin"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv"
|
|
33
|
+
Repository = "https://github.com/ch32-riscv-ug/pytest-embedded-arduino-cli-ch32rv"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.wheel]
|
|
36
|
+
packages = ["src/pytest_embedded_arduino_cli_ch32rv"]
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
pythonpath = ["src"]
|
|
40
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""pytest-embedded-arduino-cli plugin for CH32 boards flashed by ch32rv.
|
|
2
|
+
|
|
3
|
+
pytest-embedded-arduino-cli already uploads (ch32rv, through the platform's upload recipe) and gives the test a `dut`
|
|
4
|
+
read through the platform's own monitor (ch32rv). This plugin adds what a CH32 bench test needs on top:
|
|
5
|
+
|
|
6
|
+
- `ch32rv` the ch32rv the platform installed (runtime.tools.ch32rv.path), as a path.
|
|
7
|
+
- `oep_host` an oep-client-python Host on the OEP probe behind the test's port, through ch32rv's broker.
|
|
8
|
+
- `ch32_uart` the DUT's UART as the probe sees it, opened at a baud rate: a WCH-Link's UART bridge, or an OEP probe's
|
|
9
|
+
oep.fixture.uart. Same expect / expect_exact / write shape as `dut`.
|
|
10
|
+
|
|
11
|
+
It knows ch32rv and OEP, not the board: which DUT USART is wired to the probe is the test's (the bench's) business.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
import time
|
|
21
|
+
import urllib.parse
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
LEASE_MS = 60000 # oep-spec: probes accept 1000..60000 as asked
|
|
27
|
+
KEEPALIVE_S = LEASE_MS / 3000.0 # refresh a third of the way in, on the next use
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ------------------------------------------------------------------ the test's port and the probe behind it
|
|
31
|
+
|
|
32
|
+
def dut_address(config: pytest.Config) -> str:
|
|
33
|
+
"""The IDE-style port the test runs against: --port as resolved by pytest-embedded-arduino-cli, with the
|
|
34
|
+
arduinomonitor:// wrapper it adds for a platform monitor taken off (`arduinomonitor://<address>?sketch=...`)."""
|
|
35
|
+
port = config.getoption("port", None) or ""
|
|
36
|
+
if port.startswith("arduinomonitor://"):
|
|
37
|
+
port = urllib.parse.unquote(port[len("arduinomonitor://"):].split("?", 1)[0])
|
|
38
|
+
if not port:
|
|
39
|
+
raise pytest.UsageError("pytest-embedded-arduino-cli-ch32rv: no port (--port, or TEST_SERIAL_PORT_<PROFILE>)")
|
|
40
|
+
return port
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def run_ch32rv(ch32rv: Path, *args: str, timeout: float = 30.0) -> dict:
|
|
44
|
+
out = subprocess.run([str(ch32rv), *args], capture_output=True, text=True, timeout=timeout)
|
|
45
|
+
try:
|
|
46
|
+
return json.loads(out.stdout)
|
|
47
|
+
except json.JSONDecodeError as e:
|
|
48
|
+
raise RuntimeError(f"ch32rv {' '.join(args)} gave no JSON (exit {out.returncode}): {out.stderr.strip()}") from e
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def wch_link_uart(ch32rv: Path, address: str) -> str | None:
|
|
52
|
+
"""The UART bridge (CDC serial port) of the WCH-Link behind `address`, or None when it is not a WCH-Link:
|
|
53
|
+
`wchlink://<serial>` names it by serial; a serial port path is a WCH-Link's own CDC when `probe list` says so."""
|
|
54
|
+
probes = run_ch32rv(ch32rv, "probe", "list", "--json").get("result", {}).get("probes", [])
|
|
55
|
+
if address.startswith("wchlink://"):
|
|
56
|
+
serial = address[len("wchlink://"):]
|
|
57
|
+
for p in probes:
|
|
58
|
+
if p.get("serial") == serial and p.get("ports"):
|
|
59
|
+
return p["ports"][0]
|
|
60
|
+
return None
|
|
61
|
+
want = os.path.realpath(address)
|
|
62
|
+
for p in probes:
|
|
63
|
+
for port in p.get("ports", []):
|
|
64
|
+
if os.path.realpath(port) == want:
|
|
65
|
+
return port
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ------------------------------------------------------------------ one expect-able byte channel
|
|
70
|
+
|
|
71
|
+
class Channel:
|
|
72
|
+
"""A byte stream with the part of pytest-embedded's Dut interface a bench test uses: expect (regex),
|
|
73
|
+
expect_exact, write. `read` returns what arrived without waiting."""
|
|
74
|
+
|
|
75
|
+
def __init__(self, read, write, name: str):
|
|
76
|
+
self._read, self._write, self.name = read, write, name
|
|
77
|
+
self.buffer = b""
|
|
78
|
+
self.log = bytearray()
|
|
79
|
+
|
|
80
|
+
def _fill(self) -> None:
|
|
81
|
+
data = self._read()
|
|
82
|
+
if data:
|
|
83
|
+
self.buffer += data
|
|
84
|
+
self.log += data
|
|
85
|
+
|
|
86
|
+
def write(self, data: str | bytes) -> None:
|
|
87
|
+
self._write(data.encode() if isinstance(data, str) else data)
|
|
88
|
+
|
|
89
|
+
def expect(self, pattern: str | bytes, timeout: float = 5.0) -> re.Match:
|
|
90
|
+
rx = re.compile(pattern.encode() if isinstance(pattern, str) else pattern)
|
|
91
|
+
end = time.monotonic() + timeout
|
|
92
|
+
while True:
|
|
93
|
+
m = rx.search(self.buffer)
|
|
94
|
+
if m:
|
|
95
|
+
self.buffer = self.buffer[m.end():]
|
|
96
|
+
return m
|
|
97
|
+
if time.monotonic() > end:
|
|
98
|
+
raise TimeoutError(f"{self.name}: {pattern!r} not seen in {timeout} s; last bytes: {bytes(self.buffer[-200:])!r}")
|
|
99
|
+
self._fill()
|
|
100
|
+
time.sleep(0.01)
|
|
101
|
+
|
|
102
|
+
def expect_exact(self, text: str | bytes, timeout: float = 5.0) -> bytes:
|
|
103
|
+
return self.expect(re.escape(text.encode() if isinstance(text, str) else text), timeout).group(0)
|
|
104
|
+
|
|
105
|
+
def read(self) -> bytes:
|
|
106
|
+
self._fill()
|
|
107
|
+
out, self.buffer = self.buffer, b""
|
|
108
|
+
return out
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class Ch32Uart:
|
|
112
|
+
"""The DUT's UART on the probe. `open(baud)` (again to change the rate) returns the Channel."""
|
|
113
|
+
|
|
114
|
+
def __init__(self, request: pytest.FixtureRequest, ch32rv: Path):
|
|
115
|
+
self._request, self._ch32rv = request, ch32rv
|
|
116
|
+
self.address = dut_address(request.config)
|
|
117
|
+
self.channel: Channel | None = None
|
|
118
|
+
self._close = None
|
|
119
|
+
|
|
120
|
+
def open(self, baud: int) -> Channel:
|
|
121
|
+
self.close()
|
|
122
|
+
bridge = wch_link_uart(self._ch32rv, self.address)
|
|
123
|
+
if bridge is not None:
|
|
124
|
+
import serial
|
|
125
|
+
s = serial.Serial(bridge, baud, timeout=0, exclusive=True)
|
|
126
|
+
self.channel = Channel(lambda: s.read(4096), s.write, f"uart {bridge} @{baud}")
|
|
127
|
+
self._close = s.close
|
|
128
|
+
else:
|
|
129
|
+
host = self._request.getfixturevalue("oep_host")
|
|
130
|
+
self.channel = host.fixture_uart(baud, name=f"uart {self.address} @{baud}")
|
|
131
|
+
self._close = None
|
|
132
|
+
return self.channel
|
|
133
|
+
|
|
134
|
+
def close(self) -> None:
|
|
135
|
+
if self._close:
|
|
136
|
+
self._close()
|
|
137
|
+
self._close, self.channel = None, None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ------------------------------------------------------------------ the OEP probe, through ch32rv's broker
|
|
141
|
+
|
|
142
|
+
class OepHost:
|
|
143
|
+
"""An oep-client-python Host in a session on the probe behind the test's port, through ch32rv's broker (the
|
|
144
|
+
one the dut's monitor started). `host` is the Host; `touch()` keeps the session's lease alive and runs on every
|
|
145
|
+
use through this object - a test that goes quiet for longer than the lease (60 s) loses its session."""
|
|
146
|
+
|
|
147
|
+
def __init__(self, endpoint: str, owner: str):
|
|
148
|
+
from oep_client import host as oh, link
|
|
149
|
+
self.link = link.SerialLink.on_stream(link.TcpStream(*_split(endpoint)), "length", 3.0)
|
|
150
|
+
self.host = oh.Host(self.link.send)
|
|
151
|
+
self.link.attach_host(self.host)
|
|
152
|
+
self.host.open(LEASE_MS, owner=owner)
|
|
153
|
+
self._last = time.monotonic()
|
|
154
|
+
|
|
155
|
+
def touch(self) -> None:
|
|
156
|
+
if time.monotonic() - self._last > KEEPALIVE_S:
|
|
157
|
+
self.host.keepalive()
|
|
158
|
+
self._last = time.monotonic()
|
|
159
|
+
|
|
160
|
+
def fixture_uart(self, baud: int, name: str) -> Channel:
|
|
161
|
+
"""The first oep.fixture.uart that takes `baud`: one whose pins the probe's saved plan assigned
|
|
162
|
+
(`oep config plan <probe> oep.fixture.uart#<n> rx=.. tx=.. --save`); the others refuse as unavailable."""
|
|
163
|
+
from oep_client import core, fixture, host as oh
|
|
164
|
+
last = None
|
|
165
|
+
for fn in core.find_all(self.host, "oep.fixture.uart"):
|
|
166
|
+
io = fixture.FixtureUartIO(self.host, fn)
|
|
167
|
+
try:
|
|
168
|
+
io.configure(baud)
|
|
169
|
+
except oh.Rejected as e:
|
|
170
|
+
last = e
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
def read(io=io):
|
|
174
|
+
self.touch()
|
|
175
|
+
return io.read(480)
|
|
176
|
+
|
|
177
|
+
def write(data: bytes, io=io):
|
|
178
|
+
self.touch()
|
|
179
|
+
io.write(data)
|
|
180
|
+
|
|
181
|
+
return Channel(read, write, f"{name} (fn {fn})")
|
|
182
|
+
raise RuntimeError(f"no oep.fixture.uart on this probe has pins for the DUT's UART ({last}); give one a "
|
|
183
|
+
f"plan: oep config plan <probe> oep.fixture.uart#<n> rx=<ch> tx=<ch> --save")
|
|
184
|
+
|
|
185
|
+
def close(self) -> None:
|
|
186
|
+
try:
|
|
187
|
+
self.host.end()
|
|
188
|
+
finally:
|
|
189
|
+
self.link.close()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _split(endpoint: str) -> tuple[str, int]:
|
|
193
|
+
host, _, port = endpoint.rpartition(":")
|
|
194
|
+
return host or "127.0.0.1", int(port)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ------------------------------------------------------------------ fixtures
|
|
198
|
+
|
|
199
|
+
@pytest.fixture(scope="module")
|
|
200
|
+
def ch32rv(arduino_cli_build_properties) -> Path:
|
|
201
|
+
"""The ch32rv the platform installed for this sketch's board (runtime.tools.ch32rv.path)."""
|
|
202
|
+
base = arduino_cli_build_properties.get("runtime.tools.ch32rv.path")
|
|
203
|
+
if not base:
|
|
204
|
+
raise pytest.UsageError("this board's platform declares no ch32rv tool (runtime.tools.ch32rv.path)")
|
|
205
|
+
exe = Path(base) / ("ch32rv.exe" if sys.platform == "win32" else "ch32rv")
|
|
206
|
+
if not exe.exists():
|
|
207
|
+
raise pytest.UsageError(f"ch32rv not found at {exe}")
|
|
208
|
+
return exe
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@pytest.fixture
|
|
212
|
+
def oep_host(request: pytest.FixtureRequest, ch32rv: Path, dut):
|
|
213
|
+
"""A session on the OEP probe behind the test's port, through the broker the dut's monitor runs. Fails (does
|
|
214
|
+
not skip) when the port is not an OEP probe: a test that asks for it needs one."""
|
|
215
|
+
address = dut_address(request.config)
|
|
216
|
+
info = run_ch32rv(ch32rv, "broker", "endpoint", "--probe", f"port:{address}", "--json")
|
|
217
|
+
endpoint = info.get("endpoint") or info.get("result", {}).get("endpoint")
|
|
218
|
+
if not endpoint:
|
|
219
|
+
raise RuntimeError(f"no ch32rv broker for {address}: is it an OEP probe, and did the dut's monitor open?")
|
|
220
|
+
h = OepHost(endpoint, owner=f"pytest {request.node.nodeid}"[:32])
|
|
221
|
+
try:
|
|
222
|
+
yield h
|
|
223
|
+
finally:
|
|
224
|
+
h.close()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@pytest.fixture
|
|
228
|
+
def ch32_uart(request: pytest.FixtureRequest, ch32rv: Path, dut):
|
|
229
|
+
"""The DUT's UART as the probe sees it; `ch32_uart.open(baud)` returns an expect-able Channel. Which DUT USART
|
|
230
|
+
and route are wired to the probe is the test's to tell the sketch."""
|
|
231
|
+
u = Ch32Uart(request, ch32rv)
|
|
232
|
+
try:
|
|
233
|
+
yield u
|
|
234
|
+
finally:
|
|
235
|
+
u.close()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Board-free checks of the plugin: the parts that do not need a probe."""
|
|
2
|
+
import types
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from pytest_embedded_arduino_cli_ch32rv import plugin
|
|
7
|
+
|
|
8
|
+
pytest_plugins = ["pytester"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def config_with_port(port):
|
|
12
|
+
return types.SimpleNamespace(getoption=lambda name, default=None: port if name == "port" else default)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize("port, address", [
|
|
16
|
+
("/dev/ttyACM3", "/dev/ttyACM3"),
|
|
17
|
+
("wchlink://FBC18F0680B0", "wchlink://FBC18F0680B0"),
|
|
18
|
+
("arduinomonitor:///dev/ttyACM3?sketch=%2Ftmp%2Fx&profile=ch32v203", "/dev/ttyACM3"),
|
|
19
|
+
("arduinomonitor://oep%3A%2F%2F30eda0e31108-hs%2Fx035?profile=ch32x035", "oep://30eda0e31108-hs/x035"),
|
|
20
|
+
])
|
|
21
|
+
def test_dut_address_takes_the_monitor_wrapper_off(port, address):
|
|
22
|
+
assert plugin.dut_address(config_with_port(port)) == address
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_dut_address_without_a_port_is_a_usage_error():
|
|
26
|
+
with pytest.raises(pytest.UsageError):
|
|
27
|
+
plugin.dut_address(config_with_port(None))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def channel(chunks):
|
|
31
|
+
sent = []
|
|
32
|
+
it = iter(chunks)
|
|
33
|
+
return plugin.Channel(lambda: next(it, b""), sent.append, "test"), sent
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_channel_expect_and_expect_exact_consume_up_to_the_match():
|
|
37
|
+
ch, sent = channel([b"hello from ", b"ch32\r\nint=42\r\n", b"hex=BEEF\r\n"])
|
|
38
|
+
assert ch.expect_exact("hello from ch32") == b"hello from ch32"
|
|
39
|
+
assert ch.expect(r"int=(\d+)").group(1) == b"42"
|
|
40
|
+
assert ch.expect_exact("hex=BEEF")
|
|
41
|
+
ch.write("RUN\n")
|
|
42
|
+
assert sent == [b"RUN\n"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_channel_expect_times_out_with_the_tail_in_the_message():
|
|
46
|
+
ch, _ = channel([b"garbage"])
|
|
47
|
+
with pytest.raises(TimeoutError, match="garbage"):
|
|
48
|
+
ch.expect_exact("never", timeout=0.1)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
PROBES = {"result": {"probes": [
|
|
52
|
+
{"serial": "FBC18F0680B0", "ports": ["/dev/ttyACM3"]},
|
|
53
|
+
{"serial": "434A124C5596", "ports": ["/dev/ttyACM1"]},
|
|
54
|
+
]}}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.parametrize("address, bridge", [
|
|
58
|
+
("wchlink://FBC18F0680B0", "/dev/ttyACM3"),
|
|
59
|
+
("/dev/ttyACM1", "/dev/ttyACM1"),
|
|
60
|
+
("oep://30eda0e31108-hs/x035", None),
|
|
61
|
+
("/dev/ttyUSB0", None),
|
|
62
|
+
])
|
|
63
|
+
def test_wch_link_uart_maps_the_port_to_the_links_bridge(monkeypatch, address, bridge):
|
|
64
|
+
monkeypatch.setattr(plugin, "run_ch32rv", lambda ch32rv, *args, **kw: PROBES)
|
|
65
|
+
assert plugin.wch_link_uart("ch32rv", address) == bridge
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_the_fixtures_are_registered(pytester):
|
|
69
|
+
result = pytester.runpytest("--fixtures")
|
|
70
|
+
out = result.stdout.str()
|
|
71
|
+
for name in ("ch32rv", "oep_host", "ch32_uart"):
|
|
72
|
+
assert name in out
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
9
|
+
PYPROJECT = ROOT / "pyproject.toml"
|
|
10
|
+
INIT_FILE = ROOT / "src" / "pytest_embedded_arduino_cli_ch32rv" / "__init__.py"
|
|
11
|
+
CHANGELOG = ROOT / "CHANGELOG.md"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def update_pyproject(version: str) -> None:
|
|
15
|
+
text = PYPROJECT.read_text(encoding="utf-8")
|
|
16
|
+
updated = re.sub(
|
|
17
|
+
r'(?m)^version = "[^"]+"$',
|
|
18
|
+
f'version = "{version}"',
|
|
19
|
+
text,
|
|
20
|
+
count=1,
|
|
21
|
+
)
|
|
22
|
+
if not re.search(r'(?m)^version = "[^"]+"$', text):
|
|
23
|
+
raise RuntimeError("Failed to update version in pyproject.toml")
|
|
24
|
+
PYPROJECT.write_text(updated, encoding="utf-8")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def update_init(version: str) -> None:
|
|
28
|
+
text = INIT_FILE.read_text(encoding="utf-8")
|
|
29
|
+
updated = re.sub(
|
|
30
|
+
r'(?m)^__version__ = "[^"]+"$',
|
|
31
|
+
f'__version__ = "{version}"',
|
|
32
|
+
text,
|
|
33
|
+
count=1,
|
|
34
|
+
)
|
|
35
|
+
if not re.search(r'(?m)^__version__ = "[^"]+"$', text):
|
|
36
|
+
raise RuntimeError("Failed to update __version__ in __init__.py")
|
|
37
|
+
INIT_FILE.write_text(updated, encoding="utf-8")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def update_changelog(version: str) -> None:
|
|
41
|
+
lines = CHANGELOG.read_text(encoding="utf-8").splitlines()
|
|
42
|
+
try:
|
|
43
|
+
unreleased_idx = lines.index("## Unreleased")
|
|
44
|
+
except ValueError as exc:
|
|
45
|
+
raise RuntimeError("CHANGELOG.md must contain '## Unreleased'") from exc
|
|
46
|
+
|
|
47
|
+
tail_start = len(lines)
|
|
48
|
+
for i in range(unreleased_idx + 1, len(lines)):
|
|
49
|
+
if lines[i].startswith("## "):
|
|
50
|
+
tail_start = i
|
|
51
|
+
break
|
|
52
|
+
|
|
53
|
+
unreleased_block = lines[unreleased_idx + 1 : tail_start]
|
|
54
|
+
unreleased_items = [line for line in unreleased_block if line.strip()]
|
|
55
|
+
|
|
56
|
+
new_lines: list[str] = []
|
|
57
|
+
new_lines.extend(lines[: unreleased_idx + 1])
|
|
58
|
+
new_lines.append("")
|
|
59
|
+
new_lines.append(f"## {version}")
|
|
60
|
+
if unreleased_items:
|
|
61
|
+
new_lines.extend(unreleased_items)
|
|
62
|
+
else:
|
|
63
|
+
new_lines.append("- (EN) No user-facing changes recorded.")
|
|
64
|
+
new_lines.append("- (JA) ユーザー向け変更の記録はありません。")
|
|
65
|
+
if tail_start < len(lines):
|
|
66
|
+
new_lines.append("")
|
|
67
|
+
new_lines.extend(lines[tail_start:])
|
|
68
|
+
|
|
69
|
+
CHANGELOG.write_text("\n".join(new_lines).rstrip() + "\n", encoding="utf-8")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main() -> None:
|
|
73
|
+
parser = argparse.ArgumentParser(description="Prepare release version and changelog.")
|
|
74
|
+
parser.add_argument("--version", required=True, help="Release version (e.g. 0.1.0, 0.1.0b1)")
|
|
75
|
+
args = parser.parse_args()
|
|
76
|
+
|
|
77
|
+
version = args.version.strip()
|
|
78
|
+
# X.Y.Z, optionally a PEP 440 pre-release (0.1.0b1, 1.0.0rc1)
|
|
79
|
+
if not re.fullmatch(r"\d+\.\d+\.\d+((a|b|rc)\d+)?", version):
|
|
80
|
+
raise SystemExit("Version must be X.Y.Z or X.Y.Z{a|b|rc}N")
|
|
81
|
+
|
|
82
|
+
update_pyproject(version)
|
|
83
|
+
update_init(version)
|
|
84
|
+
update_changelog(version)
|
|
85
|
+
print(f"Prepared release: {version}")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
main()
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 2
|
|
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 = "filelock"
|
|
28
|
+
version = "4.0.6"
|
|
29
|
+
source = { registry = "https://pypi.org/simple" }
|
|
30
|
+
sdist = { url = "https://files.pythonhosted.org/packages/2b/2d/5cb7a5ac017031e96a63173f3d57a8a5162ce36f9ff461e62bc6da4d88ab/filelock-4.0.6.tar.gz", hash = "sha256:323fab3b2fb22d889b29fa83774f60029addddb4b6a1bcfa1e73066eabffb5f2", size = 248237, upload_time = "2026-09-28T22:16:16.257Z" }
|
|
31
|
+
wheels = [
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/a9/3b/b74ae9db2f78f1354278731372ae89870626be7b86cbb46b8d707acd1a98/filelock-4.0.6-py3-none-any.whl", hash = "sha256:9b139fb93b2ac5807f7feaf63aa4546fbd74074a2d3f554c040f40a4694d7b9f", size = 109077, upload_time = "2026-09-28T22:16:14.731Z" },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[package]]
|
|
36
|
+
name = "iniconfig"
|
|
37
|
+
version = "2.3.0"
|
|
38
|
+
source = { registry = "https://pypi.org/simple" }
|
|
39
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload_time = "2025-10-18T21:55:43.219Z" }
|
|
40
|
+
wheels = [
|
|
41
|
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload_time = "2025-10-18T21:55:41.639Z" },
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "oep-client-python"
|
|
46
|
+
version = "0.0.4"
|
|
47
|
+
source = { registry = "https://pypi.org/simple" }
|
|
48
|
+
dependencies = [
|
|
49
|
+
{ name = "pyserial" },
|
|
50
|
+
{ name = "pyusb" },
|
|
51
|
+
]
|
|
52
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9e/f4/fa5969338950f368e43be5f82ea01dbe8c7783972385785e686ee27df093/oep_client_python-0.0.4.tar.gz", hash = "sha256:58b5bcef213acf92b8d41da8fadace2ee848bdafa21581eb6262a4edf03b7aa7", size = 137650, upload_time = "2026-09-29T12:03:44.591Z" }
|
|
53
|
+
wheels = [
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/d7/84/ba91bb3ac770a8dab36b278dcef2822553a34e482463249f46e1d3d79159/oep_client_python-0.0.4-py3-none-any.whl", hash = "sha256:08d289f5812348d257a3eb023528ed577902b548d85a452fe1b6c2f4d748c598", size = 119993, upload_time = "2026-09-29T12:03:43.083Z" },
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[[package]]
|
|
58
|
+
name = "packaging"
|
|
59
|
+
version = "26.3"
|
|
60
|
+
source = { registry = "https://pypi.org/simple" }
|
|
61
|
+
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" }
|
|
62
|
+
wheels = [
|
|
63
|
+
{ 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" },
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[[package]]
|
|
67
|
+
name = "pexpect"
|
|
68
|
+
version = "4.9.0"
|
|
69
|
+
source = { registry = "https://pypi.org/simple" }
|
|
70
|
+
dependencies = [
|
|
71
|
+
{ name = "ptyprocess" },
|
|
72
|
+
]
|
|
73
|
+
sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload_time = "2023-11-25T09:07:26.339Z" }
|
|
74
|
+
wheels = [
|
|
75
|
+
{ url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload_time = "2023-11-25T06:56:14.81Z" },
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[[package]]
|
|
79
|
+
name = "pluggy"
|
|
80
|
+
version = "1.6.0"
|
|
81
|
+
source = { registry = "https://pypi.org/simple" }
|
|
82
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload_time = "2025-05-15T12:30:07.975Z" }
|
|
83
|
+
wheels = [
|
|
84
|
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload_time = "2025-05-15T12:30:06.134Z" },
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[[package]]
|
|
88
|
+
name = "portalocker"
|
|
89
|
+
version = "4.4.0"
|
|
90
|
+
source = { registry = "https://pypi.org/simple" }
|
|
91
|
+
sdist = { url = "https://files.pythonhosted.org/packages/81/cd/d2a23fc80c26f539ac77e7d61bd5e4af5d0b3a09a78ac4c716eead345129/portalocker-4.4.0.tar.gz", hash = "sha256:90c0df939d4ffba121f8e925bbf98ecea8b9381718666ab871a226938d2b63b2", size = 304906, upload_time = "2026-09-19T16:11:09.114Z" }
|
|
92
|
+
wheels = [
|
|
93
|
+
{ url = "https://files.pythonhosted.org/packages/52/6c/07fa2775e87b6e241c2aca5cef79f65e450bc115de55f03cda6251f81690/portalocker-4.4.0-py3-none-any.whl", hash = "sha256:a8e99ea29bfb61766ee0b4008cbaf0651e8e050f7a2485ebf54316480e99226e", size = 129647, upload_time = "2026-09-19T16:11:07.377Z" },
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
[[package]]
|
|
97
|
+
name = "ptyprocess"
|
|
98
|
+
version = "0.7.0"
|
|
99
|
+
source = { registry = "https://pypi.org/simple" }
|
|
100
|
+
sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload_time = "2020-12-28T15:15:30.155Z" }
|
|
101
|
+
wheels = [
|
|
102
|
+
{ url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload_time = "2020-12-28T15:15:28.35Z" },
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
[[package]]
|
|
106
|
+
name = "pygments"
|
|
107
|
+
version = "2.21.0"
|
|
108
|
+
source = { registry = "https://pypi.org/simple" }
|
|
109
|
+
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" }
|
|
110
|
+
wheels = [
|
|
111
|
+
{ 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" },
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
[[package]]
|
|
115
|
+
name = "pyserial"
|
|
116
|
+
version = "3.5"
|
|
117
|
+
source = { registry = "https://pypi.org/simple" }
|
|
118
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", size = 159125, upload_time = "2020-11-23T03:59:15.045Z" }
|
|
119
|
+
wheels = [
|
|
120
|
+
{ url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585, upload_time = "2020-11-23T03:59:13.41Z" },
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
[[package]]
|
|
124
|
+
name = "pytest"
|
|
125
|
+
version = "9.1.1"
|
|
126
|
+
source = { registry = "https://pypi.org/simple" }
|
|
127
|
+
dependencies = [
|
|
128
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
129
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
130
|
+
{ name = "iniconfig" },
|
|
131
|
+
{ name = "packaging" },
|
|
132
|
+
{ name = "pluggy" },
|
|
133
|
+
{ name = "pygments" },
|
|
134
|
+
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
|
135
|
+
]
|
|
136
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload_time = "2026-06-19T10:58:32.857Z" }
|
|
137
|
+
wheels = [
|
|
138
|
+
{ url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload_time = "2026-06-19T10:58:31.347Z" },
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
[[package]]
|
|
142
|
+
name = "pytest-embedded"
|
|
143
|
+
version = "2.9.3"
|
|
144
|
+
source = { registry = "https://pypi.org/simple" }
|
|
145
|
+
dependencies = [
|
|
146
|
+
{ name = "filelock" },
|
|
147
|
+
{ name = "pexpect" },
|
|
148
|
+
{ name = "pytest" },
|
|
149
|
+
]
|
|
150
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6a/cb/4b907df70f8d0a0f09093d8e01aa4838a50ae0ef6df9c7625ce971698c54/pytest_embedded-2.9.3.tar.gz", hash = "sha256:f49933a65324b0b244cc3a82fb1e926ee3a012b40dfada65508b9dbc7c451119", size = 37647, upload_time = "2026-08-31T11:53:19.769Z" }
|
|
151
|
+
wheels = [
|
|
152
|
+
{ url = "https://files.pythonhosted.org/packages/79/7f/792a19a23317d9a2c89b126ed52ab5d4bab1665c38924bd46014906bc048/pytest_embedded-2.9.3-py3-none-any.whl", hash = "sha256:82ad366a6808c4c932a025f1187b1d24213b9a56b1a778500f08d7d645feb45d", size = 34605, upload_time = "2026-08-31T11:53:18.644Z" },
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
[[package]]
|
|
156
|
+
name = "pytest-embedded-arduino-cli"
|
|
157
|
+
version = "1.7.0"
|
|
158
|
+
source = { registry = "https://pypi.org/simple" }
|
|
159
|
+
dependencies = [
|
|
160
|
+
{ name = "portalocker" },
|
|
161
|
+
{ name = "pytest" },
|
|
162
|
+
{ name = "pytest-embedded" },
|
|
163
|
+
{ name = "pytest-embedded-serial" },
|
|
164
|
+
{ name = "pyyaml" },
|
|
165
|
+
]
|
|
166
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7e/17/924624d61d4f56cc9b6058a60741050c12e1f35e5f9284f35beb3e6ca6cd/pytest_embedded_arduino_cli-1.7.0.tar.gz", hash = "sha256:eb8f8975c0b695c72a9cc2a85f918933418d6527842f42646474ec172de40797", size = 305523, upload_time = "2026-09-29T09:08:09.175Z" }
|
|
167
|
+
wheels = [
|
|
168
|
+
{ url = "https://files.pythonhosted.org/packages/1d/b4/8276ae582e51f5d0bba25e9a7f8d5e34540f4c6613c5e5f09d8188099860/pytest_embedded_arduino_cli-1.7.0-py3-none-any.whl", hash = "sha256:534d528e78443a6840def389d5b3e440a9c9cee4f99407ff6190bfd25cb98690", size = 46649, upload_time = "2026-09-29T09:08:07.746Z" },
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
[[package]]
|
|
172
|
+
name = "pytest-embedded-arduino-cli-ch32rv"
|
|
173
|
+
version = "0.0.1"
|
|
174
|
+
source = { editable = "." }
|
|
175
|
+
dependencies = [
|
|
176
|
+
{ name = "oep-client-python" },
|
|
177
|
+
{ name = "pyserial" },
|
|
178
|
+
{ name = "pytest" },
|
|
179
|
+
{ name = "pytest-embedded-arduino-cli" },
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
[package.metadata]
|
|
183
|
+
requires-dist = [
|
|
184
|
+
{ name = "oep-client-python", specifier = ">=0.0.4" },
|
|
185
|
+
{ name = "pyserial", specifier = ">=3.5" },
|
|
186
|
+
{ name = "pytest", specifier = ">=8" },
|
|
187
|
+
{ name = "pytest-embedded-arduino-cli", specifier = ">=1.7.0" },
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
[[package]]
|
|
191
|
+
name = "pytest-embedded-serial"
|
|
192
|
+
version = "2.9.3"
|
|
193
|
+
source = { registry = "https://pypi.org/simple" }
|
|
194
|
+
dependencies = [
|
|
195
|
+
{ name = "pyserial" },
|
|
196
|
+
{ name = "pytest-embedded" },
|
|
197
|
+
]
|
|
198
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c8/f3/62f2ced4415c51d70ac1bca4631457857c8600bd81f8db5311d874a8200b/pytest_embedded_serial-2.9.3.tar.gz", hash = "sha256:74dba0b5d8ef62015d4b4df0aa8a90c3b25bc6fe8fe832c159dc3e55675d9d8a", size = 5575, upload_time = "2026-08-31T11:53:21.541Z" }
|
|
199
|
+
wheels = [
|
|
200
|
+
{ url = "https://files.pythonhosted.org/packages/b3/ee/69ee4e98400cd4680745ee77183b101e5d2f220a1f308c21f012ea266c0a/pytest_embedded_serial-2.9.3-py3-none-any.whl", hash = "sha256:1cf6b6c3acbe3496c4f5ed7af78d281271c644c2552c5640aff1d576a78a9c31", size = 5890, upload_time = "2026-08-31T11:53:20.703Z" },
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
[[package]]
|
|
204
|
+
name = "pyusb"
|
|
205
|
+
version = "1.3.1"
|
|
206
|
+
source = { registry = "https://pypi.org/simple" }
|
|
207
|
+
sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281, upload_time = "2025-01-08T23:45:01.866Z" }
|
|
208
|
+
wheels = [
|
|
209
|
+
{ url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465, upload_time = "2025-01-08T23:45:00.029Z" },
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
[[package]]
|
|
213
|
+
name = "pyyaml"
|
|
214
|
+
version = "6.0.3"
|
|
215
|
+
source = { registry = "https://pypi.org/simple" }
|
|
216
|
+
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" }
|
|
217
|
+
wheels = [
|
|
218
|
+
{ url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload_time = "2025-09-25T21:31:46.04Z" },
|
|
219
|
+
{ url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload_time = "2025-09-25T21:31:47.706Z" },
|
|
220
|
+
{ url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload_time = "2025-09-25T21:31:49.21Z" },
|
|
221
|
+
{ url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload_time = "2025-09-25T21:31:50.735Z" },
|
|
222
|
+
{ url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload_time = "2025-09-25T21:31:51.828Z" },
|
|
223
|
+
{ url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload_time = "2025-09-25T21:31:53.282Z" },
|
|
224
|
+
{ url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload_time = "2025-09-25T21:31:54.807Z" },
|
|
225
|
+
{ url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload_time = "2025-09-25T21:31:55.885Z" },
|
|
226
|
+
{ url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload_time = "2025-09-25T21:31:57.406Z" },
|
|
227
|
+
{ url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload_time = "2025-09-25T21:31:58.655Z" },
|
|
228
|
+
{ url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload_time = "2025-09-25T21:32:00.088Z" },
|
|
229
|
+
{ url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload_time = "2025-09-25T21:32:01.31Z" },
|
|
230
|
+
{ url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload_time = "2025-09-25T21:32:03.376Z" },
|
|
231
|
+
{ url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload_time = "2025-09-25T21:32:04.553Z" },
|
|
232
|
+
{ url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload_time = "2025-09-25T21:32:06.152Z" },
|
|
233
|
+
{ url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload_time = "2025-09-25T21:32:07.367Z" },
|
|
234
|
+
{ url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload_time = "2025-09-25T21:32:08.95Z" },
|
|
235
|
+
{ url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload_time = "2025-09-25T21:32:09.96Z" },
|
|
236
|
+
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload_time = "2025-09-25T21:32:11.445Z" },
|
|
237
|
+
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload_time = "2025-09-25T21:32:12.492Z" },
|
|
238
|
+
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload_time = "2025-09-25T21:32:13.652Z" },
|
|
239
|
+
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload_time = "2025-09-25T21:32:15.21Z" },
|
|
240
|
+
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload_time = "2025-09-25T21:32:16.431Z" },
|
|
241
|
+
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload_time = "2025-09-25T21:32:17.56Z" },
|
|
242
|
+
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload_time = "2025-09-25T21:32:18.834Z" },
|
|
243
|
+
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload_time = "2025-09-25T21:32:20.209Z" },
|
|
244
|
+
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload_time = "2025-09-25T21:32:21.167Z" },
|
|
245
|
+
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload_time = "2025-09-25T21:32:22.617Z" },
|
|
246
|
+
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload_time = "2025-09-25T21:32:23.673Z" },
|
|
247
|
+
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload_time = "2025-09-25T21:32:25.149Z" },
|
|
248
|
+
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload_time = "2025-09-25T21:32:26.575Z" },
|
|
249
|
+
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload_time = "2025-09-25T21:32:27.727Z" },
|
|
250
|
+
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload_time = "2025-09-25T21:32:28.878Z" },
|
|
251
|
+
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload_time = "2025-09-25T21:32:30.178Z" },
|
|
252
|
+
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload_time = "2025-09-25T21:32:31.353Z" },
|
|
253
|
+
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload_time = "2025-09-25T21:32:32.58Z" },
|
|
254
|
+
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload_time = "2025-09-25T21:32:33.659Z" },
|
|
255
|
+
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload_time = "2025-09-25T21:32:34.663Z" },
|
|
256
|
+
{ 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" },
|
|
257
|
+
{ 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" },
|
|
258
|
+
{ 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" },
|
|
259
|
+
{ 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" },
|
|
260
|
+
{ 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" },
|
|
261
|
+
{ 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" },
|
|
262
|
+
{ 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" },
|
|
263
|
+
{ 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" },
|
|
264
|
+
{ 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" },
|
|
265
|
+
{ 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" },
|
|
266
|
+
{ 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" },
|
|
267
|
+
{ 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" },
|
|
268
|
+
{ 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" },
|
|
269
|
+
{ 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" },
|
|
270
|
+
{ 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" },
|
|
271
|
+
{ 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" },
|
|
272
|
+
{ 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" },
|
|
273
|
+
{ 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" },
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
[[package]]
|
|
277
|
+
name = "tomli"
|
|
278
|
+
version = "2.4.1"
|
|
279
|
+
source = { registry = "https://pypi.org/simple" }
|
|
280
|
+
sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload_time = "2026-03-25T20:22:03.828Z" }
|
|
281
|
+
wheels = [
|
|
282
|
+
{ url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload_time = "2026-03-25T20:21:10.473Z" },
|
|
283
|
+
{ url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload_time = "2026-03-25T20:21:12.036Z" },
|
|
284
|
+
{ url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload_time = "2026-03-25T20:21:13.098Z" },
|
|
285
|
+
{ url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload_time = "2026-03-25T20:21:14.569Z" },
|
|
286
|
+
{ url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload_time = "2026-03-25T20:21:15.712Z" },
|
|
287
|
+
{ url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload_time = "2026-03-25T20:21:17.001Z" },
|
|
288
|
+
{ url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload_time = "2026-03-25T20:21:18.079Z" },
|
|
289
|
+
{ url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload_time = "2026-03-25T20:21:18.978Z" },
|
|
290
|
+
{ url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload_time = "2026-03-25T20:21:20.309Z" },
|
|
291
|
+
{ url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload_time = "2026-03-25T20:21:21.626Z" },
|
|
292
|
+
{ url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload_time = "2026-03-25T20:21:23.002Z" },
|
|
293
|
+
{ url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload_time = "2026-03-25T20:21:24.04Z" },
|
|
294
|
+
{ url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload_time = "2026-03-25T20:21:25.177Z" },
|
|
295
|
+
{ url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload_time = "2026-03-25T20:21:26.364Z" },
|
|
296
|
+
{ url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload_time = "2026-03-25T20:21:27.46Z" },
|
|
297
|
+
{ url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload_time = "2026-03-25T20:21:28.492Z" },
|
|
298
|
+
{ url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload_time = "2026-03-25T20:21:29.386Z" },
|
|
299
|
+
{ url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload_time = "2026-03-25T20:21:30.677Z" },
|
|
300
|
+
{ url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload_time = "2026-03-25T20:21:31.65Z" },
|
|
301
|
+
{ url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload_time = "2026-03-25T20:21:33.028Z" },
|
|
302
|
+
{ url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload_time = "2026-03-25T20:21:34.51Z" },
|
|
303
|
+
{ url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload_time = "2026-03-25T20:21:36.012Z" },
|
|
304
|
+
{ url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload_time = "2026-03-25T20:21:37.136Z" },
|
|
305
|
+
{ url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload_time = "2026-03-25T20:21:38.298Z" },
|
|
306
|
+
{ url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload_time = "2026-03-25T20:21:39.316Z" },
|
|
307
|
+
{ url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload_time = "2026-03-25T20:21:40.248Z" },
|
|
308
|
+
{ url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload_time = "2026-03-25T20:21:41.219Z" },
|
|
309
|
+
{ url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload_time = "2026-03-25T20:21:42.23Z" },
|
|
310
|
+
{ url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload_time = "2026-03-25T20:21:43.386Z" },
|
|
311
|
+
{ url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload_time = "2026-03-25T20:21:44.474Z" },
|
|
312
|
+
{ url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload_time = "2026-03-25T20:21:45.62Z" },
|
|
313
|
+
{ url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload_time = "2026-03-25T20:21:46.937Z" },
|
|
314
|
+
{ url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload_time = "2026-03-25T20:21:48.467Z" },
|
|
315
|
+
{ url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload_time = "2026-03-25T20:21:49.526Z" },
|
|
316
|
+
{ url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload_time = "2026-03-25T20:21:50.506Z" },
|
|
317
|
+
{ url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload_time = "2026-03-25T20:21:51.474Z" },
|
|
318
|
+
{ url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload_time = "2026-03-25T20:21:52.543Z" },
|
|
319
|
+
{ url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload_time = "2026-03-25T20:21:53.674Z" },
|
|
320
|
+
{ url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload_time = "2026-03-25T20:21:55.129Z" },
|
|
321
|
+
{ url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload_time = "2026-03-25T20:21:56.228Z" },
|
|
322
|
+
{ url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload_time = "2026-03-25T20:21:57.653Z" },
|
|
323
|
+
{ url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload_time = "2026-03-25T20:21:59.089Z" },
|
|
324
|
+
{ url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload_time = "2026-03-25T20:22:00.214Z" },
|
|
325
|
+
{ url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload_time = "2026-03-25T20:22:01.169Z" },
|
|
326
|
+
{ url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload_time = "2026-03-25T20:22:02.137Z" },
|
|
327
|
+
{ url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload_time = "2026-03-25T20:22:03.012Z" },
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
[[package]]
|
|
331
|
+
name = "typing-extensions"
|
|
332
|
+
version = "4.16.0"
|
|
333
|
+
source = { registry = "https://pypi.org/simple" }
|
|
334
|
+
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" }
|
|
335
|
+
wheels = [
|
|
336
|
+
{ 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" },
|
|
337
|
+
]
|