From 23829706749dea77555883a57e43e6d1d5afe9ed Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sat, 5 Oct 2024 22:45:13 +0900 Subject: [PATCH 01/12] =?UTF-8?q?annofabapi=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .devcontainer/devcontainer.json | 3 +- poetry.lock | 324 +++++++++++++++++--------------- pyproject.toml | 2 +- 3 files changed, 171 insertions(+), 158 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fb8bc80..169906a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,7 +19,8 @@ "--init", "--net=host", "--env=ANNOFAB_USER_ID", - "--env=ANNOFAB_PASSWORD" + "--env=ANNOFAB_PASSWORD", + "--env=ANNOFAB_PAT" ], "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind,consistency=cached", "workspaceFolder": "/workspaces", diff --git a/poetry.lock b/poetry.lock index 0c83628..578a7a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,13 +13,13 @@ files = [ [[package]] name = "annofabapi" -version = "0.74.0" +version = "1.0.0" description = "Python Clinet Library of Annofab WebAPI (https://annofab.com/docs/api/)" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "annofabapi-0.74.0-py3-none-any.whl", hash = "sha256:30f418f89f4a261ec43da7153e2473778804b5aa30e152e0a9d496bab1041a37"}, - {file = "annofabapi-0.74.0.tar.gz", hash = "sha256:fb944dfa8626df1473e63ff841e85053c012475927c12b27fbfc682a2b8349f0"}, + {file = "annofabapi-1.0.0-py3-none-any.whl", hash = "sha256:07fc091ffb467d7f4ac77368031426000515c1c84de5162df572f41372c8e615"}, + {file = "annofabapi-1.0.0.tar.gz", hash = "sha256:3941943859c1bff81d1d26452a280b877dfb2b932283b52b7dbe8e96aec5ec83"}, ] [package.dependencies] @@ -34,13 +34,13 @@ segmentation = ["numpy (<1.25)", "numpy (>=1.26)", "pillow"] [[package]] name = "astroid" -version = "3.2.4" +version = "3.3.5" description = "An abstract syntax tree for Python with inference support." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25"}, - {file = "astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a"}, + {file = "astroid-3.3.5-py3-none-any.whl", hash = "sha256:a9d1c946ada25098d790e079ba2a1b112157278f3fb7e718ae6a9252f5835dc8"}, + {file = "astroid-3.3.5.tar.gz", hash = "sha256:5cfc40ae9f68311075d27ef68a4841bdc5cc7f6cf86671b49f00607d30188e2d"}, ] [package.dependencies] @@ -48,13 +48,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] @@ -129,17 +129,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.34.154" +version = "1.35.34" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.154-py3-none-any.whl", hash = "sha256:7ca22adef4c77ee128e1e1dc7d48bc9512a87cc6fe3d771b3f913d5ecd41c057"}, - {file = "boto3-1.34.154.tar.gz", hash = "sha256:864f06528c583dc7b02adf12db395ecfadbf9cb0da90e907e848ffb27128ce19"}, + {file = "boto3-1.35.34-py3-none-any.whl", hash = "sha256:291e7b97a34967ed93297e6171f1bebb8529e64633dd48426760e3fdef1cdea8"}, + {file = "boto3-1.35.34.tar.gz", hash = "sha256:57e6ee8504e7929bc094bb2afc879943906064179a1e88c23b4812e2c6f61532"}, ] [package.dependencies] -botocore = ">=1.34.154,<1.35.0" +botocore = ">=1.35.34,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -148,13 +148,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.154" +version = "1.35.34" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.154-py3-none-any.whl", hash = "sha256:4eef4b1bb809b382ba9dc9c88f5fcc4a133f221a1acb693ee6bee4de9f325979"}, - {file = "botocore-1.34.154.tar.gz", hash = "sha256:64d9b4c85a504d77cb56dabb2ad717cd8e1717424a88edb458b01d1e5797262a"}, + {file = "botocore-1.35.34-py3-none-any.whl", hash = "sha256:ccb0fe397b11b81c9abc0c87029d17298e17bf658d8db5c0c5a551a12a207e7a"}, + {file = "botocore-1.35.34.tar.gz", hash = "sha256:789b6501a3bb4a9591c1fe10da200cc315c1fa5df5ada19c720d8ef06439b3e3"}, ] [package.dependencies] @@ -166,17 +166,17 @@ urllib3 = [ ] [package.extras] -crt = ["awscrt (==0.20.11)"] +crt = ["awscrt (==0.22.0)"] [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -320,13 +320,13 @@ typing-inspect = ">=0.4.0,<1" [[package]] name = "dill" -version = "0.3.8" +version = "0.3.9" description = "serialize all of Python" optional = false python-versions = ">=3.8" files = [ - {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, - {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] @@ -360,16 +360,15 @@ test = ["pytest (>=6)"] [[package]] name = "fire" -version = "0.6.0" +version = "0.7.0" description = "A library for automatically generating command line interfaces." optional = false python-versions = "*" files = [ - {file = "fire-0.6.0.tar.gz", hash = "sha256:54ec5b996ecdd3c0309c800324a0703d6da512241bc73b553db959d98de0aa66"}, + {file = "fire-0.7.0.tar.gz", hash = "sha256:961550f07936eaf65ad1dc8360f2b2bf8408fad46abbfa4d2a3794f8d2a95cdf"}, ] [package.dependencies] -six = "*" termcolor = "*" [[package]] @@ -390,15 +389,18 @@ pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -412,22 +414,26 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.2.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, - {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -577,13 +583,13 @@ files = [ [[package]] name = "marshmallow" -version = "3.21.3" +version = "3.22.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, - {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, + {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, + {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, ] [package.dependencies] @@ -591,7 +597,7 @@ packaging = ">=17.0" [package.extras] dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -648,38 +654,38 @@ files = [ [[package]] name = "mypy" -version = "1.11.1" +version = "1.11.2" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, - {file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, - {file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"}, - {file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"}, - {file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"}, - {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, - {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, - {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, - {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, - {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, - {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, - {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, - {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, - {file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"}, - {file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"}, - {file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"}, - {file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"}, - {file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"}, - {file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"}, - {file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"}, - {file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"}, - {file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"}, - {file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"}, - {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, - {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, + {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, + {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, + {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, + {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, + {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, + {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, + {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, + {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, + {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, + {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, + {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, + {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, ] [package.dependencies] @@ -799,19 +805,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -889,17 +895,17 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pylint" -version = "3.2.6" +version = "3.3.1" description = "python code static checker" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "pylint-3.2.6-py3-none-any.whl", hash = "sha256:03c8e3baa1d9fb995b12c1dbe00aa6c4bcef210c2a2634374aedeb22fb4a8f8f"}, - {file = "pylint-3.2.6.tar.gz", hash = "sha256:a5d01678349454806cff6d886fb072294f56a58c4761278c97fb557d708e1eb3"}, + {file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"}, + {file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"}, ] [package.dependencies] -astroid = ">=3.2.4,<=3.3.0-dev0" +astroid = ">=3.3.4,<=3.4.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -955,62 +961,64 @@ six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] @@ -1117,13 +1125,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.5" +version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] @@ -1271,24 +1279,24 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] [[package]] name = "tomlkit" -version = "0.13.0" +version = "0.13.2" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" files = [ - {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"}, - {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"}, + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] [[package]] @@ -1307,13 +1315,13 @@ types-urllib3 = "*" [[package]] name = "types-requests" -version = "2.32.0.20240712" +version = "2.32.0.20240914" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358"}, - {file = "types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3"}, + {file = "types-requests-2.32.0.20240914.tar.gz", hash = "sha256:2850e178db3919d9bf809e434eef65ba49d0e7e33ac92d588f4a5e295fffd405"}, + {file = "types_requests-2.32.0.20240914-py3-none-any.whl", hash = "sha256:59c2f673eb55f32a99b2894faf6020e1a9f4a402ad0f192bfee0b64469054310"}, ] [package.dependencies] @@ -1358,13 +1366,13 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "1.26.19" +version = "1.26.20" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, + {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, + {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, ] [package.extras] @@ -1374,13 +1382,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -1391,20 +1399,24 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "zipp" -version = "3.19.2" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "193da62c72c03ba3f49b7860e107b3b30da1d8cfd24681c9abedd74ca73f4086" +content-hash = "9c3a382a63f800295c563c5a153397596194e1323c69668d1a750a7a00a6b282" diff --git a/pyproject.toml b/pyproject.toml index fe675ff..be1381d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ packages = [ [tool.poetry.dependencies] python = "^3.9" -annofabapi = ">=0.71.1" +annofabapi = "^1" dataclasses-json = ">=0.5.7,<1" fire = ">=0.3.1,<1" more-itertools = "^8.5.0" From 069c0ff8d2867bd330d835eb9f9248a69331953b Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sat, 5 Oct 2024 22:55:52 +0900 Subject: [PATCH 02/12] =?UTF-8?q?`--annofab=5Fpat`=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/annofab/client.py | 21 +++- anno3d/app.py | 206 +++++++++++++++++++++++++++++---------- 2 files changed, 170 insertions(+), 57 deletions(-) diff --git a/anno3d/annofab/client.py b/anno3d/annofab/client.py index 1f74bd7..d5b00a7 100644 --- a/anno3d/annofab/client.py +++ b/anno3d/annofab/client.py @@ -6,13 +6,21 @@ class ClientLoader: - _annofab_id: str - _annofab_pass: str + _annofab_id: Optional[str] + _annofab_pass: Optional[str] + _annofab_pat: Optional[str] _annofab_endpoint: Optional[str] - def __init__(self, annofab_id: str, annofab_pass: str, endpoint: Optional[str]) -> None: + def __init__( + self, + annofab_id: Optional[str], + annofab_pass: Optional[str], + annofab_pat: Optional[str], + endpoint: Optional[str], + ) -> None: self._annofab_id = annofab_id self._annofab_pass = annofab_pass + self._annofab_pat = annofab_pat self._annofab_endpoint = endpoint @contextmanager @@ -20,7 +28,12 @@ def open_resource(self) -> Generator[Resource, None, None]: endpoint = ( self._annofab_endpoint if self._annofab_endpoint is not None else annofabapi.resource.DEFAULT_ENDPOINT_URL ) - resource = annofabapi.build(self._annofab_id, self._annofab_pass, endpoint_url=endpoint) + resource = annofabapi.build( + self._annofab_id, + self._annofab_pass, + self._annofab_pat, + endpoint_url=endpoint, + ) try: yield resource finally: diff --git a/anno3d/app.py b/anno3d/app.py index dd991d5..5ae12da 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -17,12 +17,20 @@ from anno3d.file_paths_loader import FilePathsLoader, ScenePathsLoader from anno3d.kitti.camera_horizontal_fov_provider import CameraHorizontalFovKind from anno3d.kitti.scene_uploader import SceneUploader, SceneUploaderInput, UploadKind -from anno3d.model.annotation_area import RectAnnotationArea, SphereAnnotationArea, WholeAnnotationArea +from anno3d.model.annotation_area import ( + RectAnnotationArea, + SphereAnnotationArea, + WholeAnnotationArea, +) from anno3d.model.file_paths import FilePaths from anno3d.model.frame import PcdFormat from anno3d.model.input_files import InputData from anno3d.model.scene import Defaults, Scene -from anno3d.simple_data_uploader import SupplementaryData, create_kitti_files, upload_async +from anno3d.simple_data_uploader import ( + SupplementaryData, + create_kitti_files, + upload_async, +) E = TypeVar("E", bound=Enum) @@ -38,7 +46,11 @@ def _decode_enum(enum: Type[E], value: Any) -> E: def add_stdout_handler(target: logging.Logger, level: int = logging.INFO): handler = logging.StreamHandler() handler.setLevel(level) - handler.setFormatter(logging.Formatter("[%(asctime)s] [%(process)d] [%(name)s] [%(levelname)s] %(message)s")) + handler.setFormatter( + logging.Formatter( + "[%(asctime)s] [%(process)d] [%(name)s] [%(levelname)s] %(message)s" + ) + ) target.addHandler(handler) @@ -50,27 +62,31 @@ def add_stdout_handler(target: logging.Logger, level: int = logging.INFO): env_annofab_user_id = os.environ.get("ANNOFAB_USER_ID") env_annofab_password = os.environ.get("ANNOFAB_PASSWORD") +env_annofab_pat = os.environ.get("ANNOFAB_PAT") env_annofab_endpoint = os.environ.get("ANNOFAB_ENDPOINT") -def validate_annofab_credential(annofab_id: Optional[str], annofab_pass: Optional[str]) -> bool: +def validate_annofab_credential( + annofab_id: Optional[str], annofab_pass: Optional[str], annofab_pat: Optional[str] +) -> bool: """ Annofabの認証情報が指定されていることを確認します。 - どちらかが指定されていない場合は処理を終了します。 + 以下の条件をすべて満たす場合は処理を終了します。 + * `annofab_pat`が指定されていない + * `annofab_id`と`annofab_pass`の両方が指定されていない """ - if annofab_id is None: - print( - "AnnofabのユーザIDが指定されていないため、終了します。環境変数'ANNOFAB_USER_ID' または コマンドライン引数 '--annofab_id' にユーザIDを指定してください。", - file=sys.stderr, - ) - return False - if annofab_pass is None: + if annofab_pat is not None: + return True + elif annofab_id is not None and annofab_pass is not None: + return True + else: print( - "Annofabのパスワードが指定されていないため、終了します。環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' にパスワードを指定してください。", + "AnnofabのユーザIDまたはパスワードが指定されていないため、終了します。" + "ユーザーIDは環境変数'ANNOFAB_USER_ID' または コマンドライン引数 '--annofab_id' に指定してください。" + "パスワードは環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' に指定してください。", file=sys.stderr, ) return False - return True def validate_aws_credentail() -> bool: @@ -111,6 +127,7 @@ def create( overview: str = "", annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -119,6 +136,7 @@ def create( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します title: projectのタイトル @@ -131,10 +149,12 @@ def create( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: created_project_id = ProjectApi(api).create_custom_project( title=title, @@ -155,6 +175,7 @@ def put_cuboid_label( color: Optional[Tuple[int, int, int]] = None, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -162,6 +183,7 @@ def put_cuboid_label( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -174,16 +196,22 @@ def put_cuboid_label( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 label_id = str(label_id) - validate_annofab_credential(annofab_id, annofab_pass) - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + validate_annofab_credential(annofab_id, annofab_pass, annofab_pat) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: - labels = ProjectApi(api).put_cuboid_label(project_id, en_name, label_id, ja_name, color) - labels_json = Label.schema().dumps(labels, many=True, ensure_ascii=False, indent=2) + labels = ProjectApi(api).put_cuboid_label( + project_id, en_name, label_id, ja_name, color + ) + labels_json = Label.schema().dumps( + labels, many=True, ensure_ascii=False, indent=2 + ) logger.info("Label(=%s) を作成・更新しました", label_id) logger.info(labels_json) @@ -199,6 +227,7 @@ def put_segment_label( color: Optional[Tuple[int, int, int]] = None, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -206,6 +235,7 @@ def put_segment_label( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -226,7 +256,7 @@ def put_segment_label( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 @@ -238,9 +268,13 @@ def put_segment_label( ) safe_segment_type = cast(Literal["SEMANTIC", "INSTANCE"], segment_type) if layer < 0: - raise RuntimeError(f"layerは、0以上の整数である必要がありますが、{layer} でした") + raise RuntimeError( + f"layerは、0以上の整数である必要がありますが、{layer} でした" + ) - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: labels = ProjectApi(api).put_segment_label( project_id, @@ -252,7 +286,9 @@ def put_segment_label( ja_name=ja_name, color=color, ) - labels_json = Label.schema().dumps(labels, many=True, ensure_ascii=False, indent=2) + labels_json = Label.schema().dumps( + labels, many=True, ensure_ascii=False, indent=2 + ) logger.info("Label(=%s) を作成・更新しました", label_id) logger.info(labels_json) @@ -262,6 +298,7 @@ def set_whole_annotation_area( annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, annofab_endpoint: Optional[str] = env_annofab_endpoint, + annofab_pat: Optional[str] = env_annofab_pat, ) -> None: """ 対象プロジェクトのアノテーション範囲を、「全体」に設定します。 @@ -270,6 +307,7 @@ def set_whole_annotation_area( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -277,13 +315,17 @@ def set_whole_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: - new_meta = ProjectApi(api).set_annotation_area(project_id, WholeAnnotationArea()) + new_meta = ProjectApi(api).set_annotation_area( + project_id, WholeAnnotationArea() + ) logger.info("メタデータを更新しました。") logger.info(new_meta.to_json(ensure_ascii=False, indent=2)) @@ -293,6 +335,7 @@ def set_sphere_annotation_area( radius: float, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -302,6 +345,7 @@ def set_sphere_annotation_area( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -310,13 +354,17 @@ def set_sphere_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: - new_meta = ProjectApi(api).set_annotation_area(project_id, SphereAnnotationArea(area_radius=str(radius))) + new_meta = ProjectApi(api).set_annotation_area( + project_id, SphereAnnotationArea(area_radius=str(radius)) + ) logger.info("メタデータを更新しました。") logger.info(new_meta.to_json(ensure_ascii=False, indent=2)) @@ -327,6 +375,7 @@ def set_rect_annotation_area( y: Tuple[float, float], annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -336,6 +385,7 @@ def set_rect_annotation_area( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -345,11 +395,13 @@ def set_rect_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) min_x = str(min(x)) max_x = str(max(x)) @@ -357,7 +409,13 @@ def set_rect_annotation_area( max_y = str(max(y)) with client_loader.open_api() as api: new_meta = ProjectApi(api).set_annotation_area( - project_id, RectAnnotationArea(area_min_x=min_x, area_max_x=max_x, area_min_y=min_y, area_max_y=max_y) + project_id, + RectAnnotationArea( + area_min_x=min_x, + area_max_x=max_x, + area_min_y=min_y, + area_max_y=max_y, + ), ) logger.info("メタデータを更新しました。") logger.info(new_meta.to_json(ensure_ascii=False, indent=2)) @@ -368,6 +426,7 @@ def remove_preset_cuboid_size( key_name: str, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -376,6 +435,7 @@ def remove_preset_cuboid_size( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -385,12 +445,14 @@ def remove_preset_cuboid_size( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert key_name.isalnum() assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: new_meta = ProjectApi(api).remove_preset_cuboid_size(project_id, key_name) @@ -409,6 +471,7 @@ def add_preset_cuboid_size( order: int, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -417,6 +480,7 @@ def add_preset_cuboid_size( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 対象プロジェクト @@ -432,12 +496,14 @@ def add_preset_cuboid_size( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert key_name.isalnum() assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: new_meta = ProjectApi(api).add_preset_cuboid_size( @@ -458,6 +524,7 @@ def upload_kitti_data( force: bool = False, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -465,6 +532,7 @@ def upload_kitti_data( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 登録先のプロジェクトid @@ -479,7 +547,7 @@ def upload_kitti_data( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None @@ -496,6 +564,7 @@ def upload_kitti_data( force, annofab_id, annofab_pass, + annofab_pat, ) ) @@ -512,16 +581,21 @@ async def _upload_kitti_data_async( force: bool, annofab_id: str, annofab_pass: str, + annofab_pat: str, # TODO ) -> None: project = project_id kitti_dir_path = Path(kitti_dir) loader = FilePathsLoader(kitti_dir_path, kitti_dir_path, kitti_dir_path) pathss = loader.load(None)[skip : (skip + size)] - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) sem_opt = asyncio.Semaphore(parallelism) if parallelism is not None else None - async def run_without_sem(paths: FilePaths) -> Tuple[str, List[SupplementaryData]]: + async def run_without_sem( + paths: FilePaths, + ) -> Tuple[str, List[SupplementaryData]]: return await upload_async( input_data_id_prefix, uploader, @@ -533,7 +607,9 @@ async def run_without_sem(paths: FilePaths) -> Tuple[str, List[SupplementaryData pcd_format=PcdFormat("xyzi"), ) - async def run_with_sem(paths: FilePaths, sem: asyncio.Semaphore) -> Tuple[str, List[SupplementaryData]]: + async def run_with_sem( + paths: FilePaths, sem: asyncio.Semaphore + ) -> Tuple[str, List[SupplementaryData]]: async with sem: return await run_without_sem(paths) @@ -575,6 +651,7 @@ def upload_scene( force: bool = False, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -583,6 +660,7 @@ def upload_scene( Args: annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します project_id: 登録先のプロジェクトid @@ -605,7 +683,7 @@ def upload_scene( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return enum_upload_kind = _decode_enum(UploadKind, upload_kind) @@ -613,16 +691,22 @@ def upload_scene( return assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: scene_uploader = SceneUploader( - api, AnnofabStorageUploader(api, project=project_id, force=force), parallelism + api, + AnnofabStorageUploader(api, project=project_id, force=force), + parallelism, ) uploader_input = SceneUploaderInput( project_id=project_id, input_data_id_prefix=input_data_id_prefix, frame_per_task=frame_per_task, - camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), + camera_horizontal_fov=_decode_enum( + CameraHorizontalFovKind, camera_horizontal_fov + ), sensor_height=sensor_height, task_id_prefix=task_id_prefix, kind=enum_upload_kind, @@ -644,6 +728,7 @@ def upload_scene_to_s3( force: bool = False, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, + annofab_pat: Optional[str] = env_annofab_pat, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -669,10 +754,11 @@ def upload_scene_to_s3( force: 入力データと補助データを上書きしてアップロードするかどうか。 annofab_id: AnnofabのユーザID。指定が無い場合は環境変数`ANNOFAB_USER_ID`の値を採用する annofab_pass: Annofabのパスワード。指定が無い場合は環境変数`ANNOFAB_PASSWORD`の値を採用する + annofab_pat: Annofabのパーソナルアクセストークン。指定が無い場合は環境変数`ANNOFAB_PAT`の値を採用する annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します """ - if not validate_annofab_credential(annofab_id, annofab_pass): + if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return assert annofab_id is not None and annofab_pass is not None if not validate_aws_credentail(): @@ -682,16 +768,22 @@ def upload_scene_to_s3( if not validate_task_id_prefix(task_id_prefix, enum_upload_kind): return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_endpoint) + client_loader = ClientLoader( + annofab_id, annofab_pass, annofab_pat, annofab_endpoint + ) with client_loader.open_api() as api: uploader = SceneUploader( - api, S3Uploader(api, project=project_id, force=force, s3_path=s3_path), parallelism + api, + S3Uploader(api, project=project_id, force=force, s3_path=s3_path), + parallelism, ) uploader_input = SceneUploaderInput( project_id=project_id, input_data_id_prefix=input_data_id_prefix, frame_per_task=frame_per_task, - camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), + camera_horizontal_fov=_decode_enum( + CameraHorizontalFovKind, camera_horizontal_fov + ), sensor_height=sensor_height, task_id_prefix=task_id_prefix, kind=enum_upload_kind, @@ -710,7 +802,9 @@ def _write_all_files_json(inputs: List[InputData], output_dir_path: Path): writer.write(input_data.to_json(ensure_ascii=False, sort_keys=True)) writer.write("\n") - logger.info("%d 件のinput dataを、%sに出力しました", len(inputs), output_dir_path) + logger.info( + "%d 件のinput dataを、%sに出力しました", len(inputs), output_dir_path + ) logger.info("メタデータ: %s", all_files_json.absolute()) @staticmethod @@ -784,7 +878,11 @@ def make_scene( if scene_path_.is_dir(): file = scene_path_ / Defaults.scene_meta_file - scene = Scene.decode_path(file) if file.is_file() else Scene.default_scene(scene_path_) + scene = ( + Scene.decode_path(file) + if file.is_file() + else Scene.default_scene(scene_path_) + ) loader = ScenePathsLoader(scene, file.parent) pathss = loader.load() @@ -793,7 +891,9 @@ def make_scene( input_data_id_prefix, output_dir_path, paths, - camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), + camera_horizontal_fov=_decode_enum( + CameraHorizontalFovKind, camera_horizontal_fov + ), fallback_horizontal_fov=None, sensor_height=sensor_height, pcd_format=PcdFormat(scene.velodyne.format), From 72de444aeb0c626abafee672167aeb9c142a95bc Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sat, 5 Oct 2024 23:09:00 +0900 Subject: [PATCH 03/12] =?UTF-8?q?mypy=E3=81=8C=E9=80=9A=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/app.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/anno3d/app.py b/anno3d/app.py index 5ae12da..cebb961 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -297,8 +297,8 @@ def set_whole_annotation_area( project_id: str, annofab_id: Optional[str] = env_annofab_user_id, annofab_pass: Optional[str] = env_annofab_password, - annofab_endpoint: Optional[str] = env_annofab_endpoint, annofab_pat: Optional[str] = env_annofab_pat, + annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ 対象プロジェクトのアノテーション範囲を、「全体」に設定します。 @@ -579,9 +579,9 @@ async def _upload_kitti_data_async( sensor_height: Optional[float], parallelism: Optional[int], force: bool, - annofab_id: str, - annofab_pass: str, - annofab_pat: str, # TODO + annofab_id: Optional[str], + annofab_pass: Optional[str], + annofab_pat: Optional[str], ) -> None: project = project_id From 3832580d5ce24520f4be99457b0e687bf37a0427 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sat, 5 Oct 2024 23:28:21 +0900 Subject: [PATCH 04/12] format --- anno3d/app.py | 128 ++++++++++++-------------------------------------- 1 file changed, 31 insertions(+), 97 deletions(-) diff --git a/anno3d/app.py b/anno3d/app.py index cebb961..4a9dc76 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -17,20 +17,12 @@ from anno3d.file_paths_loader import FilePathsLoader, ScenePathsLoader from anno3d.kitti.camera_horizontal_fov_provider import CameraHorizontalFovKind from anno3d.kitti.scene_uploader import SceneUploader, SceneUploaderInput, UploadKind -from anno3d.model.annotation_area import ( - RectAnnotationArea, - SphereAnnotationArea, - WholeAnnotationArea, -) +from anno3d.model.annotation_area import RectAnnotationArea, SphereAnnotationArea, WholeAnnotationArea from anno3d.model.file_paths import FilePaths from anno3d.model.frame import PcdFormat from anno3d.model.input_files import InputData from anno3d.model.scene import Defaults, Scene -from anno3d.simple_data_uploader import ( - SupplementaryData, - create_kitti_files, - upload_async, -) +from anno3d.simple_data_uploader import SupplementaryData, create_kitti_files, upload_async E = TypeVar("E", bound=Enum) @@ -46,11 +38,7 @@ def _decode_enum(enum: Type[E], value: Any) -> E: def add_stdout_handler(target: logging.Logger, level: int = logging.INFO): handler = logging.StreamHandler() handler.setLevel(level) - handler.setFormatter( - logging.Formatter( - "[%(asctime)s] [%(process)d] [%(name)s] [%(levelname)s] %(message)s" - ) - ) + handler.setFormatter(logging.Formatter("[%(asctime)s] [%(process)d] [%(name)s] [%(levelname)s] %(message)s")) target.addHandler(handler) @@ -151,10 +139,7 @@ def create( """ if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: created_project_id = ProjectApi(api).create_custom_project( title=title, @@ -198,20 +183,14 @@ def put_cuboid_label( """ if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None + # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 label_id = str(label_id) validate_annofab_credential(annofab_id, annofab_pass, annofab_pat) - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: - labels = ProjectApi(api).put_cuboid_label( - project_id, en_name, label_id, ja_name, color - ) - labels_json = Label.schema().dumps( - labels, many=True, ensure_ascii=False, indent=2 - ) + labels = ProjectApi(api).put_cuboid_label(project_id, en_name, label_id, ja_name, color) + labels_json = Label.schema().dumps(labels, many=True, ensure_ascii=False, indent=2) logger.info("Label(=%s) を作成・更新しました", label_id) logger.info(labels_json) @@ -258,7 +237,7 @@ def put_segment_label( """ if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None + # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 label_id = str(label_id) @@ -268,13 +247,9 @@ def put_segment_label( ) safe_segment_type = cast(Literal["SEMANTIC", "INSTANCE"], segment_type) if layer < 0: - raise RuntimeError( - f"layerは、0以上の整数である必要がありますが、{layer} でした" - ) + raise RuntimeError(f"layerは、0以上の整数である必要がありますが、{layer} でした") - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: labels = ProjectApi(api).put_segment_label( project_id, @@ -286,9 +261,7 @@ def put_segment_label( ja_name=ja_name, color=color, ) - labels_json = Label.schema().dumps( - labels, many=True, ensure_ascii=False, indent=2 - ) + labels_json = Label.schema().dumps(labels, many=True, ensure_ascii=False, indent=2) logger.info("Label(=%s) を作成・更新しました", label_id) logger.info(labels_json) @@ -318,14 +291,9 @@ def set_whole_annotation_area( if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: - new_meta = ProjectApi(api).set_annotation_area( - project_id, WholeAnnotationArea() - ) + new_meta = ProjectApi(api).set_annotation_area(project_id, WholeAnnotationArea()) logger.info("メタデータを更新しました。") logger.info(new_meta.to_json(ensure_ascii=False, indent=2)) @@ -357,14 +325,9 @@ def set_sphere_annotation_area( if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: - new_meta = ProjectApi(api).set_annotation_area( - project_id, SphereAnnotationArea(area_radius=str(radius)) - ) + new_meta = ProjectApi(api).set_annotation_area(project_id, SphereAnnotationArea(area_radius=str(radius))) logger.info("メタデータを更新しました。") logger.info(new_meta.to_json(ensure_ascii=False, indent=2)) @@ -398,10 +361,7 @@ def set_rect_annotation_area( if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) min_x = str(min(x)) max_x = str(max(x)) @@ -449,10 +409,8 @@ def remove_preset_cuboid_size( return assert key_name.isalnum() - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).remove_preset_cuboid_size(project_id, key_name) @@ -500,10 +458,8 @@ def add_preset_cuboid_size( return assert key_name.isalnum() - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).add_preset_cuboid_size( @@ -550,7 +506,6 @@ def upload_kitti_data( if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None asyncio.run( ProjectCommand._upload_kitti_data_async( project_id, @@ -588,9 +543,7 @@ async def _upload_kitti_data_async( kitti_dir_path = Path(kitti_dir) loader = FilePathsLoader(kitti_dir_path, kitti_dir_path, kitti_dir_path) pathss = loader.load(None)[skip : (skip + size)] - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) sem_opt = asyncio.Semaphore(parallelism) if parallelism is not None else None async def run_without_sem( @@ -607,9 +560,7 @@ async def run_without_sem( pcd_format=PcdFormat("xyzi"), ) - async def run_with_sem( - paths: FilePaths, sem: asyncio.Semaphore - ) -> Tuple[str, List[SupplementaryData]]: + async def run_with_sem(paths: FilePaths, sem: asyncio.Semaphore) -> Tuple[str, List[SupplementaryData]]: async with sem: return await run_without_sem(paths) @@ -690,10 +641,7 @@ def upload_scene( if not validate_task_id_prefix(task_id_prefix, enum_upload_kind): return - assert annofab_id is not None and annofab_pass is not None - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: scene_uploader = SceneUploader( api, @@ -704,9 +652,7 @@ def upload_scene( project_id=project_id, input_data_id_prefix=input_data_id_prefix, frame_per_task=frame_per_task, - camera_horizontal_fov=_decode_enum( - CameraHorizontalFovKind, camera_horizontal_fov - ), + camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), sensor_height=sensor_height, task_id_prefix=task_id_prefix, kind=enum_upload_kind, @@ -760,7 +706,7 @@ def upload_scene_to_s3( """ if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): return - assert annofab_id is not None and annofab_pass is not None + if not validate_aws_credentail(): return @@ -768,9 +714,7 @@ def upload_scene_to_s3( if not validate_task_id_prefix(task_id_prefix, enum_upload_kind): return - client_loader = ClientLoader( - annofab_id, annofab_pass, annofab_pat, annofab_endpoint - ) + client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) with client_loader.open_api() as api: uploader = SceneUploader( api, @@ -781,9 +725,7 @@ def upload_scene_to_s3( project_id=project_id, input_data_id_prefix=input_data_id_prefix, frame_per_task=frame_per_task, - camera_horizontal_fov=_decode_enum( - CameraHorizontalFovKind, camera_horizontal_fov - ), + camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), sensor_height=sensor_height, task_id_prefix=task_id_prefix, kind=enum_upload_kind, @@ -802,9 +744,7 @@ def _write_all_files_json(inputs: List[InputData], output_dir_path: Path): writer.write(input_data.to_json(ensure_ascii=False, sort_keys=True)) writer.write("\n") - logger.info( - "%d 件のinput dataを、%sに出力しました", len(inputs), output_dir_path - ) + logger.info("%d 件のinput dataを、%sに出力しました", len(inputs), output_dir_path) logger.info("メタデータ: %s", all_files_json.absolute()) @staticmethod @@ -878,11 +818,7 @@ def make_scene( if scene_path_.is_dir(): file = scene_path_ / Defaults.scene_meta_file - scene = ( - Scene.decode_path(file) - if file.is_file() - else Scene.default_scene(scene_path_) - ) + scene = Scene.decode_path(file) if file.is_file() else Scene.default_scene(scene_path_) loader = ScenePathsLoader(scene, file.parent) pathss = loader.load() @@ -891,9 +827,7 @@ def make_scene( input_data_id_prefix, output_dir_path, paths, - camera_horizontal_fov=_decode_enum( - CameraHorizontalFovKind, camera_horizontal_fov - ), + camera_horizontal_fov=_decode_enum(CameraHorizontalFovKind, camera_horizontal_fov), fallback_horizontal_fov=None, sensor_height=sensor_height, pcd_format=PcdFormat(scene.velodyne.format), From f201380a59271daa9b913a10b0c6d56f23da49e2 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sat, 5 Oct 2024 23:28:38 +0900 Subject: [PATCH 05/12] =?UTF-8?q?pylint=E3=81=AE=E3=83=AB=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=82=92=E4=B8=80=E9=83=A8=E7=84=A1=E8=A6=96=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pylintrc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 23eb91c..598229e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -28,4 +28,6 @@ disable= cyclic-import, similarities, # Similar lines in 2 files # ===== 修正すべき項目 ===== - empty-docstring, \ No newline at end of file + empty-docstring, + too-many-positional-arguments, # コマンドに対応するメソッドでは引数の数が多くなるため + \ No newline at end of file From 86c8ac033861e7551d9e948e427db53b09898de4 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Mon, 7 Oct 2024 09:34:49 +0900 Subject: [PATCH 06/12] =?UTF-8?q?ClientLoader=E3=81=AB=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=81=A8validation=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/annofab/client.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/anno3d/annofab/client.py b/anno3d/annofab/client.py index d5b00a7..98cdd33 100644 --- a/anno3d/annofab/client.py +++ b/anno3d/annofab/client.py @@ -6,6 +6,11 @@ class ClientLoader: + """ + Raises: + ValueError: 「`annofab_pat`がNone」 AND 「`annofab_id` OR `annofab_pass`がNone」のとき + """ + _annofab_id: Optional[str] _annofab_pass: Optional[str] _annofab_pat: Optional[str] @@ -18,6 +23,9 @@ def __init__( annofab_pat: Optional[str], endpoint: Optional[str], ) -> None: + if annofab_pass is None and (annofab_id is None or annofab_pass is None): + raise ValueError("以下のいずれかの条件を満たす必要があります。(A) 'annofab_pat'を指定する。 (B) 'annofab_id'と'annofab_pass'の両方を指定する。") + self._annofab_id = annofab_id self._annofab_pass = annofab_pass self._annofab_pat = annofab_pat From b330cbaab54fda38591716a1afbe8252e3c1926e Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 8 Oct 2024 10:18:15 +0900 Subject: [PATCH 07/12] =?UTF-8?q?AnnofabCredential=E3=82=92=E5=AE=9A?= =?UTF-8?q?=E7=BE=A9=E3=81=99=E3=82=8B=E3=80=82=E8=AA=8D=E8=A8=BC=E6=83=85?= =?UTF-8?q?=E5=A0=B1=E3=81=AE=E5=84=AA=E5=85=88=E9=A0=86=E4=BD=8D=E3=82=92?= =?UTF-8?q?`get=5Fannofab=5Fcredential`=E3=81=A7=E5=AE=9A=E7=BE=A9?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/annofab/client.py | 61 +++++++++++------ anno3d/app.py | 143 ++++++++++++++++++++++++++++++--------- anno3d/util/type_util.py | 6 ++ 3 files changed, 156 insertions(+), 54 deletions(-) create mode 100644 anno3d/util/type_util.py diff --git a/anno3d/annofab/client.py b/anno3d/annofab/client.py index 98cdd33..2d05b7e 100644 --- a/anno3d/annofab/client.py +++ b/anno3d/annofab/client.py @@ -1,34 +1,40 @@ from contextlib import contextmanager -from typing import Generator, Optional +from dataclasses import dataclass +from typing import Generator, Optional, Union import annofabapi from annofabapi import AnnofabApi, Resource +from anno3d.util.type_util import assert_noreturn -class ClientLoader: - """ - Raises: - ValueError: 「`annofab_pat`がNone」 AND 「`annofab_id` OR `annofab_pass`がNone」のとき - """ - _annofab_id: Optional[str] - _annofab_pass: Optional[str] - _annofab_pat: Optional[str] - _annofab_endpoint: Optional[str] +@dataclass(frozen=True) +class IdPass: + """ユーザIDとパスワード""" + + user_id: str + password: str + + +@dataclass(frozen=True) +class Pat: + """Personal Access Token""" + + token: str + + +Credential = Union[IdPass, Pat] + + +class ClientLoader: + _credential: Credential def __init__( self, - annofab_id: Optional[str], - annofab_pass: Optional[str], - annofab_pat: Optional[str], + credential: Credential, endpoint: Optional[str], ) -> None: - if annofab_pass is None and (annofab_id is None or annofab_pass is None): - raise ValueError("以下のいずれかの条件を満たす必要があります。(A) 'annofab_pat'を指定する。 (B) 'annofab_id'と'annofab_pass'の両方を指定する。") - - self._annofab_id = annofab_id - self._annofab_pass = annofab_pass - self._annofab_pat = annofab_pat + self._credential = credential self._annofab_endpoint = endpoint @contextmanager @@ -36,10 +42,21 @@ def open_resource(self) -> Generator[Resource, None, None]: endpoint = ( self._annofab_endpoint if self._annofab_endpoint is not None else annofabapi.resource.DEFAULT_ENDPOINT_URL ) + annofab_id = None + annofab_pass = None + annofab_pat = None + if isinstance(self._credential, IdPass): + annofab_id = self._credential.user_id + annofab_pass = self._credential.password + elif isinstance(self._credential, Pat): + annofab_pat = self._credential.token + else: + assert_noreturn(self._credential) + resource = annofabapi.build( - self._annofab_id, - self._annofab_pass, - self._annofab_pat, + annofab_id, + annofab_pass, + annofab_pat, endpoint_url=endpoint, ) try: diff --git a/anno3d/app.py b/anno3d/app.py index 4a9dc76..d5600ba 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -11,6 +11,8 @@ from anno3d import __version__ from anno3d.annofab.client import ClientLoader +from anno3d.annofab.client import Credential as AnnofabCredential +from anno3d.annofab.client import IdPass, Pat from anno3d.annofab.constant import segment_type_instance, segment_type_semantic from anno3d.annofab.project import Label, ProjectApi from anno3d.annofab.uploader import AnnofabStorageUploader, S3Uploader @@ -54,6 +56,65 @@ def add_stdout_handler(target: logging.Logger, level: int = logging.INFO): env_annofab_endpoint = os.environ.get("ANNOFAB_ENDPOINT") +class InvalidCredentialError(Exception): + pass + + +def get_annofab_credential( + cli_annofab_id: Optional[str], + cli_annofab_pass: Optional[str], + cli_annofab_pat: Optional[str], +) -> AnnofabCredential: + """ + Annofabの認証情報を取得します。 + + 認証情報の優先順位は以下の通りです。 + + 1. コマンドライン引数で指定されたAnnofabのパーソナルアクセストークン + 2. コマンドライン引数で指定されたAnnofabのユーザーID + 3. 環境変数`ANNOFAB_PAT`に設定されたAnnofabのパーソナルアクセストークン + 4. 環境変数`ANNOFAB_USER_ID`に設定されたAnnofabのユーザーID + + + Args: + cli_annofab_id: コマンドライン引数で指定されたAnnofabのユーザーID + cli_annofab_pass: コマンドライン引数で指定されたAnnofabのパスワード + cli_annofab_pat: コマンドライン引数で指定されたAnnofabのパーソナルアクセストークン + """ + password = cli_annofab_pass if cli_annofab_pass is not None else os.environ.get("ANNOFAB_PASSWORD") + if cli_annofab_pat is not None: + return Pat(token=cli_annofab_pat) + + if cli_annofab_id is not None: + if password is None: + print( + "Annofabのパスワードが指定されていないため、終了します。環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' にパスワードを指定してください。", + file=sys.stderr, + ) + raise InvalidCredentialError("Annofabのパスワードが指定されていません。") + return IdPass(user_id=cli_annofab_id, password=password) + + if env_annofab_pat is not None: + return Pat(token=env_annofab_pat) + + if env_annofab_user_id is not None and env_annofab_password is not None: + if password is None: + print( + "Annofabのパスワードが指定されていないため、終了します。環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' にパスワードを指定してください。", + file=sys.stderr, + ) + raise InvalidCredentialError("Annofabのパスワードが指定されていません。") + return IdPass(user_id=env_annofab_user_id, password=password) + + print( + "AnnofabのユーザーIDまたはパーソナルアクセストークンが指定されていないため、終了します。" + "ユーザーIDは環境変数'ANNOFAB_USER_ID' または コマンドライン引数 '--annofab_id' に指定してください。" + "パーソナルアクセストークンは環境変数'ANNOFAB_PAT' または コマンドライン引数 '--annofab_pat' に指定してください。", + file=sys.stderr, + ) + raise InvalidCredentialError("AnnofabのユーザーIDまたはパスワードが指定されていません。") + + def validate_annofab_credential( annofab_id: Optional[str], annofab_pass: Optional[str], annofab_pat: Optional[str] ) -> bool: @@ -113,9 +174,9 @@ def create( plugin_id: str = "", specs_plugin_id: str = "", overview: str = "", - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -137,9 +198,12 @@ def create( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: created_project_id = ProjectApi(api).create_custom_project( title=title, @@ -181,13 +245,14 @@ def put_cuboid_label( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 label_id = str(label_id) - validate_annofab_credential(annofab_id, annofab_pass, annofab_pat) - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: labels = ProjectApi(api).put_cuboid_label(project_id, en_name, label_id, ja_name, color) labels_json = Label.schema().dumps(labels, many=True, ensure_ascii=False, indent=2) @@ -235,7 +300,9 @@ def put_segment_label( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return # 数値に変換可能な場合は型がintに変わるので、strに明示的に変換する。 @@ -249,7 +316,7 @@ def put_segment_label( if layer < 0: raise RuntimeError(f"layerは、0以上の整数である必要がありますが、{layer} でした") - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: labels = ProjectApi(api).put_segment_label( project_id, @@ -288,10 +355,12 @@ def set_whole_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).set_annotation_area(project_id, WholeAnnotationArea()) logger.info("メタデータを更新しました。") @@ -322,10 +391,12 @@ def set_sphere_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).set_annotation_area(project_id, SphereAnnotationArea(area_radius=str(radius))) logger.info("メタデータを更新しました。") @@ -358,10 +429,12 @@ def set_rect_annotation_area( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) min_x = str(min(x)) max_x = str(max(x)) @@ -405,12 +478,14 @@ def remove_preset_cuboid_size( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return assert key_name.isalnum() - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).remove_preset_cuboid_size(project_id, key_name) @@ -454,12 +529,14 @@ def add_preset_cuboid_size( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return assert key_name.isalnum() - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: new_meta = ProjectApi(api).add_preset_cuboid_size( @@ -503,7 +580,9 @@ def upload_kitti_data( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return asyncio.run( @@ -517,9 +596,7 @@ def upload_kitti_data( sensor_height, parallelism, force, - annofab_id, - annofab_pass, - annofab_pat, + annofab_credential, ) ) @@ -534,16 +611,14 @@ async def _upload_kitti_data_async( sensor_height: Optional[float], parallelism: Optional[int], force: bool, - annofab_id: Optional[str], - annofab_pass: Optional[str], - annofab_pat: Optional[str], + annofab_credential: AnnofabCredential, ) -> None: project = project_id kitti_dir_path = Path(kitti_dir) loader = FilePathsLoader(kitti_dir_path, kitti_dir_path, kitti_dir_path) pathss = loader.load(None)[skip : (skip + size)] - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) sem_opt = asyncio.Semaphore(parallelism) if parallelism is not None else None async def run_without_sem( @@ -634,14 +709,16 @@ def upload_scene( Returns: """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return enum_upload_kind = _decode_enum(UploadKind, upload_kind) if not validate_task_id_prefix(task_id_prefix, enum_upload_kind): return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: scene_uploader = SceneUploader( api, @@ -704,7 +781,9 @@ def upload_scene_to_s3( annofab_endpoint: AnnofabのAPIアクセス先エンドポイントを指定します。 省略した場合は環境変数`ANNOFAB_ENDPOINT`の値を利用します。\ 環境変数も指定されていない場合、デフォルトのエンドポイント(https://annofab.com)を利用します """ - if not validate_annofab_credential(annofab_id, annofab_pass, annofab_pat): + try: + annofab_credential = get_annofab_credential(annofab_id, annofab_pass, annofab_pat) + except InvalidCredentialError: return if not validate_aws_credentail(): @@ -714,7 +793,7 @@ def upload_scene_to_s3( if not validate_task_id_prefix(task_id_prefix, enum_upload_kind): return - client_loader = ClientLoader(annofab_id, annofab_pass, annofab_pat, annofab_endpoint) + client_loader = ClientLoader(annofab_credential, annofab_endpoint) with client_loader.open_api() as api: uploader = SceneUploader( api, diff --git a/anno3d/util/type_util.py b/anno3d/util/type_util.py new file mode 100644 index 0000000..d7199cc --- /dev/null +++ b/anno3d/util/type_util.py @@ -0,0 +1,6 @@ +from typing import NoReturn + + +def assert_noreturn(x: NoReturn) -> NoReturn: + """python 3.11 以降に追加されたassert_neverの代わり""" + raise AssertionError(f"Invalid value: {x!r}") # x!rは repr(x)と等価 From 42be5746badb00837b9ac19aa030dc3e21960062 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 8 Oct 2024 11:02:04 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/app.py | 71 +++++++++++++------------- tests/test_app.py | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 35 deletions(-) create mode 100644 tests/test_app.py diff --git a/anno3d/app.py b/anno3d/app.py index d5600ba..e932b81 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -50,9 +50,6 @@ def add_stdout_handler(target: logging.Logger, level: int = logging.INFO): logger = logging.getLogger(__name__) -env_annofab_user_id = os.environ.get("ANNOFAB_USER_ID") -env_annofab_password = os.environ.get("ANNOFAB_PASSWORD") -env_annofab_pat = os.environ.get("ANNOFAB_PAT") env_annofab_endpoint = os.environ.get("ANNOFAB_ENDPOINT") @@ -81,7 +78,11 @@ def get_annofab_credential( cli_annofab_pass: コマンドライン引数で指定されたAnnofabのパスワード cli_annofab_pat: コマンドライン引数で指定されたAnnofabのパーソナルアクセストークン """ - password = cli_annofab_pass if cli_annofab_pass is not None else os.environ.get("ANNOFAB_PASSWORD") + env_annofab_user_id = os.environ.get("ANNOFAB_USER_ID") + env_annofab_password = os.environ.get("ANNOFAB_PASSWORD") + env_annofab_pat = os.environ.get("ANNOFAB_PAT") + + password = cli_annofab_pass if cli_annofab_pass is not None else env_annofab_password if cli_annofab_pat is not None: return Pat(token=cli_annofab_pat) @@ -97,7 +98,7 @@ def get_annofab_credential( if env_annofab_pat is not None: return Pat(token=env_annofab_pat) - if env_annofab_user_id is not None and env_annofab_password is not None: + if env_annofab_user_id is not None: if password is None: print( "Annofabのパスワードが指定されていないため、終了します。環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' にパスワードを指定してください。", @@ -222,9 +223,9 @@ def put_cuboid_label( label_id: str = "", ja_name: str = "", color: Optional[Tuple[int, int, int]] = None, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -269,9 +270,9 @@ def put_segment_label( label_id: str = "", ja_name: str = "", color: Optional[Tuple[int, int, int]] = None, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -335,9 +336,9 @@ def put_segment_label( @staticmethod def set_whole_annotation_area( project_id: str, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -370,9 +371,9 @@ def set_whole_annotation_area( def set_sphere_annotation_area( project_id: str, radius: float, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -407,9 +408,9 @@ def set_rect_annotation_area( project_id: str, x: Tuple[float, float], y: Tuple[float, float], - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -457,9 +458,9 @@ def set_rect_annotation_area( def remove_preset_cuboid_size( project_id: str, key_name: str, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -502,9 +503,9 @@ def add_preset_cuboid_size( height: float, depth: float, order: int, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -555,9 +556,9 @@ def upload_kitti_data( sensor_height: Optional[float] = None, parallelism: Optional[int] = None, force: bool = False, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -675,9 +676,9 @@ def upload_scene( upload_kind: str = UploadKind.CREATE_ANNOTATION.value, parallelism: Optional[int] = None, force: bool = False, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ @@ -749,9 +750,9 @@ def upload_scene_to_s3( upload_kind: str = UploadKind.CREATE_ANNOTATION.value, parallelism: Optional[int] = None, force: bool = False, - annofab_id: Optional[str] = env_annofab_user_id, - annofab_pass: Optional[str] = env_annofab_password, - annofab_pat: Optional[str] = env_annofab_pat, + annofab_id: Optional[str] = None, + annofab_pass: Optional[str] = None, + annofab_pat: Optional[str] = None, annofab_endpoint: Optional[str] = env_annofab_endpoint, ) -> None: """ diff --git a/tests/test_app.py b/tests/test_app.py new file mode 100644 index 0000000..4f29c2d --- /dev/null +++ b/tests/test_app.py @@ -0,0 +1,127 @@ +import os + +import pytest + +from anno3d.annofab.client import ClientLoader, IdPass, Pat +from anno3d.app import InvalidCredentialError, get_annofab_credential + + +class Test引数なしでbuildした時: + @pytest.fixture(autouse=True) + def setup(self): + print("clear env") + os.environ.pop("ANNOFAB_USER_ID", None) + os.environ.pop("ANNOFAB_PASSWORD", None) + os.environ.pop("ANNOFAB_PAT", None) + yield + # もとに戻す + + def test_コマンドライン引数で指定されたパーソナルアクセストークンの優先順位は1番目( + self, + ): + os.environ["ANNOFAB_USER_ID"] = "env_user_id" + os.environ["ANNOFAB_PAT"] = "env_pat" + credential = get_annofab_credential( + cli_annofab_id="cli_user_id", + cli_annofab_pass="cli_password", + cli_annofab_pat="cli_pat", + ) + assert isinstance(credential, Pat) + assert credential.token == "cli_pat" + + def test_コマンドライン引数で指定されたユーザーIDの優先順位は2番目( + self, + ): + os.environ["ANNOFAB_USER_ID"] = "env_user_id" + os.environ["ANNOFAB_PAT"] = "env_pat" + credential = get_annofab_credential( + cli_annofab_id="cli_user_id", + cli_annofab_pass="cli_password", + cli_annofab_pat=None, + ) + assert isinstance(credential, IdPass) + assert credential.user_id == "cli_user_id" + assert credential.password == "cli_password" + + def test_環境変数で指定されたパーソナルアクセストークンの優先順位は3番目( + self, + ): + os.environ["ANNOFAB_USER_ID"] = "env_user_id" + os.environ["ANNOFAB_PAT"] = "env_pat" + credential = get_annofab_credential( + cli_annofab_id=None, + cli_annofab_pass="cli_password", + cli_annofab_pat=None, + ) + assert isinstance(credential, Pat) + assert credential.token == "env_pat" + + def test_環境変数で指定されたユーザーIDの優先順位は4番目( + self, + ): + os.environ["ANNOFAB_USER_ID"] = "env_user_id" + credential = get_annofab_credential( + cli_annofab_id=None, + cli_annofab_pass="cli_password", + cli_annofab_pat=None, + ) + assert isinstance(credential, IdPass) + assert credential.user_id == "env_user_id" + assert credential.password == "cli_password" + + def test_コマンドライン引数で指定されたパスワードは環境変数で指定されたパスワードより優先順位が高い( + self, + ): + os.environ["ANNOFAB_PASSWORD"] = "env_password" + credential = get_annofab_credential( + cli_annofab_id="cli_user_id", + cli_annofab_pass="cli_password", + cli_annofab_pat=None, + ) + assert isinstance(credential, IdPass) + assert credential.user_id == "cli_user_id" + assert credential.password == "cli_password" + + def test_環境変数で指定されたパスワードが参照されること( + self, + ): + os.environ["ANNOFAB_PASSWORD"] = "env_password" + credential = get_annofab_credential( + cli_annofab_id="cli_user_id", + cli_annofab_pass=None, + cli_annofab_pat=None, + ) + assert isinstance(credential, IdPass) + assert credential.user_id == "cli_user_id" + assert credential.password == "env_password" + + def test_コマンドライン引数でユーザーIDが指定されている状態でパスワードが指定されないとInvalidCredentialErrorがraiseされる( + self, + ): + with pytest.raises(InvalidCredentialError): + get_annofab_credential( + cli_annofab_id="cli_user_id", + cli_annofab_pass=None, + cli_annofab_pat=None, + ) + + def test_環境変数でユーザーIDが指定されている状態でパスワードが指定されないとInvalidCredentialErrorがraiseされる( + self, + ): + os.environ["ANNOFAB_USER_ID"] = "env_user_id" + with pytest.raises(InvalidCredentialError): + get_annofab_credential( + cli_annofab_id=None, + cli_annofab_pass=None, + cli_annofab_pat=None, + ) + + def test_ユーザーIDとパーソナルアクセストークンの両方が指定されていないとInvalidCredentialErrorがraiseされる( + self, + ): + with pytest.raises(InvalidCredentialError): + get_annofab_credential( + cli_annofab_id=None, + cli_annofab_pass=None, + cli_annofab_pat=None, + ) From 47e7fbb1b0e0c8c1983fe6a5703de9af4fd3c661 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 8 Oct 2024 11:05:59 +0900 Subject: [PATCH 09/12] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E9=96=A2?= =?UTF-8?q?=E6=95=B0=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/app.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/anno3d/app.py b/anno3d/app.py index e932b81..7fb4726 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -116,29 +116,6 @@ def get_annofab_credential( raise InvalidCredentialError("AnnofabのユーザーIDまたはパスワードが指定されていません。") -def validate_annofab_credential( - annofab_id: Optional[str], annofab_pass: Optional[str], annofab_pat: Optional[str] -) -> bool: - """ - Annofabの認証情報が指定されていることを確認します。 - 以下の条件をすべて満たす場合は処理を終了します。 - * `annofab_pat`が指定されていない - * `annofab_id`と`annofab_pass`の両方が指定されていない - """ - if annofab_pat is not None: - return True - elif annofab_id is not None and annofab_pass is not None: - return True - else: - print( - "AnnofabのユーザIDまたはパスワードが指定されていないため、終了します。" - "ユーザーIDは環境変数'ANNOFAB_USER_ID' または コマンドライン引数 '--annofab_id' に指定してください。" - "パスワードは環境変数'ANNOFAB_PASSWORD' または コマンドライン引数 '--annofab_pass' に指定してください。", - file=sys.stderr, - ) - return False - - def validate_aws_credentail() -> bool: if boto3.DEFAULT_SESSION is None: boto3.setup_default_session() From 1260191abec465ee3e519d2a7cf7640ea19ab746 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 8 Oct 2024 11:17:26 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=AF?= =?UTF-8?q?=E3=83=A9=E3=82=B9=E3=81=AE=E5=90=8D=E5=89=8D=E3=82=92=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_app.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_app.py b/tests/test_app.py index 4f29c2d..8d4eeba 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -2,19 +2,16 @@ import pytest -from anno3d.annofab.client import ClientLoader, IdPass, Pat +from anno3d.annofab.client import IdPass, Pat from anno3d.app import InvalidCredentialError, get_annofab_credential -class Test引数なしでbuildした時: +class Test_get_annofab_credential: @pytest.fixture(autouse=True) def setup(self): - print("clear env") os.environ.pop("ANNOFAB_USER_ID", None) os.environ.pop("ANNOFAB_PASSWORD", None) os.environ.pop("ANNOFAB_PAT", None) - yield - # もとに戻す def test_コマンドライン引数で指定されたパーソナルアクセストークンの優先順位は1番目( self, From 7740add4df71ec7beebd49db9a17f2676c48c6c1 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 8 Oct 2024 11:19:28 +0900 Subject: [PATCH 11/12] =?UTF-8?q?pylint=E3=81=AE=E3=83=AB=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=82=92=E7=84=A1=E8=A6=96=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pylintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.pylintrc b/.pylintrc index 598229e..6a42ff9 100644 --- a/.pylintrc +++ b/.pylintrc @@ -30,4 +30,5 @@ disable= # ===== 修正すべき項目 ===== empty-docstring, too-many-positional-arguments, # コマンドに対応するメソッドでは引数の数が多くなるため + non-ascii-name, # テストメソッドの名前に日本語を利用するため \ No newline at end of file From 420234ea1636387ddbe99455a50e7cc1cfd138c8 Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Thu, 10 Oct 2024 17:18:46 +0900 Subject: [PATCH 12/12] =?UTF-8?q?InvalidCredentialError=E3=81=AE=E3=83=A1?= =?UTF-8?q?=E3=83=83=E3=82=BB=E3=83=BC=E3=82=B8=E3=81=8C=E9=96=93=E9=81=95?= =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F=E3=81=AE=E3=81=A7=E3=80=81?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anno3d/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anno3d/app.py b/anno3d/app.py index 7fb4726..33a67ff 100644 --- a/anno3d/app.py +++ b/anno3d/app.py @@ -113,7 +113,7 @@ def get_annofab_credential( "パーソナルアクセストークンは環境変数'ANNOFAB_PAT' または コマンドライン引数 '--annofab_pat' に指定してください。", file=sys.stderr, ) - raise InvalidCredentialError("AnnofabのユーザーIDまたはパスワードが指定されていません。") + raise InvalidCredentialError("AnnofabのユーザーIDまたはパーソナルアクセストークンが指定されていません。") def validate_aws_credentail() -> bool: