From 6386c2807da7039e0554379bab67a2c1b939872b Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Tue, 13 May 2025 14:33:46 +0300 Subject: [PATCH 01/10] add manager_dn, user_dn --- pybotx/client/users_api/user_from_csv.py | 6 ++++++ pybotx/models/users.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/pybotx/client/users_api/user_from_csv.py b/pybotx/client/users_api/user_from_csv.py index ba18e976..319ccea5 100644 --- a/pybotx/client/users_api/user_from_csv.py +++ b/pybotx/client/users_api/user_from_csv.py @@ -30,6 +30,8 @@ class BotXAPIUserFromCSVResult(VerifiedPayloadBaseModel): office: Optional[str] = Field(alias="Office") manager: Optional[str] = Field(alias="Manager") manager_huid: Optional[UUID] = Field(alias="Manager HUID") + manager_dn: Optional[str] = Field(alias="Manager DN") + user_dn: Optional[str] = Field(alias="User DN") description: Optional[str] = Field(alias="Description") phone: Optional[str] = Field(alias="Phone") other_phone: Optional[str] = Field(alias="Other phone") @@ -47,6 +49,7 @@ class BotXAPIUserFromCSVResult(VerifiedPayloadBaseModel): "office", "manager", "manager_huid", + "manager_dn", "description", "phone", "other_phone", @@ -80,6 +83,9 @@ def to_domain(self) -> UserFromCSV: office=self.office, manager=self.manager, manager_huid=self.manager_huid, + #TODO: remove else clause + manager_dn=self.manager_dn if self.manager_dn else str(self.manager_huid), + user_dn = self.user_dn if self.user_dn else str(self.huid), description=self.description, phone=self.phone, other_phone=self.other_phone, diff --git a/pybotx/models/users.py b/pybotx/models/users.py index 567a31c2..5bb6151f 100644 --- a/pybotx/models/users.py +++ b/pybotx/models/users.py @@ -79,6 +79,8 @@ class UserFromCSV: office: Office info. manager: User's manager full name. manager_huid: User's manager huid. + manager_dn: User's manager DN. + user_dn: User DN. description: Description. phone: Phone number. other_phone: Extra phone number. @@ -109,3 +111,6 @@ class UserFromCSV: ip_phone: Optional[str] = None other_ip_phone: Optional[str] = None personnel_number: Optional[str] = None + #TODO: remove Optional from user_dn + user_dn: Optional[str] = None + manager_dn: Optional[str] = None From 2df26ec6033c7c87fa7cc9106477fcd7d9c90e5d Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Tue, 13 May 2025 17:09:27 +0300 Subject: [PATCH 02/10] add manager_dn, user_dn --- pybotx/client/users_api/user_from_csv.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pybotx/client/users_api/user_from_csv.py b/pybotx/client/users_api/user_from_csv.py index 319ccea5..65f3df4d 100644 --- a/pybotx/client/users_api/user_from_csv.py +++ b/pybotx/client/users_api/user_from_csv.py @@ -83,8 +83,9 @@ def to_domain(self) -> UserFromCSV: office=self.office, manager=self.manager, manager_huid=self.manager_huid, - #TODO: remove else clause - manager_dn=self.manager_dn if self.manager_dn else str(self.manager_huid), + #TODO: fix manager_dn=self.manager_dn, + manager_dn=str(self.manager_huid), + # TODO: fix remove else clause user_dn = self.user_dn if self.user_dn else str(self.huid), description=self.description, phone=self.phone, From 6168f4f255b382b54f776e3c68b72df83564bae6 Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 15:08:04 +0300 Subject: [PATCH 03/10] refactor tests, fix lunters --- poetry.lock | 121 +++-------------- pybotx/client/users_api/user_from_csv.py | 6 +- pybotx/models/users.py | 2 +- pyproject.toml | 4 +- tests/client/users_api/conftest.py | 83 +++++++++++- tests/client/users_api/factories.py | 52 ++++++++ tests/client/users_api/test_users_as_csv.py | 136 +++++++++++--------- 7 files changed, 228 insertions(+), 176 deletions(-) create mode 100644 tests/client/users_api/factories.py diff --git a/poetry.lock b/poetry.lock index d79752e7..ccb0c785 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "add-trailing-comma" @@ -6,7 +6,6 @@ version = "2.2.1" description = "Automatically add trailing commas to calls and literals" optional = false python-versions = ">=3.6.1" -groups = ["dev"] files = [ {file = "add_trailing_comma-2.2.1-py2.py3-none-any.whl", hash = "sha256:981c18282b38ec5bceab80ef11485440334d2a274fcf3fce1f91692374b6d818"}, {file = "add_trailing_comma-2.2.1.tar.gz", hash = "sha256:1640e97c4e85132633a6cb19b29e392dbaf9516292388afa685f7ef1012468e0"}, @@ -21,7 +20,6 @@ version = "1.2.5" description = "Asynchronous CSV reading/writing" optional = false python-versions = ">=3.6, <4" -groups = ["main"] files = [ {file = "aiocsv-1.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8221a24220c3dfed5df80c87bb1e15d4863816954b5f1fca1dcfc14328c0131"}, {file = "aiocsv-1.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274df72bc8d0d11060c148523203f93cfa830dc9901a053d27032e4be0acb50e"}, @@ -56,7 +54,6 @@ version = "23.2.1" description = "File support for asyncio." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, @@ -68,7 +65,6 @@ version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, @@ -82,7 +78,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] [[package]] @@ -91,7 +87,6 @@ version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, @@ -109,7 +104,6 @@ version = "0.8.1" description = "Read/rewrite/write Python ASTs" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -groups = ["dev"] files = [ {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, @@ -121,7 +115,6 @@ version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, @@ -132,8 +125,8 @@ cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6) ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\""] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +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" @@ -141,7 +134,6 @@ version = "1.7.8" description = "Removes unused imports and unused variables" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"}, {file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"}, @@ -157,7 +149,6 @@ version = "1.7.2" description = "Security oriented static analyser for python code." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "bandit-1.7.2-py3-none-any.whl", hash = "sha256:e20402cadfd126d85b68ed4c8862959663c8c372dbbb1fca8f8e2c9f55a067ec"}, {file = "bandit-1.7.2.tar.gz", hash = "sha256:6d11adea0214a43813887bfe71a377b5a9955e4c826c8ffd341b494e3ab25260"}, @@ -180,7 +171,6 @@ version = "22.3.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.6.2" -groups = ["dev"] files = [ {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, @@ -227,7 +217,6 @@ version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, @@ -239,7 +228,6 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" -groups = ["dev"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -339,7 +327,6 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -354,12 +341,10 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "sys_platform == \"win32\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "coverage" @@ -367,7 +352,6 @@ version = "7.5.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, @@ -427,7 +411,7 @@ files = [ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] +toml = ["tomli"] [[package]] name = "darglint" @@ -435,7 +419,6 @@ version = "1.8.1" description = "A utility for ensuring Google-style docstrings stay up to date with the source code." optional = false python-versions = ">=3.6,<4.0" -groups = ["dev"] files = [ {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"}, {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"}, @@ -447,7 +430,6 @@ version = "8.4.2" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "deepdiff-8.4.2-py3-none-any.whl", hash = "sha256:7e39e5b26f3747c54f9d0e8b9b29daab670c3100166b77cc0185d5793121b099"}, {file = "deepdiff-8.4.2.tar.gz", hash = "sha256:5c741c0867ebc7fcb83950ad5ed958369c17f424e14dee32a11c56073f4ee92a"}, @@ -466,7 +448,6 @@ version = "0.20.1" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, @@ -478,7 +459,6 @@ version = "2.3.0" description = "Removes commented-out code." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "eradicate-2.3.0-py3-none-any.whl", hash = "sha256:2b29b3dd27171f209e4ddd8204b70c02f0682ae95eecb353f10e8d72b149c63e"}, {file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"}, @@ -490,8 +470,6 @@ version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, @@ -506,7 +484,6 @@ version = "3.3.1" description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "factory_boy-3.3.1-py2.py3-none-any.whl", hash = "sha256:7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca"}, {file = "factory_boy-3.3.1.tar.gz", hash = "sha256:8317aa5289cdfc45f9cae570feb07a6177316c82e34d14df3c2e1f22f26abef0"}, @@ -525,7 +502,6 @@ version = "35.2.2" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "Faker-35.2.2-py3-none-any.whl", hash = "sha256:94216ce3d8affdc0a8fd0ea8219c184c346a1dcf07b03f193e52f3116186621e"}, {file = "faker-35.2.2.tar.gz", hash = "sha256:0a79ebe8f0ea803f7bd288d51e2d445b86035a2480e048daee1bffbd4d69b32b"}, @@ -541,7 +517,6 @@ version = "0.95.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, {file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, @@ -563,7 +538,6 @@ version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, @@ -580,7 +554,6 @@ version = "2.1.2" description = "Automated security testing with bandit and flake8." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"}, ] @@ -597,7 +570,6 @@ version = "0.4.0" description = "Flake8 plugin to forbid backslashes for line breaks" optional = false python-versions = ">=3.6,<4.0" -groups = ["dev"] files = [ {file = "flake8-broken-line-0.4.0.tar.gz", hash = "sha256:771aab5aa0997666796fed249d0e48e6c01cdfeca8c95521eea28a38b7ced4c7"}, {file = "flake8_broken_line-0.4.0-py3-none-any.whl", hash = "sha256:e9c522856862239a2c7ef2c1de0276fa598572aa864bd4e9c7efc2a827538515"}, @@ -612,7 +584,6 @@ version = "21.11.29" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "flake8-bugbear-21.11.29.tar.gz", hash = "sha256:8b04cb2fafc6a78e1a9d873bd3988e4282f7959bb6b0d7c1ae648ec09b937a7b"}, {file = "flake8_bugbear-21.11.29-py36.py37.py38-none-any.whl", hash = "sha256:179e41ddae5de5e3c20d1f61736feeb234e70958fbb56ab3c28a67739c8e9a82"}, @@ -631,7 +602,6 @@ version = "2.1.0" description = "Flake8 lint for trailing commas." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-commas-2.1.0.tar.gz", hash = "sha256:940441ab8ee544df564ae3b3f49f20462d75d5c7cac2463e0b27436e2050f263"}, {file = "flake8_commas-2.1.0-py2.py3-none-any.whl", hash = "sha256:ebb96c31e01d0ef1d0685a21f3f0e2f8153a0381430e748bf0bbbb5d5b453d54"}, @@ -646,7 +616,6 @@ version = "3.15.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "flake8_comprehensions-3.15.0-py3-none-any.whl", hash = "sha256:b7e027bbb52be2ceb779ee12484cdeef52b0ad3c1fcb8846292bdb86d3034681"}, {file = "flake8_comprehensions-3.15.0.tar.gz", hash = "sha256:923c22603e0310376a6b55b03efebdc09753c69f2d977755cba8bb73458a5d4d"}, @@ -661,7 +630,6 @@ version = "4.1.2" description = "ipdb/pdb statement checker plugin for flake8" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "flake8-debugger-4.1.2.tar.gz", hash = "sha256:52b002560941e36d9bf806fca2523dc7fb8560a295d5f1a6e15ac2ded7a73840"}, {file = "flake8_debugger-4.1.2-py3-none-any.whl", hash = "sha256:0a5e55aeddcc81da631ad9c8c366e7318998f83ff00985a49e6b3ecf61e571bf"}, @@ -677,7 +645,6 @@ version = "1.7.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, @@ -693,7 +660,6 @@ version = "1.4.0" description = "Flake8 plugin to find commented out code" optional = false python-versions = ">=3.7,<4.0" -groups = ["dev"] files = [ {file = "flake8-eradicate-1.4.0.tar.gz", hash = "sha256:3088cfd6717d1c9c6c3ac45ef2e5f5b6c7267f7504d5a74b781500e95cb9c7e1"}, {file = "flake8_eradicate-1.4.0-py3-none-any.whl", hash = "sha256:e3bbd0871be358e908053c1ab728903c114f062ba596b4d40c852fd18f473d56"}, @@ -710,7 +676,6 @@ version = "4.2.0" description = "flake8 plugin that integrates isort ." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-isort-4.2.0.tar.gz", hash = "sha256:26571500cd54976bbc0cf1006ffbcd1a68dd102f816b7a1051b219616ba9fee0"}, {file = "flake8_isort-4.2.0-py3-none-any.whl", hash = "sha256:5b87630fb3719bf4c1833fd11e0d9534f43efdeba524863e15d8f14a7ef6adbf"}, @@ -729,7 +694,6 @@ version = "1.0.2" description = "Polyfill package for Flake8 plugins" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, @@ -744,7 +708,6 @@ version = "3.4.0" description = "Flake8 lint for quotes." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-quotes-3.4.0.tar.gz", hash = "sha256:aad8492fb710a2d3eabe68c5f86a1428de650c8484127e14c43d0504ba30276c"}, ] @@ -759,7 +722,6 @@ version = "0.2.7" description = "Python docstring reStructuredText (RST) validator" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "flake8-rst-docstrings-0.2.7.tar.gz", hash = "sha256:2740067ab9237559dd45a3434d8c987792c7b259ca563621a3b95efe201f5382"}, {file = "flake8_rst_docstrings-0.2.7-py3-none-any.whl", hash = "sha256:5d56075dce360bcc9c6775bfe7cb431aa395de600ca7e8d40580a28d50b2a803"}, @@ -776,7 +738,6 @@ version = "0.3.0" description = "string format checker, plugin for flake8" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"}, {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"}, @@ -791,7 +752,6 @@ version = "4.0.11" description = "Git Object Database" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, @@ -806,7 +766,6 @@ version = "3.1.43" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, @@ -817,7 +776,7 @@ gitdb = ">=4.0.1,<5" [package.extras] doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] -test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3.8\"", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions ; python_version < \"3.11\""] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] [[package]] name = "h11" @@ -825,7 +784,6 @@ version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, @@ -837,7 +795,6 @@ version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, @@ -859,7 +816,6 @@ version = "0.25.2" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpx-0.25.2-py3-none-any.whl", hash = "sha256:a05d3d052d9b2dfce0e3896636467f8a5342fb2b902c819428e1ac65413ca118"}, {file = "httpx-0.25.2.tar.gz", hash = "sha256:8b8fcaa0c8ea7b05edd69a094e63a2094c4efcb48129fb757361bc423c0ad9e8"}, @@ -873,7 +829,7 @@ idna = "*" sniffio = "*" [package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -884,7 +840,6 @@ version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" -groups = ["main", "dev"] files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -896,7 +851,6 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -908,7 +862,6 @@ version = "5.10.1" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.6.1,<4.0" -groups = ["dev"] files = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, @@ -926,7 +879,6 @@ version = "0.6.0" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, @@ -937,7 +889,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (>=4.1.1) ; python_version >= \"3.6\"", "black (>=19.10b0) ; python_version >= \"3.6\"", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1) ; python_version >= \"3.6\"", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1) ; python_version >= \"3.6\"", "sphinx-rtd-theme (>=0.4.3) ; python_version >= \"3.6\"", "tox (>=3.9.0)"] +dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] [[package]] name = "mccabe" @@ -945,7 +897,6 @@ version = "0.6.1" description = "McCabe checker, plugin for flake8" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -957,7 +908,6 @@ version = "0.910" description = "Optional static typing for Python" optional = false python-versions = ">=3.5" -groups = ["dev"] files = [ {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, @@ -999,7 +949,6 @@ version = "0.4.4" description = "Experimental type system extensions for programs checked with the mypy typechecker." optional = false python-versions = ">=2.7" -groups = ["main", "dev"] files = [ {file = "mypy_extensions-0.4.4.tar.gz", hash = "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd"}, ] @@ -1010,7 +959,6 @@ version = "5.3.2" description = "Orderly set" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "orderly_set-5.3.2-py3-none-any.whl", hash = "sha256:81250ce092333db454a70e5d7ef1409ec4d3002e0d2c7546d710f4639f20f19d"}, {file = "orderly_set-5.3.2.tar.gz", hash = "sha256:5fd6d917788d0e2196582f38a1c4b74591963d4df9be24ae5a51ba4cea2c987f"}, @@ -1022,7 +970,6 @@ version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -1034,7 +981,6 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1046,7 +992,6 @@ version = "6.0.0" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" -groups = ["dev"] files = [ {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, @@ -1058,7 +1003,6 @@ version = "0.12.1" description = "Check PEP-8 naming conventions, plugin for flake8" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"}, {file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"}, @@ -1074,7 +1018,6 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -1091,7 +1034,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1107,7 +1049,6 @@ version = "2.8.0" description = "Python style guide checker" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] files = [ {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, @@ -1119,7 +1060,6 @@ version = "1.10.17" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "pydantic-1.10.17-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fa51175313cc30097660b10eec8ca55ed08bfa07acbfe02f7a42f6c242e9a4b"}, {file = "pydantic-1.10.17-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7e8988bb16988890c985bd2093df9dd731bfb9d5e0860db054c23034fab8f7a"}, @@ -1179,7 +1119,6 @@ version = "6.3.0" description = "Python docstring style checker" optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, @@ -1189,7 +1128,7 @@ files = [ snowballstemmer = ">=2.2.0" [package.extras] -toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""] +toml = ["tomli (>=1.2.3)"] [[package]] name = "pyflakes" @@ -1197,7 +1136,6 @@ version = "2.4.0" description = "passive checker of Python programs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] files = [ {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, @@ -1209,7 +1147,6 @@ version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -1224,7 +1161,6 @@ version = "2.8.0" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, @@ -1242,7 +1178,6 @@ version = "7.2.0" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, @@ -1266,7 +1201,6 @@ version = "0.16.0" description = "Pytest support for asyncio." optional = false python-versions = ">= 3.6" -groups = ["dev"] files = [ {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, @@ -1284,7 +1218,6 @@ version = "4.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, @@ -1303,7 +1236,6 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1318,7 +1250,6 @@ version = "6.0.1" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, @@ -1379,7 +1310,6 @@ version = "2.31.0" description = "Python HTTP for Humans." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, @@ -1401,7 +1331,6 @@ version = "0.20.2" description = "A utility for mocking out the Python HTTPX and HTTP Core libraries." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "respx-0.20.2-py2.py3-none-any.whl", hash = "sha256:ab8e1cf6da28a5b2dd883ea617f8130f77f676736e6e9e4a25817ad116a172c9"}, {file = "respx-0.20.2.tar.gz", hash = "sha256:07cf4108b1c88b82010f67d3c831dae33a375c7b436e54d87737c7f9f99be643"}, @@ -1416,7 +1345,6 @@ version = "1.4.0" description = "reStructuredText linter" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, ] @@ -1430,7 +1358,6 @@ version = "70.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, @@ -1438,7 +1365,7 @@ files = [ [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-ruff (>=0.3.2) ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1446,7 +1373,6 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -1458,7 +1384,6 @@ version = "5.0.1" description = "A pure Python implementation of a sliding window memory map manager" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, @@ -1470,7 +1395,6 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -1482,7 +1406,6 @@ version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, @@ -1494,7 +1417,6 @@ version = "0.27.0" description = "The little ASGI library that shines." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, @@ -1513,7 +1435,6 @@ version = "5.2.0" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"}, {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"}, @@ -1528,7 +1449,6 @@ version = "5.2.0" description = "A wrapper around the stdlib `tokenize` which roundtrips." optional = false python-versions = ">=3.8" -groups = ["dev"] 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"}, @@ -1540,7 +1460,6 @@ version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -groups = ["dev"] files = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -1552,8 +1471,6 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" -groups = ["dev"] -markers = "python_full_version <= \"3.11.0a6\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -1565,7 +1482,6 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -1577,14 +1493,13 @@ version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1595,7 +1510,6 @@ version = "0.16.0" description = "The lightning-fast ASGI server." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "uvicorn-0.16.0-py3-none-any.whl", hash = "sha256:d8c839231f270adaa6d338d525e2652a0b4a5f4c2430b5c4ef6ae4d11776b0d2"}, {file = "uvicorn-0.16.0.tar.gz", hash = "sha256:eacb66afa65e0648fcbce5e746b135d09722231ffffc61883d4fac2b62fbea8d"}, @@ -1607,7 +1521,7 @@ click = ">=7.0" h11 = ">=0.8" [package.extras] -standard = ["PyYAML (>=5.1)", "colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.2.0,<0.4.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchgod (>=0.6)", "websockets (>=10.0) ; python_version >= \"3.7\"", "websockets (>=9.1) ; python_version < \"3.7\""] +standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.2.0,<0.4.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchgod (>=0.6)", "websockets (>=10.0)", "websockets (>=9.1)"] [[package]] name = "wemake-python-styleguide" @@ -1615,7 +1529,6 @@ version = "0.16.0" description = "The strictest and most opinionated python linter ever" optional = false python-versions = ">=3.6,<4.0" -groups = ["dev"] files = [ {file = "wemake-python-styleguide-0.16.0.tar.gz", hash = "sha256:3bf0a4962404e6fd6fa479e72e2ba3fb75d5920ea6c44b72b45240c9e519543c"}, {file = "wemake_python_styleguide-0.16.0-py3-none-any.whl", hash = "sha256:8caa92b4aa77b08a505d718553238812d1b612b1036bc171ca3aa18345efe0b4"}, @@ -1648,17 +1561,15 @@ version = "1.1.0" description = "A small Python utility to set file creation time on Windows" optional = false python-versions = ">=3.5" -groups = ["main"] -markers = "sys_platform == \"win32\"" files = [ {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, ] [package.extras] -dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] -lock-version = "2.1" -python-versions = ">=3.8,<3.13" -content-hash = "9187a163486342201a77557fae635b26dda81aec54b321d0ed6a2ef355efefcf" +lock-version = "2.0" +python-versions = ">=3.9,<=3.13" +content-hash = "8467b00af9e95cec4a0ecb9e1407d2025e59c9ff7a8fd59684fe5e76a3003775" diff --git a/pybotx/client/users_api/user_from_csv.py b/pybotx/client/users_api/user_from_csv.py index 65f3df4d..a0df8052 100644 --- a/pybotx/client/users_api/user_from_csv.py +++ b/pybotx/client/users_api/user_from_csv.py @@ -83,10 +83,8 @@ def to_domain(self) -> UserFromCSV: office=self.office, manager=self.manager, manager_huid=self.manager_huid, - #TODO: fix manager_dn=self.manager_dn, - manager_dn=str(self.manager_huid), - # TODO: fix remove else clause - user_dn = self.user_dn if self.user_dn else str(self.huid), + manager_dn=self.manager_dn, + user_dn=self.user_dn, description=self.description, phone=self.phone, other_phone=self.other_phone, diff --git a/pybotx/models/users.py b/pybotx/models/users.py index 5bb6151f..b902398c 100644 --- a/pybotx/models/users.py +++ b/pybotx/models/users.py @@ -111,6 +111,6 @@ class UserFromCSV: ip_phone: Optional[str] = None other_ip_phone: Optional[str] = None personnel_number: Optional[str] = None - #TODO: remove Optional from user_dn + # TODO: remove Optional from user_dn user_dn: Optional[str] = None manager_dn: Optional[str] = None diff --git a/pyproject.toml b/pyproject.toml index cf319fde..41ba4cc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pybotx" -version = "0.74.0" +version = "0.75.2" description = "A python library for interacting with eXpress BotX API" authors = [ "Sidnev Nikolay ", @@ -13,7 +13,7 @@ repository = "https://github.com/ExpressApp/pybotx" [tool.poetry.dependencies] -python = ">=3.8,<3.13" +python = ">=3.9,<=3.13" aiofiles = ">=0.7.0,<24.0.0" httpx = "^0.25.0" diff --git a/tests/client/users_api/conftest.py b/tests/client/users_api/conftest.py index 78279acc..3436c646 100644 --- a/tests/client/users_api/conftest.py +++ b/tests/client/users_api/conftest.py @@ -1,10 +1,15 @@ -from typing import Any, Dict +import csv +from http import HTTPStatus +from io import StringIO +from typing import Any, Dict, List from uuid import UUID +import httpx import pytest from pybotx import UserFromSearch, UserKinds from tests.client.users_api.convert_to_datetime import convert_to_datetime +from tests.client.users_api.factories import CsvUserResponseValues @pytest.fixture() @@ -115,3 +120,79 @@ def user_from_search_without_data() -> UserFromSearch: rts_id=None, updated_at=None, ) + + +@pytest.fixture +def csv_users_from_api() -> list[dict[str, str]]: + """Generate a list of user dictionaries for CSV testing. + + This fixture creates a list of dictionaries representing user data as it would + appear in a CSV response from the BotX API. + + return: A list of dictionaries where each dictionary represents + a user with CSV column names as keys and corresponding values as strings. + """ + return [ + CsvUserResponseValues( + Manager_DN=f"manager_dn_{index}", + User_DN=f"user_dn_{index}", + ) + for index in range(2) + ] + + +@pytest.fixture +def users_csv_response(csv_users_from_api: List[Dict[str, str]]) -> httpx.Response: + """ + Create a mock HTTP response with CSV user data. + + This fixture takes the user data from ``csv_users_from_api`` and converts it into + CSV format. It then returns an ``httpx.Response`` object containing the CSV content. + + :param: A list of dictionaries containing user data for CSV conversion. + + :return: An HTTP response object with status code 200 (OK) and CSV-formatted + user data as content. + """ + + csv_columns = [ + "HUID", + "AD Login", + "Domain", + "AD E-mail", + "Name", + "Sync source", + "Active", + "Kind", + "User DN", + "Company", + "Department", + "Position", + "Manager", + "Manager HUID", + "Manager DN", + "Personnel number", + "Description", + "IP phone", + "Other IP phone", + "Phone", + "Other phone", + "Avatar", + "Office", + "Avatar preview", + ] + + output = StringIO() + writer = csv.DictWriter(output, fieldnames=csv_columns) + writer.writeheader() + + for user in csv_users_from_api: + ordered_row_values = { + column_name: user[column_name] for column_name in csv_columns + } + writer.writerow(ordered_row_values) + + return httpx.Response( + status_code=HTTPStatus.OK, + content=output.getvalue().encode("utf-8"), + ) diff --git a/tests/client/users_api/factories.py b/tests/client/users_api/factories.py new file mode 100644 index 00000000..e00eb0d1 --- /dev/null +++ b/tests/client/users_api/factories.py @@ -0,0 +1,52 @@ +from random import choice + +import factory # type: ignore + + +class CsvUserResponseValues(factory.DictFactory): # type: ignore[misc] + """Factory for generating CSV user response data. + + This factory creates dictionaries that simulate user data as it would appear + in a CSV response from the BotX API. + + """ + + HUID = factory.Faker("uuid4") + AD_Login = factory.Faker("user_name") + Domain = "cts.example.com" + AD_E_mail = factory.Faker("email") + Name = factory.Faker("name") + Sync_source = "ad" + Active = factory.LazyFunction(lambda: choice(["true", "false"])) # noqa: S311 + Kind = "cts_user" + User_DN = factory.Faker("uuid4") + Company = factory.Faker("company") + Department = factory.Faker("catch_phrase") + Position = factory.Faker("job") + Manager = factory.Faker("name") + Manager_HUID = "" + Manager_DN = "" + Personnel_number = "" + Description = factory.Faker("sentence") + IP_phone = factory.Faker("phone_number") + Other_IP_phone = factory.Faker("phone_number") + Phone = factory.Faker("phone_number") + Other_phone = factory.Faker("phone_number") + Avatar = factory.Faker("file_name", category="image") + Office = factory.Faker("city") + Avatar_preview = factory.Faker("file_name", category="image") + + class Meta: + rename = { + "AD_Login": "AD Login", + "AD_E_mail": "AD E-mail", + "Sync_source": "Sync source", + "IP_phone": "IP phone", + "Other_IP_phone": "Other IP phone", + "Other_phone": "Other phone", + "Avatar_preview": "Avatar preview", + "Manager_HUID": "Manager HUID", + "Manager_DN": "Manager DN", + "Personnel_number": "Personnel number", + "User_DN": "User DN", + } diff --git a/tests/client/users_api/test_users_as_csv.py b/tests/client/users_api/test_users_as_csv.py index 57d776cd..d78bb0e9 100644 --- a/tests/client/users_api/test_users_as_csv.py +++ b/tests/client/users_api/test_users_as_csv.py @@ -1,15 +1,14 @@ from http import HTTPStatus +from typing import Any, Dict, List from uuid import UUID import httpx import pytest from respx.router import MockRouter -from pybotx import Bot, HandlerCollector, lifespan_wrapper +from pybotx import Bot, HandlerCollector, SyncSourceTypes, UserFromCSV, lifespan_wrapper from pybotx.client.exceptions.users import NoUserKindSelectedError from pybotx.models.bot_account import BotAccountWithSecret -from pybotx.models.enums import SyncSourceTypes, UserKinds -from pybotx.models.users import UserFromCSV pytestmark = [ pytest.mark.asyncio, @@ -18,6 +17,66 @@ ] +def assert_csv_user_consist_csv_data( # noqa: WPS218 + csv_user: UserFromCSV, + original_row: Dict[str, str], +) -> None: + """Verify that a UserFromCSV object contains the correct data from a CSV row. + + This function performs assertions to check that all fields in the UserFromCSV object + match the corresponding values in the original CSV row dictionary. + + Args: + csv_user: A UserFromCSV object created from CSV data + original_row: A dictionary containing the original CSV row data + """ + assert csv_user.username == original_row["Name"] + assert csv_user.ad_domain == original_row["Domain"] + assert csv_user.email == original_row["AD E-mail"] + assert str(csv_user.active).lower() == original_row["Active"] + assert str(csv_user.huid) == original_row["HUID"] + assert csv_user.user_kind.value.lower() == original_row["Kind"] + if isinstance(csv_user.sync_source, SyncSourceTypes): + assert str(csv_user.sync_source.value).lower() == original_row["Sync source"] + else: + assert str(csv_user).lower() == original_row["Sync source"] + + if original_row["Manager HUID"]: + assert str(csv_user.manager_huid) == original_row["Manager HUID"] + else: + assert csv_user.manager_huid is None + + string_fields = [ + "AD Login", + "User DN", + "Company", + "Department", + "Position", + "Manager", + "Manager HUID", + "Manager DN", + "Personnel number", + "Description", + "IP phone", + "Other IP phone", + "Phone", + "Other phone", + "Avatar", + "Office", + "Avatar preview", + ] + + for string_field_name in string_fields: + object_field_name = string_field_name.lower().replace(" ", "_") + if original_row[string_field_name]: + assert original_row[string_field_name] == getattr( + csv_user, + object_field_name, + ) + else: + assert getattr(csv_user, object_field_name) is None + + async def test__users_as_csv__no_user_kind_selected_error( respx_mock: MockRouter, host: str, @@ -63,21 +122,19 @@ async def test__users_as_csv__succeed( host: str, bot_id: UUID, bot_account: BotAccountWithSecret, + csv_users_from_api: List[Dict[str, Any]], + users_csv_response: httpx.Response, ) -> None: + """Test successful retrieval of users as CSV. + + This test verifies that the users_as_csv method correctly retrieves users + in CSV format from the BotX API and converts them to UserFromCSV objects. + """ endpoint = respx_mock.get( url=f"https://{host}/api/v3/botx/users/users_as_csv", headers={"Authorization": "Bearer token"}, params={"cts_user": True, "unregistered": True, "botx": False}, - ).mock( - return_value=httpx.Response( - status_code=HTTPStatus.OK, - content=( - b"HUID,AD Login,Domain,AD E-mail,Name,Sync source,Active,Kind,Company,Department,Position,Manager,Manager HUID,Personnel number,Description,IP phone,Other IP phone,Phone,Other phone,Avatar,Office,Avatar preview\n" - b"dbc8934f-d0d7-4a9e-89df-d45c137a851c,test_user_17,cts.example.com,,test_user_17,ad,false,cts_user,Company,Department,Position,Manager John,13a6909c-bce1-4dbf-8359-efb7ef8e5b34,Some number,Description,IP phone,Other IP phone,Phone,Other_phone,Avatar,Office,Avatar_preview\n" - b"13a6909c-bce1-4dbf-8359-efb7ef8e5b34,test_user_18,cts.example.com,,test_user_18,unsupported,true,cts_user,,,,,,,,,,,,,," - ), - ), - ) + ).mock(return_value=users_csv_response) built_bot = Bot(collectors=[HandlerCollector()], bot_accounts=[bot_account]) users_from_csv = [] @@ -90,53 +147,6 @@ async def test__users_as_csv__succeed( # - Assert - assert endpoint.called - assert users_from_csv == [ - UserFromCSV( - huid=UUID("dbc8934f-d0d7-4a9e-89df-d45c137a851c"), - ad_login="test_user_17", - ad_domain="cts.example.com", - username="test_user_17", - sync_source=SyncSourceTypes.AD, - active=False, - user_kind=UserKinds.CTS_USER, - email=None, - company="Company", - department="Department", - position="Position", - personnel_number="Some number", - manager="Manager John", - manager_huid=UUID("13a6909c-bce1-4dbf-8359-efb7ef8e5b34"), - description="Description", - ip_phone="IP phone", - other_ip_phone="Other IP phone", - phone="Phone", - other_phone="Other_phone", - avatar="Avatar", - office="Office", - avatar_preview="Avatar_preview", - ), - UserFromCSV( - huid=UUID("13a6909c-bce1-4dbf-8359-efb7ef8e5b34"), - ad_login="test_user_18", - ad_domain="cts.example.com", - username="test_user_18", - sync_source="UNSUPPORTED", - active=True, - user_kind=UserKinds.CTS_USER, - email=None, - company=None, - department=None, - position=None, - manager=None, - manager_huid=None, - personnel_number=None, - description=None, - ip_phone=None, - other_ip_phone=None, - phone=None, - other_phone=None, - avatar=None, - office=None, - avatar_preview=None, - ), - ] + + for generated_user, original_user in zip(users_from_csv, csv_users_from_api): + assert_csv_user_consist_csv_data(generated_user, original_user) From 55cc08dc09659f54fd2eee76b80d71dd44d30fdc Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 15:14:18 +0300 Subject: [PATCH 04/10] merge master --- poetry.lock | 127 ++++---------------- pybotx/async_buffer.py | 12 +- pybotx/bot/callbacks/callback_manager.py | 6 +- pybotx/bot/callbacks/callback_repo_proto.py | 15 ++- pybotx/bot/handler.py | 10 +- pybotx/bot/handler_collector.py | 6 +- pybotx/models/enums.py | 12 +- tests/test_handler_collector.py | 3 +- 8 files changed, 58 insertions(+), 133 deletions(-) diff --git a/poetry.lock b/poetry.lock index 64746db8..6b514b2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "add-trailing-comma" @@ -6,7 +6,6 @@ version = "3.1.0" description = "Automatically add trailing commas to calls and literals" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "add_trailing_comma-3.1.0-py2.py3-none-any.whl", hash = "sha256:160207e2ac414a841a71f4f5095f7350f87af460aab3dfe36cfa037992530e5c"}, {file = "add_trailing_comma-3.1.0.tar.gz", hash = "sha256:b255319d7ef6dca308b051ffd80fccf98c018879744c7c7e03083b2eee079c45"}, @@ -21,7 +20,6 @@ version = "1.2.5" description = "Asynchronous CSV reading/writing" optional = false python-versions = ">=3.6, <4" -groups = ["main"] files = [ {file = "aiocsv-1.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8221a24220c3dfed5df80c87bb1e15d4863816954b5f1fca1dcfc14328c0131"}, {file = "aiocsv-1.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274df72bc8d0d11060c148523203f93cfa830dc9901a053d27032e4be0acb50e"}, @@ -56,7 +54,6 @@ version = "23.2.1" description = "File support for asyncio." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, @@ -68,7 +65,6 @@ version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, @@ -82,7 +78,7 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] @@ -91,7 +87,6 @@ version = "0.8.1" description = "Read/rewrite/write Python ASTs" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -groups = ["dev"] files = [ {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, @@ -103,19 +98,18 @@ version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "autoflake" @@ -123,7 +117,6 @@ version = "2.3.1" description = "Removes unused imports and unused variables" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840"}, {file = "autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e"}, @@ -139,7 +132,6 @@ version = "1.8.3" description = "Security oriented static analyser for python code." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "bandit-1.8.3-py3-none-any.whl", hash = "sha256:28f04dc0d258e1dd0f99dee8eefa13d1cb5e3fde1a5ab0c523971f97b289bcd8"}, {file = "bandit-1.8.3.tar.gz", hash = "sha256:f5847beb654d309422985c36644649924e0ea4425c76dec2e89110b87506193a"}, @@ -155,7 +147,7 @@ stevedore = ">=1.20.0" baseline = ["GitPython (>=3.1.30)"] sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"] test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"] -toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""] +toml = ["tomli (>=1.1.0)"] yaml = ["PyYAML"] [[package]] @@ -164,7 +156,6 @@ version = "25.1.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, @@ -211,7 +202,6 @@ version = "2025.4.26" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"}, {file = "certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6"}, @@ -223,7 +213,6 @@ version = "3.4.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, @@ -325,7 +314,6 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -340,12 +328,10 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "sys_platform == \"win32\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "coverage" @@ -353,7 +339,6 @@ version = "7.8.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"}, {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"}, @@ -424,7 +409,7 @@ files = [ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] +toml = ["tomli"] [[package]] name = "darglint" @@ -432,7 +417,6 @@ version = "1.8.1" description = "A utility for ensuring Google-style docstrings stay up to date with the source code." optional = false python-versions = ">=3.6,<4.0" -groups = ["dev"] files = [ {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"}, {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"}, @@ -444,7 +428,6 @@ version = "8.5.0" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "deepdiff-8.5.0-py3-none-any.whl", hash = "sha256:d4599db637f36a1c285f5fdfc2cd8d38bde8d8be8636b65ab5e425b67c54df26"}, {file = "deepdiff-8.5.0.tar.gz", hash = "sha256:a4dd3529fa8d4cd5b9cbb6e3ea9c95997eaa919ba37dac3966c1b8f872dc1cd1"}, @@ -456,7 +439,7 @@ orderly-set = ">=5.4.1,<6" [package.extras] cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"] coverage = ["coverage (>=7.6.0,<7.7.0)"] -dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0) ; python_version < \"3.10\"", "numpy (>=2.2.0,<2.3.0) ; python_version >= \"3.10\"", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)"] +dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0)", "numpy (>=2.2.0,<2.3.0)", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)"] docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"] optimize = ["orjson"] static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"] @@ -468,7 +451,6 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -480,7 +462,6 @@ version = "2.3.0" description = "Removes commented-out code." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "eradicate-2.3.0-py3-none-any.whl", hash = "sha256:2b29b3dd27171f209e4ddd8204b70c02f0682ae95eecb353f10e8d72b149c63e"}, {file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"}, @@ -492,8 +473,6 @@ version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -511,7 +490,6 @@ version = "3.3.3" description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc"}, {file = "factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03"}, @@ -530,7 +508,6 @@ version = "37.1.0" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "faker-37.1.0-py3-none-any.whl", hash = "sha256:dc2f730be71cb770e9c715b13374d80dbcee879675121ab51f9683d262ae9a1c"}, {file = "faker-37.1.0.tar.gz", hash = "sha256:ad9dc66a3b84888b837ca729e85299a96b58fdaef0323ed0baace93c9614af06"}, @@ -545,7 +522,6 @@ version = "0.115.12" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d"}, {file = "fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681"}, @@ -566,7 +542,6 @@ version = "7.2.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "flake8-7.2.0-py2.py3-none-any.whl", hash = "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343"}, {file = "flake8-7.2.0.tar.gz", hash = "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426"}, @@ -583,7 +558,6 @@ version = "4.1.1" description = "Automated security testing with bandit and flake8." optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "flake8_bandit-4.1.1-py3-none-any.whl", hash = "sha256:4c8a53eb48f23d4ef1e59293657181a3c989d0077c9952717e98a0eace43e06d"}, {file = "flake8_bandit-4.1.1.tar.gz", hash = "sha256:068e09287189cbfd7f986e92605adea2067630b75380c6b5733dab7d87f9a84e"}, @@ -599,7 +573,6 @@ version = "1.0.0" description = "Flake8 plugin to forbid backslashes for line breaks" optional = false python-versions = ">=3.8,<4.0" -groups = ["dev"] files = [ {file = "flake8_broken_line-1.0.0-py3-none-any.whl", hash = "sha256:96c964336024a5030dc536a9f6fb02aa679e2d2a6b35b80a558b5136c35832a9"}, {file = "flake8_broken_line-1.0.0.tar.gz", hash = "sha256:e2c6a17f8d9a129e99c1320fce89b33843e2963871025c4c2bb7b8b8d8732a85"}, @@ -614,7 +587,6 @@ version = "24.12.12" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." optional = false python-versions = ">=3.8.1" -groups = ["dev"] files = [ {file = "flake8_bugbear-24.12.12-py3-none-any.whl", hash = "sha256:1b6967436f65ca22a42e5373aaa6f2d87966ade9aa38d4baf2a1be550767545e"}, {file = "flake8_bugbear-24.12.12.tar.gz", hash = "sha256:46273cef0a6b6ff48ca2d69e472f41420a42a46e24b2a8972e4f0d6733d12a64"}, @@ -633,7 +605,6 @@ version = "2.1.0" description = "Flake8 lint for trailing commas." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-commas-2.1.0.tar.gz", hash = "sha256:940441ab8ee544df564ae3b3f49f20462d75d5c7cac2463e0b27436e2050f263"}, {file = "flake8_commas-2.1.0-py2.py3-none-any.whl", hash = "sha256:ebb96c31e01d0ef1d0685a21f3f0e2f8153a0381430e748bf0bbbb5d5b453d54"}, @@ -648,7 +619,6 @@ version = "3.16.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "flake8_comprehensions-3.16.0-py3-none-any.whl", hash = "sha256:7c1eadc9d22e765f39857798febe7766b4d9c519793c6c149e3e13bf99693f70"}, {file = "flake8_comprehensions-3.16.0.tar.gz", hash = "sha256:9cbf789905a8f03f9d350fb82b17b264d9a16c7ce3542b2a7b871ef568cafabe"}, @@ -663,7 +633,6 @@ version = "4.1.2" description = "ipdb/pdb statement checker plugin for flake8" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "flake8-debugger-4.1.2.tar.gz", hash = "sha256:52b002560941e36d9bf806fca2523dc7fb8560a295d5f1a6e15ac2ded7a73840"}, {file = "flake8_debugger-4.1.2-py3-none-any.whl", hash = "sha256:0a5e55aeddcc81da631ad9c8c366e7318998f83ff00985a49e6b3ecf61e571bf"}, @@ -679,7 +648,6 @@ version = "1.7.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, @@ -695,7 +663,6 @@ version = "1.5.0" description = "Flake8 plugin to find commented out code" optional = false python-versions = ">=3.8,<4.0" -groups = ["dev"] files = [ {file = "flake8_eradicate-1.5.0-py3-none-any.whl", hash = "sha256:18acc922ad7de623f5247c7d5595da068525ec5437dd53b22ec2259b96ce9d22"}, {file = "flake8_eradicate-1.5.0.tar.gz", hash = "sha256:aee636cb9ecb5594a7cd92d67ad73eb69909e5cc7bd81710cf9d00970f3983a6"}, @@ -712,7 +679,6 @@ version = "6.1.2" description = "flake8 plugin that integrates isort" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "flake8_isort-6.1.2-py3-none-any.whl", hash = "sha256:549197dedf0273502fb74f04c080beed9e62a7eb70244610413d27052e78bd3b"}, {file = "flake8_isort-6.1.2.tar.gz", hash = "sha256:9d0452acdf0e1cd6f2d6848e3605e66b54d920e73471fb4744eef0f93df62d5d"}, @@ -731,7 +697,6 @@ version = "3.4.0" description = "Flake8 lint for quotes." optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-quotes-3.4.0.tar.gz", hash = "sha256:aad8492fb710a2d3eabe68c5f86a1428de650c8484127e14c43d0504ba30276c"}, ] @@ -746,7 +711,6 @@ version = "0.3.1" description = "Python docstring reStructuredText (RST) validator for flake8" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "flake8_rst_docstrings-0.3.1-py3-none-any.whl", hash = "sha256:ed831afca7ee47851e2162d5fa726b823b446fd46085c2164d7979ae5d9a96d7"}, {file = "flake8_rst_docstrings-0.3.1.tar.gz", hash = "sha256:26dcc1338caf985990677696a8a6a274f73a0c6845b85f567befd3b648db78e2"}, @@ -766,7 +730,6 @@ version = "0.3.0" description = "string format checker, plugin for flake8" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"}, {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"}, @@ -781,7 +744,6 @@ version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, @@ -793,7 +755,6 @@ version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, @@ -815,7 +776,6 @@ version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, @@ -828,7 +788,7 @@ httpcore = "==1.*" idna = "*" [package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -840,7 +800,6 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -855,7 +814,6 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, @@ -867,7 +825,6 @@ version = "6.0.1" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.9.0" -groups = ["dev"] files = [ {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, @@ -883,7 +840,6 @@ version = "0.6.0" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, @@ -894,7 +850,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (>=4.1.1) ; python_version >= \"3.6\"", "black (>=19.10b0) ; python_version >= \"3.6\"", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1) ; python_version >= \"3.6\"", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1) ; python_version >= \"3.6\"", "sphinx-rtd-theme (>=0.4.3) ; python_version >= \"3.6\"", "tox (>=3.9.0)"] +dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] [[package]] name = "markdown-it-py" @@ -902,7 +858,6 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -927,7 +882,6 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -939,7 +893,6 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -951,7 +904,6 @@ version = "1.15.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, @@ -1005,7 +957,6 @@ version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, @@ -1017,7 +968,6 @@ version = "5.4.1" description = "Orderly set" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, @@ -1029,7 +979,6 @@ version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, @@ -1041,7 +990,6 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1053,7 +1001,6 @@ version = "6.1.1" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" -groups = ["dev"] files = [ {file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"}, {file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"}, @@ -1068,7 +1015,6 @@ version = "0.13.3" description = "Check PEP-8 naming conventions, plugin for flake8" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971"}, {file = "pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80"}, @@ -1083,7 +1029,6 @@ version = "4.3.8" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, @@ -1100,7 +1045,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1116,7 +1060,6 @@ version = "2.13.0" description = "Python style guide checker" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9"}, {file = "pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae"}, @@ -1128,7 +1071,6 @@ version = "1.10.22" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "pydantic-1.10.22-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:57889565ccc1e5b7b73343329bbe6198ebc472e3ee874af2fa1865cfe7048228"}, {file = "pydantic-1.10.22-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90729e22426de79bc6a3526b4c45ec4400caf0d4f10d7181ba7f12c01bb3897d"}, @@ -1195,7 +1137,6 @@ version = "6.3.0" description = "Python docstring style checker" optional = false python-versions = ">=3.6" -groups = ["dev"] files = [ {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, @@ -1205,7 +1146,7 @@ files = [ snowballstemmer = ">=2.2.0" [package.extras] -toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""] +toml = ["tomli (>=1.2.3)"] [[package]] name = "pyflakes" @@ -1213,7 +1154,6 @@ version = "3.3.2" description = "passive checker of Python programs" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pyflakes-3.3.2-py2.py3-none-any.whl", hash = "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a"}, {file = "pyflakes-3.3.2.tar.gz", hash = "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b"}, @@ -1225,7 +1165,6 @@ version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, @@ -1240,7 +1179,6 @@ version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, @@ -1258,7 +1196,6 @@ version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, @@ -1281,7 +1218,6 @@ version = "0.26.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0"}, {file = "pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f"}, @@ -1301,7 +1237,6 @@ version = "6.1.1" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde"}, {file = "pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a"}, @@ -1320,7 +1255,6 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -1383,7 +1317,6 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1405,7 +1338,6 @@ version = "0.22.0" description = "A utility for mocking out the Python HTTPX and HTTP Core libraries." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "respx-0.22.0-py2.py3-none-any.whl", hash = "sha256:631128d4c9aba15e56903fb5f66fb1eff412ce28dd387ca3a81339e52dbd3ad0"}, {file = "respx-0.22.0.tar.gz", hash = "sha256:3c8924caa2a50bd71aefc07aa812f2466ff489f1848c96e954a5362d17095d91"}, @@ -1420,7 +1352,6 @@ version = "1.4.0" description = "reStructuredText linter" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, ] @@ -1434,7 +1365,6 @@ version = "14.0.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" -groups = ["dev"] files = [ {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, @@ -1454,20 +1384,19 @@ version = "80.4.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "setuptools-80.4.0-py3-none-any.whl", hash = "sha256:6cdc8cb9a7d590b237dbe4493614a9b75d0559b888047c1f67d49ba50fc3edb2"}, {file = "setuptools-80.4.0.tar.gz", hash = "sha256:5a78f61820bc088c8e4add52932ae6b8cf423da2aff268c23f813cfbb13b4006"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] +core = ["importlib_metadata (>=6)", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "sniffio" @@ -1475,7 +1404,6 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -1487,7 +1415,6 @@ version = "3.0.1" description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" -groups = ["dev"] files = [ {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, @@ -1499,7 +1426,6 @@ version = "0.46.2" description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35"}, {file = "starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5"}, @@ -1518,7 +1444,6 @@ version = "5.4.1" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"}, {file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"}, @@ -1533,7 +1458,6 @@ version = "6.1.0" description = "A wrapper around the stdlib `tokenize` which roundtrips." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "tokenize_rt-6.1.0-py2.py3-none-any.whl", hash = "sha256:d706141cdec4aa5f358945abe36b911b8cbdc844545da99e811250c0cee9b6fc"}, {file = "tokenize_rt-6.1.0.tar.gz", hash = "sha256:e8ee836616c0877ab7c7b54776d2fefcc3bde714449a206762425ae114b53c86"}, @@ -1545,8 +1469,6 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -groups = ["dev"] -markers = "python_full_version <= \"3.11.0a6\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -1588,7 +1510,6 @@ version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, @@ -1600,7 +1521,6 @@ version = "2025.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" -groups = ["dev"] files = [ {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, @@ -1612,14 +1532,13 @@ version = "2.4.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1630,7 +1549,6 @@ version = "0.34.2" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403"}, {file = "uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328"}, @@ -1642,7 +1560,7 @@ h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "wemake-python-styleguide" @@ -1650,7 +1568,6 @@ version = "0.19.2" description = "The strictest and most opinionated python linter ever" optional = false python-versions = "<4.0,>=3.9" -groups = ["dev"] files = [ {file = "wemake_python_styleguide-0.19.2-py3-none-any.whl", hash = "sha256:d53205dbb629755026d853d15fb3ca03ebb2717c97de4198b5676b9bdc0663bd"}, {file = "wemake_python_styleguide-0.19.2.tar.gz", hash = "sha256:850fe70e6d525fd37ac51778e552a121a489f1bd057184de96ffd74a09aef414"}, @@ -1684,17 +1601,15 @@ version = "1.2.0" description = "A small Python utility to set file creation time on Windows" optional = false python-versions = ">=3.5" -groups = ["main"] -markers = "sys_platform == \"win32\"" files = [ {file = "win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390"}, {file = "win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0"}, ] [package.extras] -dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = ">=3.9,<3.14" content-hash = "78fb399feb9a1fab9b80489c8630431c8b7be1e939d110d0eb04bd79debf29b3" diff --git a/pybotx/async_buffer.py b/pybotx/async_buffer.py index ab965560..6c448e9a 100644 --- a/pybotx/async_buffer.py +++ b/pybotx/async_buffer.py @@ -13,14 +13,17 @@ async def seek( self, cursor: int, whence: int = os.SEEK_SET, - ) -> int: ... + ) -> int: + ... - async def tell(self) -> int: ... + async def tell(self) -> int: + ... class AsyncBufferWritable(AsyncBufferBase): @abc.abstractmethod - async def write(self, content: bytes) -> int: ... + async def write(self, content: bytes) -> int: + ... class AsyncBufferReadable(AsyncBufferBase): @@ -28,7 +31,8 @@ class AsyncBufferReadable(AsyncBufferBase): async def read( self, bytes_to_read: Optional[int] = None, - ) -> bytes: ... + ) -> bytes: + ... async def get_file_size(async_buffer: AsyncBufferReadable) -> int: diff --git a/pybotx/bot/callbacks/callback_manager.py b/pybotx/bot/callbacks/callback_manager.py index 7b17a2b9..d4852202 100644 --- a/pybotx/bot/callbacks/callback_manager.py +++ b/pybotx/bot/callbacks/callback_manager.py @@ -69,14 +69,16 @@ def setup_callback_timeout_alarm(self, sync_id: UUID, timeout: float) -> None: def cancel_callback_timeout_alarm( self, sync_id: UUID, - ) -> None: ... # noqa: WPS428, E704 + ) -> None: + ... # noqa: WPS428, E704 @overload def cancel_callback_timeout_alarm( self, sync_id: UUID, return_remaining_time: Literal[True], - ) -> float: ... # noqa: WPS428, E704 + ) -> float: + ... # noqa: WPS428, E704 def cancel_callback_timeout_alarm( self, diff --git a/pybotx/bot/callbacks/callback_repo_proto.py b/pybotx/bot/callbacks/callback_repo_proto.py index 7c34bf11..7e6b664f 100644 --- a/pybotx/bot/callbacks/callback_repo_proto.py +++ b/pybotx/bot/callbacks/callback_repo_proto.py @@ -16,22 +16,27 @@ class CallbackRepoProto(Protocol): async def create_botx_method_callback( self, sync_id: UUID, - ) -> None: ... # noqa: WPS428, E704 + ) -> None: + ... # noqa: WPS428, E704 async def set_botx_method_callback_result( self, callback: BotXMethodCallback, - ) -> None: ... # noqa: WPS428, E704 + ) -> None: + ... # noqa: WPS428, E704 async def wait_botx_method_callback( self, sync_id: UUID, timeout: float, - ) -> BotXMethodCallback: ... # noqa: WPS428, E704 + ) -> BotXMethodCallback: + ... # noqa: WPS428, E704 async def pop_botx_method_callback( self, sync_id: UUID, - ) -> "Future[BotXMethodCallback]": ... # noqa: WPS428, E704 + ) -> "Future[BotXMethodCallback]": + ... # noqa: WPS428, E704 - async def stop_callbacks_waiting(self) -> None: ... # noqa: WPS428, E704 + async def stop_callbacks_waiting(self) -> None: + ... # noqa: WPS428, E704 diff --git a/pybotx/bot/handler.py b/pybotx/bot/handler.py index a4933e31..b3b989ab 100644 --- a/pybotx/bot/handler.py +++ b/pybotx/bot/handler.py @@ -1,14 +1,6 @@ from dataclasses import dataclass from functools import partial -from typing import ( - TYPE_CHECKING, - Awaitable, - Callable, - List, - Literal, - TypeVar, - Union, -) +from typing import TYPE_CHECKING, Awaitable, Callable, List, Literal, TypeVar, Union from pybotx.models.commands import BotCommand from pybotx.models.message.incoming_message import IncomingMessage diff --git a/pybotx/bot/handler_collector.py b/pybotx/bot/handler_collector.py index 3d07d146..f3908d79 100644 --- a/pybotx/bot/handler_collector.py +++ b/pybotx/bot/handler_collector.py @@ -199,14 +199,16 @@ def decorator( def default_message_handler( self, handler_func: IncomingMessageHandlerFunc, - ) -> IncomingMessageHandlerFunc: ... # noqa: WPS428, E704 + ) -> IncomingMessageHandlerFunc: + ... # noqa: WPS428, E704 @overload def default_message_handler( self, *, middlewares: Optional[Sequence[Middleware]] = None, - ) -> MessageHandlerDecorator: ... # noqa: WPS428, E704 + ) -> MessageHandlerDecorator: + ... # noqa: WPS428, E704 def default_message_handler( # noqa: WPS320 self, diff --git a/pybotx/models/enums.py b/pybotx/models/enums.py index 05bc35fa..b8a4c446 100644 --- a/pybotx/models/enums.py +++ b/pybotx/models/enums.py @@ -307,13 +307,15 @@ def convert_chat_type_from_domain(chat_type: ChatTypes) -> APIChatTypes: @overload def convert_chat_type_to_domain( chat_type: APIChatTypes, -) -> ChatTypes: ... # noqa: WPS428, E704 +) -> ChatTypes: + ... # noqa: WPS428, E704 @overload def convert_chat_type_to_domain( chat_type: str, -) -> UNSUPPORTED: ... # noqa: WPS428, E704 +) -> UNSUPPORTED: + ... # noqa: WPS428, E704 def convert_chat_type_to_domain( @@ -340,13 +342,15 @@ def convert_chat_type_to_domain( @overload def convert_sync_source_type_to_domain( sync_type: APISyncSourceTypes, -) -> SyncSourceTypes: ... # noqa: WPS428, E704 +) -> SyncSourceTypes: + ... # noqa: WPS428, E704 @overload def convert_sync_source_type_to_domain( sync_type: str, -) -> UNSUPPORTED: ... # noqa: WPS428, E704 +) -> UNSUPPORTED: + ... # noqa: WPS428, E704 def convert_sync_source_type_to_domain( diff --git a/tests/test_handler_collector.py b/tests/test_handler_collector.py index 727227f0..40304ece 100644 --- a/tests/test_handler_collector.py +++ b/tests/test_handler_collector.py @@ -562,6 +562,7 @@ async def test__handler_collector__sync_smartapp_event__decorator__handler_alrea @collector.sync_smartapp_event async def duplicated_handle_sync_smartapp_event( *_: Any, - ) -> Any: ... # noqa: E704 + ) -> Any: + ... # noqa: E704 assert str(exc.value) == "Handler for sync smartapp event already registered" From 1b617468ecbd8b842ff4cb9dc20eab6ab1bd2e50 Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 16:03:41 +0300 Subject: [PATCH 05/10] fix lint issues --- pybotx/async_buffer.py | 12 ++---- pybotx/bot/callbacks/callback_manager.py | 6 +-- pybotx/bot/callbacks/callback_repo_proto.py | 15 +++----- pybotx/bot/handler_collector.py | 6 +-- pybotx/models/enums.py | 12 ++---- tests/client/users_api/conftest.py | 4 +- tests/client/users_api/factories.py | 42 ++++++++++----------- tests/test_handler_collector.py | 3 +- 8 files changed, 40 insertions(+), 60 deletions(-) diff --git a/pybotx/async_buffer.py b/pybotx/async_buffer.py index 6c448e9a..ab965560 100644 --- a/pybotx/async_buffer.py +++ b/pybotx/async_buffer.py @@ -13,17 +13,14 @@ async def seek( self, cursor: int, whence: int = os.SEEK_SET, - ) -> int: - ... + ) -> int: ... - async def tell(self) -> int: - ... + async def tell(self) -> int: ... class AsyncBufferWritable(AsyncBufferBase): @abc.abstractmethod - async def write(self, content: bytes) -> int: - ... + async def write(self, content: bytes) -> int: ... class AsyncBufferReadable(AsyncBufferBase): @@ -31,8 +28,7 @@ class AsyncBufferReadable(AsyncBufferBase): async def read( self, bytes_to_read: Optional[int] = None, - ) -> bytes: - ... + ) -> bytes: ... async def get_file_size(async_buffer: AsyncBufferReadable) -> int: diff --git a/pybotx/bot/callbacks/callback_manager.py b/pybotx/bot/callbacks/callback_manager.py index d4852202..7b17a2b9 100644 --- a/pybotx/bot/callbacks/callback_manager.py +++ b/pybotx/bot/callbacks/callback_manager.py @@ -69,16 +69,14 @@ def setup_callback_timeout_alarm(self, sync_id: UUID, timeout: float) -> None: def cancel_callback_timeout_alarm( self, sync_id: UUID, - ) -> None: - ... # noqa: WPS428, E704 + ) -> None: ... # noqa: WPS428, E704 @overload def cancel_callback_timeout_alarm( self, sync_id: UUID, return_remaining_time: Literal[True], - ) -> float: - ... # noqa: WPS428, E704 + ) -> float: ... # noqa: WPS428, E704 def cancel_callback_timeout_alarm( self, diff --git a/pybotx/bot/callbacks/callback_repo_proto.py b/pybotx/bot/callbacks/callback_repo_proto.py index 7e6b664f..7c34bf11 100644 --- a/pybotx/bot/callbacks/callback_repo_proto.py +++ b/pybotx/bot/callbacks/callback_repo_proto.py @@ -16,27 +16,22 @@ class CallbackRepoProto(Protocol): async def create_botx_method_callback( self, sync_id: UUID, - ) -> None: - ... # noqa: WPS428, E704 + ) -> None: ... # noqa: WPS428, E704 async def set_botx_method_callback_result( self, callback: BotXMethodCallback, - ) -> None: - ... # noqa: WPS428, E704 + ) -> None: ... # noqa: WPS428, E704 async def wait_botx_method_callback( self, sync_id: UUID, timeout: float, - ) -> BotXMethodCallback: - ... # noqa: WPS428, E704 + ) -> BotXMethodCallback: ... # noqa: WPS428, E704 async def pop_botx_method_callback( self, sync_id: UUID, - ) -> "Future[BotXMethodCallback]": - ... # noqa: WPS428, E704 + ) -> "Future[BotXMethodCallback]": ... # noqa: WPS428, E704 - async def stop_callbacks_waiting(self) -> None: - ... # noqa: WPS428, E704 + async def stop_callbacks_waiting(self) -> None: ... # noqa: WPS428, E704 diff --git a/pybotx/bot/handler_collector.py b/pybotx/bot/handler_collector.py index f3908d79..3d07d146 100644 --- a/pybotx/bot/handler_collector.py +++ b/pybotx/bot/handler_collector.py @@ -199,16 +199,14 @@ def decorator( def default_message_handler( self, handler_func: IncomingMessageHandlerFunc, - ) -> IncomingMessageHandlerFunc: - ... # noqa: WPS428, E704 + ) -> IncomingMessageHandlerFunc: ... # noqa: WPS428, E704 @overload def default_message_handler( self, *, middlewares: Optional[Sequence[Middleware]] = None, - ) -> MessageHandlerDecorator: - ... # noqa: WPS428, E704 + ) -> MessageHandlerDecorator: ... # noqa: WPS428, E704 def default_message_handler( # noqa: WPS320 self, diff --git a/pybotx/models/enums.py b/pybotx/models/enums.py index b8a4c446..05bc35fa 100644 --- a/pybotx/models/enums.py +++ b/pybotx/models/enums.py @@ -307,15 +307,13 @@ def convert_chat_type_from_domain(chat_type: ChatTypes) -> APIChatTypes: @overload def convert_chat_type_to_domain( chat_type: APIChatTypes, -) -> ChatTypes: - ... # noqa: WPS428, E704 +) -> ChatTypes: ... # noqa: WPS428, E704 @overload def convert_chat_type_to_domain( chat_type: str, -) -> UNSUPPORTED: - ... # noqa: WPS428, E704 +) -> UNSUPPORTED: ... # noqa: WPS428, E704 def convert_chat_type_to_domain( @@ -342,15 +340,13 @@ def convert_chat_type_to_domain( @overload def convert_sync_source_type_to_domain( sync_type: APISyncSourceTypes, -) -> SyncSourceTypes: - ... # noqa: WPS428, E704 +) -> SyncSourceTypes: ... # noqa: WPS428, E704 @overload def convert_sync_source_type_to_domain( sync_type: str, -) -> UNSUPPORTED: - ... # noqa: WPS428, E704 +) -> UNSUPPORTED: ... # noqa: WPS428, E704 def convert_sync_source_type_to_domain( diff --git a/tests/client/users_api/conftest.py b/tests/client/users_api/conftest.py index 3436c646..fdb0757d 100644 --- a/tests/client/users_api/conftest.py +++ b/tests/client/users_api/conftest.py @@ -129,11 +129,11 @@ def csv_users_from_api() -> list[dict[str, str]]: This fixture creates a list of dictionaries representing user data as it would appear in a CSV response from the BotX API. - return: A list of dictionaries where each dictionary represents + :return: A list of dictionaries where each dictionary represents a user with CSV column names as keys and corresponding values as strings. """ return [ - CsvUserResponseValues( + CsvUserResponseValues( # type: ignore Manager_DN=f"manager_dn_{index}", User_DN=f"user_dn_{index}", ) diff --git a/tests/client/users_api/factories.py b/tests/client/users_api/factories.py index e00eb0d1..2ee3dc85 100644 --- a/tests/client/users_api/factories.py +++ b/tests/client/users_api/factories.py @@ -1,9 +1,7 @@ -from random import choice +from factory import DictFactory, Faker # type: ignore -import factory # type: ignore - -class CsvUserResponseValues(factory.DictFactory): # type: ignore[misc] +class CsvUserResponseValues(DictFactory): """Factory for generating CSV user response data. This factory creates dictionaries that simulate user data as it would appear @@ -11,30 +9,30 @@ class CsvUserResponseValues(factory.DictFactory): # type: ignore[misc] """ - HUID = factory.Faker("uuid4") - AD_Login = factory.Faker("user_name") + HUID = Faker("uuid4") # type: ignore + AD_Login = Faker("user_name") # type: ignore Domain = "cts.example.com" - AD_E_mail = factory.Faker("email") - Name = factory.Faker("name") + AD_E_mail = Faker("email") # type: ignore + Name = Faker("name") # type: ignore Sync_source = "ad" - Active = factory.LazyFunction(lambda: choice(["true", "false"])) # noqa: S311 + Active = "true" Kind = "cts_user" - User_DN = factory.Faker("uuid4") - Company = factory.Faker("company") - Department = factory.Faker("catch_phrase") - Position = factory.Faker("job") - Manager = factory.Faker("name") + User_DN = Faker("uuid4") # type: ignore + Company = Faker("company") # type: ignore + Department = Faker("catch_phrase") # type: ignore + Position = Faker("job") # type: ignore + Manager = Faker("name") # type: ignore Manager_HUID = "" Manager_DN = "" Personnel_number = "" - Description = factory.Faker("sentence") - IP_phone = factory.Faker("phone_number") - Other_IP_phone = factory.Faker("phone_number") - Phone = factory.Faker("phone_number") - Other_phone = factory.Faker("phone_number") - Avatar = factory.Faker("file_name", category="image") - Office = factory.Faker("city") - Avatar_preview = factory.Faker("file_name", category="image") + Description = Faker("sentence") # type: ignore + IP_phone = Faker("phone_number") # type: ignore + Other_IP_phone = Faker("phone_number") # type: ignore + Phone = Faker("phone_number") # type: ignore + Other_phone = Faker("phone_number") # type: ignore + Avatar = Faker("file_name", category="image") # type: ignore + Office = Faker("city") # type: ignore + Avatar_preview = Faker("file_name", category="image") # type: ignore class Meta: rename = { diff --git a/tests/test_handler_collector.py b/tests/test_handler_collector.py index 40304ece..727227f0 100644 --- a/tests/test_handler_collector.py +++ b/tests/test_handler_collector.py @@ -562,7 +562,6 @@ async def test__handler_collector__sync_smartapp_event__decorator__handler_alrea @collector.sync_smartapp_event async def duplicated_handle_sync_smartapp_event( *_: Any, - ) -> Any: - ... # noqa: E704 + ) -> Any: ... # noqa: E704 assert str(exc.value) == "Handler for sync smartapp event already registered" From 43901980f1504659f32a590c98e2faf4b4a37f0b Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 17:00:55 +0300 Subject: [PATCH 06/10] fix coverage --- tests/client/users_api/conftest.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/client/users_api/conftest.py b/tests/client/users_api/conftest.py index fdb0757d..bfc4a27a 100644 --- a/tests/client/users_api/conftest.py +++ b/tests/client/users_api/conftest.py @@ -132,7 +132,7 @@ def csv_users_from_api() -> list[dict[str, str]]: :return: A list of dictionaries where each dictionary represents a user with CSV column names as keys and corresponding values as strings. """ - return [ + result_list = [ CsvUserResponseValues( # type: ignore Manager_DN=f"manager_dn_{index}", User_DN=f"user_dn_{index}", @@ -140,6 +140,15 @@ def csv_users_from_api() -> list[dict[str, str]]: for index in range(2) ] + # add extra value for check SyncSource convertion + result_list.append(CsvUserResponseValues( # type: ignore + Manager_DN=f"manager_dn_unsupported_source", + User_DN=f"user_dn_unsupported_source", + Sync_source="unsupported", ), + ) + + return result_list + @pytest.fixture def users_csv_response(csv_users_from_api: List[Dict[str, str]]) -> httpx.Response: From 694a5adf8264406a81f6fd383c3a82d01b3af725 Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 17:03:01 +0300 Subject: [PATCH 07/10] fix coverage --- tests/client/users_api/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/client/users_api/conftest.py b/tests/client/users_api/conftest.py index bfc4a27a..5a641955 100644 --- a/tests/client/users_api/conftest.py +++ b/tests/client/users_api/conftest.py @@ -140,7 +140,7 @@ def csv_users_from_api() -> list[dict[str, str]]: for index in range(2) ] - # add extra value for check SyncSource convertion + # add extra value for check APISyncSourceTypes convertion result_list.append(CsvUserResponseValues( # type: ignore Manager_DN=f"manager_dn_unsupported_source", User_DN=f"user_dn_unsupported_source", From df3d9eeb6c2241e0ee3f661bac22ee284c29d452 Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 17:10:18 +0300 Subject: [PATCH 08/10] fix test --- tests/client/users_api/test_users_as_csv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/client/users_api/test_users_as_csv.py b/tests/client/users_api/test_users_as_csv.py index d78bb0e9..6ed470e0 100644 --- a/tests/client/users_api/test_users_as_csv.py +++ b/tests/client/users_api/test_users_as_csv.py @@ -39,7 +39,7 @@ def assert_csv_user_consist_csv_data( # noqa: WPS218 if isinstance(csv_user.sync_source, SyncSourceTypes): assert str(csv_user.sync_source.value).lower() == original_row["Sync source"] else: - assert str(csv_user).lower() == original_row["Sync source"] + assert str(csv_user.sync_source).lower() == original_row["Sync source"] if original_row["Manager HUID"]: assert str(csv_user.manager_huid) == original_row["Manager HUID"] From cd42e066e8b65f79f6e7196da5ce9bea92396cda Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Fri, 16 May 2025 17:21:03 +0300 Subject: [PATCH 09/10] fix test --- tests/client/users_api/conftest.py | 14 ++------------ tests/client/users_api/factories.py | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/tests/client/users_api/conftest.py b/tests/client/users_api/conftest.py index 5a641955..83e3989b 100644 --- a/tests/client/users_api/conftest.py +++ b/tests/client/users_api/conftest.py @@ -132,20 +132,10 @@ def csv_users_from_api() -> list[dict[str, str]]: :return: A list of dictionaries where each dictionary represents a user with CSV column names as keys and corresponding values as strings. """ - result_list = [ - CsvUserResponseValues( # type: ignore - Manager_DN=f"manager_dn_{index}", - User_DN=f"user_dn_{index}", - ) - for index in range(2) - ] + result_list = CsvUserResponseValues.create_batch(2) # add extra value for check APISyncSourceTypes convertion - result_list.append(CsvUserResponseValues( # type: ignore - Manager_DN=f"manager_dn_unsupported_source", - User_DN=f"user_dn_unsupported_source", - Sync_source="unsupported", ), - ) + result_list.append(CsvUserResponseValues(Sync_source="unsupported")) # type: ignore return result_list diff --git a/tests/client/users_api/factories.py b/tests/client/users_api/factories.py index 2ee3dc85..301c24b7 100644 --- a/tests/client/users_api/factories.py +++ b/tests/client/users_api/factories.py @@ -17,7 +17,7 @@ class CsvUserResponseValues(DictFactory): Sync_source = "ad" Active = "true" Kind = "cts_user" - User_DN = Faker("uuid4") # type: ignore + User_DN = Faker("name") # type: ignore Company = Faker("company") # type: ignore Department = Faker("catch_phrase") # type: ignore Position = Faker("job") # type: ignore From cbdad9c5da8a137ebb4ea30b693513a00b937028 Mon Sep 17 00:00:00 2001 From: vladimirgubarik Date: Wed, 11 Jun 2025 10:32:36 +0300 Subject: [PATCH 10/10] remove optional user_dn --- pybotx/client/users_api/user_from_csv.py | 2 +- pybotx/models/users.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pybotx/client/users_api/user_from_csv.py b/pybotx/client/users_api/user_from_csv.py index a0df8052..015af69b 100644 --- a/pybotx/client/users_api/user_from_csv.py +++ b/pybotx/client/users_api/user_from_csv.py @@ -31,7 +31,7 @@ class BotXAPIUserFromCSVResult(VerifiedPayloadBaseModel): manager: Optional[str] = Field(alias="Manager") manager_huid: Optional[UUID] = Field(alias="Manager HUID") manager_dn: Optional[str] = Field(alias="Manager DN") - user_dn: Optional[str] = Field(alias="User DN") + user_dn: str = Field(alias="User DN") description: Optional[str] = Field(alias="Description") phone: Optional[str] = Field(alias="Phone") other_phone: Optional[str] = Field(alias="Other phone") diff --git a/pybotx/models/users.py b/pybotx/models/users.py index b902398c..c7affa71 100644 --- a/pybotx/models/users.py +++ b/pybotx/models/users.py @@ -111,6 +111,5 @@ class UserFromCSV: ip_phone: Optional[str] = None other_ip_phone: Optional[str] = None personnel_number: Optional[str] = None - # TODO: remove Optional from user_dn user_dn: Optional[str] = None manager_dn: Optional[str] = None