diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 000000000..452121ef0 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,61 @@ +--- +"name": "Docs (release notes)" +"on": + "push": + "pull_request": + "workflow_dispatch": + +permissions: + contents: read + +env: + poetry_version: '1.8.3' + +jobs: + generate-releasenotes: + name: Generate list of images for release notes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Cache poetry in ~/.local + uses: actions/cache/restore@v4 + id: cache-poetry-restore + with: + path: ~/.local + key: "${{ runner.os }}-local-${{ env.poetry_version }}" + + - name: Install poetry + if: steps.cache-poetry-restore.outputs.cache-hit != 'true' + run: pipx install poetry==${{ env.poetry_version }} + env: + PIPX_HOME: /home/runner/.local/pipx + PIPX_BIN_DIR: /home/runner/.local/bin + + - name: Check poetry is installed correctly + run: poetry env info + + - name: Save cache + if: steps.cache-poetry-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/.local + key: ${{ steps.cache-poetry-restore.outputs.cache-primary-key }} + + - name: Set up Python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'poetry' + + - name: Configure poetry + run: poetry env use "${{ steps.setup-python.outputs.python-path }}" + + - name: Install deps + run: poetry install --sync + + - name: Run the release notes script + run: | + set -Eeuxo pipefail + poetry run ci/package_versions.py | tee ${GITHUB_STEP_SUMMARY} diff --git a/ci/package_versions.py b/ci/package_versions.py new file mode 100755 index 000000000..c21be54c5 --- /dev/null +++ b/ci/package_versions.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import dataclasses +import glob +import io +import json +import pathlib +import typing +import unittest + +import yaml + +import package_versions_selftestdata + +"""Generates the workbench software listings for https://access.redhat.com/articles/rhoai-supported-configs +using the Markdown variant described at https://access.redhat.com/articles/7056942""" + +ROOT_DIR = pathlib.Path(__file__).parent.parent + + +@dataclasses.dataclass +class Manifest: + _data: any + + @property + def name(self) -> str: + return self._data['metadata']['annotations']['opendatahub.io/notebook-image-name'] + + @property + def order(self) -> int: + return int(self._data['metadata']['annotations']['opendatahub.io/notebook-image-order']) + + @property + def tags(self) -> list[Tag]: + return [Tag(tag) for tag in self._data['spec']['tags']] + + +@dataclasses.dataclass() +class Tag: + _data: any + + @property + def name(self) -> str: + return self._data['name'] + + @property + def recommended(self) -> bool: + if 'opendatahub.io/workbench-image-recommended' not in self._data['annotations']: + return False + return self._data['annotations']['opendatahub.io/workbench-image-recommended'] == 'true' + + @property + def outdated(self) -> bool: + if 'opendatahub.io/image-tag-outdated' not in self._data['annotations']: + return False + return self._data['annotations']['opendatahub.io/image-tag-outdated'] == 'true' + + @property + def sw_general(self) -> list[typing.TypedDict("Software", {"name": str, "version": str})]: + return json.loads(self._data['annotations']['opendatahub.io/notebook-software']) + + @property + def sw_python(self) -> list[typing.TypedDict("Software", {"name": str, "version": str})]: + return json.loads(self._data['annotations']['opendatahub.io/notebook-python-dependencies']) + + +def main(): + pathname = 'manifests/base/*.yaml' + # pathname = 'manifests/overlays/additional/*.yaml' + imagestreams: list[Manifest] = [] + for fn in glob.glob(pathname, root_dir=ROOT_DIR): + # there may be more than one yaml document in a file (e.g. rstudio buildconfigs) + with (open(ROOT_DIR / fn, 'rt') as fp): + for data in yaml.safe_load_all(fp): + if 'kind' not in data or data['kind'] != 'ImageStream': + continue + if 'labels' not in data['metadata']: + continue + if ('opendatahub.io/notebook-image' not in data['metadata']['labels'] or + data['metadata']['labels']['opendatahub.io/notebook-image'] != 'true'): + continue + imagestream = Manifest(data) + imagestreams.append(imagestream) + + print('Image name | Image version | Preinstalled packages') + print('--------- | ---------') + + # todo(jdanek): maybe we want to change to sorting by `imagestream.order` + # for imagestream in sorted(imagestreams, key=lambda imagestream: imagestream.order): + for imagestream in sorted(imagestreams, key=lambda imagestream: imagestream.name): + name = imagestream.name + + prev_tag = None + for tag in imagestream.tags: + if tag.outdated: + continue + + tag_name = tag.name + recommended = tag.recommended + + sw_general = tag.sw_general + sw_python = tag.sw_python + + software: list[str] = [] + for item in sw_general: + sw_name: str + sw_version: str + sw_name, sw_version = item['name'], item['version'] + sw_version = sw_version.lstrip("v") + + # do not allow duplicates when general and python lists both contain e.g. TensorFlow + if sw_name in set(item['name'] for item in sw_python): + continue + software.append(f"{sw_name} {sw_version}") + for item in sw_python: + sw_name: str + sw_version: str + sw_name, sw_version = item['name'], item['version'] + sw_version = sw_version.lstrip("v") + software.append(f"{sw_name}: {sw_version}") + + maybe_techpreview = "" if name not in ('code-server',) else " (Technology Preview)" + maybe_recommended = "" if not recommended or len(imagestream.tags) == 1 else ' (Recommended)' + if not prev_tag: + print(f'{name}{maybe_techpreview} | {tag_name}{maybe_recommended} | {', '.join(software)}') + else: + print(f'| {tag_name}{maybe_recommended} | {', '.join(software)}') + + prev_tag = tag + + +class TestManifest(unittest.TestCase): + _data = yaml.safe_load(io.StringIO(package_versions_selftestdata.imagestream)) + manifest = Manifest(_data) + + def test_name(self): + assert self.manifest.name == "Minimal Python" + + def test_order(self): + assert self.manifest.order == 1 + + def test_tag_name(self): + assert self.manifest.tags[0].name == "2024.2" + + def test_tag_recommended(self): + assert self.manifest.tags[0].recommended is True + + def test_tag_sw_general(self): + assert self.manifest.tags[0].sw_general == [{'name': 'Python', 'version': 'v3.11'}] + + def test_tag_sw_python(self): + assert self.manifest.tags[0].sw_python == [{'name': 'JupyterLab', 'version': '4.2'}] + + +if __name__ == '__main__': + main() diff --git a/ci/package_versions_selftestdata.py b/ci/package_versions_selftestdata.py new file mode 100644 index 000000000..1fdeed0ef --- /dev/null +++ b/ci/package_versions_selftestdata.py @@ -0,0 +1,63 @@ +imagestream = """ +--- +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + labels: + opendatahub.io/notebook-image: "true" + annotations: + opendatahub.io/notebook-image-url: "https://github.com//opendatahub-io/notebooks/tree/main/jupyter/minimal" + opendatahub.io/notebook-image-name: "Minimal Python" + opendatahub.io/notebook-image-desc: "Jupyter notebook image with minimal dependency set to start experimenting with Jupyter environment." + opendatahub.io/notebook-image-order: "1" + name: jupyter-minimal-notebook +spec: + lookupPolicy: + local: true + tags: + # N Version of the image + - annotations: + # language=json + opendatahub.io/notebook-software: | + [ + {"name": "Python", "version": "v3.11"} + ] + # language=json + opendatahub.io/notebook-python-dependencies: | + [ + {"name": "JupyterLab","version": "4.2"} + ] + openshift.io/imported-from: quay.io/opendatahub/workbench-images + opendatahub.io/workbench-image-recommended: 'true' + opendatahub.io/default-image: "true" + opendatahub.io/notebook-build-commit: $(odh-minimal-notebook-image-commit-n) + from: + kind: DockerImage + name: $(odh-minimal-notebook-image-n) + name: "2024.2" + referencePolicy: + type: Source + # N Version of the image + - annotations: + # language=json + opendatahub.io/notebook-software: | + [ + {"name": "Python", "version": "v3.9"} + ] + # language=json + opendatahub.io/notebook-python-dependencies: | + [ + {"name": "JupyterLab","version": "3.6"}, + {"name": "Notebook","version": "6.5"} + ] + openshift.io/imported-from: quay.io/opendatahub/workbench-images + opendatahub.io/workbench-image-recommended: 'false' + opendatahub.io/default-image: "true" + opendatahub.io/notebook-build-commit: $(odh-minimal-notebook-image-commit-n-1) + from: + kind: DockerImage + name: $(odh-minimal-notebook-image-n-1) + name: "2024.1" + referencePolicy: + type: Source +""" \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 88d4fcd77..de2920d96 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,20 +1,20 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "attrs" -version = "24.2.0" +version = "24.3.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, + {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] @@ -69,13 +69,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pyfakefs" -version = "5.7.2" +version = "5.7.3" description = "pyfakefs implements a fake file system that mocks the Python file system modules." optional = false python-versions = ">=3.7" files = [ - {file = "pyfakefs-5.7.2-py3-none-any.whl", hash = "sha256:e1527b0e8e4b33be52f0b024ca1deb269c73eecd68457c6b0bf608d6dab12ebd"}, - {file = "pyfakefs-5.7.2.tar.gz", hash = "sha256:40da84175c5af8d9c4f3b31800b8edc4af1e74a212671dd658b21cc881c60000"}, + {file = "pyfakefs-5.7.3-py3-none-any.whl", hash = "sha256:53702780b38b24a48a9b8481c971abf1675f5abfd7d44653c2bcdd90b9751224"}, + {file = "pyfakefs-5.7.3.tar.gz", hash = "sha256:cd53790761d0fc030a9cf41fd541bfd28c1ea681b1a7c5df8834f3c9e511ac5f"}, ] [[package]] @@ -113,7 +113,69 @@ files = [ attrs = ">=19.2.0" pytest = ">=7.0" +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + [metadata] lock-version = "2.0" python-versions = "~3.12" -content-hash = "b3040f243a10b6a64e04b687a322b7ab735d82fefc4dc45d8177c2c4f286e049" +content-hash = "1bd8986aa91d470c5a0c3c8885d5bf86874344a7a8aefc6c0f500e5f6a5f2be9" diff --git a/pyproject.toml b/pyproject.toml index 0873cd45b..ea81be70a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ package-mode = false [tool.poetry.dependencies] python = "~3.12" - +pyyaml = "^6.0.2" [tool.poetry.group.dev.dependencies] pytest = "^8.2.2"