diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d39b0ef..866765b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,70 +1,98 @@ -exclude: '^.*\.(md|MD|xml|yml|yaml|json|ini|cfg|txt)$|^\.idea/' +exclude: '^.*\.(md|MD|xml|ini|cfg|txt)$|^\.idea/' repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: trailing-whitespace - # 删除行尾空格 - - id: check-added-large-files - # 检查是否有大文件被错误地添加到git - - id: end-of-file-fixer - # 确保文件以一个空行结尾 - - id: mixed-line-ending - # 统一文件的行结束符(例如,将CRLF转换为LF) - args: ["--fix=lf"] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + # 检查YAML文件是否格式正确 + - id: check-json + # 检查JSON文件是否格式正确 + - id: trailing-whitespace + # 删除行尾空格 + - id: check-added-large-files + # 检查是否有大文件被错误地添加到git + - id: end-of-file-fixer + # 确保文件以一个空行结尾 + - id: mixed-line-ending + # 统一文件的行结束符(例如,将CRLF转换为LF) + args: [ "--fix=lf" ] - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - # 对Python的import语句进行排序和格式化 - args: - [ - "--profile", - "black", - "--multi-line=3", - "--trailing-comma", - "--force-grid-wrap=0", - "--use-parentheses", - "--line-width=88", - ] + - repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + files: \.(py|sh|rst|yml|yaml)$ - - repo: https://github.com/myint/autoflake.git - rev: v2.2.1 - hooks: - - id: autoflake - # 移除未使用的导入和变量 - args: - [ - "--in-place", - "--remove-all-unused-imports", - "--ignore-init-module-imports", - ] + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + # 对Python的import语句进行排序和格式化 + args: + [ + "--profile", + "black", + "--multi-line=3", + "--trailing-comma", + "--force-grid-wrap=0", + "--use-parentheses", + "--line-width=88", + ] - - repo: https://github.com/psf/black - rev: "23.12.1" - hooks: - - id: black - # 自动格式化Python代码,符合PEP 8风格指南 + - repo: https://github.com/myint/autoflake.git + rev: v2.2.1 + hooks: + - id: autoflake + # 移除未使用的导入和变量 + args: + [ + "--in-place", + "--remove-all-unused-imports", + "--ignore-init-module-imports", + ] - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 - hooks: - - id: pyupgrade - # 将Python代码升级到新版本的Python语法 - args: ["--py310-plus"] + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + # 将Python代码升级到新版本的Python语法 + args: [ "--py310-plus" ] - - repo: https://github.com/commitizen-tools/commitizen - rev: v3.13.0 - hooks: - - id: commitizen - # 确保commit信息遵循Conventional Commits标准 - stages: [commit-msg] + - repo: https://github.com/psf/black + rev: "23.12.1" + hooks: + - id: black + # 自动格式化Python代码,符合PEP 8风格指南 + args: [--line-length=88] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 - hooks: - - id: mypy - args: [--ignore-missing-imports,--disallow-untyped-defs, --show-error-codes ] + - repo: https://github.com/commitizen-tools/commitizen + rev: v3.13.0 + hooks: + - id: commitizen + # 确保commit信息遵循Conventional Commits标准 + stages: [ commit-msg ] + + - repo: 'https://github.com/PyCQA/flake8' + rev: 7.0.0 + hooks: + - id: flake8 + args: + - '--max-line-length=88' + - '--ignore=E203,W503,F401' + language: python + types: [ python ] + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + args: [ --ignore-missing-imports,--disallow-untyped-defs, --show-error-codes ] # additional_dependencies: [ types-requests, types-setuptools ] # 如果需要额外的类型存根 +ci: + # Settings for the https://pre-commit.ci/ continuous integration service + autofix_prs: false + # Default message is more verbose + autoupdate_commit_msg: '[pre-commit.ci] autoupdate' + # Default is weekly + autoupdate_schedule: monthly diff --git a/poetry.lock b/poetry.lock index 61e8aa0..98ef2fa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -168,19 +168,6 @@ files = [ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] -[[package]] -name = "asyncio" -version = "3.4.3" -description = "reference implementation of PEP 3156" -optional = false -python-versions = "*" -files = [ - {file = "asyncio-3.4.3-cp33-none-win32.whl", hash = "sha256:b62c9157d36187eca799c378e572c969f0da87cd5fc42ca372d92cdb06e7e1de"}, - {file = "asyncio-3.4.3-cp33-none-win_amd64.whl", hash = "sha256:c46a87b48213d7464f22d9a497b9eef8c1928b68320a2fa94240f969f6fec08c"}, - {file = "asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d"}, - {file = "asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41"}, -] - [[package]] name = "attrs" version = "23.2.0" @@ -200,67 +187,6 @@ 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 = "autoflake" -version = "2.2.1" -description = "Removes unused imports and unused variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, - {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, -] - -[package.dependencies] -pyflakes = ">=3.0.0" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} - -[[package]] -name = "black" -version = "23.12.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[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 = "certifi" version = "2023.11.17" @@ -967,29 +893,15 @@ files = [ {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.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1185,64 +1097,6 @@ files = [ {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] -[[package]] -name = "mypy" -version = "1.8.0" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - -[[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 = "nodeenv" version = "1.8.0" @@ -1282,17 +1136,6 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] -[[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.1.0" @@ -1325,13 +1168,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "postgrest" -version = "0.13.1" +version = "0.13.2" description = "PostgREST client for Python. This library provides an ORM interface to PostgREST." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "postgrest-0.13.1-py3-none-any.whl", hash = "sha256:d84533c48b37c05f95aacd4c4a5c211f2ae30e7e4f42b21374f2f6ebe622ca19"}, - {file = "postgrest-0.13.1.tar.gz", hash = "sha256:bd2078d899f29525fb8d5450f1a349058d8a87dea1528da00032a8afd6273bdf"}, + {file = "postgrest-0.13.2-py3-none-any.whl", hash = "sha256:a1a120ca982617d90c8906b85e2731fac4a3a3a5c7a3ca1095fe1cebd0bc02be"}, + {file = "postgrest-0.13.2.tar.gz", hash = "sha256:aaaec0fd7e4745dc02c77e1b310689fcdfb669e43b4cb36d462221dc1d19a1bf"}, ] [package.dependencies] @@ -1535,17 +1378,6 @@ files = [ pydantic = ">=2.3.0" python-dotenv = ">=0.21.0" -[[package]] -name = "pyflakes" -version = "3.2.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, - {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, -] - [[package]] name = "pygments" version = "2.17.2" @@ -1707,20 +1539,6 @@ docs = ["Sphinx (<=6.0.0)", "furo (>=2023.3.27)", "sphinx-autobuild (==2021.03.1 mypy = ["mypy", "types-requests"] test = ["coverage[toml] (>=6,<8)", "pytest (>=7,<8)", "pytest-clarity (>=1.0.1)", "pytest-cov (>=4,<5)", "pytest-lazy-fixture (>=0.6.3,<0.7.0)", "pytest-mock (>=3,<4)", "pytest-pretty (>=1.2.0,<2)", "pytest-xdist (>=2,<4)", "requests-mock (>=1.10.0,<2)", "responses (==0.23.3)", "types-pytest-lazy-fixture (>=0.6.3.3)"] -[[package]] -name = "pyupgrade" -version = "3.15.0" -description = "A tool to automatically upgrade syntax for newer versions." -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "pyupgrade-3.15.0-py2.py3-none-any.whl", hash = "sha256:8dc8ebfaed43566e2c65994162795017c7db11f531558a74bc8aa077907bc305"}, - {file = "pyupgrade-3.15.0.tar.gz", hash = "sha256:a7fde381060d7c224f55aef7a30fae5ac93bbc428367d27e70a603bc2acd4f00"}, -] - -[package.dependencies] -tokenize-rt = ">=5.2.0" - [[package]] name = "pyyaml" version = "6.0.1" @@ -1986,13 +1804,13 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "supabase-py-async" -version = "2.3.1" +version = "2.4.2" description = "supabase-py with async synax" optional = false python-versions = ">=3.9,<4.0" files = [ - {file = "supabase_py_async-2.3.1-py3-none-any.whl", hash = "sha256:92ea5c6ea39fd278132f4b79b6eb081800ccd08d46a6dd8646d0faa371ba79b9"}, - {file = "supabase_py_async-2.3.1.tar.gz", hash = "sha256:6c761339f5c6e6dae9fe52d1af33fe1cc11dfce4fc083a27883154aaf06cdf15"}, + {file = "supabase_py_async-2.4.2-py3-none-any.whl", hash = "sha256:b1227cdd1fc02808d7be8d66b7faaeb378ee62d2243f46e4a7bd70974ad516e3"}, + {file = "supabase_py_async-2.4.2.tar.gz", hash = "sha256:7e4abb68907a90a2b87f73d31deb76c89d199300c083fba66e861e40bd997ee3"}, ] [package.dependencies] @@ -2033,17 +1851,6 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] -[[package]] -name = "tokenize-rt" -version = "5.2.0" -description = "A wrapper around the stdlib `tokenize` which roundtrips." -optional = false -python-versions = ">=3.8" -files = [ - {file = "tokenize_rt-5.2.0-py2.py3-none-any.whl", hash = "sha256:b79d41a65cfec71285433511b50271b05da3584a1da144a0752e9c621a285289"}, - {file = "tokenize_rt-5.2.0.tar.gz", hash = "sha256:9fe80f8a5c1edad2d3ede0f37481cc0cc1538a2f442c9c2f9e4feacd2792d054"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -2363,4 +2170,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "ef4eb0cad31a854839fdbaa1d1464d481c51c178a4880e672ba1afff1bc429b8" +content-hash = "6132a11fd78691d039925404671a6d84a7cdea4514a8d9e29f361cdefa2c1e71" diff --git a/poetry_scripts.py b/poetry_scripts.py index 412179d..7fa5a0c 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -11,7 +11,9 @@ def run_tests() -> None: # Run pre-commit tests # run_cmd("poetry run pre-commit autoupdate") - run_cmd("poetry run pre-commit run --all-files") + # run_cmd("poetry run pre-commit clean") + # run_cmd("poetry run pre-commit install") + # run_cmd("poetry run pre-commit run --all-files") # Generate coverage report --cov=./ --cov-report=xml --cov-report=html -vv run_cmd("poetry run pytest --cov=./ --cov-report=xml --cov-report=html -vv") diff --git a/pyproject.toml b/pyproject.toml index ae7730d..53d82c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,33 +9,27 @@ packages = [{include = "app", from = "src"}] [tool.poetry.dependencies] python = ">=3.9,<3.13" fastapi = {extras = ["full"], version = "^0.108.0"} -supabase-py-async = "*" python-dotenv = "^1.0.0" uvicorn = "^0.25.0" pydantic = {extras = ["email"], version = "^2.5.3"} pydantic-settings = "^2.1.0" python-multipart = "^0.0.6" +supabase-py-async = "*" [tool.poetry.group.dev.dependencies] pytest-dotenv = "^0.5.2" pytest = "^7.4.3" faker = "^22.2.0" -isort = "^5.13.2" -autoflake = "^2.2.1" -pyupgrade = "^3.15.0" -black = "^23.12.1" python-semantic-release = "^8.7.0" pre-commit = "^3.6.0" pytest-cov = "^4.1.0" -mypy = "^1.8.0" -commitizen = "^3.13.0" -asyncio = "^3.4.3" anyio = "^4.2.0" trio = "^0.24.0" + [tool.poetry.scripts] tests = 'poetry_scripts:run_tests' diff --git a/src/app/api/api_v1/endpoints/items.py b/src/app/api/api_v1/endpoints/items.py index e8e1a3c..ba60cda 100644 --- a/src/app/api/api_v1/endpoints/items.py +++ b/src/app/api/api_v1/endpoints/items.py @@ -14,7 +14,7 @@ async def create_item(item_in: ItemCreate, session: SessionDep) -> Item: @router.get("/read-item", response_model=list[Item]) async def read_items(session: SessionDep) -> list[Item]: - return await item.get_multi_by_table_name(session) + return await item.get_all(session) @router.put("/update-item", response_model=Item) diff --git a/src/app/api/deps.py b/src/app/api/deps.py index dd545e2..ef1c13d 100644 --- a/src/app/api/deps.py +++ b/src/app/api/deps.py @@ -18,7 +18,7 @@ from app.core.events import super_client reusable_oauth2 = OAuth2PasswordBearer( - tokenUrl=f"please login by supabase-js to get token" + tokenUrl="please login by supabase-js to get token" ) TokenDep = Annotated[str, Depends(reusable_oauth2)] diff --git a/src/app/core/config.py b/src/app/core/config.py index c58e8de..a0e6328 100644 --- a/src/app/core/config.py +++ b/src/app/core/config.py @@ -7,9 +7,10 @@ """ import logging import os +from typing import ClassVar from dotenv import load_dotenv -from pydantic import AnyHttpUrl, Field +from pydantic import AnyHttpUrl, ConfigDict, Field from pydantic_settings import BaseSettings log_format = logging.Formatter("%(asctime)s : %(levelname)s - %(message)s") @@ -55,6 +56,7 @@ class Settings(BaseSettings): # """sensitive to lowercase""" # # case_sensitive = True + Config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) settings = Settings() diff --git a/src/app/crud/base.py b/src/app/crud/base.py index 9eeb055..71ac6d5 100644 --- a/src/app/crud/base.py +++ b/src/app/crud/base.py @@ -1,4 +1,3 @@ -import logging from typing import Generic, TypeVar from supabase_py_async import AsyncClient @@ -14,21 +13,40 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): def __init__(self, model: type[ModelType]): self.model = model - async def get(self, db: AsyncClient, *, id: str) -> ModelType: - """get by table_name""" + async def get(self, db: AsyncClient, *, id: str) -> ModelType | None: + """get by table_name by id""" data, count = ( await db.table(self.model.table_name).select("*").eq("id", id).execute() ) - return self.model(**data[0]) + _, got = data + return self.model(**got[0]) if got else None + + async def get_all(self, db: AsyncClient) -> list[ModelType]: + """get all by table_name""" + data, count = await db.table(self.model.table_name).select("*").execute() + _, got = data + return [self.model(**item) for item in got] + + async def get_multi_by_owner(self, db: AsyncClient) -> list[ModelType]: + """get by owner,use it if rls failed to use""" + user_rps = await db.auth.get_user() + user_id = user_rps.user.id + data, count = ( + await db.table(self.model.table_name) + .select("*") + .eq("user_id", user_id) + .execute() + ) + _, got = data + return [self.model(**item) for item in got] async def create(self, db: AsyncClient, *, obj_in: CreateSchemaType) -> ModelType: """create by CreateSchemaType""" - # FIXME: create with wrong url - logging.info(obj_in.model_dump()) data, count = ( await db.table(self.model.table_name).insert(obj_in.model_dump()).execute() ) - return self.model(**data[0]) + _, created = data + return self.model(**created[0]) async def update(self, db: AsyncClient, *, obj_in: UpdateSchemaType) -> ModelType: """update by UpdateSchemaType""" @@ -38,11 +56,13 @@ async def update(self, db: AsyncClient, *, obj_in: UpdateSchemaType) -> ModelTyp .eq("id", obj_in.id) .execute() ) - return self.model(**data[0]) + _, updated = data + return self.model(**updated[0]) async def delete(self, db: AsyncClient, *, obj_in: UpdateSchemaType) -> ModelType: """remove by UpdateSchemaType""" data, count = ( await db.table(self.model.table_name).delete().eq("id", obj_in.id).execute() ) - return self.model(**data[0]) + _, deleted = data + return self.model(**deleted[0]) diff --git a/src/app/crud/crud_item.py b/src/app/crud/crud_item.py index e8c25bd..8ad62e2 100644 --- a/src/app/crud/crud_item.py +++ b/src/app/crud/crud_item.py @@ -8,23 +8,14 @@ class CRUDItem(CRUDBase[Item, ItemCreate, ItemUpdate]): async def create(self, db: AsyncClient, *, obj_in: ItemCreate) -> Item: return await super().create(db, obj_in=obj_in) - async def get(self, db: AsyncClient, *, id: str) -> Item: + async def get(self, db: AsyncClient, *, id: str) -> Item | None: return await super().get(db, id=id) + async def get_all(self, db: AsyncClient) -> list[Item]: + return await super().get_all(db) + async def get_multi_by_owner(self, db: AsyncClient) -> list[Item]: - user_rps = await db.auth.get_user() - user_id = user_rps.user.id - data, count = ( - await db.table(self.model.table_name) - .select("*") - .eq("user_id", user_id) - .execute() - ) - return [self.model(**item) for item in data] - - async def get_multi_by_table_name(self, db: AsyncClient) -> list[Item]: - data, count = await db.table(self.model.table_name).select("*").execute() - return [self.model(**item) for item in data] + return await super().get_multi_by_owner(db) async def update(self, db: AsyncClient, *, obj_in: ItemUpdate) -> Item: return await super().update(db, obj_in=obj_in) diff --git a/src/app/schemas/auth.py b/src/app/schemas/auth.py index bfbfd9d..f8b5ad8 100644 --- a/src/app/schemas/auth.py +++ b/src/app/schemas/auth.py @@ -13,7 +13,7 @@ class Token(BaseModel): token_type: str -## request +# request # Properties to receive via API on creation # in class UserCreate(BaseModel): @@ -26,7 +26,7 @@ class UserUpdate(UserAttributes): pass -## response +# response class UserInDBBase(BaseModel): diff --git a/src/app/schemas/base.py b/src/app/schemas/base.py index 46e2888..418a751 100644 --- a/src/app/schemas/base.py +++ b/src/app/schemas/base.py @@ -5,9 +5,11 @@ @Date Created : 11/01/2024 @Description : """ -from pydantic import BaseModel, Extra +from typing import ClassVar -## request +from pydantic import BaseModel, ConfigDict + +# request # Shared properties @@ -32,7 +34,7 @@ class UpdateBase(BaseModel): id: str -## response +# response # Properties shared by models stored in DB @@ -47,9 +49,5 @@ class InDBBase(BaseModel): # out class ResponseBase(InDBBase): # inherent to add more properties for responding - @property - def table_name(self) -> str: - return self.__class__.__name__.lower() - - class Config: - extra = Extra.ignore + table_name: ClassVar[str] = "ResponseBase".lower() + Config: ClassVar[ConfigDict] = ConfigDict(extra="ignore") diff --git a/src/app/schemas/item.py b/src/app/schemas/item.py index a25f041..c6675df 100644 --- a/src/app/schemas/item.py +++ b/src/app/schemas/item.py @@ -1,7 +1,9 @@ +from typing import ClassVar + from app.schemas.base import CreateBase, InDBBase, ResponseBase, UpdateBase -## request +# request # Properties to receive on item creation # in class ItemCreate(CreateBase): @@ -20,10 +22,7 @@ class ItemUpdate(UpdateBase): class Item(ResponseBase): test_data: str - # note: if u directly define table_name in this class, will failed to get by class name - @property - def table_name(self) -> str: - return "test_table" + table_name: ClassVar[str] = "test_table" # Properties properties stored in DB diff --git a/tests/conftest.py b/tests/conftest.py index 2b701ff..125e616 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,9 +5,9 @@ from pathlib import Path import pytest -from _pytest.config import Config from dotenv import load_dotenv from fastapi.testclient import TestClient +from pydantic import ConfigDict from supabase_py_async import AsyncClient, create_client from app.main import app @@ -45,8 +45,13 @@ def setup_logging(level: int = logging.INFO) -> None: setup_logging() -def pytest_configure(config: Config) -> None: - load_dotenv(dotenv_path="tests/tests.env") +@pytest.fixture(scope="module") +def anyio_backend() -> str: + return "asyncio" + + +def pytest_configure(config: ConfigDict) -> None: + load_dotenv() @pytest.fixture(scope="module") @@ -67,7 +72,7 @@ async def db() -> AsyncGenerator[AsyncClient, None]: ) get_session = await db_client.auth.get_session() assert get_session.user is not None - logging.info("db_client.get_session", get_session.user.model_dump()) + # logging.info("db_client.get_session", get_session.user.model_dump()) try: yield db_client # 提供数据库客户端给测试用例 finally: diff --git a/tests/crud/test_item.py b/tests/crud/test_item.py index eaf79af..410e283 100644 --- a/tests/crud/test_item.py +++ b/tests/crud/test_item.py @@ -3,7 +3,7 @@ from supabase_py_async import AsyncClient from app import crud -from app.schemas.item import Item, ItemCreate +from app.schemas.item import Item, ItemCreate, ItemUpdate @pytest.mark.anyio @@ -14,39 +14,38 @@ async def test_create_item(db: AsyncClient) -> None: assert item.test_data == test_data -# -# @pytest.mark.anyio -# async def test_get_item(db: AsyncClient) -> None: -# test_data = Faker().text() -# item_in = ItemCreate(table_name="test_table", test_data=test_data) -# item: Item = await crud.item.create(db=db, obj_in=item_in) -# stored_item = await crud.item.get(db, table_name="test_table", id=item.id) -# assert stored_item -# assert item.id == stored_item.id -# assert item.test_data == stored_item.test_data -# -# -# @pytest.mark.anyio -# async def test_update_item(db: AsyncClient) -> None: -# test_data = Faker().text() -# item_in = ItemCreate(table_name="test_table", test_data=test_data) -# item: Item = await crud.item.create(db=db, obj_in=item_in) -# test_data2 = Faker().text() -# item_update = ItemUpdate(table_name="test_table", id=item.id, test_data=test_data2) -# item2 = await crud.item.update(db=db, obj_in=item_update) -# assert item.id == item2.id -# assert item.test_data == item2.test_data -# assert item2.test_data == test_data2 -# -# -# @pytest.mark.anyio -# async def test_delete_item(db: AsyncClient) -> None: -# test_data = Faker().text() -# item_in = ItemCreate(table_name="test_table", test_data=test_data) -# item: Item = await crud.item.create(db=db, obj_in=item_in) -# item2 = await crud.item.delete(db=db, obj_in=item) -# item3 = await crud.item.get(db, table_name="test_table", id=item.id) -# assert item3 is None -# assert item.id == item2.id -# assert item.test_data == item2.test_data -# assert item2.test_data == test_data +@pytest.mark.anyio +async def test_get_item(db: AsyncClient) -> None: + test_data = Faker().text() + item_in = ItemCreate(table_name="test_table", test_data=test_data) + item: Item = await crud.item.create(db=db, obj_in=item_in) + stored_item = await crud.item.get(db, id=item.id) + assert stored_item + assert item.id == stored_item.id + assert item.test_data == stored_item.test_data + + +@pytest.mark.anyio +async def test_update_item(db: AsyncClient) -> None: + test_data = Faker().text() + item_in = ItemCreate(table_name="test_table", test_data=test_data) + item: Item = await crud.item.create(db=db, obj_in=item_in) + test_data2 = Faker().text() + item_update = ItemUpdate(table_name="test_table", id=item.id, test_data=test_data2) + item2 = await crud.item.update(db=db, obj_in=item_update) + assert item.id == item2.id + assert item.test_data != item2.test_data + assert item2.test_data == test_data2 + + +@pytest.mark.anyio +async def test_delete_item(db: AsyncClient) -> None: + test_data = Faker().text() + item_in = ItemCreate(table_name="test_table", test_data=test_data) + item: Item = await crud.item.create(db=db, obj_in=item_in) + item2 = await crud.item.delete(db=db, obj_in=item) + item3 = await crud.item.get(db, id=item.id) + assert item3 is None + assert item.id == item2.id + assert item.test_data == item2.test_data + assert item2.test_data == test_data diff --git a/tests/tests.env b/tests/tests.env deleted file mode 100644 index c2caf80..0000000 --- a/tests/tests.env +++ /dev/null @@ -1,2 +0,0 @@ -SUPABASE_TEST_URL=https://vtqsboqphlisizfwhrtg.supabase.co -SUPABASE_TEST_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZ0cXNib3FwaGxpc2l6ZndocnRnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDQ1MzY4NzIsImV4cCI6MjAyMDExMjg3Mn0.OgApaTXDr7llopKTplpXCsUzDubjbiQFXlaaFf6wlbY