diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..0a5d792c --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,4 @@ +template: | + ## What’s Changed + + $CHANGES \ No newline at end of file diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index d77354c5..2a738a19 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -1,64 +1,33 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python -name: Python package +name: PR Check on: pull_request: - branches: [ "main", "release" ] - -permissions: - contents: read jobs: - package: - runs-on: ubuntu-latest + test-api-only: + strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10"] + os: [ macos-latest, windows-latest, ubuntu-latest ] + python-version: ["3.9", "3.10", "3.11", "3.12"] + pydantic: ["pydantic>=2.0.0", "pydantic<2.0.0"] + runs-on: ${{ matrix.os }} steps: - #---------------------------------------------- - # check-out repo and set-up python - #---------------------------------------------- - - name: Check out repository - uses: actions/checkout@v2 - - name: Set up python - id: setup-python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - #---------------------------------------------- - # ----- install & configure poetry ----- - #---------------------------------------------- - - name: Install Poetry - uses: snok/install-poetry@v1 - #---------------------------------------------- - # install dependencies if cache does not exist - #---------------------------------------------- - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - #---------------------------------------------- - # lint & test - #---------------------------------------------- - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - poetry run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - poetry run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - poetry run pytest - #---------------------------------------------- - # build & upload - #---------------------------------------------- - - name: Build package - run: poetry build - - name: Upload distribution - uses: actions/upload-artifact@v3 - with: - name: distribution - path: dist/* \ No newline at end of file + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install requirements + run: | + pip install poetry + poetry export --with=dev --without-hashes -o requirements.txt + pip install -r requirements.txt + pip install "${{ matrix.pydantic }}" + - name: Test with pytest + run: pytest \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 2403e3a6..035d1baa 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,57 +1,54 @@ -# This workflow will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -name: Upload Python Package +name: Release on: - release: - types: [ published ] - -permissions: - contents: read + push: + tags: + - v* jobs: - upload: + publish-pypi-github: runs-on: ubuntu-latest + environment: + name: release + url: https://pypi.org/p/nonebot-plugin-pixivbot + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + steps: - #---------------------------------------------- - # check-out repo and set-up python - #---------------------------------------------- - - name: Check out repository - uses: actions/checkout@v2 - - name: Set up python - id: setup-python - uses: actions/setup-python@v2 - with: - python-version: 3.x - #---------------------------------------------- - # ----- install & configure poetry ----- - #---------------------------------------------- - - name: Install Poetry - uses: snok/install-poetry@v1 - #---------------------------------------------- - # install dependencies if cache does not exist - #---------------------------------------------- - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - #---------------------------------------------- - # build & publish - #---------------------------------------------- - - name: Build package - run: poetry build - - name: Upload distribution - uses: actions/upload-artifact@v3 + - uses: actions/checkout@v3 + + - name: Setup Python environment + uses: actions/setup-python@v3 with: - name: distribution - path: dist/* - - name: Publish package - uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + python-version: "3.11" + + - name: Setup Poetry + run: | + pip install poetry + + - run: | + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - uses: release-drafter/release-drafter@v5 with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} + name: Release ${{ env.TAG_NAME }} + tag: ${{ env.TAG_NAME }} + publish: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish PyPI and Github + run: | + poetry build + ls dist/ + gh release upload --clobber ${{ env.TAG_NAME }} dist/*.tar.gz dist/*.whl + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish pypi + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/bot.py b/bot.py index 23adfcb7..2e404ac4 100644 --- a/bot.py +++ b/bot.py @@ -1,10 +1,8 @@ import nonebot -from nonebot.adapters.qqguild import Adapter nonebot.init() driver = nonebot.get_driver() -driver.register_adapter(Adapter) nonebot.load_plugin("nonebot_plugin_pixivbot") diff --git a/poetry.lock b/poetry.lock index 49b438de..5dfc2147 100644 --- a/poetry.lock +++ b/poetry.lock @@ -200,6 +200,17 @@ typing-extensions = ">=4" [package.extras] tz = ["backports.zoneinfo"] +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + [[package]] name = "anyio" version = "4.4.0" @@ -288,6 +299,37 @@ types-python-dateutil = ">=2.8.10" doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "async-asgi-testclient" +version = "1.4.11" +description = "Async client for testing ASGI web applications" +optional = false +python-versions = "*" +files = [ + {file = "async-asgi-testclient-1.4.11.tar.gz", hash = "sha256:4449ac85d512d661998ec61f91c9ae01851639611d748d81ae7f816736551792"}, +] + +[package.dependencies] +multidict = ">=4.0,<7.0" +requests = ">=2.21,<3.0" + [[package]] name = "async-timeout" version = "4.0.3" @@ -558,6 +600,93 @@ pyyaml = ">=5.3.1" requests = ">=2.23.0" rich = "*" +[[package]] +name = "coverage" +version = "7.6.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "deprecated" version = "1.2.14" @@ -1015,13 +1144,13 @@ files = [ [[package]] name = "idna" -version = "3.9" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.9-py3-none-any.whl", hash = "sha256:69297d5da0cc9281c77efffb4e730254dd45943f45bbfb461de5991713989b1e"}, - {file = "idna-3.9.tar.gz", hash = "sha256:e5c5dafde284f26e9e0f28f6ea2d6400abd5ca099864a67f576f3981c6476124"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] [package.extras] @@ -1068,6 +1197,17 @@ enabler = ["pytest-enabler (>=2.2)"] test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] type = ["pytest-mypy"] +[[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 = "jinja2" version = "3.1.4" @@ -1252,79 +1392,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "msgpack" -version = "1.1.0" -description = "MessagePack serializer" -optional = false -python-versions = ">=3.8" -files = [ - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, - {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, - {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, - {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, - {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, - {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, - {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, - {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, - {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, - {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, - {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, - {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, - {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, - {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, -] - [[package]] name = "multidict" version = "6.1.0" @@ -1472,61 +1539,15 @@ files = [ tarina = ">=0.5.1" typing-extensions = ">=4.5.0" -[[package]] -name = "nonebot-adapter-kaiheila" -version = "0.2.12" -description = "kaiheila adapter for nonebot2" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "nonebot_adapter_kaiheila-0.2.12-py3-none-any.whl", hash = "sha256:3ddc7e47b7213807d652428b95663e03991d1d89e79f434fbcf8b73a95a7a5ee"}, - {file = "nonebot_adapter_kaiheila-0.2.12.tar.gz", hash = "sha256:102e00642e693f859b3263f53dc41675e4c8ec6c123e253fdddecf3b3f2ec61f"}, -] - -[package.dependencies] -nonebot2 = ">=2.0.0,<3.0.0" - -[[package]] -name = "nonebot-adapter-onebot" -version = "2.4.4" -description = "OneBot(CQHTTP) adapter for nonebot2" -optional = false -python-versions = "<4.0,>=3.9" -files = [ - {file = "nonebot_adapter_onebot-2.4.4-py3-none-any.whl", hash = "sha256:4dceeec7332bb560652c764405e9dd350268303f69b7c0e92b7cfebe876e8d39"}, - {file = "nonebot_adapter_onebot-2.4.4.tar.gz", hash = "sha256:c8a3645f74a3e43c85f092fb670508c662c36831f019a15e4d74eaac686089f0"}, -] - -[package.dependencies] -msgpack = ">=1.0.3,<2.0.0" -nonebot2 = ">=2.2.0,<3.0.0" -pydantic = ">=1.10.0,<2.5.0 || >2.5.0,<2.5.1 || >2.5.1,<3.0.0" -typing-extensions = ">=4.0.0,<5.0.0" - -[[package]] -name = "nonebot-adapter-qqguild" -version = "0.2.5" -description = "QQ Guild adapter for nonebot2" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "nonebot_adapter_qqguild-0.2.5-py3-none-any.whl", hash = "sha256:9fa3e1a86d5ba6bb49bd8f6b1766e0d70204a97026316c4f6426bc09abb8e9fb"}, - {file = "nonebot_adapter_qqguild-0.2.5.tar.gz", hash = "sha256:b6fef5daf54a4ce41221945a6fb3c5c63763a9950377f1e3e50191602b8b8098"}, -] - -[package.dependencies] -nonebot2 = ">=2.0.0-beta.1,<3.0.0" -pydantic = ">=1.9.0,<2.0.0" - [[package]] name = "nonebot-plugin-access-control" -version = "1.2.1b4" +version = "1.2.1" description = "" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "nonebot_plugin_access_control-1.2.1b4-py3-none-any.whl", hash = "sha256:1180c5c9884cabb827653b61278fb77646bf8630564944fe2837009a0f3cd933"}, - {file = "nonebot_plugin_access_control-1.2.1b4.tar.gz", hash = "sha256:d3ef7206a0db8a46bd7118c4687bdd6acfe8d04876798decd744acff1c9019d5"}, + {file = "nonebot_plugin_access_control-1.2.1-py3-none-any.whl", hash = "sha256:a5b13c68e25b2f6dab48cb8084747bc0868e25bedf0eba2e3d176d636a03dfc8"}, + {file = "nonebot_plugin_access_control-1.2.1.tar.gz", hash = "sha256:0c033ab0f96afedf1bb419d8cdac9b00389896bfe696b78b0031aa0839a4127f"}, ] [package.dependencies] @@ -1713,6 +1734,24 @@ httpx = ["httpx[http2] (>=0.20.0,<1.0.0)"] quart = ["Quart (>=0.18.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)"] websockets = ["websockets (>=10.0)"] +[[package]] +name = "nonebug" +version = "0.3.7" +description = "nonebot2 test framework" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "nonebug-0.3.7-py3-none-any.whl", hash = "sha256:c39f462aafe20660602a8b789a575db6c9346ab5b6f1985eb9d98b861528299a"}, + {file = "nonebug-0.3.7.tar.gz", hash = "sha256:8a75183400681f34eafc7caa2bb6dd511c3b5660c59264f1c379a088c7ac2247"}, +] + +[package.dependencies] +asgiref = ">=3.4.0,<4.0.0" +async-asgi-testclient = ">=1.4.8,<2.0.0" +nonebot2 = ">=2.2.0,<3.0.0" +pytest = ">=7.0.0,<9.0.0" +typing-extensions = ">=4.0.0,<5.0.0" + [[package]] name = "noneprompt" version = "0.1.9" @@ -1781,6 +1820,17 @@ files = [ {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, ] +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + [[package]] name = "pillow" version = "10.4.0" @@ -1910,6 +1960,21 @@ docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-a test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] type = ["mypy (>=1.11.2)"] +[[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 = "prompt-toolkit" version = "3.0.47" @@ -1937,62 +2002,147 @@ files = [ [[package]] name = "pydantic" -version = "1.10.18" -description = "Data validation and settings management using python type hints" +version = "2.9.1" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"}, + {file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.23.3" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.23.3" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"}, + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"}, + {file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"}, + {file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"}, + {file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"}, + {file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"}, + {file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"}, + {file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"}, + {file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"}, + {file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"}, + {file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"}, + {file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"}, + {file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"}, + {file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"}, + {file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.5.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" files = [ - {file = "pydantic-1.10.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e405ffcc1254d76bb0e760db101ee8916b620893e6edfbfee563b3c6f7a67c02"}, - {file = "pydantic-1.10.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e306e280ebebc65040034bff1a0a81fd86b2f4f05daac0131f29541cafd80b80"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11d9d9b87b50338b1b7de4ebf34fd29fdb0d219dc07ade29effc74d3d2609c62"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b661ce52c7b5e5f600c0c3c5839e71918346af2ef20062705ae76b5c16914cab"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c20f682defc9ef81cd7eaa485879ab29a86a0ba58acf669a78ed868e72bb89e0"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5ae6b7c8483b1e0bf59e5f1843e4fd8fd405e11df7de217ee65b98eb5462861"}, - {file = "pydantic-1.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:74fe19dda960b193b0eb82c1f4d2c8e5e26918d9cda858cbf3f41dd28549cb70"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72fa46abace0a7743cc697dbb830a41ee84c9db8456e8d77a46d79b537efd7ec"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef0fe7ad7cbdb5f372463d42e6ed4ca9c443a52ce544472d8842a0576d830da5"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00e63104346145389b8e8f500bc6a241e729feaf0559b88b8aa513dd2065481"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae6fa2008e1443c46b7b3a5eb03800121868d5ab6bc7cda20b5df3e133cde8b3"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9f463abafdc92635da4b38807f5b9972276be7c8c5121989768549fceb8d2588"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3445426da503c7e40baccefb2b2989a0c5ce6b163679dd75f55493b460f05a8f"}, - {file = "pydantic-1.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:467a14ee2183bc9c902579bb2f04c3d3dac00eff52e252850509a562255b2a33"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:efbc8a7f9cb5fe26122acba1852d8dcd1e125e723727c59dcd244da7bdaa54f2"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24a4a159d0f7a8e26bf6463b0d3d60871d6a52eac5bb6a07a7df85c806f4c048"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74be007703547dc52e3c37344d130a7bfacca7df112a9e5ceeb840a9ce195c7"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcb20d4cb355195c75000a49bb4a31d75e4295200df620f454bbc6bdf60ca890"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46f379b8cb8a3585e3f61bf9ae7d606c70d133943f339d38b76e041ec234953f"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbfbca662ed3729204090c4d09ee4beeecc1a7ecba5a159a94b5a4eb24e3759a"}, - {file = "pydantic-1.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:c6d0a9f9eccaf7f438671a64acf654ef0d045466e63f9f68a579e2383b63f357"}, - {file = "pydantic-1.10.18-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d5492dbf953d7d849751917e3b2433fb26010d977aa7a0765c37425a4026ff1"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe734914977eed33033b70bfc097e1baaffb589517863955430bf2e0846ac30f"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15fdbe568beaca9aacfccd5ceadfb5f1a235087a127e8af5e48df9d8a45ae85c"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c3e742f62198c9eb9201781fbebe64533a3bbf6a76a91b8d438d62b813079dbc"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19a3bd00b9dafc2cd7250d94d5b578edf7a0bd7daf102617153ff9a8fa37871c"}, - {file = "pydantic-1.10.18-cp37-cp37m-win_amd64.whl", hash = "sha256:2ce3fcf75b2bae99aa31bd4968de0474ebe8c8258a0110903478bd83dfee4e3b"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:335a32d72c51a313b33fa3a9b0fe283503272ef6467910338e123f90925f0f03"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34a3613c7edb8c6fa578e58e9abe3c0f5e7430e0fc34a65a415a1683b9c32d9a"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ee4e6ca1d9616797fa2e9c0bfb8815912c7d67aca96f77428e316741082a1b"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23e8ec1ce4e57b4f441fc91e3c12adba023fedd06868445a5b5f1d48f0ab3682"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:44ae8a3e35a54d2e8fa88ed65e1b08967a9ef8c320819a969bfa09ce5528fafe"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5389eb3b48a72da28c6e061a247ab224381435256eb541e175798483368fdd3"}, - {file = "pydantic-1.10.18-cp38-cp38-win_amd64.whl", hash = "sha256:069b9c9fc645474d5ea3653788b544a9e0ccd3dca3ad8c900c4c6eac844b4620"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80b982d42515632eb51f60fa1d217dfe0729f008e81a82d1544cc392e0a50ddf"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aad8771ec8dbf9139b01b56f66386537c6fe4e76c8f7a47c10261b69ad25c2c9"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941a2eb0a1509bd7f31e355912eb33b698eb0051730b2eaf9e70e2e1589cae1d"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65f7361a09b07915a98efd17fdec23103307a54db2000bb92095457ca758d485"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6951f3f47cb5ca4da536ab161ac0163cab31417d20c54c6de5ddcab8bc813c3f"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a4c5eec138a9b52c67f664c7d51d4c7234c5ad65dd8aacd919fb47445a62c86"}, - {file = "pydantic-1.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:49e26c51ca854286bffc22b69787a8d4063a62bf7d83dc21d44d2ff426108518"}, - {file = "pydantic-1.10.18-py3-none-any.whl", hash = "sha256:06a189b81ffc52746ec9c8c007f16e5167c8b0a696e1a726369327e3db7b2a82"}, - {file = "pydantic-1.10.18.tar.gz", hash = "sha256:baebdff1907d1d96a139c25136a9bb7d17e118f133a76a2ef3b845e831e3403a"}, -] - -[package.dependencies] -typing-extensions = ">=4.2.0" + {file = "pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907"}, + {file = "pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pyfiglet" @@ -2041,6 +2191,64 @@ files = [ {file = "pygtrie-2.5.0.tar.gz", hash = "sha256:203514ad826eb403dab1d2e2ddd034e0d1534bbe4dbe0213bb0593f66beba4e2"}, ] +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.2" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, + {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -2351,13 +2559,13 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "ssttkkl-nonebot-utils" -version = "0.1.21" +version = "0.1.22" description = "" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "ssttkkl_nonebot_utils-0.1.21-py3-none-any.whl", hash = "sha256:c6d63fd539be5247e585b561d87046f347c3fae43dd8fa83eec60507219873df"}, - {file = "ssttkkl_nonebot_utils-0.1.21.tar.gz", hash = "sha256:aec48a7ea25a36f2d2d1c669fc6d5e82354e87e53a6793043001979fab618521"}, + {file = "ssttkkl_nonebot_utils-0.1.22-py3-none-any.whl", hash = "sha256:6f86efb1f77184d6098256fbf713960b6cc089dc7c0a73adc662a9cbc1958621"}, + {file = "ssttkkl_nonebot_utils-0.1.22.tar.gz", hash = "sha256:cbb97b2ef5419453bdc1ef532c768d29c47914bf5d097de75f5c12ba367c53fd"}, ] [package.dependencies] @@ -3076,4 +3284,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "04e7abbb72a82dfdb689dd1eaaa15ea470f68287ef4ce15444f296baf79f511f" +content-hash = "2dd6c333f16a2ca14a9ee97db5998ef5aac9f09d30ec654898afd706e7c16a8d" diff --git a/pyproject.toml b/pyproject.toml index 5bfa2d4e..42ac03ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ packages = [ [tool.poetry.dependencies] python = "^3.9" -nonebot2 = "^2.0" +nonebot2 = "^2.3" nonebot_plugin_apscheduler = ">=0.3.0" nonebot-plugin-access-control = "^1.2" nonebot-plugin-session = ">=0.2.0" @@ -39,11 +39,13 @@ nb-cli = "^1.0.5" flake8 = "^6.0.0" #asyncpg = "^0.27.0" aiohttp-socks = ">=0.8.0" -nonebot2 = { extras = ["fastapi", "websocket", "httpx"], version = "^2.0" } -nonebot-adapter-onebot = "^2.2.1" -nonebot-adapter-kaiheila = "^0.2.0" -nonebot-adapter-qqguild = "^0.2.2" +nonebot2 = { extras = ["fastapi", "websocket", "httpx"], version = "^2.3" } autopep8 = "^2.0.4" +nonebug = "^0.3.6" +pytest = "^7.4.3" +pytest-asyncio = "^0.21.1" +pytest-cov = "^4.1.0" +pydantic-settings = "^2.4.0" [tool.nonebot] plugins = ["nonebot_plugin_pixivbot"] diff --git a/src/nonebot_plugin_pixivbot/config.py b/src/nonebot_plugin_pixivbot/config.py index 8d8a1899..f52ef52f 100644 --- a/src/nonebot_plugin_pixivbot/config.py +++ b/src/nonebot_plugin_pixivbot/config.py @@ -1,20 +1,18 @@ +from collections.abc import Sequence from functools import partial from pathlib import Path -from typing import Optional, List, Literal +from typing import Optional, List, Literal, Any, Dict from urllib.parse import urlparse -from nonebot import logger, require -from pydantic import validator, root_validator -from pydantic.fields import ModelField -from ssttkkl_nonebot_utils.config_loader import BaseSettings, load_conf - -from .global_context import context - -require("nonebot_plugin_localstore") - import nonebot_plugin_localstore as store +from nonebot import logger +from nonebot.compat import PYDANTIC_V2 +from pydantic import conlist +from ssttkkl_nonebot_utils.config_loader import BaseSettings, load_conf from .enums import * +from .enums import RandomIllustMethod +from .global_context import context def _get_default_sql_conn_url(): @@ -26,90 +24,118 @@ def _get_default_sql_conn_url(): return "sqlite+aiosqlite:///" + str(data_file) +def compatible_model_pre_validator(func): + if PYDANTIC_V2: + from pydantic import model_validator + + @model_validator(mode='before') + @classmethod + def checker(cls, values: dict[str]): + return func(cls, values) + + return checker + else: + from pydantic import root_validator + return root_validator(pre=True, allow_reuse=True)(func) + + +def compatible_field_validator(*fields: str): + def wrapper(func): + if PYDANTIC_V2: + from pydantic import field_validator + from pydantic_core.core_schema import ValidationInfo + + @field_validator(*fields) + @classmethod + def checker(cls, v: str, info: ValidationInfo): + return func(cls, v, info.data, {"name": info.field_name}) + + return checker + else: + from pydantic import validator + from pydantic.fields import ModelField + + @validator(*fields, allow_reuse=True) + def checker(cls, v: str, values: Dict[str, Any], field: ModelField): + return func(cls, v, values, {"name": field.name}) + + return checker + + return wrapper + + class Config(BaseSettings): - @root_validator(pre=True, allow_reuse=True) - def deprecated_access_control_config(cls, values): + @compatible_model_pre_validator + def deprecated_access_control_config(cls, values: Dict[str, Any]): for name in {"blacklist", "pixiv_query_cooldown", "pixiv_no_query_cooldown_users"}: if name in values: logger.warning(f"config \"{name}\" is deprecated, use nonebot-plugin-access-control instead " "(MORE INFO: https://github.com/ssttkkl/nonebot-plugin-pixivbot#%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6)") return values - @root_validator(pre=True, allow_reuse=True) - def deprecated_mongodb_config(cls, values): + @compatible_model_pre_validator + def deprecated_mongodb_config(cls, values: Dict[str, Any]): if values.get("pixiv_data_source", "sql") == "mongo" or "pixiv_mongo_conn_url" in values: logger.warning("mongo support was removed, use sql instead") return values pixiv_refresh_token: str - pixiv_sql_conn_url: str - pixiv_sql_dialect: str - - @root_validator(pre=True, allow_reuse=True) - def default_sql_conn_url(cls, values): - if "pixiv_sql_conn_url" not in values: - values["pixiv_sql_conn_url"] = _get_default_sql_conn_url() - return values - - @root_validator(pre=True, allow_reuse=True) - def detect_sql_dialect(cls, values): - values["pixiv_mongo_conn_url"] = "" - values["pixiv_mongo_database_name"] = "" + pixiv_sql_conn_url: str = _get_default_sql_conn_url() - url = urlparse(values["pixiv_sql_conn_url"]) + @property + def pixiv_sql_dialect(self) -> str: + url = urlparse(self.pixiv_sql_conn_url) if '+' in url.scheme: pixiv_sql_dialect = url.scheme.split('+')[0] else: pixiv_sql_dialect = url.scheme - values["pixiv_sql_dialect"] = pixiv_sql_dialect - - return values + return pixiv_sql_dialect pixiv_use_local_cache: bool = True pixiv_local_cache_type: Literal["sql", "file"] = "file" - pixiv_proxy: Optional[str] + pixiv_proxy: Optional[str] = None pixiv_query_timeout: float = 60.0 pixiv_loading_prompt_delayed_time: float = 5.0 pixiv_simultaneous_query: int = 8 - pixiv_download_cache_expires_in = 3600 * 24 * 7 - pixiv_illust_detail_cache_expires_in = 3600 * 24 * 7 - pixiv_user_detail_cache_expires_in = 3600 * 24 * 7 - pixiv_illust_ranking_cache_expires_in = 3600 * 6 - pixiv_search_illust_cache_expires_in = 3600 * 24 - pixiv_search_illust_cache_delete_in = 3600 * 24 * 30 - pixiv_search_user_cache_expires_in = 3600 * 24 - pixiv_search_user_cache_delete_in = 3600 * 24 * 30 - pixiv_user_illusts_cache_expires_in = 3600 * 24 - pixiv_user_illusts_cache_delete_in = 3600 * 24 * 30 - pixiv_user_bookmarks_cache_expires_in = 3600 * 24 - pixiv_user_bookmarks_cache_delete_in = 3600 * 24 * 30 - pixiv_related_illusts_cache_expires_in = 3600 * 24 - pixiv_other_cache_expires_in = 3600 * 6 + pixiv_download_cache_expires_in: int = 3600 * 24 * 7 + pixiv_illust_detail_cache_expires_in: int = 3600 * 24 * 7 + pixiv_user_detail_cache_expires_in: int = 3600 * 24 * 7 + pixiv_illust_ranking_cache_expires_in: int = 3600 * 6 + pixiv_search_illust_cache_expires_in: int = 3600 * 24 + pixiv_search_illust_cache_delete_in: int = 3600 * 24 * 30 + pixiv_search_user_cache_expires_in: int = 3600 * 24 + pixiv_search_user_cache_delete_in: int = 3600 * 24 * 30 + pixiv_user_illusts_cache_expires_in: int = 3600 * 24 + pixiv_user_illusts_cache_delete_in: int = 3600 * 24 * 30 + pixiv_user_bookmarks_cache_expires_in: int = 3600 * 24 + pixiv_user_bookmarks_cache_delete_in: int = 3600 * 24 * 30 + pixiv_related_illusts_cache_expires_in: int = 3600 * 24 + pixiv_other_cache_expires_in: int = 3600 * 6 pixiv_block_tags: List[str] = [] pixiv_block_action: BlockAction = BlockAction.no_image pixiv_exclude_ai_illusts: bool = False - pixiv_download_custom_domain: Optional[str] + pixiv_download_custom_domain: Optional[str] = None pixiv_compression_enabled: bool = False - pixiv_compression_max_size: Optional[int] - pixiv_compression_quantity: Optional[float] + pixiv_compression_max_size: Optional[int] = None + pixiv_compression_quantity: Optional[float] = None # 不加allow_reuse跑pytest会报错 - @validator('pixiv_compression_max_size', 'pixiv_compression_quantity', allow_reuse=True) - def compression_validator(cls, v, values, field: ModelField): + @compatible_field_validator('pixiv_compression_max_size', 'pixiv_compression_quantity') + def compression_validator(cls, v, values, field: dict): if values['pixiv_compression_enabled'] and v is None: raise ValueError( - f'pixiv_compression_enabled is True but {field.name} got None.') + f'pixiv_compression_enabled is True but {field["name"]} got None.') return v - pixiv_query_to_me_only = False - pixiv_command_to_me_only = False + pixiv_query_to_me_only: bool = False + pixiv_command_to_me_only: bool = False pixiv_poke_action: Literal[ "", "ranking", "random_recommended_illust", "random_bookmark"] = "random_recommended_illust" @@ -117,76 +143,76 @@ def compression_validator(cls, v, values, field: ModelField): pixiv_send_illust_link: bool = False pixiv_send_forward_message: Literal['always', 'auto', 'never'] = 'auto' - pixiv_max_item_per_query = 10 - pixiv_max_page_per_illust = 10 + pixiv_max_item_per_query: int = 10 + pixiv_max_page_per_illust: int = 10 - pixiv_tag_translation_enabled = True + pixiv_tag_translation_enabled: bool = True - pixiv_more_enabled = True - pixiv_query_expires_in = 10 * 60 + pixiv_more_enabled: bool = True + pixiv_query_expires_in: int = 10 * 60 - pixiv_illust_query_enabled = True - pixiv_illust_sniffer_enabled = True + pixiv_illust_query_enabled: bool = True + pixiv_illust_sniffer_enabled: bool = True - pixiv_ranking_query_enabled = True + pixiv_ranking_query_enabled: bool = True pixiv_ranking_default_mode: RankingMode = RankingMode.day - pixiv_ranking_default_range = [1, 3] - pixiv_ranking_fetch_item = 150 - pixiv_ranking_max_item_per_query = 10 - - @validator('pixiv_ranking_default_range', allow_reuse=True) - def ranking_default_range_validator(cls, v, field: ModelField): - if len(v) < 2 or v[0] > v[1]: - raise ValueError(f'illegal {field.name} value: {v}') + pixiv_ranking_default_range: Sequence[int] = [1, 3] + pixiv_ranking_fetch_item: int = 150 + pixiv_ranking_max_item_per_query: int = 10 + + @compatible_field_validator('pixiv_ranking_default_range') + def ranking_default_range_validator(cls, v, values, field: dict): + if len(v) != 2 or v[0] > v[1]: + raise ValueError(f'illegal {field["name"]} value: {v}') return v - pixiv_random_illust_query_enabled = True - pixiv_random_illust_method = RandomIllustMethod.bookmark_proportion - pixiv_random_illust_min_bookmark = 0 - pixiv_random_illust_min_view = 0 - pixiv_random_illust_max_page = 20 - pixiv_random_illust_max_item = 500 - - pixiv_random_recommended_illust_query_enabled = True - pixiv_random_recommended_illust_method = RandomIllustMethod.uniform - pixiv_random_recommended_illust_min_bookmark = 0 - pixiv_random_recommended_illust_min_view = 0 - pixiv_random_recommended_illust_max_page = 40 - pixiv_random_recommended_illust_max_item = 1000 - - pixiv_random_related_illust_query_enabled = True - pixiv_random_related_illust_method = RandomIllustMethod.bookmark_proportion - pixiv_random_related_illust_min_bookmark = 0 - pixiv_random_related_illust_min_view = 0 - pixiv_random_related_illust_max_page = 4 - pixiv_random_related_illust_max_item = 100 - - pixiv_random_user_illust_query_enabled = True - pixiv_random_user_illust_method = RandomIllustMethod.timedelta_proportion - pixiv_random_user_illust_min_bookmark = 0 - pixiv_random_user_illust_min_view = 0 - pixiv_random_user_illust_max_page = 2 ** 31 - pixiv_random_user_illust_max_item = 2 ** 31 - - pixiv_random_bookmark_query_enabled = True + pixiv_random_illust_query_enabled: bool = True + pixiv_random_illust_method: RandomIllustMethod = RandomIllustMethod.bookmark_proportion + pixiv_random_illust_min_bookmark: int = 0 + pixiv_random_illust_min_view: int = 0 + pixiv_random_illust_max_page: int = 20 + pixiv_random_illust_max_item: int = 500 + + pixiv_random_recommended_illust_query_enabled: bool = True + pixiv_random_recommended_illust_method: RandomIllustMethod = RandomIllustMethod.uniform + pixiv_random_recommended_illust_min_bookmark: int = 0 + pixiv_random_recommended_illust_min_view: int = 0 + pixiv_random_recommended_illust_max_page: int = 40 + pixiv_random_recommended_illust_max_item: int = 1000 + + pixiv_random_related_illust_query_enabled: bool = True + pixiv_random_related_illust_method: RandomIllustMethod = RandomIllustMethod.bookmark_proportion + pixiv_random_related_illust_min_bookmark: int = 0 + pixiv_random_related_illust_min_view: int = 0 + pixiv_random_related_illust_max_page: int = 4 + pixiv_random_related_illust_max_item: int = 100 + + pixiv_random_user_illust_query_enabled: bool = True + pixiv_random_user_illust_method: RandomIllustMethod = RandomIllustMethod.timedelta_proportion + pixiv_random_user_illust_min_bookmark: int = 0 + pixiv_random_user_illust_min_view: int = 0 + pixiv_random_user_illust_max_page: int = 2 ** 31 + pixiv_random_user_illust_max_item: int = 2 ** 31 + + pixiv_random_bookmark_query_enabled: bool = True pixiv_random_bookmark_user_id: Optional[int] = None - pixiv_random_bookmark_method = RandomIllustMethod.uniform - pixiv_random_bookmark_min_bookmark = 0 - pixiv_random_bookmark_min_view = 0 - pixiv_random_bookmark_max_page = 2 ** 31 - pixiv_random_bookmark_max_item = 2 ** 31 - - pixiv_random_following_illust_query_enabled = True - pixiv_random_following_illust_method = RandomIllustMethod.timedelta_proportion - pixiv_random_following_illust_min_bookmark = 0 - pixiv_random_following_illust_min_view = 0 - pixiv_random_following_illust_max_page = 2 ** 31 - pixiv_random_following_illust_max_item = 2 ** 31 - - pixiv_watch_interval = 600 - - access_control_reply_on_permission_denied: Optional[str] - access_control_reply_on_rate_limited: Optional[str] + pixiv_random_bookmark_method: RandomIllustMethod = RandomIllustMethod.uniform + pixiv_random_bookmark_min_bookmark: int = 0 + pixiv_random_bookmark_min_view: int = 0 + pixiv_random_bookmark_max_page: int = 2 ** 31 + pixiv_random_bookmark_max_item: int = 2 ** 31 + + pixiv_random_following_illust_query_enabled: bool = True + pixiv_random_following_illust_method: RandomIllustMethod = RandomIllustMethod.timedelta_proportion + pixiv_random_following_illust_min_bookmark: int = 0 + pixiv_random_following_illust_min_view: int = 0 + pixiv_random_following_illust_max_page: int = 2 ** 31 + pixiv_random_following_illust_max_item: int = 2 ** 31 + + pixiv_watch_interval: int = 600 + + access_control_reply_on_permission_denied: Optional[str] = None + access_control_reply_on_rate_limited: Optional[str] = None class Config: extra = "ignore" diff --git a/src/nonebot_plugin_pixivbot/data/pixiv_repo/mediator_repo.py b/src/nonebot_plugin_pixivbot/data/pixiv_repo/mediator_repo.py index 18be4f0f..58910052 100644 --- a/src/nonebot_plugin_pixivbot/data/pixiv_repo/mediator_repo.py +++ b/src/nonebot_plugin_pixivbot/data/pixiv_repo/mediator_repo.py @@ -5,6 +5,7 @@ from nonebot import logger from pydantic import BaseModel +from nonebot.compat import PYDANTIC_V2 from nonebot_plugin_pixivbot.config import Config from nonebot_plugin_pixivbot.enums import RankingMode from nonebot_plugin_pixivbot.global_context import context @@ -36,6 +37,7 @@ def __str__(self): class Config: frozen = True + arbitrary_types_allowed = True class PixivSharedAsyncGeneratorManager(SharedAsyncGeneratorManager[SharedAgenIdentifier, Any]): diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 00000000..fccbfab8 --- /dev/null +++ b/src/tests/__init__.py @@ -0,0 +1,10 @@ +import pytest + + +class MyTest: + @pytest.fixture(autouse=True) + def load_pixivbot(self, nonebug_init): + import nonebot # 这里的导入必须在函数内 + + # 加载插件 + return nonebot.load_plugins("nonebot_plugin_pixivbot") diff --git a/src/tests/conftest.py b/src/tests/conftest.py new file mode 100644 index 00000000..73e8dcdc --- /dev/null +++ b/src/tests/conftest.py @@ -0,0 +1,7 @@ +import pytest + + +@pytest.fixture(autouse=True) +def conf_env(monkeypatch): + monkeypatch.setenv("PIXIV_REFRESH_TOKEN", "123") + monkeypatch.setenv("SUPERUSERS", "[\"test:123456\"]") diff --git a/src/tests/test_context.py b/src/tests/test_context.py new file mode 100644 index 00000000..0a3f8eff --- /dev/null +++ b/src/tests/test_context.py @@ -0,0 +1,83 @@ +from unittest.mock import MagicMock + +import pytest + +from tests import MyTest + +cnt = 0 + + +class A: + def __init__(self, data): + global cnt + cnt += 1 + self.data = data + + def hello(self): + return self.data + + +class B(A): + def __init__(self, data): + super().__init__(data) + + def hello(self): + return "Hello " + str(self.data) + + +class TestContext(MyTest): + @pytest.fixture + def context(self): + from nonebot_plugin_pixivbot.context import Context + + context = Context() + return context + + def test_register_require_contains(self, context): + context.register(A, A(1)) + assert context.require(A).hello() == 1 + assert A in context + + def test_register_lazy(self, context): + initializer = MagicMock(side_effect=lambda: A(2)) + context.register_lazy(A, initializer) + initializer.assert_not_called() + assert context.require(A).hello() == 2 + initializer.assert_called_once() + + def test_register_singleton(self, context): + old_cnt = cnt + context.register_singleton(3)(A) + assert cnt == old_cnt + assert context.require(A).hello() == 3 + assert cnt == old_cnt + 1 + + def test_register_eager_singleton(self, context): + old_cnt = cnt + context.register_eager_singleton(4)(A) + assert cnt == old_cnt + 1 + assert context.require(A).hello() == 4 + assert cnt == old_cnt + 1 + + def test_bind_to(self, context): + context.register(B, B("world")) + context.bind(A, B) + + assert context.require(A).hello() == "Hello world" + + def test_bind_instance(self, context): + @context.bind_singleton_to(B, "world") + class C(B): + def __init__(self, data): + super().__init__(data) + + assert context.require(C).hello() == "Hello world" + + def test_parent(self, context): + from nonebot_plugin_pixivbot.context import Context + second = Context(context) + third = Context(second) + + context.register(A, A(10)) + assert third.require(A).hello() == 10 + assert A in third diff --git a/src/tests/utils/__init__.py b/src/tests/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/tests/utils/test_expires_lru_dict.py b/src/tests/utils/test_expires_lru_dict.py new file mode 100644 index 00000000..42f02481 --- /dev/null +++ b/src/tests/utils/test_expires_lru_dict.py @@ -0,0 +1,138 @@ +from asyncio import sleep +from datetime import datetime, timedelta, timezone +from unittest.mock import MagicMock + +import pytest + +from tests import MyTest + + +class TestExpiresLruDict(MyTest): + @pytest.fixture + def lru(self): + from nonebot_plugin_pixivbot.utils.expires_lru_dict import AsyncExpiresLruDict + + lru = AsyncExpiresLruDict(10) + lru.on_cleanup = MagicMock() + + async def side_effect(*args, **kwargs): + pass + + lru.on_cleanup.side_effect = side_effect + return lru + + @pytest.mark.asyncio + async def test_expires(self, lru): + expires = datetime.now(timezone.utc) + timedelta(seconds=1) + await lru.add("hello", "world", expires) + assert await lru.get("hello") == "world" + + await sleep(2) + assert await lru.get("hello") is None + lru.on_cleanup.assert_called_once_with("hello", "world") + + expires = datetime.now(timezone.utc) + timedelta(seconds=30) + await lru.add("hello", "test", expires) + assert await lru.get("hello") == "test" + + @pytest.mark.asyncio + async def test_lru(self, lru): + expires = datetime.now(timezone.utc) + timedelta(seconds=3) + for i in range(11): + await lru.add(i, i, expires) + + assert await lru.get(0) is None + lru.on_cleanup.assert_called_once_with(0, 0) + for i in range(1, 11): + assert await lru.get(i) == i + + @pytest.mark.asyncio + async def test_expires_lru(self, lru): + now = datetime.now(timezone.utc) + for i in range(5): + await lru.add(i, i, now + timedelta(seconds=2)) + for i in range(5, 10): + await lru.add(i, i, now + timedelta(seconds=20)) + # except: 0 1 2 3 4 5 6 7 8 9 + + await sleep(3) + for i in range(5): + assert await lru.get(i) is None + for i in range(5, 10): + assert await lru.get(i) == i + # except: 5 6 7 8 9 + + now = datetime.now(timezone.utc) + for i in range(10, 18): + await lru.add(i, i, now + timedelta(seconds=20)) + # except: 8 9 10 11 12 13 14 15 16 17 + + for i in range(5, 8): + assert await lru.get(i) is None + for i in range(8, 18): + assert await lru.get(i) == i + + @pytest.mark.asyncio + async def test_set(self, lru): + now = datetime.now(timezone.utc) + + await lru.add("hello", "world", now + timedelta(seconds=1)) + assert await lru.get("hello") == "world" + + await lru.set("hello", "python") + assert await lru.get("hello") == "python" + + @pytest.mark.asyncio + async def test_add_key_error(self, lru): + now = datetime.now(timezone.utc) + await lru.add("test", "py", now + timedelta(seconds=1)) + with pytest.raises(KeyError): + await lru.add("test", "pyyy", now + timedelta(seconds=1)) + + @pytest.mark.asyncio + async def test_set_key_error(self, lru): + with pytest.raises(KeyError): + await lru.set("test", "py") + + @pytest.mark.asyncio + async def test_del(self, lru): + now = datetime.now(timezone.utc) + + await lru.add("hello", "world", now + timedelta(seconds=1)) + await lru.pop("hello") + assert await lru.get("hello") is None + + await lru.add("hello", "python", now + timedelta(seconds=30)) + await sleep(1.5) + assert await lru.get("hello") == "python" + + @pytest.mark.asyncio + async def test_del2(self, lru): + now = datetime.now(timezone.utc) + + await lru.add("hello", "world", now + timedelta(seconds=1)) + await lru.pop("hello") + assert await lru.get("hello") is None + + await lru.add("hello", "python", now + timedelta(seconds=1)) + assert await lru.get("hello") == "python" + + await sleep(1.5) + assert await lru.get("hello") is None + + @pytest.mark.asyncio + async def test_collate_expires_heap(self, lru): + now = datetime.now(timezone.utc) + for i in range(1, 21): + await lru.add(i, i, now + timedelta(milliseconds=100 * i)) + print(len(lru._expires_heap)) + + await sleep(3) + + now = datetime.now(timezone.utc) + await lru.add("hello", "world", now + timedelta(seconds=20)) + + for i in range(1, 21): + assert await lru.get(i) is None + + assert await lru.get("hello") == "world" diff --git a/src/tests/utils/test_lazy_delegation.py b/src/tests/utils/test_lazy_delegation.py new file mode 100644 index 00000000..f959d10d --- /dev/null +++ b/src/tests/utils/test_lazy_delegation.py @@ -0,0 +1,24 @@ +from unittest.mock import MagicMock + +from tests import MyTest + + +class TestLazyDelegation(MyTest): + def test_lazy_delegation(self): + from nonebot_plugin_pixivbot.utils.lazy_delegation import LazyDelegation + + class A: + def __init__(self): + self.hello = "world" + self.cache = "cache" + self.builder = "builder" + + builder = MagicMock(return_value=A()) + delegation = LazyDelegation(builder) + + builder.assert_not_called() + assert delegation.hello == "world" + builder.assert_called() + + assert delegation.cache == "cache" + assert delegation.builder == "builder" diff --git a/src/tests/utils/test_shared_agen.py b/src/tests/utils/test_shared_agen.py new file mode 100644 index 00000000..8efd0747 --- /dev/null +++ b/src/tests/utils/test_shared_agen.py @@ -0,0 +1,220 @@ +# from asyncio import sleep, create_task, gather +# from datetime import datetime, timedelta, timezone +# from typing import AsyncGenerator +# from unittest.mock import MagicMock, AsyncMock, call +# +# import pytest +# +# from tests import MyTest +# +# +# class TestSharedAsyncGeneratorContextManager(MyTest): +# @pytest.fixture +# def origin_agen(self): +# cnt = 0 +# +# async def agen(): +# nonlocal cnt +# for i in range(10): +# await sleep(0.1) +# yield cnt +# cnt += 1 +# +# return agen() +# +# @pytest.fixture +# def origin_agen_raises(self): +# cnt = 0 +# +# async def agen(): +# nonlocal cnt +# for i in range(10): +# await sleep(0.1) +# yield cnt +# cnt += 1 +# raise RuntimeError() +# +# return agen() +# +# @pytest.fixture +# def ctx_mgr_factory(self): +# from nonebot_plugin_pixivbot.utils.shared_agen import SharedAsyncGeneratorHolder +# +# def factory(origin_agen): +# on_each = AsyncMock() +# on_stop = AsyncMock() +# on_error = AsyncMock() +# on_consumers_changed = MagicMock() +# +# # noinspection PyTypeChecker +# return SharedAsyncGeneratorHolder( +# origin_agen, +# on_each=on_each, +# on_stop=on_stop, +# on_error=on_error, +# on_consumers_changed=on_consumers_changed +# ) +# +# return factory +# +# @pytest.mark.asyncio +# async def test_on_each_and_on_stop(self, ctx_mgr_factory, origin_agen): +# ctx_mgr = ctx_mgr_factory(origin_agen) +# with ctx_mgr as iter: +# items = [i async for i in iter] +# +# # noinspection PyUnresolvedReferences +# ctx_mgr._on_each.assert_has_awaits([call(i) for i in range(10)]) +# # noinspection PyUnresolvedReferences +# ctx_mgr._on_stop.assert_awaited_once_with([i for i in range(10)]) +# +# @pytest.mark.asyncio +# async def test_on_error(self, ctx_mgr_factory, origin_agen_raises): +# ctx_mgr = ctx_mgr_factory(origin_agen_raises) +# with pytest.raises(RuntimeError) as e: +# with ctx_mgr as iter: +# items = [i async for i in iter] +# +# # noinspection PyUnresolvedReferences +# ctx_mgr._on_error.assert_awaited_once_with(e) +# +# @pytest.mark.asyncio +# async def test_single_consumer(self, ctx_mgr_factory, origin_agen): +# ctx_mgr = ctx_mgr_factory(origin_agen) +# with ctx_mgr as iter: +# items = [i async for i in iter] +# +# assert items == [i for i in range(10)] +# +# # noinspection PyTypeChecker +# on_consumers_changed: MagicMock = ctx_mgr._on_consumers_changed +# assert on_consumers_changed.call_args_list[0].args == (ctx_mgr, 1) +# assert on_consumers_changed.call_args_list[1].args == (ctx_mgr, 0) +# +# @pytest.mark.asyncio +# async def test_multi_consumer(self, ctx_mgr_factory, origin_agen): +# ctx_mgr = ctx_mgr_factory(origin_agen) +# +# async def consume(): +# with ctx_mgr as iter: +# items = [i async for i in iter] +# +# assert items == [i for i in range(10)] +# +# # consumer2 except to wait for all the 10 items together +# consumer1 = create_task(consume()) +# await sleep(0.25) +# +# # consumer2 except to get 2 generated items, then wait for the rest 8 items together +# consumer2 = create_task(consume()) +# +# # consumer3 begin collecting after the agen stopped +# await sleep(1.5) +# consumer3 = create_task(consume()) +# +# await gather(consumer1, consumer2, consumer3) +# +# # noinspection PyTypeChecker +# on_consumers_changed: MagicMock = ctx_mgr._on_consumers_changed +# assert on_consumers_changed.call_args_list[0].args == (ctx_mgr, 1) +# assert on_consumers_changed.call_args_list[1].args == (ctx_mgr, 2) +# assert on_consumers_changed.call_args_list[2].args == (ctx_mgr, 1) +# assert on_consumers_changed.call_args_list[3].args == (ctx_mgr, 0) +# assert on_consumers_changed.call_args_list[4].args == (ctx_mgr, 1) +# assert on_consumers_changed.call_args_list[5].args == (ctx_mgr, 0) +# +# @pytest.mark.asyncio +# async def test_close(self, ctx_mgr_factory, origin_agen): +# ctx_mgr = ctx_mgr_factory(origin_agen) +# with ctx_mgr as iter: +# await iter.__anext__() +# await iter.__anext__() +# +# ctx_mgr.close() +# +# with ctx_mgr as iter: +# await iter.__anext__() +# await iter.__anext__() +# with pytest.raises(StopAsyncIteration): +# await iter.__anext__() +# +# +# class TestSharedAsyncGeneratorManager(MyTest): +# @pytest.fixture +# def shared_agen_mgr(self): +# from nonebot_plugin_pixivbot.utils.shared_agen import SharedAsyncGeneratorManager +# +# class SharedAsyncGeneratorManagerImpl(SharedAsyncGeneratorManager[int, int]): +# def agen(self, identifier: int, *args, **kwargs) -> AsyncGenerator[int, None]: +# async def agen(): +# cnt = identifier +# for i in range(10): +# await sleep(0.1) +# yield cnt +# cnt += 1 +# +# return agen() +# +# impl = SharedAsyncGeneratorManagerImpl() +# impl.on_agen_next = AsyncMock() +# impl.on_agen_stop = AsyncMock() +# return impl +# +# @pytest.mark.asyncio +# async def test_get(self, shared_agen_mgr): +# # except same +# inst = shared_agen_mgr.get(0) +# with inst as iter: +# inst2 = shared_agen_mgr.get(0) +# with inst2 as iter2: +# assert inst == inst2 +# +# # prev inst was except to be destroyed +# +# inst3 = shared_agen_mgr.get(0) +# assert inst != inst3 +# +# @pytest.mark.asyncio +# async def test_set_expires_time(self, shared_agen_mgr): +# inst = shared_agen_mgr.get(0) +# with inst as iter: +# await iter.__anext__() +# await iter.__anext__() +# +# await shared_agen_mgr.set_expires_time(0, datetime.now(timezone.utc) + timedelta(seconds=1)) +# +# # prev inst was except to be saved +# +# inst2 = shared_agen_mgr.get(0) +# assert inst == inst2 +# +# await sleep(1.5) +# +# # prev inst was except to be removed +# +# inst2 = shared_agen_mgr.get(0) +# assert inst != inst2 +# +# @pytest.mark.asyncio +# async def test_invalidate(self, shared_agen_mgr): +# inst = shared_agen_mgr.get(0) +# with inst as iter: +# await iter.__anext__() +# await iter.__anext__() +# +# await shared_agen_mgr.set_expires_time(0, datetime.now(timezone.utc) + timedelta(seconds=1)) +# +# # prev inst was except to be saved +# +# inst2 = shared_agen_mgr.get(0) +# assert inst == inst2 +# +# await shared_agen_mgr.invalidate(0) +# +# # prev inst was except to be removed +# +# inst2 = shared_agen_mgr.get(0) +# assert inst != inst2 +# +# # invalidate a non-existing key should not raise +# await shared_agen_mgr.invalidate(114514)