From 0dc3710ec9c6ee6e4e1c8136b6208b739c55ac32 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 05:19:12 +0100 Subject: [PATCH 01/20] move connection test from init to execute for ListFiles plugin --- cmem_plugin_ssh/list.py | 10 +++++++--- tests/test_list.py | 12 ++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cmem_plugin_ssh/list.py b/cmem_plugin_ssh/list.py index 4e014ac..63fea9f 100644 --- a/cmem_plugin_ssh/list.py +++ b/cmem_plugin_ssh/list.py @@ -151,6 +151,9 @@ class ListFiles(WorkflowPlugin): """List Plugin SSH""" + ssh_client: paramiko.SSHClient + sftp: paramiko.SFTPClient + def __init__( # noqa: PLR0913 self, hostname: str, @@ -178,9 +181,6 @@ def __init__( # noqa: PLR0913 self.max_workers = setup_max_workers(max_workers) self.input_ports = FixedNumberOfInputs([]) self.output_port = FixedSchemaPort(schema=generate_list_schema()) - self.ssh_client = paramiko.SSHClient() - self.connect_ssh_client() - self.sftp = self.ssh_client.open_sftp() def close_connections(self) -> None: """Close connection from sftp and ssh""" @@ -228,6 +228,10 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti ) entities = [] + self.ssh_client = paramiko.SSHClient() + self.connect_ssh_client() + self.sftp = self.ssh_client.open_sftp() + retrieval = SSHRetrieval( ssh_client=self.ssh_client, no_subfolder=self.no_subfolder, diff --git a/tests/test_list.py b/tests/test_list.py index ca8751a..0904b13 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -26,7 +26,7 @@ def test_private_key_with_wrong_password(testing_environment: TestingEnvironment regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_private_key_with_password_execution(testing_environment: TestingEnvironment) -> None: @@ -78,7 +78,7 @@ def test_plugin_wrong_hostname(testing_environment: TestingEnvironment) -> None: regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_plugin_wrong_username(testing_environment: TestingEnvironment) -> None: @@ -95,7 +95,7 @@ def test_plugin_wrong_username(testing_environment: TestingEnvironment) -> None: regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_plugin_wrong_port(testing_environment: TestingEnvironment) -> None: @@ -112,7 +112,7 @@ def test_plugin_wrong_port(testing_environment: TestingEnvironment) -> None: regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_plugin_wrong_private_key(testing_environment: TestingEnvironment) -> None: @@ -129,7 +129,7 @@ def test_plugin_wrong_private_key(testing_environment: TestingEnvironment) -> No regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_plugin_wrong_password(testing_environment: TestingEnvironment) -> None: @@ -146,7 +146,7 @@ def test_plugin_wrong_password(testing_environment: TestingEnvironment) -> None: regex=testing_environment.regex, no_subfolder=testing_environment.no_subfolder, error_handling=testing_environment.error_handling, - ) + ).execute(inputs=[], context=TestExecutionContext()) def test_plugin_password_authentication_only(testing_environment: TestingEnvironment) -> None: From 7bac2c8f9176035f2b13f9689a1769babb7db653 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 06:47:48 +0100 Subject: [PATCH 02/20] add dev dependency testcontainers --- poetry.lock | 499 +++++++++++++++++++++++++++++++------------------ pyproject.toml | 1 + 2 files changed, 319 insertions(+), 181 deletions(-) diff --git a/poetry.lock b/poetry.lock index a0e9314..ebc0d2e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -102,14 +102,14 @@ lxml = ["lxml"] [[package]] name = "certifi" -version = "2025.7.14" +version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, - {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] [[package]] @@ -345,14 +345,14 @@ dev = ["mypy", "pytest"] [[package]] name = "cmem-cmemc" -version = "25.3.0" +version = "25.4.0" description = "Command line client for eccenca Corporate Memory" optional = false python-versions = "<4.0,>=3.10" groups = ["dev"] files = [ - {file = "cmem_cmemc-25.3.0-py3-none-any.whl", hash = "sha256:6281e9ec769e112ab286cf02ab1b1aa9d6b2d1301e88deb99b9a8855e8e691b2"}, - {file = "cmem_cmemc-25.3.0.tar.gz", hash = "sha256:a42b6d8db2dbe42544ab37b8405eb2476ab874d23b8efb9e055558c9bd456776"}, + {file = "cmem_cmemc-25.4.0-py3-none-any.whl", hash = "sha256:68e6ffea3d102f0480f5ceeb87578182018a829c057c2ab256b713c2f0b34e76"}, + {file = "cmem_cmemc-25.4.0.tar.gz", hash = "sha256:aa04dc3f0354d62cbbf0bf421512a483a63b0e4dceb6c104bf89d140bd4f5790"}, ] [package.dependencies] @@ -361,7 +361,7 @@ certifi = ">=2024.2.2" click = ">=8.1.8,<8.2.0" click-didyoumean = ">=0.3.1,<0.4.0" click-help-colors = ">=0.9.4,<0.10.0" -cmem-cmempy = "25.2.0" +cmem-cmempy = "25.3.0" configparser = ">=7.2.0,<8.0.0" jinja2 = ">=3.1.6,<4.0.0" junit-xml = ">=1.9,<2.0" @@ -381,14 +381,14 @@ urllib3 = ">=2.3.0,<3.0.0" [[package]] name = "cmem-cmempy" -version = "25.2.0" +version = "25.3.0" description = "API for eccenca Corporate Memory" optional = false python-versions = "<4.0,>=3.9" groups = ["main", "dev"] files = [ - {file = "cmem_cmempy-25.2.0-py3-none-any.whl", hash = "sha256:c44fd780ff042c754ff92abdc7ba9a91b915694bc8b2725b399fee3144706d32"}, - {file = "cmem_cmempy-25.2.0.tar.gz", hash = "sha256:ad4bf2a8c97079d2076ad85ad56e0667ad310f04acc87899caee27d01701a319"}, + {file = "cmem_cmempy-25.3.0-py3-none-any.whl", hash = "sha256:75f9c6900661b5573615b43086897eb4b5fccdb1ec953fa9e20cdaecaeea75c2"}, + {file = "cmem_cmempy-25.3.0.tar.gz", hash = "sha256:ccef1410bde7e248d4b89b37366e7c386c8a1558190a07090f0d3c11e3b16ff4"}, ] [package.dependencies] @@ -450,79 +450,100 @@ type = ["pytest-mypy"] [[package]] name = "coverage" -version = "7.9.2" +version = "7.10.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "coverage-7.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:66283a192a14a3854b2e7f3418d7db05cdf411012ab7ff5db98ff3b181e1f912"}, - {file = "coverage-7.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4e01d138540ef34fcf35c1aa24d06c3de2a4cffa349e29a10056544f35cca15f"}, - {file = "coverage-7.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f22627c1fe2745ee98d3ab87679ca73a97e75ca75eb5faee48660d060875465f"}, - {file = "coverage-7.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b1c2d8363247b46bd51f393f86c94096e64a1cf6906803fa8d5a9d03784bdbf"}, - {file = "coverage-7.9.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c10c882b114faf82dbd33e876d0cbd5e1d1ebc0d2a74ceef642c6152f3f4d547"}, - {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:de3c0378bdf7066c3988d66cd5232d161e933b87103b014ab1b0b4676098fa45"}, - {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1e2f097eae0e5991e7623958a24ced3282676c93c013dde41399ff63e230fcf2"}, - {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28dc1f67e83a14e7079b6cea4d314bc8b24d1aed42d3582ff89c0295f09b181e"}, - {file = "coverage-7.9.2-cp310-cp310-win32.whl", hash = "sha256:bf7d773da6af9e10dbddacbf4e5cab13d06d0ed93561d44dae0188a42c65be7e"}, - {file = "coverage-7.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:0c0378ba787681ab1897f7c89b415bd56b0b2d9a47e5a3d8dc0ea55aac118d6c"}, - {file = "coverage-7.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a7a56a2964a9687b6aba5b5ced6971af308ef6f79a91043c05dd4ee3ebc3e9ba"}, - {file = "coverage-7.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123d589f32c11d9be7fe2e66d823a236fe759b0096f5db3fb1b75b2fa414a4fa"}, - {file = "coverage-7.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:333b2e0ca576a7dbd66e85ab402e35c03b0b22f525eed82681c4b866e2e2653a"}, - {file = "coverage-7.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:326802760da234baf9f2f85a39e4a4b5861b94f6c8d95251f699e4f73b1835dc"}, - {file = "coverage-7.9.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19e7be4cfec248df38ce40968c95d3952fbffd57b400d4b9bb580f28179556d2"}, - {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0b4a4cb73b9f2b891c1788711408ef9707666501ba23684387277ededab1097c"}, - {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2c8937fa16c8c9fbbd9f118588756e7bcdc7e16a470766a9aef912dd3f117dbd"}, - {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:42da2280c4d30c57a9b578bafd1d4494fa6c056d4c419d9689e66d775539be74"}, - {file = "coverage-7.9.2-cp311-cp311-win32.whl", hash = "sha256:14fa8d3da147f5fdf9d298cacc18791818f3f1a9f542c8958b80c228320e90c6"}, - {file = "coverage-7.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:549cab4892fc82004f9739963163fd3aac7a7b0df430669b75b86d293d2df2a7"}, - {file = "coverage-7.9.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2667a2b913e307f06aa4e5677f01a9746cd08e4b35e14ebcde6420a9ebb4c62"}, - {file = "coverage-7.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae9eb07f1cfacd9cfe8eaee6f4ff4b8a289a668c39c165cd0c8548484920ffc0"}, - {file = "coverage-7.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ce85551f9a1119f02adc46d3014b5ee3f765deac166acf20dbb851ceb79b6f3"}, - {file = "coverage-7.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8f6389ac977c5fb322e0e38885fbbf901743f79d47f50db706e7644dcdcb6e1"}, - {file = "coverage-7.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d9eae8cdfcd58fe7893b88993723583a6ce4dfbfd9f29e001922544f95615"}, - {file = "coverage-7.9.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae939811e14e53ed8a9818dad51d434a41ee09df9305663735f2e2d2d7d959b"}, - {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:31991156251ec202c798501e0a42bbdf2169dcb0f137b1f5c0f4267f3fc68ef9"}, - {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d0d67963f9cbfc7c7f96d4ac74ed60ecbebd2ea6eeb51887af0f8dce205e545f"}, - {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49b752a2858b10580969ec6af6f090a9a440a64a301ac1528d7ca5f7ed497f4d"}, - {file = "coverage-7.9.2-cp312-cp312-win32.whl", hash = "sha256:88d7598b8ee130f32f8a43198ee02edd16d7f77692fa056cb779616bbea1b355"}, - {file = "coverage-7.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:9dfb070f830739ee49d7c83e4941cc767e503e4394fdecb3b54bfdac1d7662c0"}, - {file = "coverage-7.9.2-cp312-cp312-win_arm64.whl", hash = "sha256:4e2c058aef613e79df00e86b6d42a641c877211384ce5bd07585ed7ba71ab31b"}, - {file = "coverage-7.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:985abe7f242e0d7bba228ab01070fde1d6c8fa12f142e43debe9ed1dde686038"}, - {file = "coverage-7.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c3939264a76d44fde7f213924021ed31f55ef28111a19649fec90c0f109e6d"}, - {file = "coverage-7.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae5d563e970dbe04382f736ec214ef48103d1b875967c89d83c6e3f21706d5b3"}, - {file = "coverage-7.9.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdd612e59baed2a93c8843c9a7cb902260f181370f1d772f4842987535071d14"}, - {file = "coverage-7.9.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:256ea87cb2a1ed992bcdfc349d8042dcea1b80436f4ddf6e246d6bee4b5d73b6"}, - {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f44ae036b63c8ea432f610534a2668b0c3aee810e7037ab9d8ff6883de480f5b"}, - {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82d76ad87c932935417a19b10cfe7abb15fd3f923cfe47dbdaa74ef4e503752d"}, - {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:619317bb86de4193debc712b9e59d5cffd91dc1d178627ab2a77b9870deb2868"}, - {file = "coverage-7.9.2-cp313-cp313-win32.whl", hash = "sha256:0a07757de9feb1dfafd16ab651e0f628fd7ce551604d1bf23e47e1ddca93f08a"}, - {file = "coverage-7.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:115db3d1f4d3f35f5bb021e270edd85011934ff97c8797216b62f461dd69374b"}, - {file = "coverage-7.9.2-cp313-cp313-win_arm64.whl", hash = "sha256:48f82f889c80af8b2a7bb6e158d95a3fbec6a3453a1004d04e4f3b5945a02694"}, - {file = "coverage-7.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:55a28954545f9d2f96870b40f6c3386a59ba8ed50caf2d949676dac3ecab99f5"}, - {file = "coverage-7.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cdef6504637731a63c133bb2e6f0f0214e2748495ec15fe42d1e219d1b133f0b"}, - {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcd5ebe66c7a97273d5d2ddd4ad0ed2e706b39630ed4b53e713d360626c3dbb3"}, - {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9303aed20872d7a3c9cb39c5d2b9bdbe44e3a9a1aecb52920f7e7495410dfab8"}, - {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc18ea9e417a04d1920a9a76fe9ebd2f43ca505b81994598482f938d5c315f46"}, - {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6406cff19880aaaadc932152242523e892faff224da29e241ce2fca329866584"}, - {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d0d4f6ecdf37fcc19c88fec3e2277d5dee740fb51ffdd69b9579b8c31e4232e"}, - {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c33624f50cf8de418ab2b4d6ca9eda96dc45b2c4231336bac91454520e8d1fac"}, - {file = "coverage-7.9.2-cp313-cp313t-win32.whl", hash = "sha256:1df6b76e737c6a92210eebcb2390af59a141f9e9430210595251fbaf02d46926"}, - {file = "coverage-7.9.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f5fd54310b92741ebe00d9c0d1d7b2b27463952c022da6d47c175d246a98d1bd"}, - {file = "coverage-7.9.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c48c2375287108c887ee87d13b4070a381c6537d30e8487b24ec721bf2a781cb"}, - {file = "coverage-7.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ddc39510ac922a5c4c27849b739f875d3e1d9e590d1e7b64c98dadf037a16cce"}, - {file = "coverage-7.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a535c0c7364acd55229749c2b3e5eebf141865de3a8f697076a3291985f02d30"}, - {file = "coverage-7.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df0f9ef28e0f20c767ccdccfc5ae5f83a6f4a2fbdfbcbcc8487a8a78771168c8"}, - {file = "coverage-7.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f3da12e0ccbcb348969221d29441ac714bbddc4d74e13923d3d5a7a0bebef7a"}, - {file = "coverage-7.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a17eaf46f56ae0f870f14a3cbc2e4632fe3771eab7f687eda1ee59b73d09fe4"}, - {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:669135a9d25df55d1ed56a11bf555f37c922cf08d80799d4f65d77d7d6123fcf"}, - {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9d3a700304d01a627df9db4322dc082a0ce1e8fc74ac238e2af39ced4c083193"}, - {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:71ae8b53855644a0b1579d4041304ddc9995c7b21c8a1f16753c4d8903b4dfed"}, - {file = "coverage-7.9.2-cp39-cp39-win32.whl", hash = "sha256:dd7a57b33b5cf27acb491e890720af45db05589a80c1ffc798462a765be6d4d7"}, - {file = "coverage-7.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f65bb452e579d5540c8b37ec105dd54d8b9307b07bcaa186818c104ffda22441"}, - {file = "coverage-7.9.2-pp39.pp310.pp311-none-any.whl", hash = "sha256:8a1166db2fb62473285bcb092f586e081e92656c7dfa8e9f62b4d39d7e6b5050"}, - {file = "coverage-7.9.2-py3-none-any.whl", hash = "sha256:e425cd5b00f6fc0ed7cdbd766c70be8baab4b7839e4d4fe5fac48581dd968ea4"}, - {file = "coverage-7.9.2.tar.gz", hash = "sha256:997024fa51e3290264ffd7492ec97d0690293ccd2b45a6cd7d82d945a4a80c8b"}, + {file = "coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65"}, + {file = "coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8"}, + {file = "coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87"}, + {file = "coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1"}, + {file = "coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce"}, + {file = "coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2"}, + {file = "coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b"}, + {file = "coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340"}, + {file = "coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388"}, + {file = "coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a"}, + {file = "coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b"}, + {file = "coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe"}, + {file = "coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb"}, + {file = "coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824"}, + {file = "coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3"}, + {file = "coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd"}, + {file = "coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8"}, + {file = "coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3"}, + {file = "coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed"}, + {file = "coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0"}, + {file = "coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf"}, + {file = "coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e33e79a219105aa315439ee051bd50b6caa705dc4164a5aba6932c8ac3ce2d98"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:be127f292496d0fbe20d8025f73221b36117b3587f890346e80a13b310712982"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0"}, + {file = "coverage-7.10.2-cp39-cp39-win32.whl", hash = "sha256:22aca3e691c7709c5999ccf48b7a8ff5cf5a8bd6fe9b36efbd4993f5a36b2fcf"}, + {file = "coverage-7.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c7195444b932356055a8e287fa910bf9753a84a1bc33aeb3770e8fca521e032e"}, + {file = "coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f"}, + {file = "coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055"}, ] [package.extras] @@ -530,49 +551,49 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "45.0.5" +version = "45.0.6" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["main", "dev"] files = [ - {file = "cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174"}, - {file = "cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9"}, - {file = "cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"}, - {file = "cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a"}, - {file = "cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f"}, - {file = "cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f"}, - {file = "cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a"}, + {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453"}, + {file = "cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159"}, + {file = "cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec"}, + {file = "cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9"}, + {file = "cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02"}, + {file = "cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043"}, + {file = "cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719"}, ] [package.dependencies] @@ -585,7 +606,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -602,28 +623,28 @@ files = [ [[package]] name = "deptry" -version = "0.23.0" +version = "0.23.1" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "deptry-0.23.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1f2a6817a37d76e8f6b667381b7caf6ea3e6d6c18b5be24d36c625f387c79852"}, - {file = "deptry-0.23.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:9601b64cc0aed42687fdd5c912d5f1e90d7f7333fb589b14e35bfdfebae866f3"}, - {file = "deptry-0.23.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6172b2205f6e84bcc9df25226693d4deb9576a6f746c2ace828f6d13401d357"}, - {file = "deptry-0.23.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cfa4b3a46ee8a026eaa38e4b9ba43fe6036a07fe16bf0a663cb611b939f6af8"}, - {file = "deptry-0.23.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9d03cc99a61c348df92074a50e0a71b28f264f0edbf686084ca90e6fd44e3abe"}, - {file = "deptry-0.23.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9a46f78098f145100dc582a59af8548b26cdfa16cf0fbd85d2d44645e724cb6a"}, - {file = "deptry-0.23.0-cp39-abi3-win_amd64.whl", hash = "sha256:d53e803b280791d89a051b6183d9dc40411200e22a8ab7e6c32c6b169822a664"}, - {file = "deptry-0.23.0-cp39-abi3-win_arm64.whl", hash = "sha256:da7678624f4626d839c8c03675452cefc59d6cf57d25c84a9711dae514719279"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:40706dcbed54141f2d23afa70a272171c8c46531cd6f0f9c8ef482c906b3cee2"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:889541844092f18e7b48631852195f36c25c5afd4d7e074b19ba824b430add50"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aff9156228eb16cd81792f920c1623c00cb59091ae572600ba0eac587da33c0c"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:583154732cfd438a4a090b7d13d8b2016f1ac2732534f34fb689345768d8538b"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:736e7bc557aec6118b2a4d454f0d81f070782faeaa9d8d3c9a15985c9f265372"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5f7e4b1a5232ed6d352fca7173750610a169377d1951d3e9782947191942a765"}, - {file = "deptry-0.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:04afae204654542406318fd3dd6f4a6697579597f37195437daf84a53ee0ebbf"}, - {file = "deptry-0.23.0.tar.gz", hash = "sha256:4915a3590ccf38ad7a9176aee376745aa9de121f50f8da8fb9ccec87fa93e676"}, + {file = "deptry-0.23.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f0b231d098fb5b48d8973c9f192c353ffdd395770063424969fa7f15ddfea7d8"}, + {file = "deptry-0.23.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf057f514bb2fa18a2b192a7f7372bd14577ff46b11486933e8383dfef461983"}, + {file = "deptry-0.23.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ee3f5663bb1c048e2aaf25a4d9e6d09cc1f3b3396ee248980878c6a6c9c0e21"}, + {file = "deptry-0.23.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae0366dc5f50a5fb29cf90de1110c5e368513de6c1b2dac439f2817f3f752616"}, + {file = "deptry-0.23.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ab156a90a9eda5819aeb1c1da585dd4d5ec509029399a38771a49e78f40db90f"}, + {file = "deptry-0.23.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:651c7eb168233755152fcc468713c024d64a03069645187edb4a17ba61ce6133"}, + {file = "deptry-0.23.1-cp39-abi3-win_amd64.whl", hash = "sha256:8da1e8f70e7086ebc228f3a4a3cfb5aa127b09b5eef60d694503d6bb79809025"}, + {file = "deptry-0.23.1-cp39-abi3-win_arm64.whl", hash = "sha256:f589497a5809717db4dcf2aa840f2847c0a4c489331608e538850b6a9ab1c30b"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6af91d86380ef703adb6ae65f273d88e3cca7fd315c4c309da857a0cfa728244"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:42a249d317c3128c286035a1f7aaa41a0c3c967f17848817c2e07ca50d5ed450"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d988c7c75201997970bae1e8d564b4c7a14d350556c4f7c269fd33f3b081c314"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae13d8e65ae88b77632c45edb4038301a6f9efcac06715abfde9a029e5879698"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:40058a7a3fe9dacb745668897ee992e58daf5aac406b668ff2eaaf0f6f586550"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d111cf4261eeadbdb20051d8d542f04deb3cfced0cb280ece8d654f7f6055921"}, + {file = "deptry-0.23.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9f9bbb92f95ada9ccfa5ecefee05ba3c39cfa0734b5483a3a1a3c4eeb9c99054"}, + {file = "deptry-0.23.1.tar.gz", hash = "sha256:5d23e0ef25f3c56405c05383a476edda55944563c5c47a3e9249ed3ec860d382"}, ] [package.dependencies] @@ -632,6 +653,29 @@ colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} packaging = ">=23.2" requirements-parser = ">=0.11.0,<1" +[[package]] +name = "docker" +version = "7.1.0" +description = "A Python library for the Docker Engine API." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, + {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, +] + +[package.dependencies] +pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} +requests = ">=2.26.0" +urllib3 = ">=1.26.0" + +[package.extras] +dev = ["coverage (==7.2.7)", "pytest (==7.4.2)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.1.0)", "ruff (==0.1.8)"] +docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] +ssh = ["paramiko (>=2.4.3)"] +websockets = ["websocket-client (>=1.3.0)"] + [[package]] name = "dparse" version = "0.6.4" @@ -959,44 +1003,50 @@ test = ["Cython", "greenlet", "ipython", "packaging", "pytest", "pytest-cov", "p [[package]] name = "mypy" -version = "1.17.0" +version = "1.17.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8e08de6138043108b3b18f09d3f817a4783912e48828ab397ecf183135d84d6"}, - {file = "mypy-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce4a17920ec144647d448fc43725b5873548b1aae6c603225626747ededf582d"}, - {file = "mypy-1.17.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff25d151cc057fdddb1cb1881ef36e9c41fa2a5e78d8dd71bee6e4dcd2bc05b"}, - {file = "mypy-1.17.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93468cf29aa9a132bceb103bd8475f78cacde2b1b9a94fd978d50d4bdf616c9a"}, - {file = "mypy-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98189382b310f16343151f65dd7e6867386d3e35f7878c45cfa11383d175d91f"}, - {file = "mypy-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:c004135a300ab06a045c1c0d8e3f10215e71d7b4f5bb9a42ab80236364429937"}, - {file = "mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be"}, - {file = "mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61"}, - {file = "mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f"}, - {file = "mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d"}, - {file = "mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3"}, - {file = "mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70"}, - {file = "mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb"}, - {file = "mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d"}, - {file = "mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8"}, - {file = "mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e"}, - {file = "mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8"}, - {file = "mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d"}, - {file = "mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06"}, - {file = "mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a"}, - {file = "mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889"}, - {file = "mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba"}, - {file = "mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658"}, - {file = "mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c"}, - {file = "mypy-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63e751f1b5ab51d6f3d219fe3a2fe4523eaa387d854ad06906c63883fde5b1ab"}, - {file = "mypy-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fb09d05e0f1c329a36dcd30e27564a3555717cde87301fae4fb542402ddfad"}, - {file = "mypy-1.17.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b72c34ce05ac3a1361ae2ebb50757fb6e3624032d91488d93544e9f82db0ed6c"}, - {file = "mypy-1.17.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434ad499ad8dde8b2f6391ddfa982f41cb07ccda8e3c67781b1bfd4e5f9450a8"}, - {file = "mypy-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f105f61a5eff52e137fd73bee32958b2add9d9f0a856f17314018646af838e97"}, - {file = "mypy-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:ba06254a5a22729853209550d80f94e28690d5530c661f9416a68ac097b13fc4"}, - {file = "mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496"}, - {file = "mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03"}, + {file = "mypy-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3fbe6d5555bf608c47203baa3e72dbc6ec9965b3d7c318aa9a4ca76f465bd972"}, + {file = "mypy-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80ef5c058b7bce08c83cac668158cb7edea692e458d21098c7d3bce35a5d43e7"}, + {file = "mypy-1.17.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a580f8a70c69e4a75587bd925d298434057fe2a428faaf927ffe6e4b9a98df"}, + {file = "mypy-1.17.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd86bb649299f09d987a2eebb4d52d10603224500792e1bee18303bbcc1ce390"}, + {file = "mypy-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a76906f26bd8d51ea9504966a9c25419f2e668f012e0bdf3da4ea1526c534d94"}, + {file = "mypy-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:e79311f2d904ccb59787477b7bd5d26f3347789c06fcd7656fa500875290264b"}, + {file = "mypy-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad37544be07c5d7fba814eb370e006df58fed8ad1ef33ed1649cb1889ba6ff58"}, + {file = "mypy-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:064e2ff508e5464b4bd807a7c1625bc5047c5022b85c70f030680e18f37273a5"}, + {file = "mypy-1.17.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70401bbabd2fa1aa7c43bb358f54037baf0586f41e83b0ae67dd0534fc64edfd"}, + {file = "mypy-1.17.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e92bdc656b7757c438660f775f872a669b8ff374edc4d18277d86b63edba6b8b"}, + {file = "mypy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c1fdf4abb29ed1cb091cf432979e162c208a5ac676ce35010373ff29247bcad5"}, + {file = "mypy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:ff2933428516ab63f961644bc49bc4cbe42bbffb2cd3b71cc7277c07d16b1a8b"}, + {file = "mypy-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69e83ea6553a3ba79c08c6e15dbd9bfa912ec1e493bf75489ef93beb65209aeb"}, + {file = "mypy-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b16708a66d38abb1e6b5702f5c2c87e133289da36f6a1d15f6a5221085c6403"}, + {file = "mypy-1.17.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89e972c0035e9e05823907ad5398c5a73b9f47a002b22359b177d40bdaee7056"}, + {file = "mypy-1.17.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03b6d0ed2b188e35ee6d5c36b5580cffd6da23319991c49ab5556c023ccf1341"}, + {file = "mypy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c837b896b37cd103570d776bda106eabb8737aa6dd4f248451aecf53030cdbeb"}, + {file = "mypy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:665afab0963a4b39dff7c1fa563cc8b11ecff7910206db4b2e64dd1ba25aed19"}, + {file = "mypy-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93378d3203a5c0800c6b6d850ad2f19f7a3cdf1a3701d3416dbf128805c6a6a7"}, + {file = "mypy-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15d54056f7fe7a826d897789f53dd6377ec2ea8ba6f776dc83c2902b899fee81"}, + {file = "mypy-1.17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:209a58fed9987eccc20f2ca94afe7257a8f46eb5df1fb69958650973230f91e6"}, + {file = "mypy-1.17.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:099b9a5da47de9e2cb5165e581f158e854d9e19d2e96b6698c0d64de911dd849"}, + {file = "mypy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ffadfbe6994d724c5a1bb6123a7d27dd68fc9c059561cd33b664a79578e14"}, + {file = "mypy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:9a2b7d9180aed171f033c9f2fc6c204c1245cf60b0cb61cf2e7acc24eea78e0a"}, + {file = "mypy-1.17.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:15a83369400454c41ed3a118e0cc58bd8123921a602f385cb6d6ea5df050c733"}, + {file = "mypy-1.17.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55b918670f692fc9fba55c3298d8a3beae295c5cded0a55dccdc5bbead814acd"}, + {file = "mypy-1.17.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62761474061feef6f720149d7ba876122007ddc64adff5ba6f374fda35a018a0"}, + {file = "mypy-1.17.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c49562d3d908fd49ed0938e5423daed8d407774a479b595b143a3d7f87cdae6a"}, + {file = "mypy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:397fba5d7616a5bc60b45c7ed204717eaddc38f826e3645402c426057ead9a91"}, + {file = "mypy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:9d6b20b97d373f41617bd0708fd46aa656059af57f2ef72aa8c7d6a2b73b74ed"}, + {file = "mypy-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d1092694f166a7e56c805caaf794e0585cabdbf1df36911c414e4e9abb62ae9"}, + {file = "mypy-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79d44f9bfb004941ebb0abe8eff6504223a9c1ac51ef967d1263c6572bbebc99"}, + {file = "mypy-1.17.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b01586eed696ec905e61bd2568f48740f7ac4a45b3a468e6423a03d3788a51a8"}, + {file = "mypy-1.17.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43808d9476c36b927fbcd0b0255ce75efe1b68a080154a38ae68a7e62de8f0f8"}, + {file = "mypy-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:feb8cc32d319edd5859da2cc084493b3e2ce5e49a946377663cc90f6c15fb259"}, + {file = "mypy-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d7598cf74c3e16539d4e2f0b8d8c318e00041553d83d4861f87c7a72e95ac24d"}, + {file = "mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9"}, + {file = "mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01"}, ] [package.dependencies] @@ -1212,14 +1262,14 @@ xmp = ["defusedxml"] [[package]] name = "pip" -version = "25.1.1" +version = "25.2" description = "The PyPA recommended tool for installing Python packages." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pip-25.1.1-py3-none-any.whl", hash = "sha256:2913a38a2abf4ea6b64ab507bd9e967f3b53dc1ede74b01b0931e1ce548751af"}, - {file = "pip-25.1.1.tar.gz", hash = "sha256:3de45d411d308d5054c2168185d8da7f9a2cd753dbac8acbfa88a8909ecd9077"}, + {file = "pip-25.2-py3-none-any.whl", hash = "sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717"}, + {file = "pip-25.2.tar.gz", hash = "sha256:578283f006390f85bb6282dffb876454593d637f5d1be494b5202ce4877e71f2"}, ] [[package]] @@ -1657,6 +1707,37 @@ files = [ [package.extras] pydantic = ["pydantic (>=2.0)"] +[[package]] +name = "pywin32" +version = "311" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, + {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, + {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, + {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, + {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, + {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, + {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, + {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, + {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, + {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, + {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, + {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, + {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, + {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, + {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, + {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, + {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, + {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, + {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, + {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, +] + [[package]] name = "rdflib" version = "7.1.4" @@ -1733,14 +1814,14 @@ packaging = ">=23.2" [[package]] name = "rich" -version = "14.0.0" +version = "14.1.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" groups = ["dev"] files = [ - {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, - {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, + {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, + {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, ] [package.dependencies] @@ -1868,27 +1949,83 @@ files = [ {file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"}, ] +[[package]] +name = "testcontainers" +version = "4.12.0" +description = "Python library for throwaway instances of anything that can run in a Docker container" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["dev"] +files = [ + {file = "testcontainers-4.12.0-py3-none-any.whl", hash = "sha256:26caef57e642d5e8c5fcc593881cf7df3ab0f0dc9170fad22765b184e226ab15"}, + {file = "testcontainers-4.12.0.tar.gz", hash = "sha256:13ee89cae995e643f225665aad8b200b25c4f219944a6f9c0b03249ec3f31b8d"}, +] + +[package.dependencies] +docker = "*" +python-dotenv = "*" +typing-extensions = "*" +urllib3 = "*" +wrapt = "*" + +[package.extras] +arangodb = ["python-arango (>=7.8,<8.0)"] +aws = ["boto3", "httpx"] +azurite = ["azure-storage-blob (>=12.19,<13.0)"] +chroma = ["chromadb-client (>=1.0.0,<2.0.0)"] +clickhouse = ["clickhouse-driver"] +cosmosdb = ["azure-cosmos"] +db2 = ["ibm_db_sa", "sqlalchemy"] +generic = ["httpx", "redis"] +google = ["google-cloud-datastore (>=2)", "google-cloud-pubsub (>=2)"] +influxdb = ["influxdb", "influxdb-client"] +k3s = ["kubernetes", "pyyaml"] +keycloak = ["python-keycloak"] +localstack = ["boto3"] +mailpit = ["cryptography"] +minio = ["minio"] +mongodb = ["pymongo"] +mssql = ["pymssql", "sqlalchemy"] +mysql = ["pymysql[rsa]", "sqlalchemy"] +nats = ["nats-py"] +neo4j = ["neo4j"] +openfga = ["openfga-sdk"] +opensearch = ["opensearch-py"] +oracle = ["oracledb", "sqlalchemy"] +oracle-free = ["oracledb", "sqlalchemy"] +qdrant = ["qdrant-client"] +rabbitmq = ["pika"] +redis = ["redis"] +registry = ["bcrypt"] +scylla = ["cassandra-driver (==3.29.1)"] +selenium = ["selenium"] +sftp = ["cryptography"] +test-module-import = ["httpx"] +trino = ["trino"] +weaviate = ["weaviate-client (>=4.5.4,<5.0.0)"] + [[package]] name = "textual" -version = "4.0.0" +version = "5.3.0" description = "Modern Text User Interface framework" optional = false python-versions = "<4.0.0,>=3.8.1" groups = ["dev"] markers = "platform_system != \"Windows\"" files = [ - {file = "textual-4.0.0-py3-none-any.whl", hash = "sha256:214051640f890676a670aa7d29cd2a37d27cfe6b2cf866e9d5abc3b6c89c5800"}, - {file = "textual-4.0.0.tar.gz", hash = "sha256:1cab4ea3cfc0e47ae773405cdd6bc2a17ed76ff7b648379ac8017ea89c5ad28c"}, + {file = "textual-5.3.0-py3-none-any.whl", hash = "sha256:02a6abc065514c4e21f94e79aaecea1f78a28a85d11d7bfc64abf3392d399890"}, + {file = "textual-5.3.0.tar.gz", hash = "sha256:1b6128b339adef2e298cc23ab4777180443240ece5c232f29b22960efd658d4d"}, ] [package.dependencies] markdown-it-py = {version = ">=2.1.0", extras = ["linkify", "plugins"]} platformdirs = ">=3.6.0,<5" +pygments = ">=2.19.2,<3.0.0" rich = ">=13.3.3" typing-extensions = ">=4.4.0,<5.0.0" [package.extras] -syntax = ["tree-sitter (>=0.23.0)", "tree-sitter-bash (>=0.23.0)", "tree-sitter-css (>=0.23.0)", "tree-sitter-go (>=0.23.0)", "tree-sitter-html (>=0.23.0)", "tree-sitter-java (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.24.0)", "tree-sitter-markdown (>=0.3.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-regex (>=0.24.0)", "tree-sitter-rust (>=0.23.0,<=0.23.2)", "tree-sitter-sql (>=0.3.0,<0.3.8)", "tree-sitter-toml (>=0.6.0)", "tree-sitter-xml (>=0.7.0)", "tree-sitter-yaml (>=0.6.0)"] +syntax = ["tree-sitter (>=0.25.0)", "tree-sitter-bash (>=0.23.0)", "tree-sitter-css (>=0.23.0)", "tree-sitter-go (>=0.23.0)", "tree-sitter-html (>=0.23.0)", "tree-sitter-java (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.24.0)", "tree-sitter-markdown (>=0.3.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-regex (>=0.24.0)", "tree-sitter-rust (>=0.23.0,<=0.23.2)", "tree-sitter-sql (>=0.3.0,<0.3.8)", "tree-sitter-toml (>=0.6.0)", "tree-sitter-xml (>=0.7.0)", "tree-sitter-yaml (>=0.6.0)"] [[package]] name = "timeago" @@ -1918,14 +2055,14 @@ six = ">=1.13.0" [[package]] name = "types-paramiko" -version = "3.5.0.20250708" +version = "3.5.0.20250801" description = "Typing stubs for paramiko" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "types_paramiko-3.5.0.20250708-py3-none-any.whl", hash = "sha256:c761ecff3445d847a40c0d831a0daaba2bddbd2bdc74315659be5ff4835bb434"}, - {file = "types_paramiko-3.5.0.20250708.tar.gz", hash = "sha256:45125bff40766db2d7d53bd1a4f329868293e512f2e6b7fe11c335111df027f2"}, + {file = "types_paramiko-3.5.0.20250801-py3-none-any.whl", hash = "sha256:3e02a0fcf2b7e7b213e0cd569f7223ff9af417052a4d149d84172ebaa6fd742e"}, + {file = "types_paramiko-3.5.0.20250801.tar.gz", hash = "sha256:e79ff84eaf44f2a5ad811743edef5d9c0cd6632a264a526f00405b87db1ec99b"}, ] [package.dependencies] @@ -2084,4 +2221,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "a086a35927b67c09d4e6d7bee0466e4b8b2cd4caa57514f193073d0519cb2f4c" +content-hash = "12bb36bd1499a20b9d8ececff8d920c483c19d1b37ee1644b4d97a49fb28909c" diff --git a/pyproject.toml b/pyproject.toml index 6d1b05f..78a67c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ pytest-html = "^4.1.1" pytest-memray = { version = "^1.7.0", markers = "platform_system != 'Windows'" } ruff = "^0.11.11" safety = "^1.10.3" +testcontainers = "^4.12.0" types-paramiko = "^3.5.0.20250516" [build-system] From 1496df4d153ffd0b4888fdfa97e1015ebc548ed9 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:22:47 +0100 Subject: [PATCH 03/20] add _initialize_ssh_and_sftp_connections for connection setup --- cmem_plugin_ssh/list.py | 16 ++++++++++------ tests/test_list.py | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmem_plugin_ssh/list.py b/cmem_plugin_ssh/list.py index 63fea9f..5fd3def 100644 --- a/cmem_plugin_ssh/list.py +++ b/cmem_plugin_ssh/list.py @@ -182,12 +182,12 @@ def __init__( # noqa: PLR0913 self.input_ports = FixedNumberOfInputs([]) self.output_port = FixedSchemaPort(schema=generate_list_schema()) - def close_connections(self) -> None: + def cleanup_ssh_connections(self) -> None: """Close connection from sftp and ssh""" self.sftp.close() self.ssh_client.close() - def connect_ssh_client(self) -> None: + def establish_ssh_connection(self) -> None: """Connect to the ssh client with the selected authentication method""" if self.authentication_method == "key": self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) @@ -211,6 +211,7 @@ def connect_ssh_client(self) -> None: def preview_results(self) -> str: """Preview the results of an execution""" + self._initialize_ssh_and_sftp_connections() return preview_results( ssh_client=self.ssh_client, no_subfolder=self.no_subfolder, @@ -220,6 +221,11 @@ def preview_results(self) -> str: max_workers=self.max_workers, ) + def _initialize_ssh_and_sftp_connections(self) -> None: + self.ssh_client = paramiko.SSHClient() + self.establish_ssh_connection() + self.sftp = self.ssh_client.open_sftp() + def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Entities: """Execute the workflow task""" _ = inputs @@ -228,9 +234,7 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti ) entities = [] - self.ssh_client = paramiko.SSHClient() - self.connect_ssh_client() - self.sftp = self.ssh_client.open_sftp() + self._initialize_ssh_and_sftp_connections() retrieval = SSHRetrieval( ssh_client=self.ssh_client, @@ -320,7 +324,7 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti ) ) - self.close_connections() + self.cleanup_ssh_connections() return Entities( entities=iter(entities), diff --git a/tests/test_list.py b/tests/test_list.py index 0904b13..9f3f612 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -219,7 +219,7 @@ def test_execution_warning_error_handling(testing_environment: TestingEnvironmen plugin = testing_environment.list_plugin plugin.error_handling = "warning" plugin.path = "/etc" - + plugin._initialize_ssh_and_sftp_connections() # noqa: SLF001 retrieval = SSHRetrieval( ssh_client=plugin.ssh_client, no_subfolder=plugin.no_subfolder, @@ -249,6 +249,7 @@ def test_execution_ignore_error_handling(testing_environment: TestingEnvironment plugin = testing_environment.list_plugin plugin.error_handling = "ignore" plugin.path = "/etc" + plugin._initialize_ssh_and_sftp_connections() # noqa: SLF001 retrieval = SSHRetrieval( ssh_client=plugin.ssh_client, From 55ecb197d8daa19f93a4be6dc6a5cac10af320a0 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:53:49 +0100 Subject: [PATCH 04/20] remove docker compose file --- docker/docker-compose.yml | 8 -------- tests/conftest.py | 35 ++++++++++++++++------------------- 2 files changed, 16 insertions(+), 27 deletions(-) delete mode 100644 docker/docker-compose.yml diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index 4ba882f..0000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - ssh-test: - build: . - container_name: ssh-test-container - ports: - - "2222:22" - volumes: - - ./volume:/home/testuser/volume \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 0ba5c83..0413364 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,13 @@ """Pytest configuration""" import shutil -import subprocess +from collections.abc import Generator from dataclasses import dataclass from pathlib import Path import pytest +from testcontainers.core.container import DockerContainer +from testcontainers.core.image import DockerImage from cmem_plugin_ssh.download import DownloadFiles from cmem_plugin_ssh.execute_commands import ExecuteCommands @@ -14,7 +16,6 @@ from tests.fixtures import ( SSH_HOSTNAME, SSH_PASSWORD, - SSH_PORT, SSH_PRIVATE_KEY, SSH_PRIVATE_KEY_WITH_PASSWORD, SSH_USERNAME, @@ -51,10 +52,10 @@ class TestingEnvironment: @pytest.fixture -def testing_environment() -> TestingEnvironment: +def testing_environment(ssh_test_container: DockerContainer) -> TestingEnvironment: """Provide testing environment""" hostname = SSH_HOSTNAME - port = SSH_PORT + port = ssh_test_container.get_exposed_port(22) username = SSH_USERNAME authentication_method = "key" private_key = SSH_PRIVATE_KEY @@ -147,21 +148,17 @@ def get_compose_cmd() -> list[str]: return ["docker", "compose"] -DOCKER_COMPOSE_DIR = Path(__file__).parent.parent / "docker" -DOCKER_COMPOSE_FILE = "docker-compose.yml" +DOCKER_DIR = Path(__file__).parent.parent / "docker" -@pytest.fixture(scope="session", autouse=True) -def ssh_test_container(): # noqa: ANN201 +@pytest.fixture(scope="session") +def ssh_test_container() -> Generator[DockerContainer, None, None]: """Start the SSH test container before tests and stop it after.""" - subprocess.run( # noqa: S603 - [*get_compose_cmd(), "-f", DOCKER_COMPOSE_FILE, "up", "--build", "-d"], - cwd=DOCKER_COMPOSE_DIR, - check=True, - ) - yield - subprocess.run( # noqa: S603 - [*get_compose_cmd(), "-f", DOCKER_COMPOSE_FILE, "down", "--rmi", "all"], - cwd=DOCKER_COMPOSE_DIR, - check=True, - ) + with ( + DockerImage(path=DOCKER_DIR, tag="test-sample:latest") as image, + DockerContainer(str(image)) + .with_exposed_ports(22) + .with_volume_mapping(DOCKER_DIR / "volume", "/home/testuser/volume", "rw") as container, + ): + container.start() + yield container From c9e5c9fa4643ea12d9422d9bad1f6366b2cedc6d Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 12:35:59 +0100 Subject: [PATCH 05/20] handle exceptions in ssh_test_container fixture --- tests/conftest.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 0413364..a636977 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ """Pytest configuration""" +import logging import shutil from collections.abc import Generator from dataclasses import dataclass @@ -13,6 +14,7 @@ from cmem_plugin_ssh.execute_commands import ExecuteCommands from cmem_plugin_ssh.list import ListFiles from cmem_plugin_ssh.upload import UploadFiles +from docker.errors import APIError from tests.fixtures import ( SSH_HOSTNAME, SSH_PASSWORD, @@ -21,6 +23,8 @@ SSH_USERNAME, ) +logger = logging.getLogger(__name__) + @dataclass class TestingEnvironment: @@ -154,11 +158,13 @@ def get_compose_cmd() -> list[str]: @pytest.fixture(scope="session") def ssh_test_container() -> Generator[DockerContainer, None, None]: """Start the SSH test container before tests and stop it after.""" - with ( - DockerImage(path=DOCKER_DIR, tag="test-sample:latest") as image, - DockerContainer(str(image)) - .with_exposed_ports(22) - .with_volume_mapping(DOCKER_DIR / "volume", "/home/testuser/volume", "rw") as container, - ): - container.start() - yield container + try: + with ( + DockerImage(path=DOCKER_DIR, tag="cmem-plugin-openssh:latest", clean_up=False) as image, + DockerContainer(str(image)) + .with_exposed_ports(22) + .with_volume_mapping(DOCKER_DIR / "volume", "/home/testuser/volume", "rw") as container, + ): + yield container + except APIError: + logger.exception("Failed to cleanup Docker container") From 451c8f2ef285126d6d4cae3eeecb674687c832e0 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 13:08:37 +0100 Subject: [PATCH 06/20] move connection test from init to execute for download, execute and upload plugin --- cmem_plugin_ssh/download.py | 20 ++++++++++++++------ cmem_plugin_ssh/execute_commands.py | 19 +++++++++++++------ cmem_plugin_ssh/upload.py | 19 +++++++++++++------ tests/test_download.py | 2 ++ 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/cmem_plugin_ssh/download.py b/cmem_plugin_ssh/download.py index 0ad768b..cedec7c 100644 --- a/cmem_plugin_ssh/download.py +++ b/cmem_plugin_ssh/download.py @@ -158,6 +158,9 @@ class DownloadFiles(WorkflowPlugin): """SSH Workflow Plugin: File download""" + ssh_client: paramiko.SSHClient + sftp: paramiko.SFTPClient + def __init__( # noqa: PLR0913 self, hostname: str, @@ -186,11 +189,8 @@ def __init__( # noqa: PLR0913 self.input_ports = FixedNumberOfInputs([FixedSchemaPort(schema=generate_list_schema())]) self.output_port = FixedSchemaPort(schema=FileEntitySchema()) self.download_dir = tempfile.mkdtemp() - self.ssh_client = paramiko.SSHClient() - self.connect_ssh_client() - self.sftp = self.ssh_client.open_sftp() - def connect_ssh_client(self) -> None: + def establish_ssh_connection(self) -> None: """Connect to the ssh client with the selected authentication method""" if self.authentication_method == "key": self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) @@ -212,13 +212,19 @@ def connect_ssh_client(self) -> None: timeout=20, ) - def close_connections(self) -> None: + def cleanup_ssh_connections(self) -> None: """Close connection from sftp and ssh""" self.sftp.close() self.ssh_client.close() + def _initialize_ssh_and_sftp_connections(self) -> None: + self.ssh_client = paramiko.SSHClient() + self.establish_ssh_connection() + self.sftp = self.ssh_client.open_sftp() + def preview_results(self) -> str: """Preview the results of an execution""" + self._initialize_ssh_and_sftp_connections() return preview_results( ssh_client=self.ssh_client, no_subfolder=self.no_subfolder, @@ -233,6 +239,8 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti _ = inputs schema = FileEntitySchema() + self._initialize_ssh_and_sftp_connections() + context.report.update( ExecutionReport(entity_count=0, operation="wait", operation_desc="files listed.") ) @@ -286,7 +294,7 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti self.update_context(context, entities, files, schema) - self.close_connections() + self.cleanup_ssh_connections() return Entities(entities=iter(entities), schema=schema) diff --git a/cmem_plugin_ssh/execute_commands.py b/cmem_plugin_ssh/execute_commands.py index 857ad9c..8786d3a 100644 --- a/cmem_plugin_ssh/execute_commands.py +++ b/cmem_plugin_ssh/execute_commands.py @@ -164,6 +164,9 @@ def setup_timeout(timeout: float) -> None | float: class ExecuteCommands(WorkflowPlugin): """Execute commands Plugin SSH""" + ssh_client: paramiko.SSHClient + sftp: paramiko.SFTPClient + def __init__( # noqa: PLR0913 self, hostname: str, @@ -191,11 +194,8 @@ def __init__( # noqa: PLR0913 self.timeout = setup_timeout(timeout) self.input_ports = self.setup_input_port() self.output_port = self.setup_output_port() - self.ssh_client = paramiko.SSHClient() - self.connect_ssh_client() - self.sftp = self.ssh_client.open_sftp() - def connect_ssh_client(self) -> None: + def establish_ssh_connection(self) -> None: """Connect to the ssh client with the selected authentication method""" if self.authentication_method == "key": self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) @@ -217,14 +217,21 @@ def connect_ssh_client(self) -> None: timeout=20, ) - def close_connections(self) -> None: + def cleanup_ssh_connections(self) -> None: """Close connection from sftp and ssh""" self.sftp.close() self.ssh_client.close() + def _initialize_ssh_and_sftp_connections(self) -> None: + self.ssh_client = paramiko.SSHClient() + self.establish_ssh_connection() + self.sftp = self.ssh_client.open_sftp() + def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Entities: """Execute the workflow task""" entities: list = [] + + self._initialize_ssh_and_sftp_connections() context.report.update( ExecutionReport( entity_count=len(entities), @@ -238,7 +245,7 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti if self.input_method == "no_input": self.no_input_execution(entities) - self.close_connections() + self.cleanup_ssh_connections() operation_desc = ( f"times executed '{self.command}'" diff --git a/cmem_plugin_ssh/upload.py b/cmem_plugin_ssh/upload.py index d3dbd8b..90d9e37 100644 --- a/cmem_plugin_ssh/upload.py +++ b/cmem_plugin_ssh/upload.py @@ -98,6 +98,9 @@ def _is_gzip(stream: io.BufferedReader) -> bool: class UploadFiles(WorkflowPlugin): """Upload Plugin SSH""" + ssh_client: paramiko.SSHClient + sftp: paramiko.SFTPClient + def __init__( # noqa: PLR0913 self, hostname: str, @@ -117,11 +120,8 @@ def __init__( # noqa: PLR0913 self.path = path self.input_ports = FixedNumberOfInputs([FixedSchemaPort(schema=FileEntitySchema())]) self.output_port = None - self.ssh_client = paramiko.SSHClient() - self.connect_ssh_client() - self.sftp = self.ssh_client.open_sftp() - def connect_ssh_client(self) -> None: + def establish_ssh_connection(self) -> None: """Connect to the ssh client with the selected authentication method""" if self.authentication_method == "key": self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) @@ -143,11 +143,16 @@ def connect_ssh_client(self) -> None: timeout=20, ) - def close_connections(self) -> None: + def cleanup_ssh_connections(self) -> None: """Close connection from sftp and ssh""" self.sftp.close() self.ssh_client.close() + def _initialize_ssh_and_sftp_connections(self) -> None: + self.ssh_client = paramiko.SSHClient() + self.establish_ssh_connection() + self.sftp = self.ssh_client.open_sftp() + def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Entities: """Execute the workflow task""" _ = inputs @@ -155,6 +160,8 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti if len(inputs) == 0: raise ValueError("No input was given!") + self._initialize_ssh_and_sftp_connections() + files: list = [] schema = FileEntitySchema() setup_cmempy_user_access(context.user) @@ -219,5 +226,5 @@ def execute(self, inputs: Sequence[Entities], context: ExecutionContext) -> Enti sample_entities=Entities(entities=iter(entities[:10]), schema=schema), ) ) - self.close_connections() + self.cleanup_ssh_connections() return Entities(entities=iter(entities), schema=schema) diff --git a/tests/test_download.py b/tests/test_download.py index 0da1618..1106edc 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -31,6 +31,7 @@ def test_download_restricted_file_warning(testing_environment: TestingEnvironmen plugin.error_handling = "warning" plugin.path = "/etc" plugin.regex = "^.*$" + plugin._initialize_ssh_and_sftp_connections() # noqa: SLF001 retrieval = SSHRetrieval( ssh_client=plugin.ssh_client, @@ -107,6 +108,7 @@ def test_download_with_input_warning(testing_environment: TestingEnvironment) -> download_plugin = testing_environment.download_plugin download_plugin.error_handling = "warning" + download_plugin._initialize_ssh_and_sftp_connections() # noqa: SLF001 downloaded_entities, faulty_entities = download_plugin.download_with_input( inputs=list_result, context=TestExecutionContext() ) From 9971945ab0326f2bd4101895c12237e2b6106d2b Mon Sep 17 00:00:00 2001 From: Saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 17:39:54 +0530 Subject: [PATCH 07/20] edit parameter description (#7) Co-authored-by: Thomas Wilmering --- CHANGELOG.md | 7 +++++++ cmem_plugin_ssh/execute_commands.py | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c7bfe9..c2f2238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/) +## [Unreleased] + +### Fixed + +- Fix typos and grammar in parameter descriptions + + ## [1.0.0] 2025-07-18 ### Changed diff --git a/cmem_plugin_ssh/execute_commands.py b/cmem_plugin_ssh/execute_commands.py index 8786d3a..6c4682e 100644 --- a/cmem_plugin_ssh/execute_commands.py +++ b/cmem_plugin_ssh/execute_commands.py @@ -99,7 +99,7 @@ def setup_timeout(timeout: float) -> None | float: PluginParameter( name="username", label="Username", - description="The username of which a connection will be instantiated.", + description="The username with which a connection will be instantiated.", ), PluginParameter( name="authentication_method", @@ -119,21 +119,21 @@ def setup_timeout(timeout: float) -> None | float: name="password", label="Password", description="Depending on your authentication method this will either be used to" - "connect via password to SSH or is used to decrypt the SSH private key", + "connect via password to SSH, or to decrypt the SSH private key", param_type=PasswordParameterType(), default_value="", ), PluginParameter( name="path", label="Path", - description="The currently selected path withing your SSH instance.", + description="The currently selected path within your SSH instance.", default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), PluginParameter( name="input_method", label="Input method", - description="Parameter to decide weather files will be used as stdin or no input is " + description="Parameter to decide whether files will be used as stdin or no input is " "needed. If 'File input' is chosen, the input port will open for all entities with" "the FileEntitySchema.", param_type=ChoiceParameterType(COMMAND_INPUT_CHOICES), @@ -142,7 +142,7 @@ def setup_timeout(timeout: float) -> None | float: name="output_method", label="Output method", description="Parameter to decide which type of output the user wants. This can be " - "either no output, a structured process output with its own schema or " + "either no output, a structured process output with its own schema, or " "a file based output", param_type=ChoiceParameterType(COMMAND_OUTPUT_CHOICES), ), From 17615860e51483380ce9ae3f78ef17fa4fa4afd5 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Fri, 8 Aug 2025 13:18:25 +0100 Subject: [PATCH 08/20] update change log --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f2238..a13a7fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Changed + +- Refactor: move connection test from init to execute phase + - Affected tasks: + - DownloadFiles + - ExecuteCommands + - ListFiles + - UploadFiles + ### Fixed - Fix typos and grammar in parameter descriptions From 223f843d31fd043cb18170fdd1c15409ac952853 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 04:05:11 +0100 Subject: [PATCH 09/20] refactor DirectoryParameterType autocomplete to remove dependency from path --- cmem_plugin_ssh/autocompletion.py | 53 +++++++++++------------- tests/test_autocompletion.py | 69 +++++++++++++++++++------------ 2 files changed, 66 insertions(+), 56 deletions(-) diff --git a/cmem_plugin_ssh/autocompletion.py b/cmem_plugin_ssh/autocompletion.py index bc867ec..330bf32 100644 --- a/cmem_plugin_ssh/autocompletion.py +++ b/cmem_plugin_ssh/autocompletion.py @@ -58,6 +58,16 @@ def close_connection(sftp: SFTPClient, ssh_client: SSHClient) -> None: ssh_client.close() +def _get_parent_folder(path: str) -> str: + paths = path.split("/") + return "/".join(paths[:-1]) + + +def _get_incomplete_folder(path: str) -> str: + paths = path.split("/") + return paths[-1] + + class DirectoryParameterType(StringParameterType): """Autocomplete class for folders on the ssh instance""" @@ -77,7 +87,6 @@ def __init__( "private_key", "password", "authentication_method", - "path", ] def autocomplete( @@ -89,17 +98,17 @@ def autocomplete( """Autocomplete the folders""" _ = context result = [] - entered_directory = "".join(query_terms) - selected_path = depend_on_parameter_values[6] - + entered_directory = " ".join(query_terms) + parent_folder = _get_parent_folder(entered_directory) + incomplete_term = _get_incomplete_folder(entered_directory) ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # noqa: S507 connect_ssh_client(depend_on_parameter_values, ssh_client) sftp = ssh_client.open_sftp() - if selected_path == "": - sftp.chdir(None) + if parent_folder == "": + sftp.chdir("/") files_and_folders = self.list_folders(sftp) folders = [ f.filename @@ -109,27 +118,16 @@ def autocomplete( current_dir = sftp.normalize(".") result = [ Autocompletion( - value=current_dir + "/" + f if current_dir != "/" else "/" + f, - label=current_dir + "/" + f if current_dir != "/" else "/" + f, + value=current_dir + f, + label=current_dir + f, ) for f in folders + if incomplete_term in f ] sort_suggestions(result, query_terms) result.append(Autocompletion(value=current_dir, label=current_dir)) - parent_dir = ( - current_dir.rsplit("/", 1)[0] or "/" if not current_dir.endswith("/") else "/" - ) - result.append(Autocompletion(value=parent_dir, label=parent_dir)) - self.suggestions = result - close_connection(sftp, ssh_client) - return self.suggestions - - if selected_path != "" and entered_directory == "": - close_connection(sftp, ssh_client) - return self.suggestions - - if entered_directory: - sftp.chdir(entered_directory) + else: + sftp.chdir(parent_folder) files_and_folders = self.list_folders(sftp) folders = [ f.filename @@ -143,17 +141,12 @@ def autocomplete( label=current_dir + "/" + f if current_dir != "/" else "/" + f, ) for f in folders + if incomplete_term in f ] sort_suggestions(result, query_terms) result.append(Autocompletion(value=current_dir, label=current_dir)) - parent_dir = ( - current_dir.rsplit("/", 1)[0] or "/" if not current_dir.endswith("/") else "/" - ) - if sftp.getcwd() != "/": - result.append(Autocompletion(value=parent_dir, label=parent_dir)) - self.suggestions = result - close_connection(sftp, ssh_client) - return self.suggestions + self.suggestions = result + close_connection(sftp, ssh_client) return self.suggestions diff --git a/tests/test_autocompletion.py b/tests/test_autocompletion.py index 65ac54b..7b1bb3b 100644 --- a/tests/test_autocompletion.py +++ b/tests/test_autocompletion.py @@ -17,7 +17,6 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: plugin.private_key, plugin.password, plugin.authentication_method, - plugin.path, ] autocompletion = DirectoryParameterType(url_expand="", display_name="") autocompletion_result = autocompletion.autocomplete( @@ -27,10 +26,7 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: ) autocompletion_values = [a.value for a in autocompletion_result] - assert "/home/testuser" in autocompletion_values - assert "/home/testuser/volume" in autocompletion_values - assert "/home/testuser/volume/TextFiles" in autocompletion_values - assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values + assert "/" in autocompletion_values autocompletion_result = autocompletion.autocomplete( query_terms=[""], @@ -38,48 +34,68 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - assert "/home/testuser" in autocompletion_values - assert "/home/testuser/volume" in autocompletion_values - assert "/home/testuser/volume/TextFiles" in autocompletion_values - assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values + for f in [ + "/bin", + "/boot", + "/dev", + "/etc", + "/home", + "/lib", + "/lib64", + "/media", + "/mnt", + "/opt", + "/proc", + "/restricted", + "/root", + "/run", + "/sbin", + "/srv", + "/sys", + "/tmp", # noqa : S108 + "/usr", + "/var", + "/", + ]: + assert f in autocompletion_values autocompletion_result = autocompletion.autocomplete( - query_terms=["volume/MoreTextFiles"], + query_terms=["/home/testuser/volume/MoreTextFiles/"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - assert "/home/testuser/volume" in autocompletion_values - assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values - assert "/home/testuser/volume/MoreTextFiles/EvenMoreFiles" in autocompletion_values - assert "/home/testuser/volume/MoreTextFiles/EvenMoreFiles2" in autocompletion_values + for f in [ + "/home/testuser/volume/MoreTextFiles/EvenMoreFiles", + "/home/testuser/volume/MoreTextFiles/EvenMoreFiles2", + "/home/testuser/volume/MoreTextFiles", + ]: + assert f in autocompletion_values autocompletion_result = autocompletion.autocomplete( - query_terms=[".."], + query_terms=["/bin"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - assert "/home/testuser" in autocompletion_values - assert "/home" in autocompletion_values + for f in ["/bin", "/sbin", "/"]: + assert f in autocompletion_values - depends_on[6] = "" autocompletion_result = autocompletion.autocomplete( - query_terms=[""], + query_terms=["/home/testuser/vol"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) + autocompletion_values = [a.value for a in autocompletion_result] - assert "/home/testuser/volume" in autocompletion_values - assert "/home/testuser/.ssh" in autocompletion_values - assert "/home/testuser" in autocompletion_values + for f in ["/home/testuser/volume", "/home/testuser"]: + assert f in autocompletion_values - depends_on[6] = "/restricted" with pytest.raises(ValueError, match=r"Permission denied"): autocompletion.autocomplete( - query_terms=["/restricted"], + query_terms=["/restricted/"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) @@ -99,9 +115,10 @@ def test_path_autocompletion_order(testing_environment: TestingEnvironment) -> N ] autocompletion = DirectoryParameterType(url_expand="", display_name="") autocompletion_result = autocompletion.autocomplete( - query_terms=["volume"], + query_terms=["/home/testuser/volume/"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) assert "/home/testuser/volume/MoreTextFiles" in autocompletion_result[0].label - assert "home/testuser" in autocompletion_result[-1].label + assert "/home/testuser/volume/TextFiles" in autocompletion_result[1].label + assert "home/testuser/volume" in autocompletion_result[2].label From 3b98d329f4f54c1ac4e44304918429b0ebd0e661 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 04:08:12 +0100 Subject: [PATCH 10/20] update change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a13a7fc..4e5f2a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - ExecuteCommands - ListFiles - UploadFiles +- Refactor: eliminate path dependency in DirectoryParameterType autocompletion logic ### Fixed From 80c64f329b8657d173f05c02fe0217c79837f905 Mon Sep 17 00:00:00 2001 From: Saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:24:04 +0530 Subject: [PATCH 11/20] undo auto completion changes --- cmem_plugin_ssh/autocompletion.py | 53 +++++++++++++----------- tests/test_autocompletion.py | 69 ++++++++++++------------------- 2 files changed, 56 insertions(+), 66 deletions(-) diff --git a/cmem_plugin_ssh/autocompletion.py b/cmem_plugin_ssh/autocompletion.py index 330bf32..bc867ec 100644 --- a/cmem_plugin_ssh/autocompletion.py +++ b/cmem_plugin_ssh/autocompletion.py @@ -58,16 +58,6 @@ def close_connection(sftp: SFTPClient, ssh_client: SSHClient) -> None: ssh_client.close() -def _get_parent_folder(path: str) -> str: - paths = path.split("/") - return "/".join(paths[:-1]) - - -def _get_incomplete_folder(path: str) -> str: - paths = path.split("/") - return paths[-1] - - class DirectoryParameterType(StringParameterType): """Autocomplete class for folders on the ssh instance""" @@ -87,6 +77,7 @@ def __init__( "private_key", "password", "authentication_method", + "path", ] def autocomplete( @@ -98,17 +89,17 @@ def autocomplete( """Autocomplete the folders""" _ = context result = [] - entered_directory = " ".join(query_terms) - parent_folder = _get_parent_folder(entered_directory) - incomplete_term = _get_incomplete_folder(entered_directory) + entered_directory = "".join(query_terms) + selected_path = depend_on_parameter_values[6] + ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # noqa: S507 connect_ssh_client(depend_on_parameter_values, ssh_client) sftp = ssh_client.open_sftp() - if parent_folder == "": - sftp.chdir("/") + if selected_path == "": + sftp.chdir(None) files_and_folders = self.list_folders(sftp) folders = [ f.filename @@ -118,16 +109,27 @@ def autocomplete( current_dir = sftp.normalize(".") result = [ Autocompletion( - value=current_dir + f, - label=current_dir + f, + value=current_dir + "/" + f if current_dir != "/" else "/" + f, + label=current_dir + "/" + f if current_dir != "/" else "/" + f, ) for f in folders - if incomplete_term in f ] sort_suggestions(result, query_terms) result.append(Autocompletion(value=current_dir, label=current_dir)) - else: - sftp.chdir(parent_folder) + parent_dir = ( + current_dir.rsplit("/", 1)[0] or "/" if not current_dir.endswith("/") else "/" + ) + result.append(Autocompletion(value=parent_dir, label=parent_dir)) + self.suggestions = result + close_connection(sftp, ssh_client) + return self.suggestions + + if selected_path != "" and entered_directory == "": + close_connection(sftp, ssh_client) + return self.suggestions + + if entered_directory: + sftp.chdir(entered_directory) files_and_folders = self.list_folders(sftp) folders = [ f.filename @@ -141,12 +143,17 @@ def autocomplete( label=current_dir + "/" + f if current_dir != "/" else "/" + f, ) for f in folders - if incomplete_term in f ] sort_suggestions(result, query_terms) result.append(Autocompletion(value=current_dir, label=current_dir)) - self.suggestions = result - close_connection(sftp, ssh_client) + parent_dir = ( + current_dir.rsplit("/", 1)[0] or "/" if not current_dir.endswith("/") else "/" + ) + if sftp.getcwd() != "/": + result.append(Autocompletion(value=parent_dir, label=parent_dir)) + self.suggestions = result + close_connection(sftp, ssh_client) + return self.suggestions return self.suggestions diff --git a/tests/test_autocompletion.py b/tests/test_autocompletion.py index 7b1bb3b..65ac54b 100644 --- a/tests/test_autocompletion.py +++ b/tests/test_autocompletion.py @@ -17,6 +17,7 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: plugin.private_key, plugin.password, plugin.authentication_method, + plugin.path, ] autocompletion = DirectoryParameterType(url_expand="", display_name="") autocompletion_result = autocompletion.autocomplete( @@ -26,7 +27,10 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: ) autocompletion_values = [a.value for a in autocompletion_result] - assert "/" in autocompletion_values + assert "/home/testuser" in autocompletion_values + assert "/home/testuser/volume" in autocompletion_values + assert "/home/testuser/volume/TextFiles" in autocompletion_values + assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values autocompletion_result = autocompletion.autocomplete( query_terms=[""], @@ -34,68 +38,48 @@ def test_autocompletion(testing_environment: TestingEnvironment) -> None: context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - for f in [ - "/bin", - "/boot", - "/dev", - "/etc", - "/home", - "/lib", - "/lib64", - "/media", - "/mnt", - "/opt", - "/proc", - "/restricted", - "/root", - "/run", - "/sbin", - "/srv", - "/sys", - "/tmp", # noqa : S108 - "/usr", - "/var", - "/", - ]: - assert f in autocompletion_values + assert "/home/testuser" in autocompletion_values + assert "/home/testuser/volume" in autocompletion_values + assert "/home/testuser/volume/TextFiles" in autocompletion_values + assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values autocompletion_result = autocompletion.autocomplete( - query_terms=["/home/testuser/volume/MoreTextFiles/"], + query_terms=["volume/MoreTextFiles"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - for f in [ - "/home/testuser/volume/MoreTextFiles/EvenMoreFiles", - "/home/testuser/volume/MoreTextFiles/EvenMoreFiles2", - "/home/testuser/volume/MoreTextFiles", - ]: - assert f in autocompletion_values + assert "/home/testuser/volume" in autocompletion_values + assert "/home/testuser/volume/MoreTextFiles" in autocompletion_values + assert "/home/testuser/volume/MoreTextFiles/EvenMoreFiles" in autocompletion_values + assert "/home/testuser/volume/MoreTextFiles/EvenMoreFiles2" in autocompletion_values autocompletion_result = autocompletion.autocomplete( - query_terms=["/bin"], + query_terms=[".."], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) autocompletion_values = [a.value for a in autocompletion_result] - for f in ["/bin", "/sbin", "/"]: - assert f in autocompletion_values + assert "/home/testuser" in autocompletion_values + assert "/home" in autocompletion_values + depends_on[6] = "" autocompletion_result = autocompletion.autocomplete( - query_terms=["/home/testuser/vol"], + query_terms=[""], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) - autocompletion_values = [a.value for a in autocompletion_result] - for f in ["/home/testuser/volume", "/home/testuser"]: - assert f in autocompletion_values + assert "/home/testuser/volume" in autocompletion_values + assert "/home/testuser/.ssh" in autocompletion_values + assert "/home/testuser" in autocompletion_values + depends_on[6] = "/restricted" with pytest.raises(ValueError, match=r"Permission denied"): autocompletion.autocomplete( - query_terms=["/restricted/"], + query_terms=["/restricted"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) @@ -115,10 +99,9 @@ def test_path_autocompletion_order(testing_environment: TestingEnvironment) -> N ] autocompletion = DirectoryParameterType(url_expand="", display_name="") autocompletion_result = autocompletion.autocomplete( - query_terms=["/home/testuser/volume/"], + query_terms=["volume"], depend_on_parameter_values=depends_on, context=TestPluginContext(), ) assert "/home/testuser/volume/MoreTextFiles" in autocompletion_result[0].label - assert "/home/testuser/volume/TextFiles" in autocompletion_result[1].label - assert "home/testuser/volume" in autocompletion_result[2].label + assert "home/testuser" in autocompletion_result[-1].label From cbe62e768643ca7a9e28633b086407ef0be07a8a Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 07:58:10 +0100 Subject: [PATCH 12/20] move docker files to tests --- {docker => tests/docker}/Dockerfile | 0 {docker => tests/docker}/authorized_keys | 0 .../docker}/volume/MoreTextFiles/EvenMoreFiles/File.txt | 0 .../docker}/volume/MoreTextFiles/EvenMoreFiles/File_2.txt | 0 .../docker}/volume/MoreTextFiles/EvenMoreFiles/File_3.md | 0 .../volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt | 0 .../volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt | 0 .../docker}/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md | 0 .../volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt | 0 {docker => tests/docker}/volume/RootFile.txt | 0 {docker => tests/docker}/volume/TextFiles/Test.txt | 0 {docker => tests/docker}/volume/TextFiles/Test2.txt | 0 {docker => tests/docker}/volume/TextFiles/Test3.txt | 0 {docker => tests/docker}/volume/TextFiles/TestMD.md | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename {docker => tests/docker}/Dockerfile (100%) rename {docker => tests/docker}/authorized_keys (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles/File.txt (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles/File_2.txt (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles/File_3.md (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md (100%) rename {docker => tests/docker}/volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt (100%) rename {docker => tests/docker}/volume/RootFile.txt (100%) rename {docker => tests/docker}/volume/TextFiles/Test.txt (100%) rename {docker => tests/docker}/volume/TextFiles/Test2.txt (100%) rename {docker => tests/docker}/volume/TextFiles/Test3.txt (100%) rename {docker => tests/docker}/volume/TextFiles/TestMD.md (100%) diff --git a/docker/Dockerfile b/tests/docker/Dockerfile similarity index 100% rename from docker/Dockerfile rename to tests/docker/Dockerfile diff --git a/docker/authorized_keys b/tests/docker/authorized_keys similarity index 100% rename from docker/authorized_keys rename to tests/docker/authorized_keys diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles/File.txt b/tests/docker/volume/MoreTextFiles/EvenMoreFiles/File.txt similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles/File.txt rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles/File.txt diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles/File_2.txt b/tests/docker/volume/MoreTextFiles/EvenMoreFiles/File_2.txt similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles/File_2.txt rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles/File_2.txt diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles/File_3.md b/tests/docker/volume/MoreTextFiles/EvenMoreFiles/File_3.md similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles/File_3.md rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles/File_3.md diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt b/tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_1.txt diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt b/tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_2.txt diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md b/tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_3.md diff --git a/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt b/tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt similarity index 100% rename from docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt rename to tests/docker/volume/MoreTextFiles/EvenMoreFiles2/Another_File_4.txt diff --git a/docker/volume/RootFile.txt b/tests/docker/volume/RootFile.txt similarity index 100% rename from docker/volume/RootFile.txt rename to tests/docker/volume/RootFile.txt diff --git a/docker/volume/TextFiles/Test.txt b/tests/docker/volume/TextFiles/Test.txt similarity index 100% rename from docker/volume/TextFiles/Test.txt rename to tests/docker/volume/TextFiles/Test.txt diff --git a/docker/volume/TextFiles/Test2.txt b/tests/docker/volume/TextFiles/Test2.txt similarity index 100% rename from docker/volume/TextFiles/Test2.txt rename to tests/docker/volume/TextFiles/Test2.txt diff --git a/docker/volume/TextFiles/Test3.txt b/tests/docker/volume/TextFiles/Test3.txt similarity index 100% rename from docker/volume/TextFiles/Test3.txt rename to tests/docker/volume/TextFiles/Test3.txt diff --git a/docker/volume/TextFiles/TestMD.md b/tests/docker/volume/TextFiles/TestMD.md similarity index 100% rename from docker/volume/TextFiles/TestMD.md rename to tests/docker/volume/TextFiles/TestMD.md From f93135f1149aafc042945e70efba08d6faead600 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:00:20 +0100 Subject: [PATCH 13/20] fix DOCKER_DIR --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index a636977..74053b1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -152,7 +152,7 @@ def get_compose_cmd() -> list[str]: return ["docker", "compose"] -DOCKER_DIR = Path(__file__).parent.parent / "docker" +DOCKER_DIR = Path(__file__).parent / "docker" @pytest.fixture(scope="session") From 56f28368e78730b1e8cf3e0eed7abce1f1e875f0 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:07:16 +0100 Subject: [PATCH 14/20] remove get_compose_cmd --- tests/conftest.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 74053b1..3247df4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,6 @@ """Pytest configuration""" import logging -import shutil from collections.abc import Generator from dataclasses import dataclass from pathlib import Path @@ -145,13 +144,6 @@ def testing_environment(ssh_test_container: DockerContainer) -> TestingEnvironme ) -def get_compose_cmd() -> list[str]: - """Get the correct compose command for environment""" - if shutil.which("docker-compose"): - return ["docker-compose"] - return ["docker", "compose"] - - DOCKER_DIR = Path(__file__).parent / "docker" From c8d3f4ff307dd366b4e329e305d8dae60f972991 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:10:29 +0100 Subject: [PATCH 15/20] fix linters --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3247df4..c1491fa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,7 @@ from pathlib import Path import pytest +from docker.errors import APIError from testcontainers.core.container import DockerContainer from testcontainers.core.image import DockerImage @@ -13,7 +14,6 @@ from cmem_plugin_ssh.execute_commands import ExecuteCommands from cmem_plugin_ssh.list import ListFiles from cmem_plugin_ssh.upload import UploadFiles -from docker.errors import APIError from tests.fixtures import ( SSH_HOSTNAME, SSH_PASSWORD, From 540850eddca40d1db14a8d5ebe515a75ae4c415d Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:21:48 +0100 Subject: [PATCH 16/20] Update path parameter description --- cmem_plugin_ssh/download.py | 2 +- cmem_plugin_ssh/list.py | 2 +- cmem_plugin_ssh/upload.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmem_plugin_ssh/download.py b/cmem_plugin_ssh/download.py index cedec7c..f24ba68 100644 --- a/cmem_plugin_ssh/download.py +++ b/cmem_plugin_ssh/download.py @@ -113,7 +113,7 @@ PluginParameter( name="path", label="Path", - description="The currently selected path withing your SSH instance.", + description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), diff --git a/cmem_plugin_ssh/list.py b/cmem_plugin_ssh/list.py index 5fd3def..2ebefea 100644 --- a/cmem_plugin_ssh/list.py +++ b/cmem_plugin_ssh/list.py @@ -106,7 +106,7 @@ PluginParameter( name="path", label="Path", - description="The currently selected path withing your SSH instance.", + description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), diff --git a/cmem_plugin_ssh/upload.py b/cmem_plugin_ssh/upload.py index 90d9e37..d66c192 100644 --- a/cmem_plugin_ssh/upload.py +++ b/cmem_plugin_ssh/upload.py @@ -89,7 +89,7 @@ def _is_gzip(stream: io.BufferedReader) -> bool: PluginParameter( name="path", label="Path", - description="The currently selected path withing your SSH instance.", + description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), From da260bef59447e84e75f08d1b5251beb4b657a7b Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:26:48 +0100 Subject: [PATCH 17/20] fix linter issues --- cmem_plugin_ssh/download.py | 6 +++++- cmem_plugin_ssh/list.py | 6 +++++- cmem_plugin_ssh/upload.py | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/cmem_plugin_ssh/download.py b/cmem_plugin_ssh/download.py index f24ba68..7219058 100644 --- a/cmem_plugin_ssh/download.py +++ b/cmem_plugin_ssh/download.py @@ -113,7 +113,11 @@ PluginParameter( name="path", label="Path", - description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", + description=( + "The currently selected path within your SSH instance." + " Auto-completion starts from user home folder, use '..' for parent directory" + " or '/' for root directory." + ), default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), diff --git a/cmem_plugin_ssh/list.py b/cmem_plugin_ssh/list.py index 2ebefea..bd66123 100644 --- a/cmem_plugin_ssh/list.py +++ b/cmem_plugin_ssh/list.py @@ -106,7 +106,11 @@ PluginParameter( name="path", label="Path", - description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", + description=( + "The currently selected path within your SSH instance." + " Auto-completion starts from user home folder, use '..' for parent directory" + " or '/' for root directory." + ), default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), diff --git a/cmem_plugin_ssh/upload.py b/cmem_plugin_ssh/upload.py index d66c192..1ea06e3 100644 --- a/cmem_plugin_ssh/upload.py +++ b/cmem_plugin_ssh/upload.py @@ -89,7 +89,11 @@ def _is_gzip(stream: io.BufferedReader) -> bool: PluginParameter( name="path", label="Path", - description="The currently selected path within your SSH instance. Auto-completion starts from user home folder, use '..' for parent directory or '/' for root directory.", + description=( + "The currently selected path within your SSH instance." + " Auto-completion starts from user home folder, use '..' for parent directory" + " or '/' for root directory." + ), default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), From 3d4f4ad359c9623a45b36338144544db3a62eb25 Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:37:02 +0100 Subject: [PATCH 18/20] fix execute and upload plugin tests --- CHANGELOG.md | 1 - tests/test_execute_commands.py | 8 +++----- tests/test_upload.py | 8 +++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e5f2a0..a13a7fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - ExecuteCommands - ListFiles - UploadFiles -- Refactor: eliminate path dependency in DirectoryParameterType autocompletion logic ### Fixed diff --git a/tests/test_execute_commands.py b/tests/test_execute_commands.py index 9cf13b0..8609a07 100644 --- a/tests/test_execute_commands.py +++ b/tests/test_execute_commands.py @@ -1,12 +1,10 @@ """Command execution workflow test suite""" -from pathlib import Path - from cmem_plugin_base.dataintegration.entity import Entities from cmem_plugin_base.dataintegration.typed_entities.file import FileEntitySchema, LocalFile from cmem_plugin_base.testing import TestExecutionContext -from tests.conftest import TestingEnvironment +from tests.conftest import DOCKER_DIR, TestingEnvironment def test_basic_command_execution(testing_environment: TestingEnvironment) -> None: @@ -32,7 +30,7 @@ def test_basic_command_execution_input_files(testing_environment: TestingEnviron execute_plugin.command = "cat" schema = FileEntitySchema() - test_file_path = Path(__file__).parent.parent / "docker" / "volume" / "RootFile.txt" + test_file_path = DOCKER_DIR / "volume" / "RootFile.txt" files = [LocalFile(path=str(test_file_path.resolve()), mime="")] entities = [schema.to_entity(file) for file in files] input_entities = Entities(entities=iter(entities), schema=schema) @@ -52,7 +50,7 @@ def test_basic_command_execution_input_files_file_output( execute_plugin.output_method = "file_output" schema = FileEntitySchema() - test_file_path = Path(__file__).parent.parent / "docker" / "volume" / "RootFile.txt" + test_file_path = DOCKER_DIR / "volume" / "RootFile.txt" files = [LocalFile(path=str(test_file_path.resolve()), mime="")] entities = [schema.to_entity(file) for file in files] input_entities = Entities(entities=iter(entities), schema=schema) diff --git a/tests/test_upload.py b/tests/test_upload.py index 2dcd2c8..fe1b6f2 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -1,7 +1,5 @@ """Upload ssh files workflow task test suite""" -from pathlib import Path - import pytest from cmem_plugin_base.dataintegration.entity import Entities from cmem_plugin_base.dataintegration.typed_entities.file import ( @@ -11,13 +9,13 @@ from cmem_plugin_base.testing import TestExecutionContext from cmem_plugin_ssh.upload import UploadFiles -from tests.conftest import TestingEnvironment +from tests.conftest import DOCKER_DIR, TestingEnvironment def test_upload_local_file(testing_environment: TestingEnvironment) -> None: """Test upload with a given input file""" schema = FileEntitySchema() - test_file_path = Path(__file__).parent.parent / "docker" / "volume" / "RootFile.txt" + test_file_path = DOCKER_DIR / "volume" / "RootFile.txt" files = [LocalFile(path=str(test_file_path.resolve()), mime="")] entities = [schema.to_entity(file) for file in files] input_entities = Entities(entities=iter(entities), schema=schema) @@ -38,7 +36,7 @@ def test_no_input(testing_environment: TestingEnvironment) -> None: def test_upload_fail_missing_permission(testing_environment: TestingEnvironment) -> None: """Test error throwing when trying to upload to folder with no permission""" schema = FileEntitySchema() - test_file_path = Path(__file__).parent.parent / "docker" / "volume" / "RootFile.txt" + test_file_path = DOCKER_DIR / "volume" / "RootFile.txt" files = [LocalFile(path=str(test_file_path.resolve()), mime="")] entities = [schema.to_entity(file) for file in files] input_entities = Entities(entities=iter(entities), schema=schema) From d1b5ce596b901211583b80344866ca0f53aee6bb Mon Sep 17 00:00:00 2001 From: saipraneeth <2506664+msaipraneeth@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:52:03 +0100 Subject: [PATCH 19/20] Update path parameter description --- cmem_plugin_ssh/download.py | 4 ++-- cmem_plugin_ssh/execute_commands.py | 6 +++++- cmem_plugin_ssh/list.py | 6 +++--- cmem_plugin_ssh/upload.py | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cmem_plugin_ssh/download.py b/cmem_plugin_ssh/download.py index 7219058..bb072fd 100644 --- a/cmem_plugin_ssh/download.py +++ b/cmem_plugin_ssh/download.py @@ -86,7 +86,7 @@ PluginParameter( name="username", label="Username", - description="The username of which a connection will be instantiated.", + description="The username with which a connection will be instantiated.", ), PluginParameter( name="authentication_method", @@ -106,7 +106,7 @@ name="password", label="Password", description="Depending on your authentication method this will either be used to" - "connect via password to SSH or is used to decrypt the SSH private key", + "connect via password to SSH, or to decrypt the SSH private key", param_type=PasswordParameterType(), default_value="", ), diff --git a/cmem_plugin_ssh/execute_commands.py b/cmem_plugin_ssh/execute_commands.py index 6c4682e..a7d1da3 100644 --- a/cmem_plugin_ssh/execute_commands.py +++ b/cmem_plugin_ssh/execute_commands.py @@ -126,7 +126,11 @@ def setup_timeout(timeout: float) -> None | float: PluginParameter( name="path", label="Path", - description="The currently selected path within your SSH instance.", + description=( + "The currently selected path within your SSH instance." + " Auto-completion starts from user home folder, use '..' for parent directory" + " or '/' for root directory." + ), default_value="", param_type=DirectoryParameterType("directories", "Folder"), ), diff --git a/cmem_plugin_ssh/list.py b/cmem_plugin_ssh/list.py index bd66123..f3b3ca9 100644 --- a/cmem_plugin_ssh/list.py +++ b/cmem_plugin_ssh/list.py @@ -68,7 +68,7 @@ PluginParameter( name="hostname", label="Hostname", - description="Hostname to connect to.Usually in the form of an IP address", + description="Hostname to connect to. Usually in the form of an IP address", ), PluginParameter( name="port", @@ -79,7 +79,7 @@ PluginParameter( name="username", label="Username", - description="The username of which a connection will be instantiated.", + description="The username with which a connection will be instantiated.", ), PluginParameter( name="authentication_method", @@ -99,7 +99,7 @@ name="password", label="Password", description="Depending on your authentication method this will either be used to" - "connect via password to SSH or is used to decrypt the SSH private key", + "connect via password to SSH, or to decrypt the SSH private key", param_type=PasswordParameterType(), default_value="", ), diff --git a/cmem_plugin_ssh/upload.py b/cmem_plugin_ssh/upload.py index 1ea06e3..9594306 100644 --- a/cmem_plugin_ssh/upload.py +++ b/cmem_plugin_ssh/upload.py @@ -62,7 +62,7 @@ def _is_gzip(stream: io.BufferedReader) -> bool: PluginParameter( name="username", label="Username", - description="The username of which a connection will be instantiated.", + description="The username with which a connection will be instantiated.", ), PluginParameter( name="authentication_method", @@ -82,7 +82,7 @@ def _is_gzip(stream: io.BufferedReader) -> bool: name="password", label="Password", description="Depending on your authentication method this will either be used to" - "connect via password to SSH or is used to decrypt the SSH private key", + "connect via password to SSH, or to decrypt the SSH private key", param_type=PasswordParameterType(), default_value="", ), From 118669879e4dbeb918bdb91bed2106b9ce1c4380 Mon Sep 17 00:00:00 2001 From: Sebastian Tramp Date: Fri, 15 Aug 2025 09:25:06 +0200 Subject: [PATCH 20/20] change log --- CHANGELOG.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a13a7fc..b5d9bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ + # Change Log All notable changes to this project will be documented in this file. @@ -6,19 +7,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] -### Changed - -- Refactor: move connection test from init to execute phase - - Affected tasks: - - DownloadFiles - - ExecuteCommands - - ListFiles - - UploadFiles - ### Fixed +- move connection test from init to execute phase (all tasks) + - this avoids project loading errors - Fix typos and grammar in parameter descriptions +### Added + +- testing infrastructure based in testcontainers + ## [1.0.0] 2025-07-18