diff --git a/.github/dodona-image.dockerfile b/.github/dodona-image.dockerfile new file mode 100644 index 00000000..d9abcfdf --- /dev/null +++ b/.github/dodona-image.dockerfile @@ -0,0 +1,12 @@ +# Inherit from the Docker image for Dodona. +FROM dodona/dodona-tested + +# Go back to being root. +USER root +WORKDIR / + +# Install some additional dependencies needed for testing. +RUN pip install --no-cache-dir --upgrade pytest pytest-mock pytest-xdist jinja2 marko + +# The source of the judge is available in TESTED_SOURCE. +CMD pytest -x -n auto ${TESTED_SOURCE}/tests/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4b07b23..3c5c9e60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,69 +4,29 @@ on: [ push ] jobs: test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: 3.11.2 - cache: 'pipenv' - - run: pip install pipenv - - run: pipenv install --dev - - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '17' - - uses: haskell/actions/setup@v2 - with: - ghc-version: '9.2' - cabal-version: '3.6' - - uses: actions/cache@v3 - name: Cache cabal - with: - path: | - ~/.cabal - ~/.ghc - dist-newstyle - key: ${{ runner.os }}-ghc-9.2.1-20220111 - restore-keys: | - ${{ runner.os }}-ghc-9.2.1- - - run: cabal v1-install aeson - - uses: actions/setup-node@v3 - with: - node-version: 16 - - run: npm install abstract-syntax-tree@2.20 - - run: npm install -g eslint@8.36 - - run: sudo apt -y install hlint cppcheck shellcheck checkstyle - - run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.48.2/ktlint && chmod a+x ktlint + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main - run: echo "${GITHUB_WORKSPACE}" >> $GITHUB_PATH - - run: pipenv run pytest -n auto --cov=tested --cov-report=xml tests/ + - run: nix flake check --print-build-logs - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: isort/isort-action@v1.0.0 - with: - sortPaths: "./tested ./tests" - - uses: psf/black@stable - with: - version: "~= 23.0" - src: "./tested ./tests" + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: echo "${GITHUB_WORKSPACE}" >> $GITHUB_PATH + - run: nix develop .#format -c poetry run isort --check-only ./tested ./tests + - run: nix develop .#format -c poetry run black --check ./tested ./tests types: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: 3.11.2 - cache: 'pipenv' - - run: pip install pipenv - - run: pipenv install --dev - - run: echo "$(pipenv --venv)/bin" >> $GITHUB_PATH - - uses: jakebailey/pyright-action@v1 - with: - version: '1.1.316' - warnings: true - working-directory: tested/ + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: echo "${GITHUB_WORKSPACE}" >> $GITHUB_PATH + - run: nix develop .#types -c pyright ./tested diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 00000000..fe673eef --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,15 @@ +name: Integration tests + +on: [ workflow_dispatch ] + +jobs: + # Runs the test suite in a slightly modified Docker image used by Dodona. + # This is the closest to actually running the production environment there is. + dodona-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: docker build -t "local-image" -f ${{ github.workspace }}/.github/dodona-image.dockerfile --network=host . + name: Build Dodona Docker image + - run: docker run -v ${{ github.workspace }}:/github/workspace -e TESTED_SOURCE=/github/workspace local-image + name: Run tests in Dodona Docker image diff --git a/.gitignore b/.gitignore index 6e9a1ac6..ad8e8b92 100644 --- a/.gitignore +++ b/.gitignore @@ -79,4 +79,5 @@ ipython_config.py generated/ venv/ venv-*/ +.venv/ node_modules/ diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 0cee1437..00000000 --- a/Pipfile +++ /dev/null @@ -1,30 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -psutil = "==5.9.5" -attrs = "==22.2.0" -cattrs = "==23.1.2" -jsonschema = "==4.18.4" -typing-inspect = "==0.9.0" -pyyaml = "==6.0" -pygments = "==2.15.1" -python-i18n = "==0.3.9" -# Required for the Python language module -pylint = "==2.17.1" -# Needed for exercise instantiation -# You'll need to install these if you want to use it. -jinja2 = "==3.1.3" -marko = "==2.0.0" - -[dev-packages] -pytest = "" -pytest-mock = "" -pytest-cov = "" -pytest-xdist = "" - -[requires] -python_version = "3.11" -python_full_version = "3.11.2" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index f647b649..00000000 --- a/Pipfile.lock +++ /dev/null @@ -1,663 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "88612961a87838fd35357ad70206c52843301ec63d1f434c351afbc417876d27" - }, - "pipfile-spec": 6, - "requires": { - "python_full_version": "3.11.2", - "python_version": "3.11" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "astroid": { - "hashes": [ - "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c", - "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd" - ], - "markers": "python_full_version >= '3.7.2'", - "version": "==2.15.6" - }, - "attrs": { - "hashes": [ - "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836", - "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99" - ], - "index": "pypi", - "version": "==22.2.0" - }, - "cattrs": { - "hashes": [ - "sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4", - "sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657" - ], - "index": "pypi", - "version": "==23.1.2" - }, - "dill": { - "hashes": [ - "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e", - "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03" - ], - "markers": "python_version >= '3.11'", - "version": "==0.3.7" - }, - "isort": { - "hashes": [ - "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504", - "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==5.12.0" - }, - "jinja2": { - "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.1.3" - }, - "jsonschema": { - "hashes": [ - "sha256:971be834317c22daaa9132340a51c01b50910724082c2c1a2ac87eeec153a3fe", - "sha256:fb3642735399fa958c0d2aad7057901554596c63349f4f6b283c493cf692a25d" - ], - "index": "pypi", - "version": "==4.18.4" - }, - "jsonschema-specifications": { - "hashes": [ - "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1", - "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb" - ], - "markers": "python_version >= '3.8'", - "version": "==2023.7.1" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382", - "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82", - "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9", - "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494", - "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46", - "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30", - "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63", - "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4", - "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae", - "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be", - "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701", - "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd", - "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006", - "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a", - "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586", - "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8", - "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821", - "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07", - "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b", - "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171", - "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b", - "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2", - "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7", - "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4", - "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8", - "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e", - "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f", - "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda", - "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4", - "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e", - "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671", - "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11", - "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455", - "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734", - "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb", - "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59" - ], - "markers": "python_version >= '3.7'", - "version": "==1.9.0" - }, - "marko": { - "hashes": [ - "sha256:d5a8221e0d4a9369e662c33ccfe33dea7deb2bebcf1ac3d5a4b46d42ab309e8f", - "sha256:efc26460893250c13751025ae9202ebb1389887036fc0df9009c6ab875467030" - ], - "index": "pypi", - "version": "==2.0.0" - }, - "markupsafe": { - "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.3" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" - ], - "markers": "python_version >= '3.6'", - "version": "==0.7.0" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, - "platformdirs": { - "hashes": [ - "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d", - "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d" - ], - "markers": "python_version >= '3.7'", - "version": "==3.10.0" - }, - "psutil": { - "hashes": [ - "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d", - "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217", - "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4", - "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c", - "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f", - "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da", - "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4", - "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42", - "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5", - "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4", - "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9", - "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f", - "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30", - "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48" - ], - "index": "pypi", - "version": "==5.9.5" - }, - "pygments": { - "hashes": [ - "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c", - "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1" - ], - "index": "pypi", - "version": "==2.15.1" - }, - "pylint": { - "hashes": [ - "sha256:8660a54e3f696243d644fca98f79013a959c03f979992c1ab59c24d3f4ec2700", - "sha256:d4d009b0116e16845533bc2163493d6681846ac725eab8ca8014afb520178ddd" - ], - "index": "pypi", - "version": "==2.17.1" - }, - "python-i18n": { - "hashes": [ - "sha256:bda5b8d889ebd51973e22e53746417bd32783c9bd6780fd27cadbb733915651d", - "sha256:df97f3d2364bf3a7ebfbd6cbefe8e45483468e52a9e30b909c6078f5f471e4e8" - ], - "index": "pypi", - "version": "==0.3.9" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "index": "pypi", - "version": "==6.0" - }, - "referencing": { - "hashes": [ - "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf", - "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0" - ], - "markers": "python_version >= '3.8'", - "version": "==0.30.2" - }, - "rpds-py": { - "hashes": [ - "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f", - "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238", - "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f", - "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f", - "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c", - "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298", - "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260", - "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1", - "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d", - "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7", - "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f", - "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876", - "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe", - "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be", - "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32", - "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3", - "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18", - "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d", - "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620", - "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b", - "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae", - "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496", - "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1", - "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67", - "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f", - "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764", - "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196", - "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e", - "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846", - "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b", - "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d", - "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26", - "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e", - "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044", - "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c", - "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d", - "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad", - "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d", - "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab", - "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920", - "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e", - "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872", - "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3", - "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611", - "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4", - "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c", - "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193", - "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af", - "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10", - "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd", - "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f", - "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b", - "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945", - "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752", - "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c", - "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387", - "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8", - "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d", - "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931", - "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03", - "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502", - "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f", - "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55", - "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82", - "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798", - "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a", - "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b", - "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa", - "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f", - "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192", - "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020", - "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7", - "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1", - "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386", - "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90", - "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f", - "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe", - "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596", - "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f", - "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387", - "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16", - "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e", - "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b", - "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6", - "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1", - "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de", - "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0", - "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3", - "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468", - "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e", - "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd", - "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324", - "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c", - "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535", - "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55", - "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6", - "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07" - ], - "markers": "python_version >= '3.8'", - "version": "==0.9.2" - }, - "tomlkit": { - "hashes": [ - "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86", - "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899" - ], - "markers": "python_version >= '3.7'", - "version": "==0.12.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", - "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" - ], - "markers": "python_version >= '3.7'", - "version": "==4.7.1" - }, - "typing-inspect": { - "hashes": [ - "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", - "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78" - ], - "index": "pypi", - "version": "==0.9.0" - }, - "wrapt": { - "hashes": [ - "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0", - "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420", - "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a", - "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c", - "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079", - "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923", - "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f", - "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1", - "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8", - "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86", - "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0", - "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364", - "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e", - "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c", - "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e", - "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c", - "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727", - "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff", - "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e", - "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29", - "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7", - "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72", - "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475", - "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a", - "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317", - "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2", - "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd", - "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640", - "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98", - "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248", - "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e", - "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d", - "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec", - "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1", - "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e", - "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9", - "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92", - "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb", - "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094", - "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46", - "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29", - "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd", - "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705", - "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8", - "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975", - "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb", - "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e", - "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b", - "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418", - "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019", - "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1", - "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba", - "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6", - "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2", - "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3", - "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7", - "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752", - "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416", - "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f", - "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1", - "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc", - "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145", - "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee", - "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a", - "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7", - "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b", - "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653", - "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0", - "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90", - "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29", - "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6", - "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034", - "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09", - "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559", - "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639" - ], - "markers": "python_version >= '3.11'", - "version": "==1.15.0" - } - }, - "develop": { - "coverage": { - "extras": [ - "toml" - ], - "hashes": [ - "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34", - "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e", - "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7", - "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b", - "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3", - "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985", - "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95", - "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2", - "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a", - "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74", - "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd", - "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af", - "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54", - "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865", - "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214", - "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54", - "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe", - "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0", - "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321", - "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446", - "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e", - "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527", - "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12", - "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f", - "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f", - "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84", - "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479", - "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e", - "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873", - "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70", - "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0", - "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977", - "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51", - "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28", - "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1", - "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254", - "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1", - "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd", - "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689", - "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d", - "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543", - "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9", - "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637", - "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071", - "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482", - "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1", - "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b", - "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5", - "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a", - "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393", - "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a", - "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba" - ], - "markers": "python_version >= '3.8'", - "version": "==7.3.0" - }, - "execnet": { - "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" - }, - "iniconfig": { - "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" - }, - "packaging": { - "hashes": [ - "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", - "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1" - }, - "pluggy": { - "hashes": [ - "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849", - "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3" - ], - "markers": "python_version >= '3.7'", - "version": "==1.2.0" - }, - "pytest": { - "hashes": [ - "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", - "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==7.4.0" - }, - "pytest-cov": { - "hashes": [ - "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", - "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==4.1.0" - }, - "pytest-mock": { - "hashes": [ - "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39", - "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.11.1" - }, - "pytest-xdist": { - "hashes": [ - "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93", - "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.3.1" - } - } -} diff --git a/README.md b/README.md index 86e14857..637bfc01 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,19 @@ We only use the Python language module in this README, but see [dependencies.md] Install [Python 3.11](https://www.python.org/downloads/) or later (including pip). Next, [clone](https://github.com/git-guides/git-clone) the TESTed repository and open a command prompt in the cloned repository. -TESTed uses [pipenv](https://pipenv.pypa.io/en/latest/installation/) to manage its Python dependencies. +TESTed uses [poetry](https://python-poetry.org/) to manage its Python dependencies. Now you can run the following commands to install them: ```bash # Pipenv install -$ pip install pipenv --user +$ pip install poetry --user # Install dependencies (include --dev for tests/development) -$ pipenv sync --dev -# Activate the virtualenv -$ pipenv shell +$ poetry install ``` +Those using [Nix](https://nixos.org/) can use `nix develop` to get a development environment. +`nix run` will run TESTed. + ## Running TESTed TESTed evaluates a submission for a programming exercise based on a test suite that specifies some test cases for the exercise. @@ -220,6 +221,8 @@ The repository of TESTed is organized as follows: - `tested`: Python code of the actual judge (run by Dodona) - `tests`: unit tests for TESTed + + You can run the basic unit tests with: ```bash diff --git a/dependencies.md b/dependencies.md index f68dbd91..317c37a2 100644 --- a/dependencies.md +++ b/dependencies.md @@ -7,7 +7,7 @@ each language, we list the required dependencies, and their install instructions See https://github.com/dodona-edu/docker-images/blob/master/dodona-tested.dockerfile -You can also take a look at the `.github/workflows/ci.yml` file, as it will also install most dependencies. +You can also take a look at the `flake.nix` file, as it will also install most dependencies. ## Languages @@ -16,14 +16,14 @@ For example, the versions in the table below are the ones we currently use to ru | Language | Version | |---------------------|---------| -| Python | 3.11 | -| Bash | 5.1 | -| gcc (C) | 10 | -| ghc (Haskell) | 8 or 9 | -| Java | 17 | -| NodeJS (Javascript) | 18 | -| Kotlin | 1.8 | -| C# (.NET 6) | 10.0 | +| Python | 3.12 | +| Bash | 5.2 | +| gcc (C) | 13 | +| ghc (Haskell) | 9.6 | +| Java | 21 | +| NodeJS (Javascript) | 22 | +| Kotlin | 2.0 | +| C# (.NET 8) | 12.0 | ## Core @@ -33,9 +33,7 @@ Therefore, the core Python dependencies are not optional. Installing dependencies: ```shell -$ pip install -r requirements.txt -# Only needed if you want to run tests -$ pip install -r requirements-tests.txt +$ poetry install ``` ## Python @@ -43,7 +41,7 @@ $ pip install -r requirements-tests.txt | Name | Versions | Installation | |----------|----------|--------------| -| `pylint` | 2.17 | Pip package | +| `pylint` | 3.2 | Pip package | Install the package as follows: @@ -55,20 +53,20 @@ $ pip install pylint | Name | Versions | Installation | |--------------|----------|--------------| -| `shellcheck` | 0.8 | OS package | +| `shellcheck` | 0.10 | OS package | ## C | Name | Versions | Installation | |------------|----------|--------------| -| `cppcheck` | 2.3-2.6 | OS package | +| `cppcheck` | 2.14 | OS package | ## Haskell | Name | Versions | Installation | |-----------|----------|-----------------------| | `aeson` | latest | Global cabal package* | -| `hlint` | 3.2 | OS package | +| `hlint` | 3.6 | OS package | Installing global cabal packages can be done as follows: @@ -80,28 +78,28 @@ $ cabal v1-install aeson | Name | Versions | Installation | |--------------|----------|--------------| -| `checkstyle` | >= 8 | OS package | +| `checkstyle` | 10.16 | OS package | ## Javascript | Name | Versions | Installation | |-------------------------|----------|--------------| -| `eslint` | 8.36 | npm package | -| `abstract-syntax-tree` | 2.16 | npm package | +| `eslint` | 8.57 | npm package | +| `abstract-syntax-tree` | 2.22 | npm package | Install npm packages as follows: ```shell -$ npm install eslint@8.36 abstract-syntax-tree@2.16 +$ npm install eslint@8.57 abstract-syntax-tree@2.22 ``` ## Kotlin | Name | Versions | Installation | |------------------------|----------|--------------| -| `klint` | 0.48 | OS package | +| `klint` | 1.2 | OS package | ## C# -C# does not have other dependencies besides .NET 6. +C# does not have other dependencies besides .NET 8. diff --git a/flake.lock b/flake.lock index f441de98..37e3aa59 100644 --- a/flake.lock +++ b/flake.lock @@ -2,17 +2,17 @@ "nodes": { "devshell": { "inputs": { + "flake-utils": "flake-utils", "nixpkgs": [ "nixpkgs" - ], - "systems": "systems" + ] }, "locked": { - "lastModified": 1688380630, - "narHash": "sha256-8ilApWVb1mAi4439zS3iFeIT0ODlbrifm/fegWwgHjA=", + "lastModified": 1713532798, + "narHash": "sha256-wtBhsdMJA3Wa32Wtm1eeo84GejtI43pMrFrmwLXrsEc=", "owner": "numtide", "repo": "devshell", - "rev": "f9238ec3d75cefbb2b42a44948c4e8fb1ae9a205", + "rev": "12e914740a25ea1891ec619bb53cf5e6ca922e40", "type": "github" }, "original": { @@ -23,14 +23,14 @@ }, "flake-utils": { "inputs": { - "systems": "systems_2" + "systems": "systems" }, "locked": { - "lastModified": 1689068808, - "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -40,12 +40,15 @@ } }, "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { - "lastModified": 1642700792, - "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -54,47 +57,52 @@ "type": "github" } }, - "mach-nix": { + "flake-utils_3": { "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs", - "pypi-deps-db": "pypi-deps-db" + "systems": "systems_3" }, "locked": { - "lastModified": 1689108475, - "narHash": "sha256-Tg8mLKfgIigFSA6IodqSaxjfYVZ0xELqUDtGJhsdN6g=", - "owner": "DavHau", - "repo": "mach-nix", - "rev": "725aab8d52eb2f5b8ff67bea61049011ef31597c", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { - "id": "mach-nix", - "type": "indirect" + "owner": "numtide", + "repo": "flake-utils", + "type": "github" } }, - "nixpkgs": { + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "poetry2nix", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1643805626, - "narHash": "sha256-AXLDVMG+UaAGsGSpOtQHPIKB+IZ0KSd9WS77aanGzgc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "554d2d8aa25b6e583575459c297ec23750adb6cb", + "lastModified": 1703863825, + "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547", "type": "github" }, "original": { - "id": "nixpkgs", - "ref": "nixos-unstable", - "type": "indirect" + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" } }, - "nixpkgs_2": { + "nixpkgs": { "locked": { - "lastModified": 1691472822, - "narHash": "sha256-XVfYZ2oB3lNPVq6sHCY9WkdQ8lHoIDzzbpg8bB6oBxA=", + "lastModified": 1716293225, + "narHash": "sha256-pU9ViBVE3XYb70xZx+jK6SEVphvt7xMTbm6yDIF4xPs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "41c7605718399dcfa53dd7083793b6ae3bc969ff", + "rev": "3eaeaeb6b1e08a016380c279f8846e0bd8808916", "type": "github" }, "original": { @@ -104,28 +112,37 @@ "type": "github" } }, - "pypi-deps-db": { - "flake": false, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils_3", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_4", + "treefmt-nix": "treefmt-nix" + }, "locked": { - "lastModified": 1685526402, - "narHash": "sha256-V0SXx0dWlUBL3E/wHWTszrkK2dOnuYYnBc7n6e0+NQU=", - "owner": "DavHau", - "repo": "pypi-deps-db", - "rev": "ba35683c35218acb5258b69a9916994979dc73a9", + "lastModified": 1715251496, + "narHash": "sha256-vRBfJCKvJtu5sYev56XStirA3lAOPv0EkoEV2Nfc+tc=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "291a863e866972f356967d0a270b259f46bf987f", "type": "github" }, "original": { - "owner": "DavHau", - "repo": "pypi-deps-db", + "owner": "nix-community", + "ref": "refs/tags/2024.5.939250", + "repo": "poetry2nix", "type": "github" } }, "root": { "inputs": { "devshell": "devshell", - "flake-utils": "flake-utils", - "mach-nix": "mach-nix", - "nixpkgs": "nixpkgs_2" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix" } }, "systems": { @@ -157,6 +174,56 @@ "repo": "default", "type": "github" } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "id": "systems", + "type": "indirect" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1714058656, + "narHash": "sha256-Qv4RBm4LKuO4fNOfx9wl40W2rBbv5u5m+whxRYUMiaA=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "c6aaf729f34a36c445618580a9f95a48f5e4e03f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index c2dcf6d1..87bc4a5d 100644 --- a/flake.nix +++ b/flake.nix @@ -8,153 +8,160 @@ url = "github:numtide/devshell"; inputs.nixpkgs.follows = "nixpkgs"; }; + poetry2nix = { + url = "github:nix-community/poetry2nix?ref=refs/tags/2024.5.939250"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, devshell, flake-utils, mach-nix, ... }: + outputs = { self, nixpkgs, devshell, flake-utils, poetry2nix, ... }: flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs { inherit system; overlays = [ devshell.overlays.default ]; }; - python = pkgs.python311; + pkgs = import nixpkgs { + inherit system; + overlays = [ devshell.overlays.default ]; + }; + poetry = poetry2nix.lib.mkPoetry2Nix { inherit pkgs; }; + + python = pkgs.python312; + + # For some Python packages, we want customization, as Nix can't build it. + overrides = final: prev: { + marko = prev.marko.overridePythonAttrs ( + old: { + format = "pyproject"; + nativeBuildInputs = [ prev.pdm-pep517 prev.pdm-backend ]; + doCheck = false; + } + ); + # We need PyYAML with C support, but poetry2nix does not do that apparently... + pyyaml = prev.pyyaml.overridePythonAttrs ( + old: { + nativeBuildInputs = old.nativeBuildInputs ++ [ prev.cython_0 prev.setuptools ]; + buildInputs = old.buildInputs ++ [ pkgs.libyaml ]; + } + ); + }; + + # This one isn't in Nix, so do it manually. ast = pkgs.buildNpmPackage rec { pname = "abstract-syntax-tree"; - version = "2.20.6"; + version = "2.22.0"; src = pkgs.fetchFromGitHub { owner = "buxlabs"; repo = pname; - rev = "94115dc1f1fd01731c7d43f3d7773dda12b9446f"; - hash = "sha256-jiXZQ0CbU2QSuDKaUBLin4LPSgiasEyBO/TlyNhNqrI="; + rev = "36b343c80d94383d2c8cd8883dba52d9bf51be71"; + hash = "sha256-ACZf8BwWY476PZ+9mqsiOx6L4yGOvDPMZNFEHmqz4j4="; }; - npmDepsHash = "sha256-ZSJvh3IP1VKJ0WR9axKEm4prUBVGyOKHyacIPSpImsU="; + npmDepsHash = "sha256-+I0Nu7KgZgjFQR12Z8iRNaFq269B7ythiq8sdi5or3Y="; dontNpmBuild = true; meta = with pkgs.lib; { description = "A library for working with abstract syntax trees"; license = licenses.mit; - maintainers = []; - }; - }; - marko = python.pkgs.buildPythonPackage rec { - pname = "marko"; - version = "2.0.0"; - format = "pyproject"; - - src = pkgs.fetchPypi { - inherit pname version; - hash = "sha256-78JkYIkyUME3UQJa6SAuuxOJiHA2/A35AJxquHVGcDA="; - }; - - nativeBuildInputs = [ - python.pkgs.pdm-pep517 python.pkgs.pdm-backend - ]; - - doCheck = false; - - meta = with pkgs.lib; { - homepage = "https://github.com/frostming/marko"; - license = licenses.mit; maintainers = [ ]; }; }; - core-packages = ps: with ps; [ - psutil - pydantic - attrs - cattrs - jsonschema - typing-inspect - pyyaml - pygments - python-i18n - ]; - python-env = python.withPackages(ps: (core-packages ps) ++ [ - ps.pylint - ps.pytest - ps.pytest-mock - ps.pytest-cov - ps.pytest-xdist - # For Pycharm - ps.setuptools - ps.isort - ps.black - ps.jinja2 - marko - ]); - core-deps = [ - (python.withPackages(ps: (core-packages ps) ++ [ps.pylint])) - ]; + + # General dependencies for other languages haskell-deps = [ - (pkgs.haskell.packages.ghc94.ghcWithPackages (p: [p.aeson])) - pkgs.hlint - ]; - node-deps = [ - pkgs.nodejs-18_x - pkgs.nodePackages.eslint - ast - ]; - bash-deps = [ - pkgs.shellcheck - ]; - c-deps = [ - pkgs.cppcheck - pkgs.gcc + (pkgs.haskell.packages.ghc96.ghcWithPackages (p: [ p.aeson ])) + pkgs.hlint ]; - java-deps = [ - pkgs.openjdk17 - pkgs.checkstyle - ]; - kotlin-deps = [ - pkgs.kotlin - pkgs.ktlint - ]; - csharp-deps = [ - pkgs.dotnetCorePackages.sdk_6_0 - ]; - in - { + node-deps = [ pkgs.nodejs_22 pkgs.nodePackages.eslint ast ]; + bash-deps = [ pkgs.shellcheck ]; + c-deps = [ pkgs.cppcheck pkgs.gcc13 ]; + java-deps = [ pkgs.openjdk21 pkgs.checkstyle ]; + kotlin-deps = [ pkgs.kotlin pkgs.ktlint ]; + csharp-deps = [ pkgs.dotnetCorePackages.sdk_8_0 ]; + + all-other-dependencies = haskell-deps ++ node-deps ++ bash-deps + ++ c-deps ++ java-deps ++ kotlin-deps ++ csharp-deps + ++ [ pkgs.coreutils ]; + + python-base-env = { + projectDir = self; + python = python; + overrides = poetry.overrides.withDefaults overrides; + }; + + python-dev-env = poetry.mkPoetryEnv python-base-env; + + tested-env = { + inherit (python-base-env) projectDir python overrides; + propagatedBuildInputs = all-other-dependencies; + }; + + unit-test = pkgs.writeShellApplication { + name = "unit-test"; + runtimeInputs = [ python-dev-env pkgs.poetry ] ++ all-other-dependencies; + text = '' + DOTNET_CLI_HOME="$(mktemp -d)" + export DOTNET_CLI_HOME + poetry run pytest -n auto --cov=tested --cov-report=xml tests/ + ''; + }; + + in { + checks = rec { + default = simple-tests; + simple-tests = pkgs.stdenvNoCC.mkDerivation { + name = "simple-tests"; + src = self; + doCheck = true; + checkInputs = [ python-dev-env pkgs.poetry ] ++ all-other-dependencies; + checkPhase = '' + DOTNET_CLI_HOME="$(mktemp -d)" + export DOTNET_CLI_HOME + poetry run pytest -n auto --cov=tested --cov-report=xml tests/ + ''; + installPhase = '' + touch $out # it worked! + ''; + }; + }; + + packages = rec { + default = tested; + tested = poetry.mkPoetryApplication { + inherit (tested-env) + projectDir python overrides propagatedBuildInputs; + doCheck = false; + }; + }; + devShells = rec { default = tested; tested = pkgs.devshell.mkShell { name = "TESTed"; - packages = [python-env pkgs.nodePackages.pyright pkgs.pipenv] ++ haskell-deps ++ node-deps ++ bash-deps ++ c-deps ++ java-deps ++ kotlin-deps ++ csharp-deps; + + packages = [ python-dev-env pkgs.nodePackages.pyright pkgs.poetry ] + ++ all-other-dependencies; + devshell.startup.link.text = '' mkdir -p "$PRJ_DATA_DIR/current" - ln -sfn "${python-env}/${python-env.sitePackages}" "$PRJ_DATA_DIR/current/python-packages" - ln -sfn "${python-env}" "$PRJ_DATA_DIR/current/python" + ln -sfn "${python-dev-env}/${python-dev-env.sitePackages}" "$PRJ_DATA_DIR/current/python-packages" + ln -sfn "${python-dev-env}" "$PRJ_DATA_DIR/current/python" ''; env = [ { name = "DOTNET_ROOT"; eval = "${pkgs.dotnetCorePackages.sdk_6_0}"; } - { + { name = "NODE_PATH"; prefix = "$(npm get prefix)"; } ]; - commands = [ - { - name = "test:stable"; - category = "tests"; - help = "Run the non-flaky tests."; - command = '' - python -m pytest tests/ -m "not flaky" - ''; - } - { - name = "test:all"; - category = "tests"; - help = "Run all tests."; - command = '' - python -m pytest tests/ - ''; - } - ]; }; + types = pkgs.mkShell { + packages = [ python-dev-env pkgs.nodePackages.pyright ]; + }; + format = pkgs.mkShell { packages = [ python-dev-env pkgs.poetry ]; }; }; - } - ); + }); } diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..2c64c486 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,833 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "astroid" +version = "3.2.2" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "astroid-3.2.2-py3-none-any.whl", hash = "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0"}, + {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "black" +version = "24.4.2" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "cattrs" +version = "23.2.3" +description = "Composable complex class support for attrs and dataclasses." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, + {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, +] + +[package.dependencies] +attrs = ">=23.1.0" + +[package.extras] +bson = ["pymongo (>=4.4.0)"] +cbor2 = ["cbor2 (>=5.4.6)"] +msgpack = ["msgpack (>=1.0.5)"] +orjson = ["orjson (>=3.9.2)"] +pyyaml = ["pyyaml (>=6.0)"] +tomlkit = ["tomlkit (>=0.11.8)"] +ujson = ["ujson (>=5.7.0)"] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.5.2" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:554c7327bf0fd688050348e22db7c8e163fb7219f3ecdd4732d7ed606b417263"}, + {file = "coverage-7.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d0305e02e40c7cfea5d08d6368576537a74c0eea62b77633179748d3519d6705"}, + {file = "coverage-7.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829fb55ad437d757c70d5b1c51cfda9377f31506a0a3f3ac282bc6a387d6a5f1"}, + {file = "coverage-7.5.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:894b1acded706f1407a662d08e026bfd0ff1e59e9bd32062fea9d862564cfb65"}, + {file = "coverage-7.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe76d6dee5e4febefa83998b17926df3a04e5089e3d2b1688c74a9157798d7a2"}, + {file = "coverage-7.5.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c7ebf2a37e4f5fea3c1a11e1f47cea7d75d0f2d8ef69635ddbd5c927083211fc"}, + {file = "coverage-7.5.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20e611fc36e1a0fc7bbf957ef9c635c8807d71fbe5643e51b2769b3cc0fb0b51"}, + {file = "coverage-7.5.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7c5c5b7ae2763533152880d5b5b451acbc1089ade2336b710a24b2b0f5239d20"}, + {file = "coverage-7.5.2-cp310-cp310-win32.whl", hash = "sha256:1e4225990a87df898e40ca31c9e830c15c2c53b1d33df592bc8ef314d71f0281"}, + {file = "coverage-7.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:976cd92d9420e6e2aa6ce6a9d61f2b490e07cb468968adf371546b33b829284b"}, + {file = "coverage-7.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5997d418c219dcd4dcba64e50671cca849aaf0dac3d7a2eeeb7d651a5bd735b8"}, + {file = "coverage-7.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ec27e93bbf5976f0465e8936f02eb5add99bbe4e4e7b233607e4d7622912d68d"}, + {file = "coverage-7.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f11f98753800eb1ec872562a398081f6695f91cd01ce39819e36621003ec52a"}, + {file = "coverage-7.5.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e34680049eecb30b6498784c9637c1c74277dcb1db75649a152f8004fbd6646"}, + {file = "coverage-7.5.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e12536446ad4527ac8ed91d8a607813085683bcce27af69e3b31cd72b3c5960"}, + {file = "coverage-7.5.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3d3f7744b8a8079d69af69d512e5abed4fb473057625588ce126088e50d05493"}, + {file = "coverage-7.5.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:431a3917e32223fcdb90b79fe60185864a9109631ebc05f6c5aa03781a00b513"}, + {file = "coverage-7.5.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a7c6574225f34ce45466f04751d957b5c5e6b69fca9351db017c9249786172ce"}, + {file = "coverage-7.5.2-cp311-cp311-win32.whl", hash = "sha256:2b144d142ec9987276aeff1326edbc0df8ba4afbd7232f0ca10ad57a115e95b6"}, + {file = "coverage-7.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:900532713115ac58bc3491b9d2b52704a05ed408ba0918d57fd72c94bc47fba1"}, + {file = "coverage-7.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9a42970ce74c88bdf144df11c52c5cf4ad610d860de87c0883385a1c9d9fa4ab"}, + {file = "coverage-7.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:26716a1118c6ce2188283b4b60a898c3be29b480acbd0a91446ced4fe4e780d8"}, + {file = "coverage-7.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60b66b0363c5a2a79fba3d1cd7430c25bbd92c923d031cae906bdcb6e054d9a2"}, + {file = "coverage-7.5.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d22eba19273b2069e4efeff88c897a26bdc64633cbe0357a198f92dca94268"}, + {file = "coverage-7.5.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bb5b92a0ab3d22dfdbfe845e2fef92717b067bdf41a5b68c7e3e857c0cff1a4"}, + {file = "coverage-7.5.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1aef719b6559b521ae913ddeb38f5048c6d1a3d366865e8b320270b7bc4693c2"}, + {file = "coverage-7.5.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8809c0ea0e8454f756e3bd5c36d04dddf222989216788a25bfd6724bfcee342c"}, + {file = "coverage-7.5.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1acc2e2ef098a1d4bf535758085f508097316d738101a97c3f996bccba963ea5"}, + {file = "coverage-7.5.2-cp312-cp312-win32.whl", hash = "sha256:97de509043d3f0f2b2cd171bdccf408f175c7f7a99d36d566b1ae4dd84107985"}, + {file = "coverage-7.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:8941e35a0e991a7a20a1fa3e3182f82abe357211f2c335a9e6007067c3392fcf"}, + {file = "coverage-7.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5662bf0f6fb6757f5c2d6279c541a5af55a39772c2362ed0920b27e3ce0e21f7"}, + {file = "coverage-7.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d9c62cff2ffb4c2a95328488fd7aa96a7a4b34873150650fe76b19c08c9c792"}, + {file = "coverage-7.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74eeaa13e8200ad72fca9c5f37395fb310915cec6f1682b21375e84fd9770e84"}, + {file = "coverage-7.5.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f29bf497d51a5077994b265e976d78b09d9d0dff6ca5763dbb4804534a5d380"}, + {file = "coverage-7.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f96aa94739593ae0707eda9813ce363a0a0374a810ae0eced383340fc4a1f73"}, + {file = "coverage-7.5.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:51b6cee539168a912b4b3b040e4042b9e2c9a7ad9c8546c09e4eaeff3eacba6b"}, + {file = "coverage-7.5.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:59a75e6aa5c25b50b5a1499f9718f2edff54257f545718c4fb100f48d570ead4"}, + {file = "coverage-7.5.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29da75ce20cb0a26d60e22658dd3230713c6c05a3465dd8ad040ffc991aea318"}, + {file = "coverage-7.5.2-cp38-cp38-win32.whl", hash = "sha256:23f2f16958b16152b43a39a5ecf4705757ddd284b3b17a77da3a62aef9c057ef"}, + {file = "coverage-7.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:9e41c94035e5cdb362beed681b58a707e8dc29ea446ea1713d92afeded9d1ddd"}, + {file = "coverage-7.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06d96b9b19bbe7f049c2be3c4f9e06737ec6d8ef8933c7c3a4c557ef07936e46"}, + {file = "coverage-7.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:878243e1206828908a6b4a9ca7b1aa8bee9eb129bf7186fc381d2646f4524ce9"}, + {file = "coverage-7.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:482df956b055d3009d10fce81af6ffab28215d7ed6ad4a15e5c8e67cb7c5251c"}, + {file = "coverage-7.5.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a35c97af60a5492e9e89f8b7153fe24eadfd61cb3a2fb600df1a25b5dab34b7e"}, + {file = "coverage-7.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24bb4c7859a3f757a116521d4d3a8a82befad56ea1bdacd17d6aafd113b0071e"}, + {file = "coverage-7.5.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e1046aab24c48c694f0793f669ac49ea68acde6a0798ac5388abe0a5615b5ec8"}, + {file = "coverage-7.5.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:448ec61ea9ea7916d5579939362509145caaecf03161f6f13e366aebb692a631"}, + {file = "coverage-7.5.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4a00bd5ba8f1a4114720bef283cf31583d6cb1c510ce890a6da6c4268f0070b7"}, + {file = "coverage-7.5.2-cp39-cp39-win32.whl", hash = "sha256:9f805481d5eff2a96bac4da1570ef662bf970f9a16580dc2c169c8c3183fa02b"}, + {file = "coverage-7.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:2c79f058e7bec26b5295d53b8c39ecb623448c74ccc8378631f5cb5c16a7e02c"}, + {file = "coverage-7.5.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:40dbb8e7727560fe8ab65efcddfec1ae25f30ef02e2f2e5d78cfb52a66781ec5"}, + {file = "coverage-7.5.2.tar.gz", hash = "sha256:13017a63b0e499c59b5ba94a8542fb62864ba3016127d1e4ef30d354fc2b00e9"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "dill" +version = "0.3.8" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "marko" +version = "2.0.3" +description = "A markdown parser with high extensibility." +optional = false +python-versions = ">=3.7" +files = [ + {file = "marko-2.0.3-py3-none-any.whl", hash = "sha256:7fca1c4ab1dbc09b4b3be83c22caafd7d97c99439cb4143d025727cb3df1f4d0"}, + {file = "marko-2.0.3.tar.gz", hash = "sha256:3b323dcd7dd48181871718ac09b3825bc8f74493cec378f2bacaaceec47577d4"}, +] + +[package.extras] +codehilite = ["pygments"] +repr = ["objprint"] +toc = ["python-slugify"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pylint" +version = "3.2.2" +description = "python code static checker" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pylint-3.2.2-py3-none-any.whl", hash = "sha256:3f8788ab20bb8383e06dd2233e50f8e08949cfd9574804564803441a4946eab4"}, + {file = "pylint-3.2.2.tar.gz", hash = "sha256:d068ca1dfd735fb92a07d33cb8f288adc0f6bc1287a139ca2425366f7cbe38f8"}, +] + +[package.dependencies] +astroid = ">=3.2.2,<=3.3.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} +isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "8.2.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, + {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2.0" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-xdist" +version = "3.6.1" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, + {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-i18n" +version = "0.3.9" +description = "Translation library for Python" +optional = false +python-versions = "*" +files = [ + {file = "python-i18n-0.3.9.tar.gz", hash = "sha256:df97f3d2364bf3a7ebfbd6cbefe8e45483468e52a9e30b909c6078f5f471e4e8"}, + {file = "python_i18n-0.3.9-py3-none-any.whl", hash = "sha256:bda5b8d889ebd51973e22e53746417bd32783c9bd6780fd27cadbb733915651d"}, +] + +[package.extras] +yaml = ["pyyaml (>=3.10)"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "rpds-py" +version = "0.18.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, +] + +[[package]] +name = "tomlkit" +version = "0.12.5" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, + {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "7478de0dafe7a1755a981e96d24f06ec5ccf153cf031c1fb6404931e8eaa60d8" diff --git a/pyproject.toml b/pyproject.toml index 295dc7a2..72ac79af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,3 +15,41 @@ markers = [ "linter", # Run linter tests "slow", # Slow tests ] + +[tool.poetry] +name = "tested" +version = "1.0.0" +description = "" +authors = ["Niko Strijbol "] +license = "MIT" +readme = "README.md" + +[tool.poetry.scripts] +tested = "tested.__main__:__main__" + +[tool.poetry.dependencies] +python = "^3.12" +psutil = "==5.9.8" +attrs = "==23.2.0" +cattrs = "==23.2.3" +jsonschema = "==4.22.0" +typing-inspect = "==0.9.0" +pyyaml = "==6.0.1" +pygments = "==2.18.0" +python-i18n = "==0.3.9" +pylint = "==3.2.2" +jinja2 = "==3.1.4" +marko = "==2.0.3" + +[tool.poetry.group.dev.dependencies] +pytest = "^8.2.1" +pytest-mock = "^3.14.0" +pytest-cov = "^5.0.0" +pytest-xdist = "^3.6.1" +black = "^24.4.2" +isort = "^5.13.2" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tested/cli.py b/tested/cli.py index 76c9c48e..191f1dd9 100644 --- a/tested/cli.py +++ b/tested/cli.py @@ -1,6 +1,7 @@ """ A module that provides a simpler CLI to TESTed. """ + import json import os import re diff --git a/tested/configs.py b/tested/configs.py index 3cf9e01e..0cb0cc03 100644 --- a/tested/configs.py +++ b/tested/configs.py @@ -1,6 +1,7 @@ """ Module for handling and bundling various configuration options for TESTed. """ + import logging from pathlib import Path from typing import IO, TYPE_CHECKING, Any, Optional diff --git a/tested/datatypes/__init__.py b/tested/datatypes/__init__.py index 746b267a..f66ea9a1 100644 --- a/tested/datatypes/__init__.py +++ b/tested/datatypes/__init__.py @@ -12,6 +12,7 @@ Additionally, the types in this file are organized by their JSON encoding type. They are also split in "basic types" and "advanced types". """ + from tested.datatypes.advanced import ( AdvancedNothingTypes, AdvancedNumericTypes, diff --git a/tested/datatypes/advanced.py b/tested/datatypes/advanced.py index 8bcdf954..726ca9fc 100644 --- a/tested/datatypes/advanced.py +++ b/tested/datatypes/advanced.py @@ -4,6 +4,7 @@ Note that these are often complementary types: the default type suffice in many cases. """ + from enum import StrEnum from typing import Union diff --git a/tested/datatypes/basic.py b/tested/datatypes/basic.py index 8881183a..e2c3b56d 100644 --- a/tested/datatypes/basic.py +++ b/tested/datatypes/basic.py @@ -1,6 +1,7 @@ """ Basic data types. """ + from enum import StrEnum, auto, unique from typing import Union diff --git a/tested/descriptions/__main__.py b/tested/descriptions/__main__.py index 4a4662c0..231dff79 100644 --- a/tested/descriptions/__main__.py +++ b/tested/descriptions/__main__.py @@ -41,6 +41,7 @@ Note that the file is first converted by Mako to a normal Markdown file. Afterwards, the code blocks are replaced. """ + import sys from argparse import ArgumentParser, FileType diff --git a/tested/descriptions/converters.py b/tested/descriptions/converters.py index a3a64fa5..c3a29a33 100644 --- a/tested/descriptions/converters.py +++ b/tested/descriptions/converters.py @@ -52,7 +52,7 @@ class GenericDatatype(Datatype): locale: str language: Language type_: AllTypes - others: tuple[NestedTypeDeclaration] + others: tuple[NestedTypeDeclaration, ...] def _types(self) -> list[str]: if len(self.others): diff --git a/tested/dodona.py b/tested/dodona.py index d945c5ea..90e5f768 100644 --- a/tested/dodona.py +++ b/tested/dodona.py @@ -9,6 +9,7 @@ be printed to stdout. This might be useful to test this implementation against the authoritative json-schema, provided by Dodona. """ + import json from enum import StrEnum, auto, unique from typing import IO, Literal, Union diff --git a/tested/dsl/ast_translator.py b/tested/dsl/ast_translator.py index 84b00e3c..0cdc0614 100644 --- a/tested/dsl/ast_translator.py +++ b/tested/dsl/ast_translator.py @@ -70,7 +70,7 @@ def _is_and_get_allowed_empty(node: ast.Call) -> Value | None: Returns the empty value if allowed, otherwise None. """ assert isinstance(node.func, ast.Name) - type_ = get_converter().structure(node.func.id, AllTypes) + type_ = get_converter().structure(node.func.id, AllTypes) # pyright: ignore if isinstance(type_, AdvancedSequenceTypes): return SequenceType(type=cast(AdvancedSequenceTypes, type_), data=[]) elif isinstance(type_, BasicSequenceTypes): @@ -223,7 +223,10 @@ def _convert_expression(node: ast.expr, is_return: bool) -> Expression: raise InvalidDslError( "The argument of a cast function must resolve to a value." ) - return evolve(value, type=get_converter().structure(node.func.id, AllTypes)) + return evolve( + value, + type=get_converter().structure(node.func.id, AllTypes), # pyright: ignore + ) elif isinstance(node, ast.Call): if is_return: raise InvalidDslError( @@ -315,13 +318,11 @@ def _translate_to_ast(node: ast.Interactive, is_return: bool) -> Statement: @overload -def parse_string(code: str, is_return: Literal[True]) -> Value: - ... +def parse_string(code: str, is_return: Literal[True]) -> Value: ... @overload -def parse_string(code: str, is_return: Literal[False] = False) -> Statement: - ... +def parse_string(code: str, is_return: Literal[False] = False) -> Statement: ... def parse_string(code: str, is_return=False) -> Statement: diff --git a/tested/dsl/translate_parser.py b/tested/dsl/translate_parser.py index 2ee33e8d..b637969a 100644 --- a/tested/dsl/translate_parser.py +++ b/tested/dsl/translate_parser.py @@ -272,7 +272,7 @@ def _validate_dsl(dsl_object: YamlObject): def _tested_type_to_value(tested_type: TestedType) -> Value: - type_enum = get_converter().structure(tested_type.type, AllTypes) + type_enum = get_converter().structure(tested_type.type, AllTypes) # pyright: ignore if isinstance(type_enum, NumericTypes): # Some special cases for advanced numeric types. if type_enum == AdvancedNumericTypes.FIXED_PRECISION: diff --git a/tested/features.py b/tested/features.py index fe5ad4af..d5407700 100644 --- a/tested/features.py +++ b/tested/features.py @@ -1,6 +1,7 @@ """ Module containing the definitions of the features we can support. """ + import logging import operator from collections import defaultdict diff --git a/tested/judge/__init__.py b/tested/judge/__init__.py index a632d086..1b742c3d 100644 --- a/tested/judge/__init__.py +++ b/tested/judge/__init__.py @@ -6,4 +6,5 @@ the judge. All other modules might be useful, but are more for the internal code organization. """ + from tested.judge.core import judge diff --git a/tested/judge/compilation.py b/tested/judge/compilation.py index 7dc6a146..b9367a5c 100644 --- a/tested/judge/compilation.py +++ b/tested/judge/compilation.py @@ -1,6 +1,7 @@ """ Functions responsible for the compilation step. """ + import logging from pathlib import Path diff --git a/tested/judge/core.py b/tested/judge/core.py index a960129d..5c2ca35c 100644 --- a/tested/judge/core.py +++ b/tested/judge/core.py @@ -231,10 +231,14 @@ def _execute_one_unit( # Execute the unit. if local_compilation_results.status == Status.CORRECT: remaining_time = plan.remaining_time() - execution_result, status = execute_unit( + execution_result_or_status = execute_unit( bundle, planned_unit, execution_dir, dependencies, remaining_time ) - local_compilation_results.status = status + if isinstance(execution_result_or_status, Status): + local_compilation_results.status = execution_result_or_status + execution_result = None + else: + execution_result = execution_result_or_status else: execution_result = None diff --git a/tested/judge/execution.py b/tested/judge/execution.py index bf677cf1..c5ee6f42 100644 --- a/tested/judge/execution.py +++ b/tested/judge/execution.py @@ -1,6 +1,5 @@ import itertools import logging -import shutil from pathlib import Path from attrs import define @@ -176,7 +175,10 @@ def set_up_unit( _logger.debug(f"Copying {origin} to {destination}") if origin == destination: continue # Don't copy the file to itself - shutil.copy2(origin, destination) + + # Use hard links instead of copying, due to issues with busy files. + # See https://github.com/dodona-edu/universal-judge/issues/57 + destination.hardlink_to(origin) return execution_dir, dependencies @@ -208,7 +210,7 @@ def execute_unit( execution_dir: Path, dependencies: list[Path], remaining_time: float, -) -> tuple[ExecutionResult | None, Status]: +) -> ExecutionResult | Status: """ Execute a unit. @@ -232,12 +234,12 @@ def execute_unit( main_file_name = unit.name argument = None - executable, status = bundle.language.find_main_file(files, main_file_name) - _logger.debug(f"Found main file: {executable}") - - if status != Status.CORRECT: - return None, status + executable_or_status = bundle.language.find_main_file(files, main_file_name) + _logger.debug(f"Searched for main file: {executable_or_status}") + if isinstance(executable_or_status, Status): + return executable_or_status + executable = executable_or_status files.remove(executable) stdin = unit.get_stdin(bundle.config.resources) @@ -257,7 +259,7 @@ def execute_unit( values = _get_contents_or_empty(value_file(bundle, execution_dir)) exceptions = _get_contents_or_empty(exception_file(bundle, execution_dir)) - result = ExecutionResult( + return ExecutionResult( stdout=base_result.stdout, stderr=base_result.stderr, exit=base_result.exit, @@ -268,5 +270,3 @@ def execute_unit( timeout=base_result.timeout, memory=base_result.memory, ) - - return result, status diff --git a/tested/judge/planning.py b/tested/judge/planning.py index c76d155a..9c22d8d5 100644 --- a/tested/judge/planning.py +++ b/tested/judge/planning.py @@ -1,6 +1,7 @@ """ This module decides what and when things are executed. """ + import time from enum import Enum, auto from pathlib import Path diff --git a/tested/judge/utils.py b/tested/judge/utils.py index 4ce85f37..19d50002 100644 --- a/tested/judge/utils.py +++ b/tested/judge/utils.py @@ -1,6 +1,7 @@ """ Common utilities for the judge. """ + import logging import shutil import subprocess diff --git a/tested/languages/__init__.py b/tested/languages/__init__.py index 1b38610a..77c7cd1f 100644 --- a/tested/languages/__init__.py +++ b/tested/languages/__init__.py @@ -6,6 +6,7 @@ In short, if it has to do with the templates or is programming language specific, you will probably find it in this package. """ + from typing import TYPE_CHECKING, Optional from tested.languages.bash.config import Bash diff --git a/tested/languages/bash/linter.py b/tested/languages/bash/linter.py index 559591ba..754d7902 100644 --- a/tested/languages/bash/linter.py +++ b/tested/languages/bash/linter.py @@ -50,9 +50,11 @@ def run_shellcheck( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.bash.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.bash.linter.memory") + ( + get_i18n_string("languages.bash.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.bash.linter.memory") + ) ], [] try: diff --git a/tested/languages/c/linter.py b/tested/languages/c/linter.py index cba07f44..e7d26d37 100644 --- a/tested/languages/c/linter.py +++ b/tested/languages/c/linter.py @@ -43,9 +43,11 @@ def run_cppcheck( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.c.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.c.linter.memory") + ( + get_i18n_string("languages.c.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.c.linter.memory") + ) ], [] try: diff --git a/tested/languages/config.py b/tested/languages/config.py index 1e8ba2cb..3d87fc7a 100644 --- a/tested/languages/config.py +++ b/tested/languages/config.py @@ -4,6 +4,7 @@ This class is the API between the core of TESTed and the language-specific details. Everything that depends on the programming language passes through this class. """ + import logging import typing from abc import ABC, abstractmethod @@ -158,7 +159,7 @@ def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: """ raise NotImplementedError - def get_string_quote(self): + def get_string_quote(self) -> str: """ :return: The symbol used to quote strings. """ @@ -347,39 +348,30 @@ def filter_function(file: Path) -> bool: return list(x for x in files if filter_function(x)) - @typing.overload - def find_main_file( - self, - files: list[Path], - name: str, - ) -> tuple[Path, typing.Literal[Status.CORRECT]]: - ... - - @typing.overload - def find_main_file(self, files: list[Path], name: str) -> tuple[None, Status]: - ... - def find_main_file( self, files: list[Path], name: str, - ) -> tuple[Path | None, Status]: + ) -> Path | Status: """ Find the "main" file in a list of files. This method is invoked to find the "main" file, i.e. the file with the main method (or at least the file that should be executed). + If something went wrong, an error status is returned. Otherwise, a path to + the main file is returned. + :param files: A list of files. :param name: The name of the main file. - :return: The main file or a list of messages. + :return: The main file or an error status. """ _logger.debug("Finding %s in %s", name, files) possible_main_files = [x for x in files if x.name.startswith(name)] if possible_main_files: - return possible_main_files[0], Status.CORRECT + return possible_main_files[0] else: - return None, Status.COMPILATION_ERROR + return Status.COMPILATION_ERROR def cleanup_stacktrace(self, stacktrace: str) -> str: """ diff --git a/tested/languages/conventionalize.py b/tested/languages/conventionalize.py index 339bb2dc..891bfced 100644 --- a/tested/languages/conventionalize.py +++ b/tested/languages/conventionalize.py @@ -1,6 +1,7 @@ """ Functions to conventionalize various aspects of a programming langauge. """ + import logging from collections.abc import Callable from typing import TYPE_CHECKING, Literal diff --git a/tested/languages/csharp/config.py b/tested/languages/csharp/config.py index 651d2ed0..0880245a 100644 --- a/tested/languages/csharp/config.py +++ b/tested/languages/csharp/config.py @@ -122,9 +122,7 @@ def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: file = OUTPUT_DIRECTORY + "/" + file return ["dotnet", file, *arguments] - def find_main_file( - self, files: list[Path], name: str - ) -> tuple[Path | None, Status]: + def find_main_file(self, files: list[Path], name: str) -> Path | Status: # TODO: specify the extension (if any) of the output files, so we don't need to # override this. logger.debug("Finding %s in %s", name, files) @@ -132,9 +130,9 @@ def find_main_file( x for x in files if x.name.startswith(name) and x.suffix == ".dll" ] if possible_main_files: - return possible_main_files[0], Status.CORRECT + return possible_main_files[0] else: - return None, Status.COMPILATION_ERROR + return Status.COMPILATION_ERROR def modify_solution(self, solution: Path): with open(solution, "r") as file: diff --git a/tested/languages/csharp/generators.py b/tested/languages/csharp/generators.py index f31d0b7a..c48b127b 100644 --- a/tested/languages/csharp/generators.py +++ b/tested/languages/csharp/generators.py @@ -162,9 +162,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_, False) return convert_declaration(base_type, None, sub_type) + "[]" @@ -173,9 +171,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) assert isinstance(value, SequenceType) base_type, sub_type = extract_type_tuple(type_, False) @@ -206,9 +202,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"List<{convert_declaration(base_type, None, sub_type)}>" @@ -216,9 +210,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"Set<{convert_declaration(base_type, None, sub_type)}>" diff --git a/tested/languages/csharp/templates/dotnet.csproj b/tested/languages/csharp/templates/dotnet.csproj index 4341abfb..e6451ca0 100644 --- a/tested/languages/csharp/templates/dotnet.csproj +++ b/tested/languages/csharp/templates/dotnet.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable enable diff --git a/tested/languages/generation.py b/tested/languages/generation.py index 60bb0ddd..442b3c1f 100644 --- a/tested/languages/generation.py +++ b/tested/languages/generation.py @@ -1,6 +1,7 @@ """ Translates items from the test suite into the actual programming language. """ + import html import json import logging diff --git a/tested/languages/haskell/config.py b/tested/languages/haskell/config.py index db674995..524264ac 100644 --- a/tested/languages/haskell/config.py +++ b/tested/languages/haskell/config.py @@ -109,10 +109,10 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_hlint(self.config.dodona, remaining) - def cleanup_description(self, description: str) -> str: - return cleanup_description(self, description) + def cleanup_description(self, statement: str) -> str: + return cleanup_description(self, statement) - def cleanup_stacktrace(self, traceback_str: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: filename = submission_file(self) context_file_regex = re.compile(r"(Context[0-9]+|Selector)") compile_line_regex = re.compile(r"^([0-9]+)(\s*\|.*)$") @@ -121,7 +121,7 @@ def cleanup_stacktrace(self, traceback_str: str) -> str: ) parse_module = r"error: parse error on input ‘module’" replace_module = r"error: unexpected ‘module’" - traceback = traceback_str.splitlines() + traceback = stacktrace.splitlines() skip_line, lines = False, [] for line in traceback: if not line or line == "undefined": diff --git a/tested/languages/haskell/linter.py b/tested/languages/haskell/linter.py index 49115923..cb69342d 100644 --- a/tested/languages/haskell/linter.py +++ b/tested/languages/haskell/linter.py @@ -51,9 +51,11 @@ def run_hlint( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.haskell.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.haskell.linter.memory") + ( + get_i18n_string("languages.haskell.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.haskell.linter.memory") + ) ], [] try: diff --git a/tested/languages/java/config.py b/tested/languages/java/config.py index 2d67f641..7b870954 100644 --- a/tested/languages/java/config.py +++ b/tested/languages/java/config.py @@ -136,8 +136,8 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_checkstyle(self.config.dodona, remaining) - def cleanup_stacktrace(self, traceback: str) -> str: - return jvm_cleanup_stacktrace(traceback, submission_file(self)) + def cleanup_stacktrace(self, stacktrace: str) -> str: + return jvm_cleanup_stacktrace(stacktrace, submission_file(self)) def generate_statement(self, statement: Statement) -> str: from tested.languages.java import generators diff --git a/tested/languages/java/generators.py b/tested/languages/java/generators.py index 9cce196b..acab03a2 100644 --- a/tested/languages/java/generators.py +++ b/tested/languages/java/generators.py @@ -166,9 +166,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_, False) return convert_declaration(base_type, None, sub_type, False) + "[]" @@ -198,9 +196,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"List<{convert_declaration(base_type, None, sub_type, True)}>" @@ -208,9 +204,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"Set<{convert_declaration(base_type, None, sub_type, True)}>" diff --git a/tested/languages/java/linter.py b/tested/languages/java/linter.py index 0eb6f72b..470009c8 100644 --- a/tested/languages/java/linter.py +++ b/tested/languages/java/linter.py @@ -46,9 +46,11 @@ def run_checkstyle( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.java.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.java.linter.memory") + ( + get_i18n_string("languages.java.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.java.linter.memory") + ) ], [] try: diff --git a/tested/languages/javascript/config.py b/tested/languages/javascript/config.py index 624374d5..1a8ed379 100644 --- a/tested/languages/javascript/config.py +++ b/tested/languages/javascript/config.py @@ -153,7 +153,7 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_eslint(self.config.dodona, remaining) - def cleanup_stacktrace(self, traceback: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: assert self.config # What this does: # 1a. While inside the submission code, replace all references to the location with @@ -168,7 +168,7 @@ def cleanup_stacktrace(self, traceback: str) -> str: submission_namespace = f"{submission_name(self)}." resulting_lines = "" - for line in traceback.splitlines(keepends=True): + for line in stacktrace.splitlines(keepends=True): # If we encounter an execution location, we are done. if re.search(execution_location_regex, line): break @@ -183,10 +183,10 @@ def cleanup_stacktrace(self, traceback: str) -> str: return resulting_lines - def cleanup_description(self, description: str) -> str: - description = cleanup_description(self, description) + def cleanup_description(self, statement: str) -> str: + statement = cleanup_description(self, statement) await_regex = re.compile(r"await\s+") - return await_regex.sub("", description) + return await_regex.sub("", statement) def generate_statement(self, statement: Statement) -> str: from tested.languages.javascript import generators diff --git a/tested/languages/javascript/linter.py b/tested/languages/javascript/linter.py index 9d6ff735..44ec8924 100644 --- a/tested/languages/javascript/linter.py +++ b/tested/languages/javascript/linter.py @@ -47,9 +47,11 @@ def run_eslint( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.javascript.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.javascript.linter.memory") + ( + get_i18n_string("languages.javascript.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.javascript.linter.memory") + ) ], [] try: diff --git a/tested/languages/kotlin/config.py b/tested/languages/kotlin/config.py index c3467605..62f00e56 100644 --- a/tested/languages/kotlin/config.py +++ b/tested/languages/kotlin/config.py @@ -184,13 +184,11 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_ktlint(self.config.dodona, remaining) - def find_main_file( - self, files: list[Path], name: str - ) -> tuple[Path | None, Status]: + def find_main_file(self, files: list[Path], name: str) -> Path | Status: logger.debug("Finding %s in %s", name, files) - main, status = Language.find_main_file(self, files, name + "Kt") - if status == Status.CORRECT: - return main, status + main_or_status = Language.find_main_file(self, files, name + "Kt") + if isinstance(main_or_status, Path): + return main_or_status else: return Language.find_main_file(self, files, name) @@ -207,8 +205,8 @@ def filter_function(file_path: Path) -> bool: return list(x for x in files if filter_function(x)) - def cleanup_stacktrace(self, traceback: str) -> str: - return jvm_cleanup_stacktrace(traceback, submission_file(self)) + def cleanup_stacktrace(self, stacktrace: str) -> str: + return jvm_cleanup_stacktrace(stacktrace, submission_file(self)) def generate_statement(self, statement: Statement) -> str: from tested.languages.kotlin import generators diff --git a/tested/languages/kotlin/generators.py b/tested/languages/kotlin/generators.py index 6b3b1e68..fcfdb5c4 100644 --- a/tested/languages/kotlin/generators.py +++ b/tested/languages/kotlin/generators.py @@ -171,9 +171,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_, False) return f"Array<{convert_declaration(base_type, None, sub_type)}>?" @@ -203,9 +201,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"List<{convert_declaration(base_type, None, sub_type)}>?" @@ -213,9 +209,7 @@ def extract_type_tuple(type_, generic=True): type_ = ( (value.get_content_type() or "Object") if isinstance(value, SequenceType) - else nt - if nt - else "Object" + else nt if nt else "Object" ) base_type, sub_type = extract_type_tuple(type_) return f"Set<{convert_declaration(base_type, None, sub_type)}>?" diff --git a/tested/languages/kotlin/ktlint.editorconfig b/tested/languages/kotlin/ktlint.editorconfig new file mode 100644 index 00000000..6ea49a7e --- /dev/null +++ b/tested/languages/kotlin/ktlint.editorconfig @@ -0,0 +1,2 @@ +[*.{kt,kts}] +ktlint_standard_filename=disabled diff --git a/tested/languages/kotlin/linter.py b/tested/languages/kotlin/linter.py index 87bd21c1..1d58eabe 100644 --- a/tested/languages/kotlin/linter.py +++ b/tested/languages/kotlin/linter.py @@ -24,25 +24,15 @@ def run_ktlint( if path := language_options.get("editorconfig", None): assert isinstance(path, str) - command.append(f"--editorconfig={config.resources / path}") - - if language_options.get("disabled_rules_ktlint", None): - rules = language_options["disabled_rules_ktlint"] - if isinstance(rules, list): - rules = ",".join(rules) - if "filename" not in rules: - rules += ",filename" - command.append(f"--disabled_rules={rules}") + editorconfig = config.resources / path else: - command.append("--disabled_rules=filename") + editorconfig = config.judge / "tested/languages/kotlin/ktlint.editorconfig" + command.append(f"--editorconfig={editorconfig}") if path := language_options.get("ktlint_ruleset", None): assert isinstance(path, str) command.append(f"--ruleset={config.resources / path}") - if language_options.get("ktlint_experimental", True): - command.append("--experimental") - submission = submission.absolute() command.append(str(submission.relative_to(submission.parent))) @@ -56,9 +46,11 @@ def run_ktlint( if execution_results.timeout or execution_results.memory: return [ - get_i18n_string("languages.kotlin.linter.timeout") - if execution_results.timeout - else get_i18n_string("languages.kotlin.linter.memory") + ( + get_i18n_string("languages.kotlin.linter.timeout") + if execution_results.timeout + else get_i18n_string("languages.kotlin.linter.memory") + ) ], [] try: @@ -85,20 +77,29 @@ def run_ktlint( message = error.get("message", None) if not message: continue - rule = error.get("rule", None) - if rule: - message += f"({rule})" + rule = error["rule"] + + # Attempt to extract rule information. + if ":" in rule: + ruleset, name = rule.split(":") + external_url = ( + f"https://pinterest.github.io/ktlint/latest/rules/{ruleset}/#{name}" + ) + message += f" ({name})" + else: + external_url = ( + "https://pinterest.github.io/ktlint/latest/rules/standard/" + ) + message += f" ({rule})" annotations.append( AnnotateCode( row=error.get("line", 1) - 1 + config.source_offset, text=message, - externalUrl="https://ktlint.github.io/#rules", + externalUrl=external_url, column=error.get("column", 1) - 1, type=Severity.INFO, ) ) - # sort linting messages on line, column and code - annotations.sort(key=lambda a: (a.row, a.column, a.text)) return [], annotations diff --git a/tested/languages/preparation.py b/tested/languages/preparation.py index ae0b4fd4..d21f00bd 100644 --- a/tested/languages/preparation.py +++ b/tested/languages/preparation.py @@ -4,6 +4,7 @@ Most input from a test suite needs to be prepared to easily generated code. This module handles that. """ + from pathlib import Path from typing import TYPE_CHECKING, Callable, Literal, cast @@ -78,9 +79,9 @@ class PreparedTestcaseStatement: """ statement: Statement | PreparedLanguageLiteral # The original statement. - value_function: Callable[ - [Expression], Statement - ] | None # The function to handle the return value of the statement, if any. + value_function: ( + Callable[[Expression], Statement] | None + ) # The function to handle the return value of the statement, if any. def input_statement(self, override: str | None = None) -> Statement: """ @@ -300,6 +301,7 @@ def _create_handling_function( evaluator_name = conventionalize_namespace(lang_config, evaluator.file.stem) else: evaluator_name = None + evaluator = None def generator(expression: Expression) -> Statement: if isinstance(output, OracleOutputChannel) and isinstance( diff --git a/tested/languages/python/config.py b/tested/languages/python/config.py index 91138f0a..8df55fc8 100644 --- a/tested/languages/python/config.py +++ b/tested/languages/python/config.py @@ -46,7 +46,7 @@ def supports_debug_information(self) -> bool: def file_extension(self) -> str: return "py" - def get_string_quote(self): + def get_string_quote(self) -> str: return "'" def naming_conventions(self) -> dict[Conventionable, NamingConventions]: @@ -158,14 +158,14 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: return linter.run_pylint(self.config.dodona, remaining) # Idea and original code: dodona/judge-pythia - def cleanup_stacktrace(self, stacktrace_str: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: context_file_regex = re.compile(r"context_[0-9]+_[0-9]+\.py") file_line_regex = re.compile(rf"\({submission_file(self)}, line (\d+)\)") file_full_regex = re.compile(rf'File "./{submission_file(self)}", line (\d+)') - stacktrace = stacktrace_str.splitlines(True) + stacktrace_split = stacktrace.splitlines(True) skip_line, lines = False, [] - for line in stacktrace: + for line in stacktrace_split: line = line.strip("\n") logger.debug(line) diff --git a/tested/languages/python/linter.py b/tested/languages/python/linter.py index 10574bd9..4557a20b 100644 --- a/tested/languages/python/linter.py +++ b/tested/languages/python/linter.py @@ -2,6 +2,7 @@ Support linting Python code. Most of this code is taken from the code from Pythia. """ + import logging from io import StringIO diff --git a/tested/languages/python/templates/values.py b/tested/languages/python/templates/values.py index ea38a0ac..d4f1a0e1 100644 --- a/tested/languages/python/templates/values.py +++ b/tested/languages/python/templates/values.py @@ -1,4 +1,5 @@ """Minimal RPC language in JSON to send data from the tests to the judge.""" + import dataclasses import decimal import io diff --git a/tested/languages/runhaskell/config.py b/tested/languages/runhaskell/config.py index 10741ed7..b0cfebb5 100644 --- a/tested/languages/runhaskell/config.py +++ b/tested/languages/runhaskell/config.py @@ -17,7 +17,7 @@ def compilation(self, files: list[str]) -> CallbackResult: def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: return ["runhaskell", file, *arguments] - def filter_dependencies(self, files: list[str], context_name: str) -> list[str]: + def filter_dependencies(self, files: list[Path], context_name: str) -> list[Path]: return files def path_to_dependencies(self) -> list[Path]: diff --git a/tested/languages/utils.py b/tested/languages/utils.py index a034def2..c62fd116 100644 --- a/tested/languages/utils.py +++ b/tested/languages/utils.py @@ -145,15 +145,13 @@ def modify_line_number(match: re.Match) -> str: @overload def convert_stacktrace_to_clickable_feedback( lang: "Language", stacktrace: str -) -> ExtendedMessage: - ... +) -> ExtendedMessage: ... @overload def convert_stacktrace_to_clickable_feedback( lang: "Language", stacktrace: None -) -> None: - ... +) -> None: ... def convert_stacktrace_to_clickable_feedback( diff --git a/tested/main.py b/tested/main.py index 43041184..b4549028 100644 --- a/tested/main.py +++ b/tested/main.py @@ -1,6 +1,7 @@ """ Main file, responsible for running TESTed based on the input given by Dodona. """ + import os from typing import IO diff --git a/tested/manual.py b/tested/manual.py index fef7da69..eab988a1 100644 --- a/tested/manual.py +++ b/tested/manual.py @@ -2,6 +2,7 @@ Run the judge manually from code. In this mode, the config is hardcoded into this file, allowing rapid testing (and, most importantly, debugging). """ + import logging import sys import time diff --git a/tested/oracles/common.py b/tested/oracles/common.py index 3e4a6068..2f54e44d 100644 --- a/tested/oracles/common.py +++ b/tested/oracles/common.py @@ -22,6 +22,7 @@ def evaluate_text(configs, channel, actual): pass """ + import functools from collections.abc import Callable from pathlib import Path @@ -56,7 +57,9 @@ class OracleResult: """ result: StatusMessage # The result of the evaluation. - readable_expected: str # A human-friendly version of what the channel should have been. + readable_expected: ( + str # A human-friendly version of what the channel should have been. + ) readable_actual: str # A human-friendly version (on a best-efforts basis) of what the channel is. messages: list[Message] = field(factory=list) is_multiline_string: bool = ( diff --git a/tested/oracles/specific.py b/tested/oracles/specific.py index d4f881b7..923215f7 100644 --- a/tested/oracles/specific.py +++ b/tested/oracles/specific.py @@ -1,6 +1,7 @@ """ Evaluate the result of a language-specific oracle. """ + import logging import traceback diff --git a/tested/oracles/text.py b/tested/oracles/text.py index 8d0eabf5..6724e18b 100644 --- a/tested/oracles/text.py +++ b/tested/oracles/text.py @@ -1,6 +1,7 @@ """ Evaluators for text. """ + import math from typing import Any diff --git a/tested/oracles/value.py b/tested/oracles/value.py index c0be00c6..a9412bcd 100644 --- a/tested/oracles/value.py +++ b/tested/oracles/value.py @@ -1,6 +1,7 @@ """ Value oracle. """ + import logging from typing import cast diff --git a/tested/parsing.py b/tested/parsing.py index 8bffaad4..3b7f3d64 100644 --- a/tested/parsing.py +++ b/tested/parsing.py @@ -4,6 +4,7 @@ Since we need to set up quite a few converters, we re-use a single converter for all, both the serialization and suite. """ + import logging from collections.abc import Callable from decimal import Decimal @@ -94,7 +95,7 @@ def parse_json_value(value: str) -> "Value": initialise_converter() from tested.serialisation import Value - return _suite_converter.loads(value, Value) + return _suite_converter.loads(value, Value) # pyright: ignore def parse_json_suite(value: str) -> "Suite": @@ -112,7 +113,9 @@ def suite_to_json(suite: "Suite") -> str: def fallback_field(converter_arg: Converter, old_to_new_field: dict[str, str]): def decorator(cls): - struct = make_dict_structure_fn(cls, converter_arg) + struct = make_dict_structure_fn( + cls, converter_arg, _cattrs_forbid_extra_keys=False + ) def structure(d, cl): for k, v in old_to_new_field.items(): @@ -133,7 +136,9 @@ def custom_fallback_field( old_to_new_field: dict[str, tuple[str, Callable[[Any], Any]]], ): def decorator(cls): - struct = make_dict_structure_fn(cls, converter_arg) + struct = make_dict_structure_fn( + cls, converter_arg, _cattrs_forbid_extra_keys=False + ) def structure(d, cl): for k, (new_name, mapper) in old_to_new_field.items(): @@ -155,7 +160,9 @@ def structure(d, cl): def ignore_field(converter_arg: Converter, *fields: str): def decorator(cls): - struct = make_dict_structure_fn(cls, converter_arg) + struct = make_dict_structure_fn( + cls, converter_arg, _cattrs_forbid_extra_keys=False + ) def structure(d, cl): for to_ignore in fields: diff --git a/tested/serialisation.py b/tested/serialisation.py index 26fc0ccb..326945ca 100644 --- a/tested/serialisation.py +++ b/tested/serialisation.py @@ -16,6 +16,7 @@ command line. The schema will be printed to stdout. This can be used to generate classes for implementations in other configs. """ + import copy import logging import math diff --git a/tested/testsuite.py b/tested/testsuite.py index d6489fc4..27564969 100644 --- a/tested/testsuite.py +++ b/tested/testsuite.py @@ -5,6 +5,7 @@ When executing this module, a json-schema is generated for the format, which can be of assistance when checking existing test suites. """ + from collections import defaultdict from collections.abc import Iterable from enum import StrEnum, auto, unique diff --git a/tests/test_functionality.py b/tests/test_functionality.py index 361fc67f..13356c44 100644 --- a/tests/test_functionality.py +++ b/tests/test_functionality.py @@ -6,6 +6,7 @@ Running the tests should happen in with the root directory (the one with src/ and tests/) as the working directory. """ + import shutil import sys from pathlib import Path diff --git a/tests/test_serialisation.py b/tests/test_serialisation.py index 8eee9b1c..cedb333c 100644 --- a/tests/test_serialisation.py +++ b/tests/test_serialisation.py @@ -10,6 +10,7 @@ Testing advanced types is a work-in progress at this point, since we test in Python, and Python doesn't have explicit support for e.g. int32, int64. """ + import itertools import sys from decimal import Decimal @@ -189,7 +190,7 @@ def run_encoder(bundle: Bundle, values: list[Value]) -> list[str]: files = filter_files(files, dest) files = bundle.language.filter_dependencies(files, name) - executable, _ = bundle.language.find_main_file(files, name) + executable = bundle.language.find_main_file(files, name) # Run the code. r = execute_file(bundle, executable.name, dest, None) diff --git a/tests/test_slow.py b/tests/test_slow.py index a310fefa..1587a375 100644 --- a/tests/test_slow.py +++ b/tests/test_slow.py @@ -1,6 +1,7 @@ """ Tests where full exercises are run. These are inherently slower. """ + from pathlib import Path import pytest