From 18c23e082b1406f7c979036e810331fe86dd5892 Mon Sep 17 00:00:00 2001 From: Aleksandra Ovchinnikova <46540441+bdjilka@users.noreply.github.com> Date: Tue, 7 Jul 2026 06:57:29 -0400 Subject: [PATCH 1/8] MPT-22777 Remove deprecated library msrest --- diworker/diworker/importers/azure.py | 28 +++---- diworker/uv.lock | 120 +++++++++++++++++++++++++-- tools/cloud_adapter/clouds/azure.py | 97 ++++++++-------------- tools/cloud_adapter/setup.py | 3 +- 4 files changed, 159 insertions(+), 89 deletions(-) diff --git a/diworker/diworker/importers/azure.py b/diworker/diworker/importers/azure.py index f996d3c50..02566dc63 100644 --- a/diworker/diworker/importers/azure.py +++ b/diworker/diworker/importers/azure.py @@ -6,9 +6,11 @@ import tools.optscale_time as opttime from diworker.diworker.utils import retry_backoff from tools.cloud_adapter.clouds.azure import ( - AzureConsumptionException, ExpenseImportScheme, - AzureErrorResponseException, AzureAuthenticationError, - AzureResourceNotFoundError) + AzureConsumptionException, + ExpenseImportScheme, + AzureAuthenticationError, + AzureResourceNotFoundError, +) from diworker.diworker.importers.base import BaseReportImporter @@ -449,13 +451,10 @@ def load_raw_data(self): LOG.info('Downloading PayAsYouGo prices') try: prices = self.cloud_adapter.get_public_prices() - except AzureErrorResponseException as exc: - code = getattr(exc.error, 'additional_properties', {}).get( - 'error', {}).get('code') + except AzureConsumptionException as exc: + code = getattr(exc.error, 'code', None) if code == 'SubscriptionNotFound': - msg = exc.error.additional_properties['error'].get( - 'message') - raise AzureResourceNotFoundError(msg) + raise AzureResourceNotFoundError(getattr(exc.error, 'message', str(exc))) else: raise exc LOG.info('Fetched %s price entries', len(prices)) @@ -554,14 +553,11 @@ def _load_raw_usage_data(self, prices): if len(chunk) == CHUNK_SIZE: self.update_raw_records(chunk) chunk = [] - except AzureErrorResponseException as ex: - code = getattr(ex.error, 'additional_properties', {}).get( - 'error', {}).get('code') + except AzureConsumptionException as exc: + code = getattr(exc.error, 'code', None) if code == 'SubscriptionNotFound': - msg = ex.error.additional_properties['error'].get( - 'message') - raise AzureResourceNotFoundError(msg) - error_message = str(ex) + raise AzureResourceNotFoundError(getattr(exc.error, 'message', str(exc))) + error_message = str(exc) if 'Unknown error' in error_message: LOG.error('No ready reports yet in cloud for %s. Will ' 'skip the remaining report import days and try ' diff --git a/diworker/uv.lock b/diworker/uv.lock index 5b590d792..f92b9a365 100644 --- a/diworker/uv.lock +++ b/diworker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -425,6 +425,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, ] [[package]] @@ -449,6 +461,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] @@ -475,6 +503,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/bb/fba7569cfad8b951b8a6497bf19ae5440ab0b305c40d680a1a2395831a1f/clickhouse_connect-0.8.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84d8067294ba6e65994fa887db3acdb6fbf3cbd850d5637c029f29e318eba116", size = 1098405, upload-time = "2025-01-25T23:42:29.322Z" }, { url = "https://files.pythonhosted.org/packages/31/5c/b1ab4ddf40ce3c786011429e5a9171b662efbb8933bf8b9a7586d9eac24a/clickhouse_connect-0.8.15-cp312-cp312-win32.whl", hash = "sha256:83527c9bc48a096e63f91cc429bf3fad01fe5b78ea83fd7751f9702f97388381", size = 228612, upload-time = "2025-01-25T23:42:30.641Z" }, { url = "https://files.pythonhosted.org/packages/fe/d4/3060fe62a3e0e1c41303acb7a00240a5a867774f176ca9c485d03727d4f6/clickhouse_connect-0.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:f63e5500d36e79deb91bfeb82548dd1737b57684405566bc9652d8fede8ce451", size = 246549, upload-time = "2025-01-25T23:42:32.574Z" }, + { url = "https://files.pythonhosted.org/packages/9d/c2/6b4cd609fbd9cbb92440ecda2978c1547dd491543ac935603ff6f9686b13/clickhouse_connect-0.8.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e62f07d31478b6005d7f64d1279b8a58acdb3d7198e28a8b9e8f192c88c885f9", size = 258435, upload-time = "2025-01-25T23:42:33.878Z" }, + { url = "https://files.pythonhosted.org/packages/e4/08/08e7a63476706104ceb9cfe1a271af250f31038c52364258b47ef69b71c2/clickhouse_connect-0.8.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7bc21760716817ae24990c0a556ee8f323f3a0da94f7386fe1eff959979994df", size = 250095, upload-time = "2025-01-25T23:42:35.09Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1d/fe258786b4d8f81368522e42e18536fb283cc93d75a6b1677aac3ebec6b8/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d1bf9fe4a53c990cd839a6fb2b11ddc9f9ca545bba7c647cf9a74697f7a32f", size = 1040094, upload-time = "2025-01-25T23:42:36.477Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/15f2b62152f1944d0c9b0627146ae0012a2c4263b9ac37f89cf3f83c59b8/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:169e4ffb8ce94ec64b25e32005c7b645bbd3075cd72cb568e3f4dbdd059400de", size = 1058517, upload-time = "2025-01-25T23:42:38.727Z" }, + { url = "https://files.pythonhosted.org/packages/ef/19/9736a9ad8f962e518aad7c24dbb4e575315244918865da2e0108d5329450/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b8afad17b50541a3822d205d9154331cef5a4422fa05331c472fd975827be43", size = 1014121, upload-time = "2025-01-25T23:42:41.117Z" }, + { url = "https://files.pythonhosted.org/packages/08/45/d3631ebea8a67d1656d4cbb7bad5207c336124c9f7102a702ad9a50aaec1/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8d3ac19f11dd4e8b0466ccfcb2def6f91ea43d6e12918669a59d10f66db56527", size = 1041140, upload-time = "2025-01-25T23:42:42.675Z" }, + { url = "https://files.pythonhosted.org/packages/63/52/de1be4adb704cb07308e0a1956bfd2a660d65400d0693e12288cee6747c4/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18640b2e5f1d4024178a7f8fa493f95e02345b4ac30648576dad16ab17b80fdd", size = 1056558, upload-time = "2025-01-25T23:42:44.405Z" }, + { url = "https://files.pythonhosted.org/packages/f9/dd/4c0e2fdde56805700de73046d8e8926bf3c2eda52498b3d02e082dcd012e/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a1c16284b414fd6391fce11d6a4f2afe5826a1c93cb89559d5287a24802ac19", size = 1083990, upload-time = "2025-01-25T23:42:45.836Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d6/ce9a629541a3528ce68bdc46a685b9701a9a2c0d7ae1fd4e8b431c451463/clickhouse_connect-0.8.15-cp313-cp313-win32.whl", hash = "sha256:e3d1b58305477be3f8ac97b433fa3fdfd8e9d6a4004abf578c142d5290f136c0", size = 227905, upload-time = "2025-01-25T23:42:47.283Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/86d2d0e4316b8b9288fb714400d828a5dcfeeaa8675753b2c49d7b806301/clickhouse_connect-0.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:d762b987a69feadf91edebe795e81743f5a8e7fbace27188e93ae4d8903b1db9", size = 245488, upload-time = "2025-01-25T23:42:49.825Z" }, ] [[package]] @@ -513,7 +551,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -536,7 +573,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -554,7 +591,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, @@ -896,6 +932,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740, upload-time = "2025-12-16T00:40:23.96Z" }, { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437, upload-time = "2025-12-16T00:35:21.395Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, + { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, ] [[package]] @@ -960,6 +1001,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/8d/9d4d27ed7f33d109c50d6b5ce578a9914aa68edab75d65869a17e630a8d1/grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f", size = 7830132, upload-time = "2026-03-30T08:47:33.254Z" }, { url = "https://files.pythonhosted.org/packages/14/e4/9990b41c6d7a44e1e9dee8ac11d7a9802ba1378b40d77468a7761d1ad288/grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193", size = 4140904, upload-time = "2026-03-30T08:47:35.319Z" }, { url = "https://files.pythonhosted.org/packages/2f/2c/296f6138caca1f4b92a31ace4ae1b87dab692fc16a7a3417af3bb3c805bf/grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff", size = 4880944, upload-time = "2026-03-30T08:47:37.831Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" }, + { url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" }, + { url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" }, + { url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" }, + { url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" }, ] [[package]] @@ -997,6 +1048,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/d6/965f36cfc367c276799b730d5dd1311b90a54a33726e561393b808339b04/grpcio_tools-1.71.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3e4b4801fabd0427fc61d50d09588a01b1cfab0ec5e8a5f5d515fbdd0891fd11", size = 2913863, upload-time = "2025-06-28T04:21:22.196Z" }, { url = "https://files.pythonhosted.org/packages/8d/f0/c05d5c3d0c1d79ac87df964e9d36f1e3a77b60d948af65bec35d3e5c75a3/grpcio_tools-1.71.2-cp312-cp312-win32.whl", hash = "sha256:84ad86332c44572305138eafa4cc30040c9a5e81826993eae8227863b700b490", size = 945744, upload-time = "2025-06-28T04:21:23.463Z" }, { url = "https://files.pythonhosted.org/packages/e2/e9/c84c1078f0b7af7d8a40f5214a9bdd8d2a567ad6c09975e6e2613a08d29d/grpcio_tools-1.71.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e1108d37eecc73b1c4a27350a6ed921b5dda25091700c1da17cfe30761cd462", size = 1117695, upload-time = "2025-06-28T04:21:25.22Z" }, + { url = "https://files.pythonhosted.org/packages/60/9c/bdf9c5055a1ad0a09123402d73ecad3629f75b9cf97828d547173b328891/grpcio_tools-1.71.2-cp313-cp313-linux_armv7l.whl", hash = "sha256:b0f0a8611614949c906e25c225e3360551b488d10a366c96d89856bcef09f729", size = 2384758, upload-time = "2025-06-28T04:21:26.712Z" }, + { url = "https://files.pythonhosted.org/packages/49/d0/6aaee4940a8fb8269c13719f56d69c8d39569bee272924086aef81616d4a/grpcio_tools-1.71.2-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:7931783ea7ac42ac57f94c5047d00a504f72fbd96118bf7df911bb0e0435fc0f", size = 5443127, upload-time = "2025-06-28T04:21:28.383Z" }, + { url = "https://files.pythonhosted.org/packages/d9/11/50a471dcf301b89c0ed5ab92c533baced5bd8f796abfd133bbfadf6b60e5/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:d188dc28e069aa96bb48cb11b1338e47ebdf2e2306afa58a8162cc210172d7a8", size = 2349627, upload-time = "2025-06-28T04:21:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/bb/66/e3dc58362a9c4c2fbe98a7ceb7e252385777ebb2bbc7f42d5ab138d07ace/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f36c4b3cc42ad6ef67430639174aaf4a862d236c03c4552c4521501422bfaa26", size = 2742932, upload-time = "2025-06-28T04:21:32.325Z" }, + { url = "https://files.pythonhosted.org/packages/b7/1e/1e07a07ed8651a2aa9f56095411198385a04a628beba796f36d98a5a03ec/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bd9ed12ce93b310f0cef304176049d0bc3b9f825e9c8c6a23e35867fed6affd", size = 2473627, upload-time = "2025-06-28T04:21:33.752Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f9/3b7b32e4acb419f3a0b4d381bc114fe6cd48e3b778e81273fc9e4748caad/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7ce27e76dd61011182d39abca38bae55d8a277e9b7fe30f6d5466255baccb579", size = 2850879, upload-time = "2025-06-28T04:21:35.241Z" }, + { url = "https://files.pythonhosted.org/packages/1e/99/cd9e1acd84315ce05ad1fcdfabf73b7df43807cf00c3b781db372d92b899/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:dcc17bf59b85c3676818f2219deacac0156492f32ca165e048427d2d3e6e1157", size = 3300216, upload-time = "2025-06-28T04:21:36.826Z" }, + { url = "https://files.pythonhosted.org/packages/9f/c0/66eab57b14550c5b22404dbf60635c9e33efa003bd747211981a9859b94b/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:706360c71bdd722682927a1fb517c276ccb816f1e30cb71f33553e5817dc4031", size = 2913521, upload-time = "2025-06-28T04:21:38.347Z" }, + { url = "https://files.pythonhosted.org/packages/05/9b/7c90af8f937d77005625d705ab1160bc42a7e7b021ee5c788192763bccd6/grpcio_tools-1.71.2-cp313-cp313-win32.whl", hash = "sha256:bcf751d5a81c918c26adb2d6abcef71035c77d6eb9dd16afaf176ee096e22c1d", size = 945322, upload-time = "2025-06-28T04:21:39.864Z" }, + { url = "https://files.pythonhosted.org/packages/5f/80/6db6247f767c94fe551761772f89ceea355ff295fd4574cb8efc8b2d1199/grpcio_tools-1.71.2-cp313-cp313-win_amd64.whl", hash = "sha256:b1581a1133552aba96a730178bc44f6f1a071f0eb81c5b6bc4c0f89f5314e2b8", size = 1117234, upload-time = "2025-06-28T04:21:41.893Z" }, ] [[package]] @@ -1118,6 +1179,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", size = 88189, upload-time = "2025-11-03T13:01:52.605Z" }, { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", size = 99497, upload-time = "2025-11-03T13:01:53.477Z" }, { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", size = 91279, upload-time = "2025-11-03T13:01:54.419Z" }, + { url = "https://files.pythonhosted.org/packages/2f/46/08fd8ef19b782f301d56a9ccfd7dafec5fd4fc1a9f017cf22a1accb585d7/lz4-4.4.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6bb05416444fafea170b07181bc70640975ecc2a8c92b3b658c554119519716c", size = 207171, upload-time = "2025-11-03T13:01:56.595Z" }, + { url = "https://files.pythonhosted.org/packages/8f/3f/ea3334e59de30871d773963997ecdba96c4584c5f8007fd83cfc8f1ee935/lz4-4.4.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b424df1076e40d4e884cfcc4c77d815368b7fb9ebcd7e634f937725cd9a8a72a", size = 207163, upload-time = "2025-11-03T13:01:57.721Z" }, + { url = "https://files.pythonhosted.org/packages/41/7b/7b3a2a0feb998969f4793c650bb16eff5b06e80d1f7bff867feb332f2af2/lz4-4.4.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:216ca0c6c90719731c64f41cfbd6f27a736d7e50a10b70fad2a9c9b262ec923d", size = 1292136, upload-time = "2025-11-03T13:02:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/89/d1/f1d259352227bb1c185288dd694121ea303e43404aa77560b879c90e7073/lz4-4.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:533298d208b58b651662dd972f52d807d48915176e5b032fb4f8c3b6f5fe535c", size = 1279639, upload-time = "2025-11-03T13:02:01.649Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fb/ba9256c48266a09012ed1d9b0253b9aa4fe9cdff094f8febf5b26a4aa2a2/lz4-4.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:451039b609b9a88a934800b5fc6ee401c89ad9c175abf2f4d9f8b2e4ef1afc64", size = 1368257, upload-time = "2025-11-03T13:02:03.35Z" }, + { url = "https://files.pythonhosted.org/packages/a5/6d/dee32a9430c8b0e01bbb4537573cabd00555827f1a0a42d4e24ca803935c/lz4-4.4.5-cp313-cp313-win32.whl", hash = "sha256:a5f197ffa6fc0e93207b0af71b302e0a2f6f29982e5de0fbda61606dd3a55832", size = 88191, upload-time = "2025-11-03T13:02:04.406Z" }, + { url = "https://files.pythonhosted.org/packages/18/e0/f06028aea741bbecb2a7e9648f4643235279a770c7ffaf70bd4860c73661/lz4-4.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:da68497f78953017deb20edff0dba95641cc86e7423dfadf7c0264e1ac60dc22", size = 99502, upload-time = "2025-11-03T13:02:05.886Z" }, + { url = "https://files.pythonhosted.org/packages/61/72/5bef44afb303e56078676b9f2486f13173a3c1e7f17eaac1793538174817/lz4-4.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:c1cfa663468a189dab510ab231aad030970593f997746d7a324d40104db0d0a9", size = 91285, upload-time = "2025-11-03T13:02:06.77Z" }, + { url = "https://files.pythonhosted.org/packages/49/55/6a5c2952971af73f15ed4ebfdd69774b454bd0dc905b289082ca8664fba1/lz4-4.4.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67531da3b62f49c939e09d56492baf397175ff39926d0bd5bd2d191ac2bff95f", size = 207348, upload-time = "2025-11-03T13:02:08.117Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d7/fd62cbdbdccc35341e83aabdb3f6d5c19be2687d0a4eaf6457ddf53bba64/lz4-4.4.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a1acbbba9edbcbb982bc2cac5e7108f0f553aebac1040fbec67a011a45afa1ba", size = 207340, upload-time = "2025-11-03T13:02:09.152Z" }, + { url = "https://files.pythonhosted.org/packages/77/69/225ffadaacb4b0e0eb5fd263541edd938f16cd21fe1eae3cd6d5b6a259dc/lz4-4.4.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a482eecc0b7829c89b498fda883dbd50e98153a116de612ee7c111c8bcf82d1d", size = 1293398, upload-time = "2025-11-03T13:02:10.272Z" }, + { url = "https://files.pythonhosted.org/packages/c6/9e/2ce59ba4a21ea5dc43460cba6f34584e187328019abc0e66698f2b66c881/lz4-4.4.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e099ddfaa88f59dd8d36c8a3c66bd982b4984edf127eb18e30bb49bdba68ce67", size = 1281209, upload-time = "2025-11-03T13:02:12.091Z" }, + { url = "https://files.pythonhosted.org/packages/80/4f/4d946bd1624ec229b386a3bc8e7a85fa9a963d67d0a62043f0af0978d3da/lz4-4.4.5-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2af2897333b421360fdcce895c6f6281dc3fab018d19d341cf64d043fc8d90d", size = 1369406, upload-time = "2025-11-03T13:02:13.683Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/d429ba4720a9064722698b4b754fb93e42e625f1318b8fe834086c7c783b/lz4-4.4.5-cp313-cp313t-win32.whl", hash = "sha256:66c5de72bf4988e1b284ebdd6524c4bead2c507a2d7f172201572bac6f593901", size = 88325, upload-time = "2025-11-03T13:02:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/4b/85/7ba10c9b97c06af6c8f7032ec942ff127558863df52d866019ce9d2425cf/lz4-4.4.5-cp313-cp313t-win_amd64.whl", hash = "sha256:cdd4bdcbaf35056086d910d219106f6a04e1ab0daa40ec0eeef1626c27d0fddb", size = 99643, upload-time = "2025-11-03T13:02:15.978Z" }, + { url = "https://files.pythonhosted.org/packages/77/4d/a175459fb29f909e13e57c8f475181ad8085d8d7869bd8ad99033e3ee5fa/lz4-4.4.5-cp313-cp313t-win_arm64.whl", hash = "sha256:28ccaeb7c5222454cd5f60fcd152564205bcb801bd80e125949d2dfbadc76bbd", size = 91504, upload-time = "2025-11-03T13:02:17.313Z" }, ] [[package]] @@ -1893,6 +1970,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, ] @@ -1948,4 +2035,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, ] diff --git a/tools/cloud_adapter/clouds/azure.py b/tools/cloud_adapter/clouds/azure.py index 4f886eba5..62bbd0d0f 100644 --- a/tools/cloud_adapter/clouds/azure.py +++ b/tools/cloud_adapter/clouds/azure.py @@ -14,11 +14,14 @@ import msal from azure.core.credentials import AccessToken, TokenCredential -from msrest.authentication import BasicTokenAuthentication from azure.mgmt.consumption import ConsumptionManagementClient -from azure.mgmt.consumption.models import (ModernUsageDetail, LegacyUsageDetail, - UsageDetail, UsageDetailsListResult) +from azure.mgmt.consumption.models import ( + ModernUsageDetail, + LegacyUsageDetail, + UsageDetail, + UsageDetailsListResult, +) from retrying import retry from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.reservations import AzureReservationAPI @@ -28,17 +31,21 @@ from azure.mgmt.compute.models import InstanceViewTypes from azure.mgmt.storage import StorageManagementClient from azure.mgmt.subscription import SubscriptionClient -from msrest.exceptions import ( - AuthenticationError, ClientRequestError, HttpOperationError) from azure.mgmt.monitor import MonitorManagementClient -from azure.core.exceptions import (HttpResponseError, ClientAuthenticationError, - ResourceNotFoundError, ServiceRequestError) +from azure.core.exceptions import ( + HttpResponseError, + ClientAuthenticationError, + ResourceNotFoundError, + ServiceRequestError, + ServiceResponseError, +) from azure.storage.blob import BlobServiceClient -from msrest import Deserializer from tools.cloud_adapter.lib.azure_partner.client import AzurePartnerClient from tools.cloud_adapter.lib.azure_partner.exceptions import ( - AzurePartnerConnectionException, AzurePartnerHttpException) + AzurePartnerConnectionException, + AzurePartnerHttpException, +) from tools.cloud_adapter.clouds.base import CloudBase from tools.cloud_adapter.model import ( InstanceResource, @@ -56,7 +63,7 @@ CloudConnectionError, MetricsNotFoundException, MetricsServerTimeoutException, - ReportFilesNotFoundException + ReportFilesNotFoundException, ) from tools.cloud_adapter.utils import ( CloudParameter, @@ -69,22 +76,14 @@ logging.getLogger('azure.identity').setLevel(logging.WARNING) LOG = logging.getLogger(__name__) -SECONDS_IN_DAY = 60 * 60 * 24 CLOUD_VALIDATION_TIMEOUT = 90 CLOUD_LINK_PATTERN = '%s%s/overview' DAYS_IN_MONTH = 30 -DESERIALIZER = Deserializer(classes={ - 'ModernUsageDetail': ModernUsageDetail, - 'LegacyUsageDetail': LegacyUsageDetail, - 'UsageDetail': UsageDetail, - 'UsageDetailsListResult': UsageDetailsListResult -}) ARM_SCOPE = "https://management.azure.com/.default" AZURE_CN_CREDS_SCOPE = "https://management.core.chinacloudapi.cn//.default" # defining it to use outside CAd AzureConsumptionException = HttpResponseError -AzureErrorResponseException = HttpOperationError AzureAuthenticationError = ClientAuthenticationError AzureResourceNotFoundError = ResourceNotFoundError @@ -123,16 +122,14 @@ class PortalUrl: AZURE_CN = 'https://portal.azure.cn/#resource' -class MsalCredential(BasicTokenAuthentication, TokenCredential): +class MsalCredential(TokenCredential): """ Uses MSAL ConfidentialClientApplication - Works for msrest-based clients via BasicTokenAuthentication, also - works for azure-core clients via TokenCredential.get_token(). + Works for azure-core clients via TokenCredential.get_token(). """ def __init__(self, tenant_id: str, client_id: str, client_secret: str, base_url=None): - super().__init__(token=None) self._tenant_id = tenant_id self._client_id = client_id self._client_secret = client_secret @@ -197,8 +194,6 @@ def _obtain_token(self, scopes: list[str]) -> tuple[str, int]: self._access_token = access_token self._expires_on = expires_on - self.token = {"access_token": access_token} - LOG.info( "MSAL: New access token acquired; expires_on=%s " "(%s seconds from now)", @@ -246,16 +241,6 @@ def get_token(self, *scopes: str, **kwargs: Any) -> AccessToken: ) return AccessToken(access_token, expires_on) - def signed_session(self, session=None): - """ - Called by msrest-based SDKs (old msrest approach). - We refresh token if needed, then delegate to the base class. - """ - LOG.debug("MSAL: signed_session() called for msrest client") - self._ensure_token(self._scopes) - LOG.info("MSAL: signed_session() using MSAL-backed access token") - return super().signed_session(session) - def _extract_azure_status_and_code(exc): """ @@ -293,7 +278,7 @@ def _extract_azure_status_and_code(exc): def _is_auth_error(exc) -> bool: - if isinstance(exc, (AuthenticationError, ClientAuthenticationError)): + if isinstance(exc, ClientAuthenticationError): return True if isinstance(exc, HttpResponseError) or hasattr(exc, "response"): @@ -402,7 +387,7 @@ def _retry_on_error(exc): return False # Network/client side transients - if isinstance(exc, (ServiceRequestError, ClientRequestError)): + if isinstance(exc, (ServiceRequestError, ServiceResponseError)): LOG.error("RETRY: network/client exception: %s", type(exc).__name__) _sleep_with_headers({}, source="network") return True @@ -733,8 +718,7 @@ def raw_client(self): def _get_service_principal_credentials(self): """ - Returns a unified MSAL-based credential that is compatible with - msrest-based clients + Returns a unified MSAL-based credential """ kwargs = { 'client_id': self.config['client_id'], @@ -753,8 +737,7 @@ def _get_service_principal_credentials(self): except AuthorizationException: raise except Exception as ex: - description = self._get_error_description(ex) - raise AuthorizationException(description) + raise AuthorizationException(str(exc)) def _get_client_secret_credentials(self): """ @@ -774,18 +757,6 @@ def _is_partner_account(self): 'partner_client_id' in self.config and 'partner_secret' in self.config) - @staticmethod - def _get_error_description(exc: Exception): - try: - if isinstance(exc, AuthenticationError): - description = exc.inner_exception.error_response.get( - 'error_description').split('\r\n')[0] - else: - description = str(exc) - except Exception: - description = str(exc) - return description - @retry(retry_on_exception=_retry_on_error, wait_fixed=2000, stop_max_attempt_number=10) def _retry(self, method, *args, **kwargs): @@ -890,11 +861,13 @@ def _get_billing_info(self): usage_detail = next(usage) currency = (getattr(usage_detail, 'billing_currency', None) or getattr(usage_detail, 'billingCurrencyCode', None)) - except (AzureConsumptionException, StopIteration, ClientRequestError, - TypeError) as exc: + except (AzureConsumptionException, StopIteration, ServiceRequestError, + ServiceResponseError, TypeError) as exc: # according to logs in this issue we get TypeError deep inside # python lib in case of timeout error - is_timeout_error = isinstance(exc, (ClientRequestError, TypeError)) + is_timeout_error = isinstance( + exc, (ServiceRequestError, ServiceResponseError, TypeError), + ) is_empty = isinstance(exc, StopIteration) is_unsupported = (isinstance(exc, AzureConsumptionException) and hasattr(exc.response, 'status_code') and int( @@ -1402,11 +1375,9 @@ def get_values(_req): if limit: url += f'&$top={limit}' - # Ensure msrest client has a fresh token from our MSAL-based credential + # Fetch a fresh bearer token from our MSAL-based credential cred = self.raw_client._config.credential - # One signed_session() call forces refresh + sets cred.token["access_token"] - cred.signed_session() - token = cred.token['access_token'] + token = cred.get_token(ARM_SCOPE).token headers = {'Authorization': f'Bearer {token}'} request = HttpRequest(method='GET', url=url, headers=headers) @@ -1872,8 +1843,8 @@ def start_instance(self, instance_name, group_name): try: return self.compute.virtual_machines.begin_start( group_name, instance_name) - except HttpOperationError as exc: - if exc.error.error == 'ResourceNotFound': + except HttpResponseError as exc: + if getattr(exc.error, 'code', None) == 'ResourceNotFound': raise ResourceNotFound(str(exc)) else: raise @@ -1882,8 +1853,8 @@ def stop_instance(self, instance_name, group_name): try: return self.compute.virtual_machines.begin_deallocate( group_name, instance_name) - except HttpOperationError as exc: - if exc.error.error == 'ResourceNotFound': + except HttpResponseError as exc: + if getattr(exc.error, 'code', None) == 'ResourceNotFound': raise ResourceNotFound(str(exc)) else: raise diff --git a/tools/cloud_adapter/setup.py b/tools/cloud_adapter/setup.py index c725285f3..f07c39596 100644 --- a/tools/cloud_adapter/setup.py +++ b/tools/cloud_adapter/setup.py @@ -28,10 +28,9 @@ "azure_mgmt_subscription==3.1.1", "azure-mgmt-consumption==10.0.0", "azure-mgmt-monitor==7.0.0", - "azure-mgmt-commerce==6.0.0", + "azure-mgmt-commerce==6.0.1", "azure-mgmt-reservations==2.3.0", "msal==1.34.0", - "msrest==0.7.1", "urllib3==2.7.0", "azure-identity==1.16.1", "oauthlib==3.2.2", From d30be5809f9a89a6c1d74e31daabce41ee6e5cbd Mon Sep 17 00:00:00 2001 From: Vladislav A Date: Tue, 7 Jul 2026 15:12:03 +0400 Subject: [PATCH 2/8] OSN-1440: Updated etcd-walker 0.6.0 --- docker_images/etcd/Dockerfile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docker_images/etcd/Dockerfile b/docker_images/etcd/Dockerfile index bb432aaa3..b16cced86 100644 --- a/docker_images/etcd/Dockerfile +++ b/docker_images/etcd/Dockerfile @@ -7,7 +7,7 @@ FROM golang:1.24.6 AS build-etcd-walker RUN git clone https://github.com/nexusriot/etcd-walker/ /tmp/etcd-walker-src WORKDIR /tmp/etcd-walker-src -RUN git checkout 0.2.1 +RUN git checkout 0.6.0 RUN go build -ldflags "-linkmode external -extldflags -static" -o etcd-walker cmd/etcd-walker/main.go RUN mv etcd-walker /bin/etcd-walker @@ -15,4 +15,14 @@ RUN chmod +x /bin/etcd-walker # NOTE: v3.6+ require significant changes as they removed support for the V2 API, see https://etcd.io/docs/v3.6/upgrades/upgrade_3_6/ FROM gcr.io/etcd-development/etcd:v3.2.13 + +# newer etcd walker versions have v3 protocol by default +RUN mkdir -p /etc/etcd-walker && tee /etc/etcd-walker/config.json >/dev/null <<'EOF' +{ + "host": "127.0.0.1", + "port": "2379", + "protocol": "v2", + "debug": false +} +EOF COPY --from=build-etcd-walker /bin/etcd-walker /bin/etcd-walker From 60209958b9e91040a61796a39ef035ee50b8be8e Mon Sep 17 00:00:00 2001 From: sd-hystax <110374605+sd-hystax@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:47:33 +0300 Subject: [PATCH 3/8] OSN-1519. Diworker: make csv_rewrite_days configurable ## Description Diworker: make csv_rewrite_days configurable ## Related issue number OSN-1519 ## Special notes ## Checklist * [ ] The pull request title is a good summary of the changes * [ ] Unit tests for the changes exist * [ ] New and existing unit tests pass locally --- diworker/diworker/importers/aws.py | 6 ++---- diworker/diworker/importers/base.py | 6 +++--- diworker/diworker/main.py | 6 +++++- optscale-deploy/optscale/templates/tpl/_config.tpl | 1 + optscale-deploy/optscale/values.yaml | 1 + 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/diworker/diworker/importers/aws.py b/diworker/diworker/importers/aws.py index ff0ee6cdd..65fc50f58 100644 --- a/diworker/diworker/importers/aws.py +++ b/diworker/diworker/importers/aws.py @@ -11,9 +11,7 @@ from datetime import datetime, timedelta, timezone from functools import cached_property -from diworker.diworker.importers.base import ( - CSVBaseReportImporter, CSV_REWRITE_DAYS -) +from diworker.diworker.importers.base import CSVBaseReportImporter import tools.optscale_time as opttime import pyarrow.parquet as pq @@ -219,7 +217,7 @@ def min_date_import_threshold(self) -> datetime: if self._is_first_import_in_month(last_import_dt): # import full previous month on the first import in month return last_import_dt.replace(day=1) - return last_import_dt - timedelta(days=CSV_REWRITE_DAYS) + return last_import_dt - timedelta(days=self.csv_rewrite_days) def get_raw_upsert_filters(self, expense): filters = super().get_raw_upsert_filters(expense) diff --git a/diworker/diworker/importers/base.py b/diworker/diworker/importers/base.py index ea231b14c..64049b90b 100644 --- a/diworker/diworker/importers/base.py +++ b/diworker/diworker/importers/base.py @@ -30,7 +30,6 @@ _THROTTLE_SEMAPHORES: dict[str, threading.Semaphore] = {} _THROTTLE_LOCK = threading.Lock() -CSV_REWRITE_DAYS = 5 GZIP_ENDING = '.gz' REPORTS_PATH_PREFIX = 'reports' @@ -47,9 +46,10 @@ class BaseReportImporter: def __init__(self, cloud_account_id, rest_cl, config_cl, mongo_raw, mongo_resources, clickhouse_cl, import_file=None, recalculate=False, detect_period_start=True, - max_tenant_concurrent=1): + max_tenant_concurrent=1, csv_rewrite_days=5): self.cloud_acc_id = cloud_account_id self.max_tenant_concurrent = max_tenant_concurrent + self.csv_rewrite_days = csv_rewrite_days self.rest_cl = rest_cl self.config_cl = config_cl self.mongo_raw = mongo_raw @@ -650,7 +650,7 @@ def min_date_import_threshold(self) -> datetime: self.cloud_acc.get('last_import_modified_at', 0), tz=timezone.utc) return last_import_dt.replace( hour=0, minute=0, second=0, microsecond=0 - ) - timedelta(days=CSV_REWRITE_DAYS) + ) - timedelta(days=self.csv_rewrite_days) def detect_period_start(self): pass diff --git a/diworker/diworker/main.py b/diworker/diworker/main.py index 9bf990e53..3942cf1ca 100755 --- a/diworker/diworker/main.py +++ b/diworker/diworker/main.py @@ -41,6 +41,7 @@ HEARTBEAT_INTERVAL = 300 DEFAULT_MAX_WORKERS = 4 DEFAULT_MAX_TENANT_WORKERS = 1 +DEFAULT_CSV_REWRITE_DAYS = 10 def _is_rate_limit_exc(exc): @@ -178,7 +179,10 @@ def report_import(self, task, config_cl, rest_cl, mongo_cl, clickhouse_cl): 'import_file': import_dict.get('import_file'), 'recalculate': is_recalculation, 'max_tenant_concurrent': int(self.diworker_settings.get( - 'max_tenant_import_workers', DEFAULT_MAX_TENANT_WORKERS))} + 'max_tenant_import_workers', DEFAULT_MAX_TENANT_WORKERS)), + 'csv_rewrite_days': int(self.diworker_settings.get( + 'csv_rewrite_days', DEFAULT_CSV_REWRITE_DAYS)) + } importer = None ca = None previous_attempt_ts = 0 diff --git a/optscale-deploy/optscale/templates/tpl/_config.tpl b/optscale-deploy/optscale/templates/tpl/_config.tpl index 91ff00076..31ebe8eff 100644 --- a/optscale-deploy/optscale/templates/tpl/_config.tpl +++ b/optscale-deploy/optscale/templates/tpl/_config.tpl @@ -288,6 +288,7 @@ etcd: demo_org_lifetime_hrs: {{ .Values.demo_org_cleanup.demo_org_lifetime_hrs }} diworker: max_report_imports_workers: {{ .Values.import_reports.max_workers }} + csv_rewrite_days: {{ .Values.import_reports.csv_rewrite_days }} opentelemetry: enable_threading: true enable_urllib3: true diff --git a/optscale-deploy/optscale/values.yaml b/optscale-deploy/optscale/values.yaml index d56b3fa9c..9ec07ccac 100644 --- a/optscale-deploy/optscale/values.yaml +++ b/optscale-deploy/optscale/values.yaml @@ -1017,6 +1017,7 @@ import_reports: message_expiration_secs: 10800 # 3 hours expiration to process a queue message not_processed_threshold_secs: 10800 # 3 hours gap for report generating max_workers: 10 + csv_rewrite_days: 10 demo: multiplier: 2 # demo multiplier default value From f1a201561cf47c5623709dc32b2804eead8b863a Mon Sep 17 00:00:00 2001 From: sd-hystax <110374605+sd-hystax@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:48:03 +0300 Subject: [PATCH 4/8] OSN-1528. Fixed images build ## Description Fixed images build ## Related issue number OSN-1528 ## Special notes ## Checklist * [ ] The pull request title is a good summary of the changes * [ ] Unit tests for the changes exist * [ ] New and existing unit tests pass locally --- bumiworker/uv.lock | 14 ++++++-------- gemini/gemini_worker/uv.lock | 14 ++++++-------- insider/insider_api/uv.lock | 14 ++++++-------- metroculus/metroculus_api/uv.lock | 14 ++++++-------- metroculus/metroculus_worker/uv.lock | 14 ++++++-------- rest_api/uv.lock | 14 ++++++-------- risp/risp_worker/uv.lock | 14 ++++++-------- trapper/trapper_worker/uv.lock | 14 ++++++-------- 8 files changed, 48 insertions(+), 64 deletions(-) diff --git a/bumiworker/uv.lock b/bumiworker/uv.lock index c62ef9bbf..812176b4b 100644 --- a/bumiworker/uv.lock +++ b/bumiworker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -558,7 +558,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -581,7 +580,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -599,7 +598,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/gemini/gemini_worker/uv.lock b/gemini/gemini_worker/uv.lock index 13ab5a88b..1f4c7b7e0 100644 --- a/gemini/gemini_worker/uv.lock +++ b/gemini/gemini_worker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -496,7 +496,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -519,7 +518,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -537,7 +536,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/insider/insider_api/uv.lock b/insider/insider_api/uv.lock index 82c104b68..54b6baafa 100644 --- a/insider/insider_api/uv.lock +++ b/insider/insider_api/uv.lock @@ -199,16 +199,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -475,7 +475,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -498,7 +497,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -516,7 +515,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/metroculus/metroculus_api/uv.lock b/metroculus/metroculus_api/uv.lock index 683b92734..82fffeccf 100644 --- a/metroculus/metroculus_api/uv.lock +++ b/metroculus/metroculus_api/uv.lock @@ -199,16 +199,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -500,7 +500,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -523,7 +522,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -541,7 +540,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/metroculus/metroculus_worker/uv.lock b/metroculus/metroculus_worker/uv.lock index 6aa44e86c..63355d3e0 100644 --- a/metroculus/metroculus_worker/uv.lock +++ b/metroculus/metroculus_worker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -505,7 +505,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -528,7 +527,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -546,7 +545,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/rest_api/uv.lock b/rest_api/uv.lock index bffd93a7e..855250267 100644 --- a/rest_api/uv.lock +++ b/rest_api/uv.lock @@ -239,16 +239,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -559,7 +559,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -582,7 +581,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -600,7 +599,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/risp/risp_worker/uv.lock b/risp/risp_worker/uv.lock index bacf7ef6b..6d484e5be 100644 --- a/risp/risp_worker/uv.lock +++ b/risp/risp_worker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -505,7 +505,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -528,7 +527,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -546,7 +545,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, diff --git a/trapper/trapper_worker/uv.lock b/trapper/trapper_worker/uv.lock index a92f854bf..ad0380c47 100644 --- a/trapper/trapper_worker/uv.lock +++ b/trapper/trapper_worker/uv.lock @@ -198,16 +198,16 @@ wheels = [ [[package]] name = "azure-mgmt-commerce" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-common" }, { name = "azure-mgmt-core" }, - { name = "msrest" }, + { name = "isodate" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b9/6751a3183f7688e0c3b23de4a0a28356b42f93b3206073dbfbe75cfbc6fd/azure-mgmt-commerce-6.0.0.zip", hash = "sha256:6f5447395503b2318f451d24f8021ee08db1cac44f1c3337ea690700419626b6", size = 4425716, upload-time = "2021-01-04T06:17:46.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/23/e5e58318f7242b76691d15ba28350d0f1bb905065ff98b22110b2ecdf07d/azure_mgmt_commerce-6.0.1.tar.gz", hash = "sha256:e4a32f2af684020b02e1e847d2d940604ddbd6010261262c33791ffc692fdeae", size = 43464, upload-time = "2026-05-15T11:06:03.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/42/a72d1c37584ce5dd98e34a3256b8480ad7c67653cc0022bb9dd0972191e0/azure_mgmt_commerce-6.0.0-py2.py3-none-any.whl", hash = "sha256:1cf047ec0d202818f014fb54a78ee0c4b9753e561d8ed03cd88977603dd7dcb8", size = 29478, upload-time = "2021-01-04T06:17:44.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3b/dfed784e68377f3e5f6bb99eac54321e8aa7bffe55cad92f99470c498707/azure_mgmt_commerce-6.0.1-py3-none-any.whl", hash = "sha256:e9e12fd467808d22fc867514ff31fdee74539119d21dbe4072cba283573b1130", size = 52774, upload-time = "2026-05-15T11:06:04.827Z" }, ] [[package]] @@ -505,7 +505,6 @@ dependencies = [ { name = "google-cloud-monitoring" }, { name = "google-cloud-storage" }, { name = "msal" }, - { name = "msrest" }, { name = "oauthlib" }, { name = "requests" }, { name = "retrying" }, @@ -528,7 +527,7 @@ requires-dist = [ { name = "aliyun-python-sdk-sts", specifier = "==3.0.2" }, { name = "aliyun-python-sdk-vpc", specifier = "==3.0.14" }, { name = "azure-identity", specifier = "==1.16.1" }, - { name = "azure-mgmt-commerce", specifier = "==6.0.0" }, + { name = "azure-mgmt-commerce", specifier = "==6.0.1" }, { name = "azure-mgmt-compute", specifier = "==37.2.0" }, { name = "azure-mgmt-consumption", specifier = "==10.0.0" }, { name = "azure-mgmt-monitor", specifier = "==7.0.0" }, @@ -546,7 +545,6 @@ requires-dist = [ { name = "google-cloud-monitoring", specifier = ">=2.15.1,<3.0" }, { name = "google-cloud-storage", specifier = ">=2.10.0,<3.0" }, { name = "msal", specifier = "==1.34.0" }, - { name = "msrest", specifier = "==0.7.1" }, { name = "oauthlib", specifier = "==3.2.2" }, { name = "requests", specifier = "==2.32.4" }, { name = "retrying", specifier = ">=1.4.1" }, From 802c86fbde9bdee51524b851ce25610f9ec857e3 Mon Sep 17 00:00:00 2001 From: maxb-hystax <24920606+maxb-hystax@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:07:05 +0400 Subject: [PATCH 5/8] OptScale on docker compose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Add Docker Compose deployment for OptScale #### Summary - Added a complete Docker Compose deployment stack that mirrors the Kubernetes Helm chart, enabling local evaluation and development without a K8s cluster. Includes two deployment variants: a default mode pulling ~40 separate per-service images, and a unified image mode that builds all first-party services into a single optscale_app Docker image selectable at runtime via OPTSCALE_MODE. - Introduced a multi-stage Dockerfile and mode-dispatching entrypoint.sh for the unified image, covering 60+ service modes (APIs, workers, schedulers, executors, maintenance jobs, and Node.js frontends). - Add all supporting infrastructure: nginx edge proxy config, etcd bootstrap config, Thanos object-store config, .env.example with documented defaults, pull.sh for rate-limit-safe image pulls, build-unified.sh for the unified image, and a comprehensive README.md. #### Motivation The existing Kubernetes/Helm deployment has a high barrier to entry for evaluation and development. Docker Compose provides a single-machine alternative with docker compose up -d. The unified image variant further reduces friction by consolidating ~40 application images into one, avoiding Docker Hub rate limits and simplifying air-gapped deployments. #### Architecture The stack is organized in layers: - Data plane — etcd, MariaDB, MongoDB, RabbitMQ, Redis, InfluxDB, ClickHouse, MinIO - Metrics — Thanos receive, store gateway, and query (backed by MinIO) - Application — all API services, workers, executors, and Node.js frontends - Cron-style schedulers — while true; sleep N loops approximating K8s CronJobs - Bootstrap — one-shot configurator that seeds etcd, creates databases, sets up queues A depends_on graph ensures correct startup ordering: datastores → configurator → API services → periodic schedulers. ### Excluded from scope - ELK stack, OpenTelemetry/Tempo, Grafana (not needed for evaluation) - Thanos compactor/web - Stripe-gated services (subsyncer, bailiff) --- .github/workflows/test_optscale_deploy.yaml | 26 + .gitignore | 3 + README.md | 19 + diworker/diworker/main.py | 3 + ...02112081330000_move_expenses_clickhouse.py | 8 +- docker_images/optscale_app/Dockerfile | 185 +++ docker_images/optscale_app/entrypoint.sh | 170 +++ .../duplicate_object_finder/aws/main.py | 3 + optscale-deploy/compose/.env.example | 60 + optscale-deploy/compose/README.md | 156 +++ optscale-deploy/compose/build-unified.sh | 70 + optscale-deploy/compose/config.yml | 280 ++++ .../compose/docker-compose.unified.yml | 1133 ++++++++++++++++ optscale-deploy/compose/docker-compose.yml | 1140 +++++++++++++++++ optscale-deploy/compose/nginx.conf | 83 ++ optscale-deploy/compose/pull.sh | 32 + optscale-deploy/compose/thanos_conf.yaml | 7 + .../tests/test_compose_deployment.py | 330 +++++ 18 files changed, 3704 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/test_optscale_deploy.yaml create mode 100644 docker_images/optscale_app/Dockerfile create mode 100644 docker_images/optscale_app/entrypoint.sh create mode 100644 optscale-deploy/compose/.env.example create mode 100644 optscale-deploy/compose/README.md create mode 100755 optscale-deploy/compose/build-unified.sh create mode 100644 optscale-deploy/compose/config.yml create mode 100644 optscale-deploy/compose/docker-compose.unified.yml create mode 100644 optscale-deploy/compose/docker-compose.yml create mode 100644 optscale-deploy/compose/nginx.conf create mode 100755 optscale-deploy/compose/pull.sh create mode 100644 optscale-deploy/compose/thanos_conf.yaml create mode 100644 optscale-deploy/tests/test_compose_deployment.py diff --git a/.github/workflows/test_optscale_deploy.yaml b/.github/workflows/test_optscale_deploy.yaml new file mode 100644 index 000000000..8eb1ff836 --- /dev/null +++ b/.github/workflows/test_optscale_deploy.yaml @@ -0,0 +1,26 @@ +name: Validate OptScale deployment manifests +run-name: Validate OptScale deployment manifests - started by ${{ github.actor }} +permissions: read-all +on: + pull_request: + types: [opened, synchronize] + paths: + - 'optscale-deploy/**' + - '.github/workflows/test_optscale_deploy.yaml' + workflow_dispatch: + + +jobs: + validate_deployment_manifests: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v6 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + - name: Install test dependencies + run: python -m pip install pytest PyYAML + - name: Validate compose and k8s parity + run: python -m pytest optscale-deploy/tests diff --git a/.gitignore b/.gitignore index c30d2cabe..9d96b70d8 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,8 @@ jira_ui/*/.env jira_ui/*/node_modules jira_ui/*/build/ +# Compose env +optscale-deploy/compose/.env + # Vagrant optscale-deploy/.vagrant/ diff --git a/README.md b/README.md index 448d2c1b3..31dd0d9ec 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,25 @@ It supports multi-cloud environments and integrates with popular data platforms, ## Getting started +### Docker Compose quickstart (try mode) + +The fastest way to try OptScale locally — no Kubernetes required. Requires Docker Engine 24+ and Docker Compose v2.20+ with at least 8 CPU cores and 16 GB RAM. + +```bash +git clone https://github.com/hystax/optscale.git +cd optscale/optscale-deploy/compose +cp .env.example .env +docker compose up -d +``` + +Once the `configurator` container exits successfully (1-2 minutes), open **http://localhost** in your browser. + +See [optscale-deploy/compose/README.md](optscale-deploy/compose/README.md) for full details, configuration options, and troubleshooting. + +> **Note:** The Docker Compose deployment is for evaluation and development only. For production, use the Kubernetes installation below. + +### Production installation (Kubernetes) + The minimum hardware requirements for OptScale cluster: CPU: 8+ cores, RAM: 16Gb, SSD: 150+ Gb. NVMe SSD is recommended. diff --git a/diworker/diworker/main.py b/diworker/diworker/main.py index 3942cf1ca..fc3228403 100755 --- a/diworker/diworker/main.py +++ b/diworker/diworker/main.py @@ -42,6 +42,7 @@ DEFAULT_MAX_WORKERS = 4 DEFAULT_MAX_TENANT_WORKERS = 1 DEFAULT_CSV_REWRITE_DAYS = 10 +MIGRATIONS_READY_FILE = '/tmp/diworker-migrations-ready' def _is_rate_limit_exc(exc): @@ -299,6 +300,8 @@ def _process_task(self, body, message): # starting at the same time on cluster with EtcdLock(config_cl, 'diworker_migrations'): migrator.migrate() + with open(MIGRATIONS_READY_FILE, 'w') as ready_file: + ready_file.write('ready\n') LOG.info("starting worker") conn_str = 'amqp://{user}:{pass}@{host}:{port}'.format( **config_cl.read_branch('/rabbit')) diff --git a/diworker/diworker/migrations/202112081330000_move_expenses_clickhouse.py b/diworker/diworker/migrations/202112081330000_move_expenses_clickhouse.py index 57de45c1b..02c101b22 100644 --- a/diworker/diworker/migrations/202112081330000_move_expenses_clickhouse.py +++ b/diworker/diworker/migrations/202112081330000_move_expenses_clickhouse.py @@ -51,10 +51,10 @@ def upgrade(self): _, resp = rest_client.cloud_account_list(organization_id) cloud_account_ids = list(map( lambda x: x['id'], resp['cloud_accounts'])) - expenses = expenses_collection.find( - {'cloud_account_id': {'$in': cloud_account_ids}} - ) - total_expenses = expenses.count_documents() + expenses_filter = {'cloud_account_id': {'$in': cloud_account_ids}} + total_expenses = expenses_collection.count_documents( + expenses_filter) + expenses = expenses_collection.find(expenses_filter) bulk = [] total_migrated = 0 LOG.info('Migrating expenses for org %s (%s/%s)...' % ( diff --git a/docker_images/optscale_app/Dockerfile b/docker_images/optscale_app/Dockerfile new file mode 100644 index 000000000..13f2aecd3 --- /dev/null +++ b/docker_images/optscale_app/Dockerfile @@ -0,0 +1,185 @@ +# Unified OptScale application image. +# Build context: repository root. +# +# docker build -f docker_images/optscale_app/Dockerfile -t optscale_app:local . +# +# At runtime, set OPTSCALE_MODE to select which service to start (see entrypoint.sh). + +# ── Stage 1: Build ngui ────────────────────────────────────────────── +FROM node:22.16.0-alpine3.21 AS ngui-builder + +RUN npm install -g pnpm@10.33.0 +ENV NODE_ENV=production + +WORKDIR /build +COPY ngui/ . +RUN pnpm install --frozen-lockfile --ignore-scripts +RUN pnpm run -r build +RUN pnpm deploy --filter=server --prod ./prod/server && \ + ./prod/server/scripts/prune_node_modules.sh +RUN rm -rf ./ui/node_modules + +# ── Stage 2: Build jira_ui ─────────────────────────────────────────── +FROM node:18.14.2-alpine3.16 AS jira-ui-builder + +ENV NODE_ENV=production +WORKDIR /build/ui +COPY jira_ui/ui/package*.json ./ +RUN npm ci --ignore-scripts --legacy-peer-deps +COPY jira_ui/ui/ ./ +RUN npm run build && rm -rf node_modules + +WORKDIR /build/server +COPY jira_ui/server/package*.json ./ +RUN npm ci --ignore-scripts +COPY jira_ui/server/ ./ +RUN ./scripts/prune_node_modules.sh + +# ── Stage 3: Runtime ───────────────────────────────────────────────── +FROM python:3.12.11-slim + +LABEL org.opencontainers.image.authors="Hystax" + +# uv (Python project manager) +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +# Node.js runtime (for ngui + jira_ui servers) +COPY --from=node:22.16.0-slim /usr/local/bin/node /usr/local/bin/node +COPY --from=node:22.16.0-slim /usr/local/lib/node_modules /usr/local/lib/node_modules +RUN ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm + +# System packages — union of per-service Dockerfiles +RUN apt-get update && apt-get install -y --no-install-recommends \ + libsodium-dev \ + sendmail \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Directories expected by specific services +RUN mkdir -p /src/archive + +WORKDIR /usr/src/app/ +ENV PYTHONPATH=/usr/src/app/ + +# ── Copy source tree (shared libs first, then services) ────────────── +COPY tools/ tools/ +COPY optscale_client/ optscale_client/ + +COPY rest_api/ rest_api/ +COPY auth/ auth/ +COPY keeper/ keeper/ +COPY herald/ herald/ +COPY katara/ katara/ +COPY insider/ insider/ +COPY slacker/ slacker/ +COPY jira_bus/ jira_bus/ +COPY metroculus/ metroculus/ +COPY diproxy/ diproxy/ +COPY subspector/ subspector/ +COPY diworker/ diworker/ +COPY bumiworker/ bumiworker/ +COPY bumischeduler/ bumischeduler/ +COPY trapper/ trapper/ +COPY risp/ risp/ +COPY gemini/ gemini/ +COPY bi_exporter/ bi_exporter/ + +COPY docker_images/configurator/ docker_images/configurator/ +COPY docker_images/resource_discovery/ docker_images/resource_discovery/ +COPY docker_images/resource_observer/ docker_images/resource_observer/ +COPY docker_images/resource_violations/ docker_images/resource_violations/ +COPY docker_images/booking_observer/ docker_images/booking_observer/ +COPY docker_images/calendar_observer/ docker_images/calendar_observer/ +COPY docker_images/organization_violations/ docker_images/organization_violations/ +COPY docker_images/power_schedule/ docker_images/power_schedule/ +COPY docker_images/live_demo_generator/ docker_images/live_demo_generator/ +COPY docker_images/webhook_executor/ docker_images/webhook_executor/ +COPY docker_images/herald_executor/ docker_images/herald_executor/ +COPY docker_images/slacker_executor/ docker_images/slacker_executor/ +COPY docker_images/keeper_executor/ docker_images/keeper_executor/ +COPY docker_images/bi_scheduler/ docker_images/bi_scheduler/ +COPY docker_images/cleanmongodb/ docker_images/cleanmongodb/ +COPY docker_images/cleaninfluxdb/ docker_images/cleaninfluxdb/ +COPY docker_images/layout_cleaner/ docker_images/layout_cleaner/ +COPY docker_images/demo_org_cleanup/ docker_images/demo_org_cleanup/ +COPY docker_images/failed_imports_dataset_generator/ docker_images/failed_imports_dataset_generator/ +COPY docker_images/users_dataset_generator/ docker_images/users_dataset_generator/ +COPY docker_images/subsyncer/ docker_images/subsyncer/ +COPY docker_images/bailiff/ docker_images/bailiff/ + +# ── Install uv-managed project dependencies ────────────────────────── +RUN uv --project rest_api sync --locked --no-dev && \ + uv --project auth sync --locked --no-dev && \ + uv --project keeper sync --locked --no-dev && \ + uv --project herald sync --locked --no-dev && \ + uv --project katara/katara_service sync --locked --no-dev && \ + uv --project katara/katara_worker sync --locked --no-dev && \ + uv --project insider/insider_api sync --locked --no-dev && \ + uv --project insider/insider_worker sync --locked --no-dev && \ + uv --project insider/insider_scheduler sync --locked --no-dev && \ + uv --project slacker sync --locked --no-dev && \ + uv --project jira_bus sync --locked --no-dev && \ + uv --project metroculus/metroculus_api sync --locked --no-dev && \ + uv --project metroculus/metroculus_worker sync --locked --no-dev && \ + uv --project metroculus/metroculus_scheduler sync --locked --no-dev && \ + uv --project diproxy sync --locked --no-dev && \ + uv --project subspector sync --locked --no-dev && \ + uv --project diworker sync --locked --no-dev && \ + uv --project bumiworker sync --locked --no-dev && \ + uv --project bumischeduler sync --locked --no-dev && \ + uv --project trapper/trapper_worker sync --locked --no-dev && \ + uv --project trapper/trapper_scheduler sync --locked --no-dev && \ + uv --project risp/risp_worker sync --locked --no-dev && \ + uv --project risp/risp_scheduler sync --locked --no-dev && \ + uv --project gemini/gemini_worker sync --locked --no-dev && \ + uv --project gemini/gemini_data_worker sync --locked --no-dev && \ + uv --project gemini/gemini_scheduler sync --locked --no-dev && \ + uv --project bi_exporter sync --locked --no-dev + +# Build-time code generation +RUN uv --project rest_api run python -u rest_api/rest_api_server/write_spec.py && \ + uv --project auth run python -u auth/auth_server/write_spec.py && \ + uv --project slacker run python -u slacker/slacker_server/write_spec.py + +# ── Install pip-managed dependencies (docker_images/* services) ────── +# Split into two passes to resolve the influxdb version conflict: +# configurator pins influxdb==4.1.1, cleaninfluxdb pins influxdb==5.2.3. +# Install cleaninfluxdb last so the newer (backward-compatible) version wins. +RUN pip install --no-cache-dir \ + -r docker_images/configurator/requirements.txt \ + -r docker_images/resource_discovery/requirements.txt \ + -r docker_images/resource_observer/requirements.txt \ + -r docker_images/resource_violations/requirements.txt \ + -r docker_images/booking_observer/requirements.txt \ + -r docker_images/calendar_observer/requirements.txt \ + -r docker_images/organization_violations/requirements.txt \ + -r docker_images/power_schedule/requirements.txt \ + -r docker_images/live_demo_generator/requirements.txt \ + -r docker_images/webhook_executor/requirements.txt \ + -r docker_images/herald_executor/requirements.txt \ + -r docker_images/slacker_executor/requirements.txt \ + -r docker_images/keeper_executor/requirements.txt \ + -r docker_images/bi_scheduler/requirements.txt \ + -r docker_images/cleanmongodb/requirements.txt \ + -r docker_images/layout_cleaner/requirements.txt \ + -r docker_images/demo_org_cleanup/requirements.txt \ + -r docker_images/failed_imports_dataset_generator/requirements.txt \ + -r docker_images/users_dataset_generator/requirements.txt \ + -r docker_images/subsyncer/requirements.txt \ + -r docker_images/bailiff/requirements.txt && \ + pip install --no-cache-dir \ + -r docker_images/cleaninfluxdb/requirements.txt + +# ── Copy Node.js frontend build artifacts ──────────────────────────── +COPY --from=ngui-builder /build/prod/server/dist /opt/ngui/server/dist +COPY --from=ngui-builder /build/prod/server/node_modules /opt/ngui/server/node_modules +COPY --from=ngui-builder /build/ui/build /opt/ngui/ui/build +COPY --from=ngui-builder /build/prepare-and-run.sh /opt/ngui/prepare-and-run.sh + +COPY --from=jira-ui-builder /build/ui/ /opt/jira_ui/ui/ +COPY --from=jira-ui-builder /build/server /opt/jira_ui/server + +# ── Entrypoint ─────────────────────────────────────────────────────── +COPY docker_images/optscale_app/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker_images/optscale_app/entrypoint.sh b/docker_images/optscale_app/entrypoint.sh new file mode 100644 index 000000000..e5c4b7942 --- /dev/null +++ b/docker_images/optscale_app/entrypoint.sh @@ -0,0 +1,170 @@ +#!/bin/sh +set -e + +# If arguments are passed, exec them directly (passthrough mode). +# This allows compose services to override CMD for scheduler loops, etc. +if [ "$#" -gt 0 ]; then + exec "$@" +fi + +OPTSCALE_MODE="${OPTSCALE_MODE:-}" +if [ -z "$OPTSCALE_MODE" ]; then + echo "ERROR: OPTSCALE_MODE is not set and no command arguments provided." >&2 + echo "Set OPTSCALE_MODE or pass a command as arguments." >&2 + exit 1 +fi + +case "$OPTSCALE_MODE" in + + # ── API services ────────────────────────────────────────────────── + restapi) + exec uv --project rest_api run python -u rest_api/rest_api_server/server.py ;; + auth) + exec uv --project auth run python -u auth/auth_server/server.py ;; + keeper) + exec uv run --project keeper python -u keeper/report_server/server.py ;; + herald) + exec uv run --project herald python -u herald/run.py ;; + katara) + exec uv run --project katara/katara_service python -u katara/katara_service/main.py ;; + insider-api) + exec uv run --project insider/insider_api python -u insider/insider_api/server.py ;; + slacker) + exec uv run --project slacker python slacker/slacker_server/server.py ;; + jira-bus) + exec uv run --project jira_bus python jira_bus/jira_bus_server/server.py ;; + metroculusapi) + exec uv run --project metroculus/metroculus_api python -u metroculus/metroculus_api/server.py ;; + diproxy) + exec uv run --project diproxy python -u diproxy/diproxy/main.py ;; + subspector) + exec uv run --project subspector uvicorn subspector.subspector_server.server:make_app \ + --factory --host 0.0.0.0 --port 8800 ;; + + # ── Workers (uv-managed) ───────────────────────────────────────── + diworker) + exec uv run --project diworker python -u diworker/diworker/main.py ;; + katara-worker) + exec uv run --project katara/katara_worker python -u katara/katara_worker/main.py ;; + insider-worker) + exec uv run --project insider/insider_worker python -u insider/insider_worker/main.py ;; + metroculus-worker) + exec uv run --project metroculus/metroculus_worker python -u metroculus/metroculus_worker/main.py ;; + bumiworker) + exec uv run --project bumiworker python -u bumiworker/bumiworker/main.py ;; + trapper-worker) + exec uv run --project trapper/trapper_worker python -u trapper/trapper_worker/main.py ;; + risp-worker) + exec uv run --project risp/risp_worker python -u risp/risp_worker/worker.py ;; + gemini-worker) + exec uv run --project gemini/gemini_worker python -u gemini/gemini_worker/main.py ;; + gemini-data-worker) + exec uv run --project gemini/gemini_data_worker python -u gemini/gemini_data_worker/main.py ;; + bi-exporter) + exec uv run --project bi_exporter python -u bi_exporter/bumblebi/exporter/main.py ;; + + # ── Schedulers (uv-managed) ────────────────────────────────────── + bumischeduler) + exec uv run --project bumischeduler python -u bumischeduler/bumischeduler/main.py ;; + trapper-scheduler) + exec uv run --project trapper/trapper_scheduler python -u trapper/trapper_scheduler/main.py ;; + risp-scheduler) + exec uv run --project risp/risp_scheduler python -u risp/risp_scheduler/scheduler.py ;; + insider-scheduler) + exec uv run --project insider/insider_scheduler python -u insider/insider_scheduler/main.py ;; + metroculus-scheduler) + exec uv run --project metroculus/metroculus_scheduler python -u metroculus/metroculus_scheduler/main.py ;; + gemini-scheduler) + exec uv run --project gemini/gemini_scheduler python -u gemini/gemini_scheduler/main.py ;; + + # ── Configurator ───────────────────────────────────────────────── + configurator) + exec python docker_images/configurator/configurator.py /config/config ;; + + # ── Executors (pip-managed) ────────────────────────────────────── + webhook-executor) + exec python3 docker_images/webhook_executor/worker.py ;; + herald-executor) + exec python3 docker_images/herald_executor/worker.py ;; + slacker-executor) + exec python3 docker_images/slacker_executor/worker.py ;; + keeper-executor) + exec python3 docker_images/keeper_executor/worker.py ;; + + # ── Workers (pip-managed docker_images) ────────────────────────── + resource-discovery-worker) + exec python3 docker_images/resource_discovery/worker.py ;; + resource-observer-worker) + exec python3 docker_images/resource_observer/worker.py ;; + resource-violations-worker) + exec python3 docker_images/resource_violations/worker.py ;; + booking-observer-worker) + exec python3 docker_images/booking_observer/worker.py ;; + calendar-observer-worker) + exec python3 docker_images/calendar_observer/worker.py ;; + organization-violations-worker) + exec python3 docker_images/organization_violations/worker.py ;; + power-schedule-worker) + exec python3 docker_images/power_schedule/worker.py ;; + live-demo-generator-worker) + exec python3 docker_images/live_demo_generator/worker.py ;; + + # ── Schedulers (pip-managed docker_images) ─────────────────────── + resource-discovery-scheduler) + exec python3 docker_images/resource_discovery/scheduler.py ;; + resource-observer-scheduler) + exec python3 docker_images/resource_observer/scheduler.py ;; + resource-violations-scheduler) + exec python3 docker_images/resource_violations/scheduler.py ;; + booking-observer-scheduler) + exec python3 docker_images/booking_observer/scheduler.py ;; + calendar-observer-scheduler) + exec python3 docker_images/calendar_observer/scheduler.py ;; + organization-violations-scheduler) + exec python3 docker_images/organization_violations/scheduler.py ;; + power-schedule-scheduler) + exec python3 docker_images/power_schedule/scheduler.py ;; + live-demo-generator-scheduler) + exec python3 docker_images/live_demo_generator/scheduler.py ;; + bi-scheduler) + exec python3 docker_images/bi_scheduler/scheduler.py ;; + + # ── Maintenance jobs (pip-managed) ─────────────────────────────── + cleanmongodb) + exec python docker_images/cleanmongodb/clean-mongo-db.py ;; + cleaninfluxdb) + exec python docker_images/cleaninfluxdb/clean-influx-db.py ;; + layout-cleaner) + exec python3 docker_images/layout_cleaner/worker.py ;; + demo-org-cleanup) + exec python3 docker_images/demo_org_cleanup/cleanup.py ;; + failed-imports-dataset-generator) + exec python docker_images/failed_imports_dataset_generator/failed_imports_dataset_generator.py ;; + users-dataset-generator) + exec python3 docker_images/users_dataset_generator/users_dataset_generator.py ;; + + # ── Node.js frontends ──────────────────────────────────────────── + ngui) + NGUI_DIR="/opt/ngui" + { + echo "window.optscale = window.optscale || {};" + env | grep '^VITE' 2>/dev/null | while IFS='=' read -r key val; do + echo "window.optscale.${key}='${val}';" + done || true + } > "${NGUI_DIR}/ui/build/config.js" + timestamp=$(date +%s) + sed -i "s/\${buildVersion}/${timestamp}/" "${NGUI_DIR}/ui/build/index.html" + cd "${NGUI_DIR}/server/dist" + exec node server.js + ;; + jira-ui) + cd /opt/jira_ui/server + exec npm start + ;; + + *) + echo "ERROR: Unknown OPTSCALE_MODE='${OPTSCALE_MODE}'" >&2 + echo "Run with --help or check docker_images/optscale_app/entrypoint.sh for valid modes." >&2 + exit 1 + ;; +esac diff --git a/gemini/gemini_worker/duplicate_object_finder/aws/main.py b/gemini/gemini_worker/duplicate_object_finder/aws/main.py index 510560b9a..c4ac27249 100644 --- a/gemini/gemini_worker/duplicate_object_finder/aws/main.py +++ b/gemini/gemini_worker/duplicate_object_finder/aws/main.py @@ -41,6 +41,9 @@ def find_duplicates( }, ) + # sqlite cannot create intermediate directories; in k8s the directory is + # created by a volume mount, but in other deployments it may not exist + os.makedirs(CACHE_PATH, exist_ok=True) cache_filename = os.path.join(CACHE_PATH, f"{random_string()}.sqlite") LOG.info(f"Cache filename is {cache_filename}") cache = SqliteCache(cache_filename, stats) diff --git a/optscale-deploy/compose/.env.example b/optscale-deploy/compose/.env.example new file mode 100644 index 000000000..94edc2a9c --- /dev/null +++ b/optscale-deploy/compose/.env.example @@ -0,0 +1,60 @@ +# OptScale Docker Compose quickstart configuration +# Copy this file to .env and adjust as needed: +# cp .env.example .env + +# ── Image version ────────────────────────────────────────────── +# Use a git tag from https://github.com/hystax/optscale/releases +# or "local" if you built images yourself with build.sh. +OPTSCALE_VERSION=latest +COMPANY=hystax + +# ── Network ──────────────────────────────────────────────────── +# Port exposed on the Docker host for the edge proxy (HTTP). +EDGE_PORT=80 + +# ── MariaDB ──────────────────────────────────────────────────── +MARIADB_ROOT_PASSWORD=my-password-01 + +# ── MongoDB ──────────────────────────────────────────────────── +MONGO_ROOT_USER=root +MONGO_ROOT_PASSWORD=SecurePassword-01-02 + +# ── RabbitMQ ─────────────────────────────────────────────────── +RABBITMQ_USER=optscale +RABBITMQ_PASSWORD=secure-password-here +RABBITMQ_ERLANG_COOKIE=dWkhXehOApH1OHshvByfpfTf3Cd8wwkADei7mWd5JF + +# ── ClickHouse ───────────────────────────────────────────────── +CLICKHOUSE_PASSWORD=secure-password-1-clk + +# ── MinIO (S3-compatible object store for Thanos) ────────────── +MINIO_ACCESS_KEY=optscale-minio +MINIO_SECRET_KEY=secret_password + +# ── Cluster secret (shared between report-import-scheduler & restapi) ── +CLUSTER_SECRET=change-me-in-production + +# ══════════════════════════════════════════════════════════════════ +# Optional integrations — uncomment and fill in to enable. +# ══════════════════════════════════════════════════════════════════ + +# ── OAuth (social login) ─────────────────────────────────────── +# https://console.developers.google.com/ for Google OAuth client +# https://portal.azure.com/ for Microsoft OAuth client +#GOOGLE_OAUTH_CLIENT_ID= +#GOOGLE_OAUTH_CLIENT_SECRET= +#MICROSOFT_OAUTH_CLIENT_ID= + +# ── Slack integration ────────────────────────────────────────── +#SLACK_SIGNING_SECRET= +#SLACK_CLIENT_ID= +#SLACK_CLIENT_SECRET= + +# ── Google Maps (used in finops dashboards) ──────────────────── +#GOOGLE_MAP_API_KEY= + +# ── Email verification ───────────────────────────────────────── +# Disabled by default for quickstart (no SMTP needed to register). +# To enable, set disable_email_verification to "" in config.yml +# and configure the smtp section there. +# Current value in config.yml: disable_email_verification: True diff --git a/optscale-deploy/compose/README.md b/optscale-deploy/compose/README.md new file mode 100644 index 000000000..16e28219f --- /dev/null +++ b/optscale-deploy/compose/README.md @@ -0,0 +1,156 @@ +# OptScale Docker Compose Quickstart (Try Mode) + +Spin up a near-full OptScale instance on a single machine for evaluation and development. +This deployment is **not intended for production** — use the [Ansible/Kubernetes path](../../README.md#getting-started) for that. + +## Prerequisites + +| Requirement | Minimum | +|---|---| +| Docker Engine | 24+ | +| Docker Compose | v2.20+ (ships with Docker Desktop) | +| CPU | 8 cores | +| RAM | 16 GB (32 GB recommended) | +| Disk | 40 GB free | + +## Quick start + +```bash +cd optscale-deploy/compose + +# 1. Create your environment file +cp .env.example .env +# Edit .env if you want to change passwords or the image version. + +# 2. Pull images sequentially (avoids Docker Hub rate limits) +./pull.sh + +# 3. Start OptScale +docker compose up -d + +# 4. Wait for the configurator to finish bootstrapping (typically 1-2 minutes) +docker compose logs -f configurator + +# 5. Once configurator exits successfully, all services will start. +# Open http://localhost in your browser. +``` + +> **Docker Hub rate limits:** The stack has 60+ services. Running `docker compose up -d` +> directly pulls many images in parallel and can hit Docker Hub's anonymous/free-tier +> pull limits. Use `./pull.sh` beforehand to pull images one at a time. If you have a +> Docker Hub account, `docker login` first — authenticated users get higher limits. + +## How it works + +The Compose stack mirrors the Kubernetes Helm chart in three layers: + +1. **Data plane** — etcd, MariaDB, MongoDB, RabbitMQ, Redis, InfluxDB, ClickHouse, MinIO. +2. **Metrics / storage** — Thanos receive, store gateway, and query (backed by MinIO). +3. **Application** — all API services exposed by the Kubernetes Ingress (auth, restapi, keeper, herald, katara, insider, slacker, metroculus, jira-bus, jira-ui, diproxy, subspector, ngui) plus background workers, executors, and schedulers. +4. **Cron-style schedulers** — loop-wrapped equivalents of every Kubernetes CronJob (resource-discovery, resource-observer, resource-violations, booking-observer, calendar-observer, organization-violations, power-schedule, live-demo-generator, report-import, cleanmongodb, cleaninfluxdb, layout-cleaner, demo-org-cleanup, dataset generators, bi-scheduler, gemini-scheduler, insider-scheduler, metroculus-scheduler, trapper-scheduler, risp-scheduler). + +An **nginx** container acts as the edge proxy, reproducing the path-based routing from the Helm Ingress template (`/auth` → auth, `/restapi` → restapi, `/report` → keeper, etc.). + +A **configurator** one-shot container seeds etcd, creates MariaDB databases, sets up RabbitMQ queues, and provisions MinIO buckets — the same bootstrap the Helm `pre-configurator` Job performs. + +## Configuration + +All credentials and the image version are set in `.env`. The file `config.yml` holds the etcd bootstrap values (equivalent to the rendered Helm `_config.tpl`). If you change passwords in `.env`, update the matching values in `config.yml` as well. + +The `thanos_conf.yaml` file configures the Thanos object-store connection to MinIO. Update its credentials if you change the MinIO keys. + +## Stopping and cleaning up + +```bash +# Stop all containers (data volumes are preserved) +docker compose down + +# Stop and remove all data volumes (full reset) +docker compose down -v +``` + +## What is excluded + +The following components from the production Helm chart are intentionally omitted to keep resource usage manageable: + +- **ELK stack** (Elasticsearch, Logstash, Kibana, Filebeat) — same as running `runkube.py` without `--with-elk`. +- **OpenTelemetry / Tempo** — disabled to reduce moving parts. +- **Grafana** — monitoring dashboards are not required for evaluation. +- **Thanos compactor / web** — not required for the try-mode metrics path. +- **Stripe-gated services** (subsyncer, bailiff) — only relevant when `stripe.enabled` is `true`. + +## Cron-style schedulers + +Kubernetes CronJobs have no direct equivalent in Docker Compose. Each scheduler runs as a long-lived container with a `while true; do …; sleep N; done` loop, approximating the original cron cadence: + +| Service | Interval | Origin K8s schedule | +|---|---|---| +| resource-discovery-scheduler | 5 min | `*/5 * * * *` | +| resource-observer-scheduler | 5 min | `*/5 * * * *` | +| resource-violations-scheduler | 5 min | `*/5 * * * *` | +| booking-observer-scheduler | 1 min | `*/1 * * * *` | +| calendar-observer-scheduler | 1 h | `0 * * * *` | +| organization-violations-scheduler | 5 min | `*/5 * * * *` | +| power-schedule-scheduler | 5 min | `*/5 * * * *` | +| live-demo-generator-scheduler | 1 h | `0 * * * *` | +| report-import-scheduler-{0,1,6,24} | 15 min / 1 h / 6 h / 24 h | varies | +| trapper-scheduler | 1 h | `45 */1 * * *` | +| risp-scheduler | 1 h | `45 */1 * * *` | +| insider-scheduler | 24 h | `0 0 * * *` | +| metroculus-scheduler | 30 min | `*/30 * * * *` | +| gemini-scheduler | 5 min | `*/5 * * * *` | +| bi-scheduler | 5 min | `*/5 * * * *` | +| bumischeduler | built-in | (image has its own loop) | +| cleanmongodb | 3 min | `*/3 * * * *` | +| cleaninfluxdb | weekly | `@weekly` | +| layout-cleaner | 24 h | `0 3 * * *` | +| demo-org-cleanup | 24 h | `0 0 * * *` | +| failed-imports-dataset-generator | 24 h | `0 0 * * *` | +| users-dataset-generator | 24 h | `0 0 * * *` | + +## Unified image mode + +The default `docker-compose.yml` pulls a separate image for each OptScale service (~40 application images). For environments where this is impractical (Docker Hub rate limits, air-gapped registries, or simply faster deploys), an alternative compose file runs every first-party service from a single `optscale_app` image. + +Data-plane images (etcd, MariaDB, Mongo, Redis, InfluxDB) are built locally by `build-unified.sh`. Upstream images (RabbitMQ, ClickHouse, MinIO, Thanos, nginx, curl) are still pulled separately. + +### Building the unified image + +```bash +cd optscale-deploy/compose + +# Build from the repository root (takes a while on first run). +# Defaults match COMPANY and OPTSCALE_VERSION from .env. +./build-unified.sh # -> hystax/optscale_app:latest, hystax/mongo:latest, etc. +./build-unified.sh latest # -> hystax/optscale_app:latest, etc. +./build-unified.sh v1.0 hystax # -> hystax/optscale_app:v1.0, etc. +``` + +### Running with the unified image + +```bash +# Make sure .env exists (same file as the default stack) +cp .env.example .env + +# Start the unified stack +docker compose -f docker-compose.unified.yml up -d +``` + +Each service container sets `OPTSCALE_MODE` to select which process runs inside the shared image. For scheduler services that need a `while true; sleep N` loop, the compose file passes the loop as `command:` args, which the entrypoint executes directly. + +### When to use which + +| | Default (`docker-compose.yml`) | Unified (`docker-compose.unified.yml`) | +|---|---|---| +| **Image pulls** | ~40 app images + data plane | 1 app image + data plane | +| **Build time** | Fast per-service rebuilds | Single long build | +| **Image size** | Small per image | One large image (~2-4 GB) | +| **Best for** | Development, CI per-service | Evaluation, air-gapped, quickstart | + +## Troubleshooting + +**Configurator fails or restarts**: check that all datastore containers are healthy first (`docker compose ps`). The configurator retries automatically, but persistent failures usually indicate a MariaDB or RabbitMQ connectivity issue. + +**Services report etcd connection errors**: the configurator must finish before app services can start. If you see these errors, wait for `docker compose logs configurator` to show `Configuration completed.` + +**Port 80 is already in use**: change `EDGE_PORT` in `.env` to another port (e.g. `8080`), then access OptScale at `http://localhost:8080`. diff --git a/optscale-deploy/compose/build-unified.sh b/optscale-deploy/compose/build-unified.sh new file mode 100755 index 000000000..b31d7d80d --- /dev/null +++ b/optscale-deploy/compose/build-unified.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build the unified OptScale application image and first-party data-plane images +# from the repository root. +# +# Usage: +# ./build-unified.sh # tags using .env/default compose values +# ./build-unified.sh latest # tags as hystax/optscale_app:latest, etc. +# ./build-unified.sh v1.0 hystax # tags as hystax/optscale_app:v1.0, etc. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +ENV_FILE="${SCRIPT_DIR}/.env" + +env_value() { + local name="$1" + local default="$2" + + if [[ -f "$ENV_FILE" ]]; then + local value + value="$(awk -F= -v name="$name" '$1 == name { value = substr($0, length(name) + 2) } END { if (value != "") printf "%s", value }' "$ENV_FILE")" + if [[ -n "$value" ]]; then + printf "%s" "$value" + return + fi + fi + + printf "%s" "$default" +} + +TAG="${1:-$(env_value "OPTSCALE_VERSION" "latest")}" +COMPANY="${2:-$(env_value "COMPANY" "hystax")}" +FLAGS="" + +if [[ "${NO_CACHE:-}" == "true" ]]; then + FLAGS="--no-cache" +fi + +build_image() { + local image_name="$1" + local dockerfile="$2" + local full_tag + + if [[ -n "$COMPANY" ]]; then + full_tag="${COMPANY}/${image_name}:${TAG}" + else + full_tag="${image_name}:${TAG}" + fi + + echo "" + echo "Building ${image_name}: ${full_tag}" + docker build \ + $FLAGS \ + -f "${REPO_ROOT}/${dockerfile}" \ + -t "${full_tag}" \ + "${REPO_ROOT}" +} + +echo "Build context: ${REPO_ROOT}" + +build_image "etcd" "docker_images/etcd/Dockerfile" +build_image "mariadb" "docker_images/mariadb/Dockerfile" +build_image "mongo" "docker_images/mongo/Dockerfile" +build_image "redis" "docker_images/redis/Dockerfile" +build_image "influxdb" "docker_images/influxdb/Dockerfile" +build_image "optscale_app" "docker_images/optscale_app/Dockerfile" + +echo "" +echo "Done. Built unified OptScale and first-party data-plane images." diff --git a/optscale-deploy/compose/config.yml b/optscale-deploy/compose/config.yml new file mode 100644 index 000000000..75686d768 --- /dev/null +++ b/optscale-deploy/compose/config.yml @@ -0,0 +1,280 @@ +# Rendered equivalent of the Helm _config.tpl for Docker Compose quickstart. +# Values mirror optscale-deploy/optscale/values.yaml defaults, with +# hostnames changed to Compose service names. + +skip_config_update: false +drop_tasks_db: false +databases: + - "auth-db" + - "my-db" + - "tasks" + - "herald" + - "katara" + - "slacker" + - "jira-bus" + - "subspector" + +etcd: + public_ip: "" + company_name: Hystax + product_name: OptScale + encryption_key: "" + release: compose + katara_scheduler_timeout: 3600 + bumi_scheduler_timeout: 300 + bumi_worker: + max_retries: 5 + wait_timeout: 7200 + task_timeout: 3600 + run_period: 10800 + optscale_service_emails: + recipient: "" + enabled: false + optscale_error_emails: + recipient: "" + enabled: false + # skip sending messages by template parameter value; must stay null + # so the configurator creates the /skip_email_filters etcd key that herald + # reads unconditionally on every email send. + # example: + # skip_email_filters: + # anomaly_detection_alert: + # texts.organization.name: ^aqa-(.*)$ + skip_email_filters: + google_calendar_service: + enabled: false + access_key: + type: "" + project_id: "" + private_key_id: "" + private_key: "" + client_email: "" + client_id: "" + auth_uri: "" + token_uri: "" + auth_provider_x509_cert_url: "" + client_x509_cert_url: "" + domains_blacklists: + new_employee_email: [] + registration: [] + failed_import_email: [] + domains_whitelists: + new_employee_email: [] + registration: [] + failed_import_email: [] + secret: + cluster: change-me-in-production + agent: "" + images_source: + host: "" + tag: "" + restapi: + invite_expiration_days: 30 + host: restapi + port: 8999 + demo: + multiplier: 2 + report_imports: + not_processed_threshold_secs: 10800 + message_expiration_secs: 10800 + auth: + host: auth + port: 8905 + katara: + host: katara + port: 8935 + herald: + host: herald-api + port: 8906 + keeper: + host: keeper + port: 8973 + insider: + host: insider-api + port: 8945 + slacker: + host: slacker + port: 80 + jirabus: + host: jira-bus + port: 8977 + metroculus: + host: metroculusapi + port: 8969 + thanos_query: + host: thanos-query + port: 10902 + thanos_receive: + host: thanos-receive + port: 19291 + path: api/v1/receive + authdb: + host: mariadb + user: root + password: my-password-01 + db: auth-db + heralddb: + host: mariadb + user: root + password: my-password-01 + db: herald + restdb: + host: mariadb + user: root + password: my-password-01 + db: my-db + port: 3306 + kataradb: + host: mariadb + user: root + password: my-password-01 + db: katara + slackerdb: + host: mariadb + user: root + password: my-password-01 + db: slacker + port: 3306 + jirabusdb: + host: mariadb + user: root + password: my-password-01 + db: jira-bus + port: 3306 + subspectordb: + host: mariadb + user: root + password: my-password-01 + db: subspector + port: 3306 + mongo: + url: mongodb://root:SecurePassword-01-02@mongo:27017 + database: keeper + influxdb: + host: influxdb + port: 8086 + user: "" + pass: "" + database: metrics + rabbit: + user: optscale + pass: secure-password-here + host: rabbitmq + port: 5672 + minio: + host: minio + port: 9000 + access: optscale-minio + secret: secret_password + clickhouse: + host: clickhouse + port: 8123 + user: default + password: secure-password-1-clk + db: default + cleanmongodb: + chunk_size: 500 + rows_limit: 10000 + archive_enable: "" + file_max_rows: 10000 + disable_email_verification: True + force_aws_edp_strip: "" + encryption_salt: "" + encryption_salt_auth: "" + certificates: {} + logstash_port: "" + events_queue: events_queue + resources_discovery_cache_time: "" + overlay_list: "" + token_expiration: 168 + users_dataset_generator: + enable: false + bucket: "" + s3_path: "" + filename: "" + aws_access_key_id: "" + aws_secret_access_key: "" + # Service credentials used by insider for cloud pricing information. + # Compose config is written to etcd from this file, so copy the same + # credential structure from optscale-deploy/overlay/user_template.yml here, + # but keep it nested under the top-level "etcd:" section. + # + # Example: + # service_credentials: + # aws: + # access_key_id: accesskeyid + # secret_access_key: secretaccesskey + # azure: + # client_id: clientid + # tenant: tenant + # secret: secret + # subscription_id: subscriptionid + # alibaba: + # access_key_id: accesskeyid + # secret_access_key: secretaccesskey + # gcp: + # credentials: + # # Service account with permissions for pricing export: + # # - bigquery.jobs.create + # # - bigquery.tables.getData + # # - compute.machineTypes.list + # type: service_account + # project_id: yourprojectid + # private_key_id: yourprivatekeyid + # private_key: | + # -----BEGIN PRIVATE KEY----- + # -----END PRIVATE KEY----- + # client_email: optscale-service-credentials@yourproject.iam.gserviceaccount.com + # client_id: "111111111" + # auth_uri: https://accounts.google.com/o/oauth2/auth + # token_uri: https://oauth2.googleapis.com/token + # auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs + # client_x509_cert_url: >- + # https://www.googleapis.com/robot/v1/metadata/x509/optscale-service-credentials%40yourproject.iam.gserviceaccount.com + # pricing_data: + # dataset_name: pricing_dataset + # table_name: cloud_pricing_export + # project_id: yourprojectid + service_credentials: {} + smtp: + server: "" + email: "" + login: "" + port: "" + password: "" + protocol: SSL + resource_discovery_settings: + discover_size: 10000 + timeout: "" + writing_timeout: 60 + observe_timeout: 7200 + debug: "" + bi_settings: + exporter_run_period: 86400 + encryption_key: 5t3X3PkQqF5edqW9_c8znow7k7GraZOpBLHhF1kFFvE= + task_wait_timeout: 259200 + failed_imports_dataset_generator: + enable: false + bucket: "" + s3_path: "" + filename: "" + aws_access_key_id: "" + aws_secret_access_key: "" + subspector: + host: subspector + port: 8800 + password_strength_settings: + min_length: "" + min_lowercase: "" + min_uppercase: "" + min_digits: "" + min_special_chars: "" + demo_org_cleanup: + demo_org_lifetime_hrs: "" + diworker: + max_report_imports_workers: 10 + exchange_rates: {} + stripe: + api_key: "" + webhook_secret: "" + enabled: false diff --git a/optscale-deploy/compose/docker-compose.unified.yml b/optscale-deploy/compose/docker-compose.unified.yml new file mode 100644 index 000000000..4cce9af9d --- /dev/null +++ b/optscale-deploy/compose/docker-compose.unified.yml @@ -0,0 +1,1133 @@ +# OptScale unified-image deployment. +# +# Instead of pulling ~40 separate application images, this variant runs every +# first-party service from a single "optscale_app" image, selected at runtime +# via the OPTSCALE_MODE environment variable. +# +# First-party data-plane images (etcd, MariaDB, Mongo, Redis, InfluxDB) remain +# separate but are built by build-unified.sh. Upstream images (RabbitMQ, +# ClickHouse, MinIO, Thanos, nginx, curl) are pulled separately. +# +# Build the unified app image and first-party data-plane images first: +# +# ./build-unified.sh +# +# Then start the stack: +# +# docker compose -f docker-compose.unified.yml up -d + +x-etcd-env: &etcd-env + HX_ETCD_HOST: etcd-client + HX_ETCD_PORT: "2379" + +x-restart: &restart + restart: unless-stopped + +x-healthcheck-tcp: &healthcheck-tcp + interval: 5s + timeout: 3s + retries: 30 + start_period: 15s + +x-optscale-app: &optscale-app + image: ${COMPANY:-hystax}/optscale_app:${OPTSCALE_VERSION:-latest} + +services: + # ───────────────────── Data plane ───────────────────── + + etcd-client: + image: ${COMPANY:-hystax}/etcd:${OPTSCALE_VERSION:-latest} + <<: *restart + command: + - /usr/local/bin/etcd + - -listen-client-urls + - http://0.0.0.0:2379 + - -advertise-client-urls + - http://etcd-client:2379 + volumes: + - etcd-data:/default.etcd + environment: + ETCD_HEARTBEAT_INTERVAL: "500" + ETCD_ELECTION_TIMEOUT: "5000" + healthcheck: + test: ["CMD", "etcdctl", "--endpoints=http://127.0.0.1:2379", "cluster-health"] + <<: *healthcheck-tcp + + mariadb: + image: ${COMPANY:-hystax}/mariadb:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + MYSQL_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD} + volumes: + - mariadb-data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${MARIADB_ROOT_PASSWORD}"] + <<: *healthcheck-tcp + + mongo: + image: ${COMPANY:-hystax}/mongo:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD} + volumes: + - mongo-data:/data/db + command: ["mongod", "--auth", "--bind_ip_all"] + healthcheck: + test: ["CMD", "mongo", "-u", "${MONGO_ROOT_USER}", "-p", "${MONGO_ROOT_PASSWORD}", "--authenticationDatabase", "admin", "--quiet", "--eval", "db.adminCommand('ping').ok"] + <<: *healthcheck-tcp + + rabbitmq: + image: rabbitmq:4.1.4-management-alpine + <<: *restart + environment: + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD} + RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE} + volumes: + - rabbitmq-data:/var/lib/rabbitmq + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + <<: *healthcheck-tcp + + redis: + image: ${COMPANY:-hystax}/redis:${OPTSCALE_VERSION:-latest} + <<: *restart + healthcheck: + test: ["CMD", "redis-cli", "ping"] + <<: *healthcheck-tcp + + influxdb: + image: ${COMPANY:-hystax}/influxdb:${OPTSCALE_VERSION:-latest} + <<: *restart + volumes: + - influxdb-data:/var/lib/influxdb + healthcheck: + test: ["CMD", "influx", "-execute", "SHOW DATABASES"] + <<: *healthcheck-tcp + + clickhouse: + image: clickhouse/clickhouse-server:24.12 + <<: *restart + environment: + CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: "1" + CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD} + volumes: + - clickhouse-data:/var/lib/clickhouse + healthcheck: + test: ["CMD-SHELL", "clickhouse-client --password '${CLICKHOUSE_PASSWORD}' -q 'SELECT 1'"] + <<: *healthcheck-tcp + + minio: + image: minio/minio:RELEASE.2020-03-19T21-49-00Z + <<: *restart + environment: + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + command: server /data + volumes: + - minio-data:/data + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"] + <<: *healthcheck-tcp + + # ───────────────────── Thanos metrics ───────────────────── + + thanos-receive: + image: thanosio/thanos:v0.39.1 + <<: *restart + user: "0" + command: + - receive + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --remote-write.address=0.0.0.0:19291 + - --objstore.config-file=/etc/thanos/thanos_conf.yaml + - --tsdb.path=/var/thanos/receive + - --tsdb.retention=4h + - --label=receive_replica="0" + volumes: + - thanos-receive-data:/var/thanos/receive + - ./thanos_conf.yaml:/etc/thanos/thanos_conf.yaml:ro + depends_on: + minio: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + thanos-storegateway: + image: thanosio/thanos:v0.39.1 + <<: *restart + user: "0" + command: + - store + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --data-dir=/var/thanos/store + - --objstore.config-file=/etc/thanos/thanos_conf.yaml + - --ignore-deletion-marks-delay=3h + volumes: + - thanos-store-data:/var/thanos/store + - ./thanos_conf.yaml:/etc/thanos/thanos_conf.yaml:ro + depends_on: + minio: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + thanos-query: + image: thanosio/thanos:v0.39.1 + <<: *restart + command: + - query + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --endpoint=thanos-receive:10901 + - --endpoint=thanos-storegateway:10901 + depends_on: + thanos-receive: + condition: service_healthy + thanos-storegateway: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + # ───────────────────── Bootstrap ───────────────────── + + configurator: + <<: *optscale-app + environment: + <<: *etcd-env + OPTSCALE_MODE: configurator + command: + - sh + - -c + - | + python - <<'PY' + import os + import etcd + from optscale_client.config_client.client import Client + + client = Client( + host=os.environ["HX_ETCD_HOST"], + port=int(os.environ["HX_ETCD_PORT"]), + ) + for key in ( + "/opentelemetry", + "/auth/opentelemetry", + "/restapi/opentelemetry", + "/diworker/opentelemetry", + ): + try: + client.delete(key, recursive=True) + except etcd.EtcdKeyNotFound: + pass + PY + python docker_images/configurator/configurator.py /config/config + python - <<'PY' + import os + from optscale_client.config_client.client import Client + + client = Client( + host=os.environ["HX_ETCD_HOST"], + port=int(os.environ["HX_ETCD_PORT"]), + ) + client.write_branch("/", { + "opentelemetry": { + "enabled": "false", + "exporter": { + "type": "console", + }, + }, + "auth": { + "opentelemetry": { + "enable_asyncio": "false", + "enable_threading": "false", + "enable_tornado": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_sqlalchemy": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + "restapi": { + "opentelemetry": { + "enable_asyncio": "false", + "enable_threading": "false", + "enable_tornado": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_sqlalchemy": "false", + "enable_mongo": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + "diworker": { + "opentelemetry": { + "enable_threading": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + }) + PY + volumes: + - ./config.yml:/config/config:ro + depends_on: + etcd-client: + condition: service_healthy + mariadb: + condition: service_healthy + mongo: + condition: service_healthy + rabbitmq: + condition: service_healthy + influxdb: + condition: service_healthy + minio: + condition: service_healthy + restart: "no" + + # ───────────────────── App services ───────────────────── + + restapi: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: restapi + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + herald-api: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "python - <<'PY'\nimport urllib.error\nimport urllib.request\ntry:\n urllib.request.urlopen('http://127.0.0.1:8999/restapi/v2/live_demo', timeout=2)\nexcept urllib.error.HTTPError as exc:\n raise SystemExit(0 if exc.code < 500 else 1)\nexcept Exception:\n raise SystemExit(1)\nPY"] + <<: *healthcheck-tcp + + auth: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: auth + OTEL_ENABLED: "false" + GOOGLE_OAUTH_CLIENT_ID: ${GOOGLE_OAUTH_CLIENT_ID:-} + GOOGLE_OAUTH_CLIENT_SECRET: ${GOOGLE_OAUTH_CLIENT_SECRET:-} + MICROSOFT_OAUTH_CLIENT_ID: ${MICROSOFT_OAUTH_CLIENT_ID:-} + depends_on: + configurator: + condition: service_completed_successfully + + keeper: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: keeper + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + herald-api: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: herald + HERALD_SERVICE: api + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "python - <<'PY'\nimport urllib.error\nimport urllib.request\ntry:\n urllib.request.urlopen('http://127.0.0.1:8906/', timeout=2)\nexcept urllib.error.HTTPError as exc:\n raise SystemExit(0 if exc.code < 500 else 1)\nexcept Exception:\n raise SystemExit(1)\nPY"] + <<: *healthcheck-tcp + + herald-engine: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: herald + HERALD_SERVICE: engine + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + + katara: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: katara + HX_KATARA_ROLE: api + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + insider-api: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: insider-api + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + slacker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: slacker + OTEL_ENABLED: "false" + SLACK_SIGNING_SECRET: ${SLACK_SIGNING_SECRET:-} + SLACK_CLIENT_ID: ${SLACK_CLIENT_ID:-} + SLACK_CLIENT_SECRET: ${SLACK_CLIENT_SECRET:-} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + auth: + condition: service_started + + jira-bus: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: jira-bus + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + auth: + condition: service_started + + jira-ui: + <<: [*optscale-app, *restart] + environment: + OPTSCALE_MODE: jira-ui + UI_BUILD_PATH: /opt/jira_ui/ui + depends_on: + configurator: + condition: service_completed_successfully + jira-bus: + condition: service_started + + metroculusapi: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: metroculusapi + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + clickhouse: + condition: service_healthy + + diproxy: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: diproxy + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + thanos-receive: + condition: service_healthy + + subspector: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: subspector + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + # ───────────────────── UI ───────────────────── + + ngui: + <<: [*optscale-app, *restart] + environment: + OPTSCALE_MODE: ngui + UI_BUILD_PATH: /opt/ngui/ui + PROXY_URL: http://edge:80 + KEEPER_ENDPOINT: http://keeper:8973 + SLACKER_ENDPOINT: http://slacker:80 + RESTAPI_ENDPOINT: http://restapi:8999 + AUTH_ENDPOINT: http://auth:8905 + VITE_GOOGLE_OAUTH_CLIENT_ID: ${GOOGLE_OAUTH_CLIENT_ID:-} + VITE_MICROSOFT_OAUTH_CLIENT_ID: ${MICROSOFT_OAUTH_CLIENT_ID:-} + VITE_GOOGLE_MAP_API_KEY: ${GOOGLE_MAP_API_KEY:-} + depends_on: + restapi: + condition: service_healthy + auth: + condition: service_started + keeper: + condition: service_started + slacker: + condition: service_started + redis: + condition: service_healthy + herald-api: + condition: service_healthy + jira-bus: + condition: service_started + healthcheck: + test: ["CMD-SHELL", "node -e \"require('http').get('http://127.0.0.1:4000/', r => process.exit(r.statusCode < 500 ? 0 : 1)).on('error', () => process.exit(1))\""] + <<: *healthcheck-tcp + + # ───────────────────── Edge proxy (replaces k8s Ingress) ───────────────────── + + edge: + image: nginx:1.27-alpine + <<: *restart + ports: + - "${EDGE_PORT:-80}:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + depends_on: + ngui: + condition: service_healthy + restapi: + condition: service_healthy + auth: + condition: service_started + keeper: + condition: service_started + herald-api: + condition: service_started + katara: + condition: service_started + insider-api: + condition: service_started + slacker: + condition: service_started + metroculusapi: + condition: service_started + jira-bus: + condition: service_started + jira-ui: + condition: service_started + diproxy: + condition: service_started + subspector: + condition: service_started + + # ───────────────────── Workers (long-running) ───────────────────── + + diworker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: diworker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "test -f /tmp/diworker-migrations-ready"] + <<: *healthcheck-tcp + + katara-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: katara-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + katara: + condition: service_started + + insider-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: insider-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + metroculus-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: metroculus-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + bumiworker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: bumiworker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + trapper-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: trapper-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + risp-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: risp-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + gemini-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: gemini-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + gemini-data-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: gemini-data-worker + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + bi-exporter: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: bi-exporter + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + resource-discovery-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: resource-discovery-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + resource-observer-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: resource-observer-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + resource-violations-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: resource-violations-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + booking-observer-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: booking-observer-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + calendar-observer-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: calendar-observer-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + organization-violations-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: organization-violations-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + power-schedule-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: power-schedule-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + live-demo-generator-worker: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: live-demo-generator-worker + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + diworker: + condition: service_healthy + + # ───────────────────── Executors ───────────────────── + + webhook-executor: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: webhook-executor + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + herald-executor: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: herald-executor + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + slacker-executor: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: slacker-executor + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + slacker: + condition: service_started + + keeper-executor: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: keeper-executor + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + # ───────────────────── Schedulers (cron-style, loop-wrapped) ──── + # K8s runs these as CronJobs. In Compose we loop: run -> sleep -> repeat. + # The entrypoint passthrough (command overrides CMD) handles the wrapping. + + bumischeduler: + <<: [*optscale-app, *restart] + environment: + <<: *etcd-env + OPTSCALE_MODE: bumischeduler + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-discovery-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/resource_discovery/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-observer-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/resource_observer/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-violations-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/resource_violations/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 1 min + booking-observer-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/booking_observer/scheduler.py; sleep 60; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + calendar-observer-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/calendar_observer/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + organization-violations-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/organization_violations/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + power-schedule-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/power_schedule/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + live-demo-generator-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/live_demo_generator/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + diworker: + condition: service_healthy + + # every hour + trapper-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do uv run --project trapper/trapper_scheduler python -u /usr/src/app/trapper/trapper_scheduler/main.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + risp-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do uv run --project risp/risp_scheduler python -u /usr/src/app/risp/risp_scheduler/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + insider-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do uv run --project insider/insider_scheduler python -u /usr/src/app/insider/insider_scheduler/main.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 30 min + metroculus-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do uv run --project metroculus/metroculus_scheduler python -u /usr/src/app/metroculus/metroculus_scheduler/main.py; sleep 1800; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + gemini-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do uv run --project gemini/gemini_scheduler python -u /usr/src/app/gemini/gemini_scheduler/main.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + bi-scheduler: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/bi_scheduler/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # ───────────────────── Report-import schedulers (curl-based) ───────── + + # every 15 min — period 0 + report-import-scheduler-0: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 0}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 900; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour — period 1 + report-import-scheduler-1: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 1}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 3600; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 6 hours — period 6 + report-import-scheduler-6: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 6}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 21600; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily — period 24 + report-import-scheduler-24: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 24}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 86400; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # ───────────────────── Maintenance jobs (cron-style, loop-wrapped) ──── + + # every 3 min + cleanmongodb: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python docker_images/cleanmongodb/clean-mongo-db.py; sleep 180; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # weekly + cleaninfluxdb: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python docker_images/cleaninfluxdb/clean-influx-db.py; sleep 604800; done"] + environment: + HX_INFLUXDB_HOST: influxdb + HX_INFLUXDB_PORT: "8086" + HX_DAYS_TO_STORE: "90" + depends_on: + influxdb: + condition: service_healthy + restapi: + condition: service_healthy + + # daily + layout-cleaner: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/layout_cleaner/worker.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + demo-org-cleanup: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/demo_org_cleanup/cleanup.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + failed-imports-dataset-generator: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python docker_images/failed_imports_dataset_generator/failed_imports_dataset_generator.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + users-dataset-generator: + <<: [*optscale-app, *restart] + command: ["sh", "-c", "while true; do python3 docker_images/users_dataset_generator/users_dataset_generator.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + +volumes: + etcd-data: + mariadb-data: + mongo-data: + rabbitmq-data: + influxdb-data: + clickhouse-data: + minio-data: + thanos-receive-data: + thanos-store-data: diff --git a/optscale-deploy/compose/docker-compose.yml b/optscale-deploy/compose/docker-compose.yml new file mode 100644 index 000000000..d78d1365f --- /dev/null +++ b/optscale-deploy/compose/docker-compose.yml @@ -0,0 +1,1140 @@ +# OptScale quickstart / try-mode deployment +# Usage: +# cp .env.example .env # adjust if needed +# ./pull.sh # optional: pull images one-by-one (avoids Docker Hub rate limits) +# docker compose up -d +# +# NOT intended for production — use the Ansible/K8s path described in the +# root README for that. + +x-etcd-env: &etcd-env + HX_ETCD_HOST: etcd-client + HX_ETCD_PORT: "2379" + +x-restart: &restart + restart: unless-stopped + +x-healthcheck-tcp: &healthcheck-tcp + interval: 5s + timeout: 3s + retries: 30 + start_period: 15s + +services: + # ───────────────────── Data plane ───────────────────── + + etcd-client: + image: ${COMPANY:-hystax}/etcd:${OPTSCALE_VERSION:-latest} + <<: *restart + command: + - /usr/local/bin/etcd + - -listen-client-urls + - http://0.0.0.0:2379 + - -advertise-client-urls + - http://etcd-client:2379 + volumes: + - etcd-data:/default.etcd + environment: + ETCD_HEARTBEAT_INTERVAL: "500" + ETCD_ELECTION_TIMEOUT: "5000" + healthcheck: + test: ["CMD", "etcdctl", "--endpoints=http://127.0.0.1:2379", "cluster-health"] + <<: *healthcheck-tcp + + mariadb: + image: ${COMPANY:-hystax}/mariadb:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + MYSQL_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD} + volumes: + - mariadb-data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${MARIADB_ROOT_PASSWORD}"] + <<: *healthcheck-tcp + + mongo: + image: ${COMPANY:-hystax}/mongo:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD} + volumes: + - mongo-data:/data/db + command: ["mongod", "--auth", "--bind_ip_all"] + healthcheck: + test: ["CMD", "mongo", "-u", "${MONGO_ROOT_USER}", "-p", "${MONGO_ROOT_PASSWORD}", "--authenticationDatabase", "admin", "--quiet", "--eval", "db.adminCommand('ping').ok"] + <<: *healthcheck-tcp + + rabbitmq: + image: rabbitmq:4.1.4-management-alpine + <<: *restart + environment: + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD} + RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE} + volumes: + - rabbitmq-data:/var/lib/rabbitmq + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + <<: *healthcheck-tcp + + redis: + image: ${COMPANY:-hystax}/redis:${OPTSCALE_VERSION:-latest} + <<: *restart + healthcheck: + test: ["CMD", "redis-cli", "ping"] + <<: *healthcheck-tcp + + influxdb: + image: ${COMPANY:-hystax}/influxdb:${OPTSCALE_VERSION:-latest} + <<: *restart + volumes: + - influxdb-data:/var/lib/influxdb + healthcheck: + test: ["CMD", "influx", "-execute", "SHOW DATABASES"] + <<: *healthcheck-tcp + + clickhouse: + image: clickhouse/clickhouse-server:24.12 + <<: *restart + environment: + CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: "1" + CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD} + volumes: + - clickhouse-data:/var/lib/clickhouse + healthcheck: + test: ["CMD-SHELL", "clickhouse-client --password '${CLICKHOUSE_PASSWORD}' -q 'SELECT 1'"] + <<: *healthcheck-tcp + + minio: + image: minio/minio:RELEASE.2020-03-19T21-49-00Z + <<: *restart + environment: + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + command: server /data + volumes: + - minio-data:/data + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"] + <<: *healthcheck-tcp + + # ───────────────────── Thanos metrics ───────────────────── + + thanos-receive: + image: thanosio/thanos:v0.39.1 + <<: *restart + user: "0" + command: + - receive + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --remote-write.address=0.0.0.0:19291 + - --objstore.config-file=/etc/thanos/thanos_conf.yaml + - --tsdb.path=/var/thanos/receive + - --tsdb.retention=4h + - --label=receive_replica="0" + volumes: + - thanos-receive-data:/var/thanos/receive + - ./thanos_conf.yaml:/etc/thanos/thanos_conf.yaml:ro + depends_on: + minio: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + thanos-storegateway: + image: thanosio/thanos:v0.39.1 + <<: *restart + user: "0" + command: + - store + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --data-dir=/var/thanos/store + - --objstore.config-file=/etc/thanos/thanos_conf.yaml + - --ignore-deletion-marks-delay=3h + volumes: + - thanos-store-data:/var/thanos/store + - ./thanos_conf.yaml:/etc/thanos/thanos_conf.yaml:ro + depends_on: + minio: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + thanos-query: + image: thanosio/thanos:v0.39.1 + <<: *restart + command: + - query + - --grpc-address=0.0.0.0:10901 + - --http-address=0.0.0.0:10902 + - --endpoint=thanos-receive:10901 + - --endpoint=thanos-storegateway:10901 + depends_on: + thanos-receive: + condition: service_healthy + thanos-storegateway: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:10902/-/healthy || exit 1"] + <<: *healthcheck-tcp + + # ───────────────────── Bootstrap ───────────────────── + + configurator: + image: ${COMPANY:-hystax}/configurator:${OPTSCALE_VERSION:-latest} + environment: + <<: *etcd-env + command: + - sh + - -c + - | + python - <<'PY' + import os + import etcd + from optscale_client.config_client.client import Client + + client = Client( + host=os.environ["HX_ETCD_HOST"], + port=int(os.environ["HX_ETCD_PORT"]), + ) + for key in ( + "/opentelemetry", + "/auth/opentelemetry", + "/restapi/opentelemetry", + "/diworker/opentelemetry", + ): + try: + client.delete(key, recursive=True) + except etcd.EtcdKeyNotFound: + pass + PY + python docker_images/configurator/configurator.py /config/config + python - <<'PY' + import os + from optscale_client.config_client.client import Client + + client = Client( + host=os.environ["HX_ETCD_HOST"], + port=int(os.environ["HX_ETCD_PORT"]), + ) + client.write_branch("/", { + "opentelemetry": { + "enabled": "false", + "exporter": { + "type": "console", + }, + }, + "auth": { + "opentelemetry": { + "enable_asyncio": "false", + "enable_threading": "false", + "enable_tornado": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_sqlalchemy": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + "restapi": { + "opentelemetry": { + "enable_asyncio": "false", + "enable_threading": "false", + "enable_tornado": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_sqlalchemy": "false", + "enable_mongo": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + "diworker": { + "opentelemetry": { + "enable_threading": "false", + "enable_urllib3": "false", + "enable_requests": "false", + "enable_kombu": "false", + "enable_clickhouse": "false", + }, + }, + }) + PY + volumes: + - ./config.yml:/config/config:ro + depends_on: + etcd-client: + condition: service_healthy + mariadb: + condition: service_healthy + mongo: + condition: service_healthy + rabbitmq: + condition: service_healthy + influxdb: + condition: service_healthy + minio: + condition: service_healthy + restart: "no" + + # ───────────────────── App services ───────────────────── + + restapi: + image: ${COMPANY:-hystax}/rest_api:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + herald-api: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "python - <<'PY'\nimport urllib.error\nimport urllib.request\ntry:\n urllib.request.urlopen('http://127.0.0.1:8999/restapi/v2/live_demo', timeout=2)\nexcept urllib.error.HTTPError as exc:\n raise SystemExit(0 if exc.code < 500 else 1)\nexcept Exception:\n raise SystemExit(1)\nPY"] + <<: *healthcheck-tcp + + auth: + image: ${COMPANY:-hystax}/auth:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + GOOGLE_OAUTH_CLIENT_ID: ${GOOGLE_OAUTH_CLIENT_ID:-} + GOOGLE_OAUTH_CLIENT_SECRET: ${GOOGLE_OAUTH_CLIENT_SECRET:-} + MICROSOFT_OAUTH_CLIENT_ID: ${MICROSOFT_OAUTH_CLIENT_ID:-} + depends_on: + configurator: + condition: service_completed_successfully + + keeper: + image: ${COMPANY:-hystax}/keeper:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + herald-api: + image: ${COMPANY:-hystax}/herald:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + HERALD_SERVICE: api + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "python - <<'PY'\nimport urllib.error\nimport urllib.request\ntry:\n urllib.request.urlopen('http://127.0.0.1:8906/', timeout=2)\nexcept urllib.error.HTTPError as exc:\n raise SystemExit(0 if exc.code < 500 else 1)\nexcept Exception:\n raise SystemExit(1)\nPY"] + <<: *healthcheck-tcp + + herald-engine: + image: ${COMPANY:-hystax}/herald:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + HERALD_SERVICE: engine + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + rabbitmq: + condition: service_healthy + + katara: + image: ${COMPANY:-hystax}/katara_service:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + HX_KATARA_ROLE: api + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + insider-api: + image: ${COMPANY:-hystax}/insider_api:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + slacker: + image: ${COMPANY:-hystax}/slacker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + SLACK_SIGNING_SECRET: ${SLACK_SIGNING_SECRET:-} + SLACK_CLIENT_ID: ${SLACK_CLIENT_ID:-} + SLACK_CLIENT_SECRET: ${SLACK_CLIENT_SECRET:-} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + auth: + condition: service_started + + jira-bus: + image: ${COMPANY:-hystax}/jira_bus:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + auth: + condition: service_started + + jira-ui: + image: ${COMPANY:-hystax}/jira_ui:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + UI_BUILD_PATH: /usr/src/app/ui + depends_on: + configurator: + condition: service_completed_successfully + jira-bus: + condition: service_started + + metroculusapi: + image: ${COMPANY:-hystax}/metroculus_api:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + clickhouse: + condition: service_healthy + + diproxy: + image: ${COMPANY:-hystax}/diproxy:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + thanos-receive: + condition: service_healthy + + subspector: + image: ${COMPANY:-hystax}/subspector:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + # ───────────────────── UI ───────────────────── + + ngui: + image: ${COMPANY:-hystax}/ngui:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + UI_BUILD_PATH: /usr/src/app/ui + PROXY_URL: http://edge:80 + KEEPER_ENDPOINT: http://keeper:8973 + SLACKER_ENDPOINT: http://slacker:80 + RESTAPI_ENDPOINT: http://restapi:8999 + AUTH_ENDPOINT: http://auth:8905 + VITE_GOOGLE_OAUTH_CLIENT_ID: ${GOOGLE_OAUTH_CLIENT_ID:-} + VITE_MICROSOFT_OAUTH_CLIENT_ID: ${MICROSOFT_OAUTH_CLIENT_ID:-} + VITE_GOOGLE_MAP_API_KEY: ${GOOGLE_MAP_API_KEY:-} + depends_on: + restapi: + condition: service_healthy + auth: + condition: service_started + keeper: + condition: service_started + slacker: + condition: service_started + redis: + condition: service_healthy + herald-api: + condition: service_healthy + jira-bus: + condition: service_started + healthcheck: + test: ["CMD-SHELL", "node -e \"require('http').get('http://127.0.0.1:4000/', r => process.exit(r.statusCode < 500 ? 0 : 1)).on('error', () => process.exit(1))\""] + <<: *healthcheck-tcp + + # ───────────────────── Edge proxy (replaces k8s Ingress) ───────────────────── + + edge: + image: nginx:1.27-alpine + <<: *restart + ports: + - "${EDGE_PORT:-80}:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + depends_on: + ngui: + condition: service_healthy + restapi: + condition: service_healthy + auth: + condition: service_started + keeper: + condition: service_started + herald-api: + condition: service_started + katara: + condition: service_started + insider-api: + condition: service_started + slacker: + condition: service_started + metroculusapi: + condition: service_started + jira-bus: + condition: service_started + jira-ui: + condition: service_started + diproxy: + condition: service_started + subspector: + condition: service_started + + # ───────────────────── Workers (long-running) ───────────────────── + + diworker: + image: ${COMPANY:-hystax}/diworker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "test -f /tmp/diworker-migrations-ready"] + <<: *healthcheck-tcp + + katara-worker: + image: ${COMPANY:-hystax}/katara_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + katara: + condition: service_started + + insider-worker: + image: ${COMPANY:-hystax}/insider_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + metroculus-worker: + image: ${COMPANY:-hystax}/metroculus_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + bumiworker: + image: ${COMPANY:-hystax}/bumiworker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + trapper-worker: + image: ${COMPANY:-hystax}/trapper_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + risp-worker: + image: ${COMPANY:-hystax}/risp_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + gemini-worker: + image: ${COMPANY:-hystax}/gemini_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + gemini-data-worker: + image: ${COMPANY:-hystax}/gemini_data_worker:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + bi-exporter: + image: ${COMPANY:-hystax}/bi_exporter:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + + resource-discovery-worker: + image: ${COMPANY:-hystax}/resource_discovery:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + resource-observer-worker: + image: ${COMPANY:-hystax}/resource_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + resource-violations-worker: + image: ${COMPANY:-hystax}/resource_violations:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + booking-observer-worker: + image: ${COMPANY:-hystax}/booking_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + calendar-observer-worker: + image: ${COMPANY:-hystax}/calendar_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + organization-violations-worker: + image: ${COMPANY:-hystax}/organization_violations:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + power-schedule-worker: + image: ${COMPANY:-hystax}/power_schedule:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + live-demo-generator-worker: + image: ${COMPANY:-hystax}/live_demo_generator:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + diworker: + condition: service_healthy + + # ───────────────────── Executors ───────────────────── + + webhook-executor: + image: ${COMPANY:-hystax}/webhook_executor:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + herald-executor: + image: ${COMPANY:-hystax}/herald_executor:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + slacker-executor: + image: ${COMPANY:-hystax}/slacker_executor:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + slacker: + condition: service_started + + keeper-executor: + image: ${COMPANY:-hystax}/keeper_executor:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + + # ───────────────────── Schedulers (cron-style, loop-wrapped) ──── + # K8s runs these as CronJobs. In Compose we loop: run → sleep → repeat. + + bumischeduler: + image: ${COMPANY:-hystax}/bumischeduler:${OPTSCALE_VERSION:-latest} + <<: *restart + environment: + <<: *etcd-env + OTEL_ENABLED: "false" + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-discovery-scheduler: + image: ${COMPANY:-hystax}/resource_discovery:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/resource_discovery/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-observer-scheduler: + image: ${COMPANY:-hystax}/resource_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/resource_observer/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + resource-violations-scheduler: + image: ${COMPANY:-hystax}/resource_violations:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/resource_violations/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 1 min + booking-observer-scheduler: + image: ${COMPANY:-hystax}/booking_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/booking_observer/scheduler.py; sleep 60; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + calendar-observer-scheduler: + image: ${COMPANY:-hystax}/calendar_observer:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/calendar_observer/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + organization-violations-scheduler: + image: ${COMPANY:-hystax}/organization_violations:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/organization_violations/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + power-schedule-scheduler: + image: ${COMPANY:-hystax}/power_schedule:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/power_schedule/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + live-demo-generator-scheduler: + image: ${COMPANY:-hystax}/live_demo_generator:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/live_demo_generator/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + diworker: + condition: service_healthy + + # every hour — uses default CMD, wraps in loop + trapper-scheduler: + image: ${COMPANY:-hystax}/trapper_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do uv run --project trapper/trapper_scheduler python -u /usr/src/app/trapper/trapper_scheduler/main.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour + risp-scheduler: + image: ${COMPANY:-hystax}/risp_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do uv run --project risp/risp_scheduler python -u /usr/src/app/risp/risp_scheduler/scheduler.py; sleep 3600; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + insider-scheduler: + image: ${COMPANY:-hystax}/insider_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do uv run --project insider/insider_scheduler python -u /usr/src/app/insider/insider_scheduler/main.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 30 min + metroculus-scheduler: + image: ${COMPANY:-hystax}/metroculus_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do uv run --project metroculus/metroculus_scheduler python -u /usr/src/app/metroculus/metroculus_scheduler/main.py; sleep 1800; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + gemini-scheduler: + image: ${COMPANY:-hystax}/gemini_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do uv run --project gemini/gemini_scheduler python -u /usr/src/app/gemini/gemini_scheduler/main.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 5 min + bi-scheduler: + image: ${COMPANY:-hystax}/bi_scheduler:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/bi_scheduler/scheduler.py; sleep 300; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # ───────────────────── Report-import schedulers (curl-based) ───────── + # These hit the restapi to trigger data imports on different cadences. + + # every 15 min — period 0 (most frequent reconciliation) + report-import-scheduler-0: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 0}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 900; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every hour — period 1 + report-import-scheduler-1: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 1}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 3600; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # every 6 hours — period 6 + report-import-scheduler-6: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 6}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 21600; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily — period 24 + report-import-scheduler-24: + image: curlimages/curl:latest + <<: *restart + entrypoint: ["sh", "-c", "while true; do curl -sS -X POST -f -H 'Content-Type: application/json' -H \"Secret: $CLUSTER_SECRET\" -d '{\"period\": 24}' http://restapi:8999/restapi/v2/schedule_imports || true; sleep 86400; done"] + environment: + CLUSTER_SECRET: ${CLUSTER_SECRET:-change-me-in-production} + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # ───────────────────── Maintenance jobs (cron-style, loop-wrapped) ──── + + # every 3 min + cleanmongodb: + image: ${COMPANY:-hystax}/cleanmongodb:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python /src/clean-mongo-db.py; sleep 180; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # weekly + cleaninfluxdb: + image: ${COMPANY:-hystax}/cleaninfluxdb:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python /src/clean-influx-db.py; sleep 604800; done"] + environment: + HX_INFLUXDB_HOST: influxdb + HX_INFLUXDB_PORT: "8086" + HX_DAYS_TO_STORE: "90" + depends_on: + influxdb: + condition: service_healthy + restapi: + condition: service_healthy + + # daily at 03:00 — just runs daily in loop + layout-cleaner: + image: ${COMPANY:-hystax}/layout_cleaner:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/layout_cleaner/worker.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + demo-org-cleanup: + image: ${COMPANY:-hystax}/demo_org_cleanup:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/demo_org_cleanup/cleanup.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + failed-imports-dataset-generator: + image: ${COMPANY:-hystax}/failed_imports_dataset_generator:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python docker_images/failed_imports_dataset_generator/failed_imports_dataset_generator.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + + # daily + users-dataset-generator: + image: ${COMPANY:-hystax}/users_dataset_generator:${OPTSCALE_VERSION:-latest} + <<: *restart + entrypoint: ["sh", "-c", "while true; do python3 docker_images/users_dataset_generator/users_dataset_generator.py; sleep 86400; done"] + environment: + <<: *etcd-env + depends_on: + configurator: + condition: service_completed_successfully + restapi: + condition: service_healthy + clickhouse: + condition: service_healthy + +volumes: + etcd-data: + mariadb-data: + mongo-data: + rabbitmq-data: + influxdb-data: + clickhouse-data: + minio-data: + thanos-receive-data: + thanos-store-data: diff --git a/optscale-deploy/compose/nginx.conf b/optscale-deploy/compose/nginx.conf new file mode 100644 index 000000000..974c3faf1 --- /dev/null +++ b/optscale-deploy/compose/nginx.conf @@ -0,0 +1,83 @@ +worker_processes auto; + +events { + worker_connections 1024; +} + +http { + client_max_body_size 512m; + + proxy_read_timeout 600; + proxy_send_timeout 600; + proxy_connect_timeout 30; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection "keep-alive"; + + # Resolve Compose service names at request time so recreated containers + # do not leave nginx proxying to stale container IPs. + resolver 127.0.0.11 ipv6=off valid=10s; + + server { + listen 80; + + location /auth/ { + set $auth_upstream http://auth:8905; + proxy_pass $auth_upstream; + } + location /restapi/ { + set $restapi_upstream http://restapi:8999; + proxy_pass $restapi_upstream; + } + location /report/ { + set $keeper_upstream http://keeper:8973; + proxy_pass $keeper_upstream; + } + location /herald/ { + set $herald_upstream http://herald-api:8906; + proxy_pass $herald_upstream; + } + location /katara/ { + set $katara_upstream http://katara:8935; + proxy_pass $katara_upstream; + } + location /insider/ { + set $insider_upstream http://insider-api:8945; + proxy_pass $insider_upstream; + } + location /slacker/ { + set $slacker_upstream http://slacker:80; + proxy_pass $slacker_upstream; + } + location /metroculus/ { + set $metroculus_upstream http://metroculusapi:8969; + proxy_pass $metroculus_upstream; + } + location /jira_bus/ { + set $jirabus_upstream http://jira-bus:8977; + proxy_pass $jirabus_upstream; + } + location /jira_ui/ { + set $jiraui_upstream http://jira-ui:4000; + proxy_pass $jiraui_upstream; + } + location /storage/ { + set $diproxy_upstream http://diproxy:8935; + proxy_pass $diproxy_upstream; + } + location /subspector/ { + set $subspector_upstream http://subspector:8800; + proxy_pass $subspector_upstream; + } + location / { + set $ngui_upstream http://ngui:4000; + proxy_pass $ngui_upstream; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + } +} diff --git a/optscale-deploy/compose/pull.sh b/optscale-deploy/compose/pull.sh new file mode 100755 index 000000000..49c6eebb7 --- /dev/null +++ b/optscale-deploy/compose/pull.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Pull all Docker Compose images one at a time to avoid Docker Hub rate limits. +# Usage: +# ./pull.sh # pull all services sequentially +# ./pull.sh --parallel # fall back to default parallel pull + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +if [[ "${1:-}" == "--parallel" ]]; then + echo "Pulling all images in parallel..." + docker compose pull + exit 0 +fi + +SERVICES=$(docker compose config --services 2>/dev/null) +TOTAL=$(echo "$SERVICES" | wc -l | tr -d ' ') +CURRENT=0 + +echo "Pulling $TOTAL service images sequentially..." +for svc in $SERVICES; do + CURRENT=$((CURRENT + 1)) + IMAGE=$(docker compose config --format json 2>/dev/null \ + | python3 -c "import sys,json; print(json.load(sys.stdin)['services']['$svc']['image'])" 2>/dev/null || true) + echo "[$CURRENT/$TOTAL] $svc ($IMAGE)" + docker compose pull --quiet "$svc" 2>/dev/null || { + echo " Warning: pull failed for $svc — may use a locally built image" + } +done +echo "All images pulled." diff --git a/optscale-deploy/compose/thanos_conf.yaml b/optscale-deploy/compose/thanos_conf.yaml new file mode 100644 index 000000000..171a70932 --- /dev/null +++ b/optscale-deploy/compose/thanos_conf.yaml @@ -0,0 +1,7 @@ +type: S3 +config: + bucket: thanos + endpoint: "minio:9000" + access_key: "optscale-minio" + secret_key: "secret_password" + insecure: true diff --git a/optscale-deploy/tests/test_compose_deployment.py b/optscale-deploy/tests/test_compose_deployment.py new file mode 100644 index 000000000..784bd0219 --- /dev/null +++ b/optscale-deploy/tests/test_compose_deployment.py @@ -0,0 +1,330 @@ +# pyright: reportMissingImports=false +import os +import shutil +import subprocess +from pathlib import Path + +import pytest +import yaml +from yaml.composer import ComposerError +from yaml.events import AliasEvent + + +DEPLOY_DIR = Path(__file__).resolve().parents[1] +COMPOSE_DIR = DEPLOY_DIR / "compose" +COMPOSE_FILES = ( + COMPOSE_DIR / "docker-compose.yml", + COMPOSE_DIR / "docker-compose.unified.yml", +) +ENV_FILE = COMPOSE_DIR / ".env.example" +VALUES_FILE = DEPLOY_DIR / "optscale" / "values.yaml" +COMPONENTS_FILE = DEPLOY_DIR / "components.yaml" + +FIRST_PARTY_IMAGE_PREFIX = "${COMPANY:-hystax}/" +EXTERNAL_IMAGE_PREFIXES = ( + "clickhouse/", + "curlimages/", + "minio/", + "nginx:", + "rabbitmq:", + "thanosio/", +) + +# Compose has an edge proxy where k8s has an Ingress resource instead. +COMPOSE_ONLY_SERVICES = {"edge"} + +# These repositories are built by dedicated Dockerfiles, but are represented in +# Compose as upstream images or generated Helm resources rather than +# components.yaml entries. +FIRST_PARTY_REPOSITORY_EXCEPTIONS = {"optscale_app"} + + +class HelmValuesLoader(yaml.SafeLoader): + """PyYAML rejects duplicate anchors that Helm's YAML parser accepts.""" + + def compose_node(self, parent, index): + if self.check_event(AliasEvent): + event = self.get_event() + anchor = event.anchor + if anchor not in self.anchors: + raise ComposerError( + None, None, f"found undefined alias {anchor!r}", + event.start_mark + ) + return self.anchors[anchor] + event = self.peek_event() + anchor = event.anchor + self.descend_resolver(parent, index) + if self.check_event(yaml.events.ScalarEvent): + node = self.compose_scalar_node(anchor) + elif self.check_event(yaml.events.SequenceStartEvent): + node = self.compose_sequence_node(anchor) + elif self.check_event(yaml.events.MappingStartEvent): + node = self.compose_mapping_node(anchor) + self.ascend_resolver() + return node + + +def load_yaml(path): + with path.open() as f: + return yaml.load(f, Loader=HelmValuesLoader) + + +def load_compose(path): + data = load_yaml(path) + assert "services" in data + return data + + +def service_names(compose_file): + return set(load_compose(compose_file)["services"]) + + +@pytest.fixture(scope="module") +def values(): + return load_yaml(VALUES_FILE) + + +@pytest.fixture(scope="module") +def components(): + return set(load_yaml(COMPONENTS_FILE)) + + +def value_name(values, key): + return values[key]["name"] + + +def value_service_name(values, key): + return values[key]["service"]["name"] + + +def k8s_equivalent_names(values): + names = { + "auth": {value_service_name(values, "auth")}, + "bi-exporter": {value_name(values, "bi_exporter")}, + "bi-scheduler": {value_name(values, "bi_scheduler")}, + "booking-observer-worker": { + f"{value_name(values, 'booking_observer')}-worker" + }, + "booking-observer-scheduler": { + f"{value_name(values, 'booking_observer')}-scheduler" + }, + "bumischeduler": {value_name(values, "bumischeduler")}, + "bumiworker": {value_name(values, "bumiworker")}, + "calendar-observer-worker": { + f"{value_name(values, 'calendar_observer')}-worker" + }, + "calendar-observer-scheduler": { + f"{value_name(values, 'calendar_observer')}-scheduler" + }, + "clickhouse": {value_service_name(values, "clickhouse")}, + "cleaninfluxdb": {value_name(values, "cleaninfluxdb")}, + "cleanmongodb": {value_name(values, "cleanmongodb")}, + "configurator": {"pre-configurator"}, + "demo-org-cleanup": {value_name(values, "demo_org_cleanup")}, + "diproxy": {value_service_name(values, "diproxy")}, + "diworker": {value_name(values, "diworker")}, + "etcd-client": {value_service_name(values, "etcd")}, + "failed-imports-dataset-generator": { + value_name(values, "failed_imports_dataset_generator") + }, + "gemini-data-worker": {value_name(values, "gemini_data_worker")}, + "gemini-scheduler": {value_name(values, "gemini_scheduler")}, + "gemini-worker": {value_name(values, "gemini_worker")}, + "herald-api": { + f"{value_name(values, 'herald')}{values['herald']['api']['role']}", + value_service_name(values, "herald"), + }, + "herald-engine": { + f"{value_name(values, 'herald')}" + f"{values['herald']['engine']['role']}" + }, + "herald-executor": {value_name(values, "herald_executor")}, + "influxdb": {value_service_name(values, "influxdb")}, + "insider-api": {value_service_name(values, "insider_api")}, + "insider-scheduler": {value_name(values, "insider_scheduler")}, + "insider-worker": {value_name(values, "insider_worker")}, + "jira-bus": {value_service_name(values, "jira_bus")}, + "jira-ui": {value_service_name(values, "jira_ui")}, + "katara": { + f"{value_name(values, 'katara_service')}" + f"{values['katara_service']['api']['role']}", + value_service_name(values, "katara_service"), + }, + "katara-worker": {value_name(values, "katara_worker")}, + "keeper": {value_service_name(values, "keeper")}, + "keeper-executor": {value_name(values, "keeper_executor")}, + "layout-cleaner": {value_name(values, "layout_cleaner")}, + "live-demo-generator-worker": { + f"{value_name(values, 'live_demo_generator')}-worker" + }, + "live-demo-generator-scheduler": { + f"{value_name(values, 'live_demo_generator')}-scheduler" + }, + "mariadb": {value_service_name(values, "mariadb")}, + "metroculusapi": {value_service_name(values, "metroculus_api")}, + "metroculus-scheduler": {value_name(values, "metroculus_scheduler")}, + "metroculus-worker": {value_name(values, "metroculus_worker")}, + "minio": {value_service_name(values, "minio")}, + "mongo": {value_service_name(values, "mongo")}, + "ngui": {value_service_name(values, "ngui")}, + "organization-violations-worker": { + f"{value_name(values, 'organization_violations')}-worker" + }, + "organization-violations-scheduler": { + f"{value_name(values, 'organization_violations')}-scheduler" + }, + "power-schedule-worker": { + f"{value_name(values, 'power_schedule')}-worker" + }, + "power-schedule-scheduler": { + f"{value_name(values, 'power_schedule')}-scheduler" + }, + "rabbitmq": {value_service_name(values, "rabbitmq")}, + "redis": {value_service_name(values, "redis")}, + "report-import-scheduler-0": { + f"{value_name(values, 'report_import_scheduler')}-0" + }, + "report-import-scheduler-1": { + f"{value_name(values, 'report_import_scheduler')}-1" + }, + "report-import-scheduler-6": { + f"{value_name(values, 'report_import_scheduler')}-6" + }, + "report-import-scheduler-24": { + f"{value_name(values, 'report_import_scheduler')}-24" + }, + "resource-discovery-worker": { + f"{value_name(values, 'resource_discovery')}-worker" + }, + "resource-discovery-scheduler": { + f"{value_name(values, 'resource_discovery')}-scheduler" + }, + "resource-observer-worker": { + f"{value_name(values, 'resource_observer')}-worker" + }, + "resource-observer-scheduler": { + f"{value_name(values, 'resource_observer')}-scheduler" + }, + "resource-violations-worker": { + f"{value_name(values, 'resource_violations')}-worker" + }, + "resource-violations-scheduler": { + f"{value_name(values, 'resource_violations')}-scheduler" + }, + "restapi": {value_service_name(values, "rest_api")}, + "risp-scheduler": {value_name(values, "risp_scheduler")}, + "risp-worker": {value_name(values, "risp_worker")}, + "slacker": {value_service_name(values, "slacker")}, + "slacker-executor": {value_name(values, "slacker_executor")}, + "subspector": {value_service_name(values, "subspector")}, + "thanos-query": {value_service_name(values, "thanos_query")}, + "thanos-receive": {value_service_name(values, "thanos_receive")}, + "thanos-storegateway": { + value_service_name(values, "thanos_storegateway") + }, + "trapper-scheduler": {value_name(values, "trapper_scheduler")}, + "trapper-worker": {value_name(values, "trapper_worker")}, + "users-dataset-generator": { + value_name(values, "users_dataset_generator") + }, + "webhook-executor": {value_name(values, "webhook_executor")}, + } + return names + + +@pytest.mark.parametrize("compose_file", COMPOSE_FILES, ids=lambda p: p.name) +def test_compose_file_is_valid_yaml(compose_file): + load_compose(compose_file) + + +@pytest.mark.parametrize("compose_file", COMPOSE_FILES, ids=lambda p: p.name) +def test_docker_compose_config_is_valid(compose_file): + if not shutil.which("docker"): + pytest.skip("docker executable is not available") + + env = os.environ.copy() + env.setdefault("DOCKER_BUILDKIT", "1") + command = ( + "docker", + "compose", + "--env-file", + str(ENV_FILE), + "-f", + str(compose_file), + "config", + "--quiet", + ) + result = subprocess.run( + command, + cwd=COMPOSE_DIR, + env=env, + text=True, + capture_output=True, + check=False, + ) + assert result.returncode == 0, result.stderr or result.stdout + + +def test_compose_variants_define_same_services_and_volumes(): + per_image = load_compose(COMPOSE_FILES[0]) + unified = load_compose(COMPOSE_FILES[1]) + + assert set(unified["services"]) == set(per_image["services"]) + assert set(unified["volumes"]) == set(per_image["volumes"]) + + +@pytest.mark.parametrize("compose_file", COMPOSE_FILES, ids=lambda p: p.name) +def test_first_party_compose_images_are_buildable_components( + compose_file, components +): + missing_components = {} + for service, config in load_compose(compose_file)["services"].items(): + image = config.get("image", "") + if image.startswith(EXTERNAL_IMAGE_PREFIXES): + continue + if not image.startswith(FIRST_PARTY_IMAGE_PREFIX): + continue + + repository = image.removeprefix(FIRST_PARTY_IMAGE_PREFIX).split( + ":", 1 + )[0] + if repository not in components | FIRST_PARTY_REPOSITORY_EXCEPTIONS: + missing_components[service] = repository + + assert missing_components == {} + + +@pytest.mark.parametrize("compose_file", COMPOSE_FILES, ids=lambda p: p.name) +def test_compose_services_have_k8s_equivalents(compose_file, values): + compose_services = service_names(compose_file) + equivalents = k8s_equivalent_names(values) + + unmapped_services = ( + compose_services - COMPOSE_ONLY_SERVICES - set(equivalents) + ) + assert unmapped_services == set() + + empty_equivalents = { + service: names + for service, names in equivalents.items() + if service in compose_services and not all(names) + } + assert empty_equivalents == {} + + stale_equivalents = set(equivalents) - compose_services + assert stale_equivalents == set() + + +def test_report_import_compose_schedulers_match_k8s_periods(values): + expected = { + f"report-import-scheduler-{period}" + for period in values["report_import_schedules"] + } + for compose_file in COMPOSE_FILES: + actual = { + service + for service in service_names(compose_file) + if service.startswith("report-import-scheduler-") + } + assert actual == expected From f428855d0b3676712e29bfbd46415e0e67c80896 Mon Sep 17 00:00:00 2001 From: sd-hystax <110374605+sd-hystax@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:48:29 +0300 Subject: [PATCH 6/8] Handle empty value for csv_rewrite_days ## Description ## Related issue number ## Special notes ## Checklist * [ ] The pull request title is a good summary of the changes * [ ] Unit tests for the changes exist * [ ] New and existing unit tests pass locally --- diworker/diworker/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diworker/diworker/main.py b/diworker/diworker/main.py index fc3228403..5964fae3e 100755 --- a/diworker/diworker/main.py +++ b/diworker/diworker/main.py @@ -182,7 +182,7 @@ def report_import(self, task, config_cl, rest_cl, mongo_cl, clickhouse_cl): 'max_tenant_concurrent': int(self.diworker_settings.get( 'max_tenant_import_workers', DEFAULT_MAX_TENANT_WORKERS)), 'csv_rewrite_days': int(self.diworker_settings.get( - 'csv_rewrite_days', DEFAULT_CSV_REWRITE_DAYS)) + 'csv_rewrite_days') or DEFAULT_CSV_REWRITE_DAYS) } importer = None ca = None From 4abf058ffacce812021fef33718ba472becaa09a Mon Sep 17 00:00:00 2001 From: Aleksandra Ovchinnikova <46540441+bdjilka@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:35:52 -0400 Subject: [PATCH 7/8] Mpt 22777 deprecated msrest library * MPT-22777 Remove deprecated library msrest * Fix get_raw_usage types mismatch --- tools/cloud_adapter/clouds/azure.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/cloud_adapter/clouds/azure.py b/tools/cloud_adapter/clouds/azure.py index 62bbd0d0f..5f047dfa4 100644 --- a/tools/cloud_adapter/clouds/azure.py +++ b/tools/cloud_adapter/clouds/azure.py @@ -1409,6 +1409,9 @@ def get_raw_usage(self, start_date, range_end, granularity='Daily'): but the missing usage for that day will appear when you query data for some later day. And usage dates in both cases will say that they are for 24h. + - It returns None instead of an empty list for days with no data, the + generated pager then does iter(None) -> TypeError; to fix it, we + use lambda expression in cls argument so it terminates cleanly. For hourly granularity - It returns an error if ranges are not aligned by hour @@ -1429,6 +1432,7 @@ def get_raw_usage(self, start_date, range_end, granularity='Daily'): reported_end_time=range_end, show_details=True, aggregation_granularity=granularity, + cls=lambda elems: elems or [], ) def get_public_prices(self, currency=None, region=None, From 10ddabe37540cfd4f04146b418b6c4abaa9b25af Mon Sep 17 00:00:00 2001 From: Francesco Faraone Date: Wed, 8 Jul 2026 14:00:30 +0200 Subject: [PATCH 8/8] Fix uv.lock conflict --- diworker/uv.lock | 402 ++++++++++++++++++----------------------------- 1 file changed, 149 insertions(+), 253 deletions(-) diff --git a/diworker/uv.lock b/diworker/uv.lock index f92b9a365..36e91c570 100644 --- a/diworker/uv.lock +++ b/diworker/uv.lock @@ -170,15 +170,15 @@ wheels = [ [[package]] name = "azure-core" -version = "1.39.0" +version = "1.41.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/34/83/bbde3faa84ddcb8eb0eca4b3ffb3221252281db4ce351300fe248c5c70b1/azure_core-1.39.0.tar.gz", hash = "sha256:8a90a562998dd44ce84597590fff6249701b98c0e8797c95fcdd695b54c35d74", size = 367531, upload-time = "2026-03-19T01:31:29.461Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f3/b416179e408990df5db0d516283022dde0f5d0111d98c1a848e41853e81c/azure_core-1.41.0.tar.gz", hash = "sha256:f46ff5dfcd230f25cf1c19e8a34b8dc08a337b2503e268bb600a16c00db8ad5a", size = 381042, upload-time = "2026-05-07T23:30:54.302Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d6/8ebcd05b01a580f086ac9a97fb9fac65c09a4b012161cc97c21a336e880b/azure_core-1.39.0-py3-none-any.whl", hash = "sha256:4ac7b70fab5438c3f68770649a78daf97833caa83827f91df9c14e0e0ea7d34f", size = 218318, upload-time = "2026-03-19T01:31:31.25Z" }, + { url = "https://files.pythonhosted.org/packages/5b/db/325c6d7312d2200251c52323878281045aaffcb5586612296484e4280eaa/azure_core-1.41.0-py3-none-any.whl", hash = "sha256:522b4011e8180b1a3dcd2024396a4e7fe9ac37fb8597db47163d230b5efe892d", size = 220920, upload-time = "2026-05-07T23:30:56.357Z" }, ] [[package]] @@ -397,87 +397,56 @@ wheels = [ [[package]] name = "certifi" -version = "2026.2.25" +version = "2026.6.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, + { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, ] [[package]] name = "cffi" -version = "2.0.0" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/85/990925db5df586ec90beb97529c853497e7f85ba0234830447faf41c3057/cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f", size = 184829, upload-time = "2026-07-06T21:32:44.324Z" }, + { url = "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde", size = 184728, upload-time = "2026-07-06T21:32:45.683Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c0/d1ec30ffb370f748f2fb54425972bfef9871e0132e82fb589c46b6676049/cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d", size = 214815, upload-time = "2026-07-06T21:32:48.557Z" }, + { url = "https://files.pythonhosted.org/packages/1b/dc/5620cf930688be01f2d673804291de757a934c90b946dbdc3d84130c2ea4/cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7", size = 222429, upload-time = "2026-07-06T21:32:49.848Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a4/77b53abbf7a1e0beb9637edbef2a94d15f9c822f591e85d439ffd91519a6/cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b", size = 210315, upload-time = "2026-07-06T21:32:51.221Z" }, + { url = "https://files.pythonhosted.org/packages/58/0c/f528df19cc94b675087324d4760d9e6d5bfae97d6217aa4fac43de4f5fcc/cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7", size = 208859, upload-time = "2026-07-06T21:32:52.512Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/c9522a81c32132799a1972c39f5c5f8b4c8b9f00488a23feaa6c06f07741/cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66", size = 221844, upload-time = "2026-07-06T21:32:53.704Z" }, + { url = "https://files.pythonhosted.org/packages/6e/28/bd53988b9833e8f8ad539d26f4c07a6b3f6bcb1e9e02e7ca038250b3428d/cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe", size = 225287, upload-time = "2026-07-06T21:32:54.907Z" }, + { url = "https://files.pythonhosted.org/packages/79/99/0d0fd37f055224085f42bbb2c022d002e17dde4a97972822327b07d84101/cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b", size = 223681, upload-time = "2026-07-06T21:32:56.329Z" }, + { url = "https://files.pythonhosted.org/packages/b0/80/c138990aa2a70b1a269f6e06348729836d733d6f970867943f61d367f8cc/cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a", size = 175269, upload-time = "2026-07-06T21:32:57.777Z" }, + { url = "https://files.pythonhosted.org/packages/a8/eb/f636456ff21a83fc13c032b58cc5dde061691546ac79efa284b2989b7982/cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384", size = 185881, upload-time = "2026-07-06T21:32:59.253Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/400ea43e721727dca8a65c4521390e9196757caba4a45643acb2b63271b8/cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6", size = 180088, upload-time = "2026-07-06T21:33:02.278Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, - { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, - { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, - { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, - { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, - { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, - { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, ] [[package]] @@ -503,16 +472,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/bb/fba7569cfad8b951b8a6497bf19ae5440ab0b305c40d680a1a2395831a1f/clickhouse_connect-0.8.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84d8067294ba6e65994fa887db3acdb6fbf3cbd850d5637c029f29e318eba116", size = 1098405, upload-time = "2025-01-25T23:42:29.322Z" }, { url = "https://files.pythonhosted.org/packages/31/5c/b1ab4ddf40ce3c786011429e5a9171b662efbb8933bf8b9a7586d9eac24a/clickhouse_connect-0.8.15-cp312-cp312-win32.whl", hash = "sha256:83527c9bc48a096e63f91cc429bf3fad01fe5b78ea83fd7751f9702f97388381", size = 228612, upload-time = "2025-01-25T23:42:30.641Z" }, { url = "https://files.pythonhosted.org/packages/fe/d4/3060fe62a3e0e1c41303acb7a00240a5a867774f176ca9c485d03727d4f6/clickhouse_connect-0.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:f63e5500d36e79deb91bfeb82548dd1737b57684405566bc9652d8fede8ce451", size = 246549, upload-time = "2025-01-25T23:42:32.574Z" }, - { url = "https://files.pythonhosted.org/packages/9d/c2/6b4cd609fbd9cbb92440ecda2978c1547dd491543ac935603ff6f9686b13/clickhouse_connect-0.8.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e62f07d31478b6005d7f64d1279b8a58acdb3d7198e28a8b9e8f192c88c885f9", size = 258435, upload-time = "2025-01-25T23:42:33.878Z" }, - { url = "https://files.pythonhosted.org/packages/e4/08/08e7a63476706104ceb9cfe1a271af250f31038c52364258b47ef69b71c2/clickhouse_connect-0.8.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7bc21760716817ae24990c0a556ee8f323f3a0da94f7386fe1eff959979994df", size = 250095, upload-time = "2025-01-25T23:42:35.09Z" }, - { url = "https://files.pythonhosted.org/packages/e9/1d/fe258786b4d8f81368522e42e18536fb283cc93d75a6b1677aac3ebec6b8/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d1bf9fe4a53c990cd839a6fb2b11ddc9f9ca545bba7c647cf9a74697f7a32f", size = 1040094, upload-time = "2025-01-25T23:42:36.477Z" }, - { url = "https://files.pythonhosted.org/packages/b8/d9/15f2b62152f1944d0c9b0627146ae0012a2c4263b9ac37f89cf3f83c59b8/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:169e4ffb8ce94ec64b25e32005c7b645bbd3075cd72cb568e3f4dbdd059400de", size = 1058517, upload-time = "2025-01-25T23:42:38.727Z" }, - { url = "https://files.pythonhosted.org/packages/ef/19/9736a9ad8f962e518aad7c24dbb4e575315244918865da2e0108d5329450/clickhouse_connect-0.8.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b8afad17b50541a3822d205d9154331cef5a4422fa05331c472fd975827be43", size = 1014121, upload-time = "2025-01-25T23:42:41.117Z" }, - { url = "https://files.pythonhosted.org/packages/08/45/d3631ebea8a67d1656d4cbb7bad5207c336124c9f7102a702ad9a50aaec1/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8d3ac19f11dd4e8b0466ccfcb2def6f91ea43d6e12918669a59d10f66db56527", size = 1041140, upload-time = "2025-01-25T23:42:42.675Z" }, - { url = "https://files.pythonhosted.org/packages/63/52/de1be4adb704cb07308e0a1956bfd2a660d65400d0693e12288cee6747c4/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18640b2e5f1d4024178a7f8fa493f95e02345b4ac30648576dad16ab17b80fdd", size = 1056558, upload-time = "2025-01-25T23:42:44.405Z" }, - { url = "https://files.pythonhosted.org/packages/f9/dd/4c0e2fdde56805700de73046d8e8926bf3c2eda52498b3d02e082dcd012e/clickhouse_connect-0.8.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a1c16284b414fd6391fce11d6a4f2afe5826a1c93cb89559d5287a24802ac19", size = 1083990, upload-time = "2025-01-25T23:42:45.836Z" }, - { url = "https://files.pythonhosted.org/packages/6c/d6/ce9a629541a3528ce68bdc46a685b9701a9a2c0d7ae1fd4e8b431c451463/clickhouse_connect-0.8.15-cp313-cp313-win32.whl", hash = "sha256:e3d1b58305477be3f8ac97b433fa3fdfd8e9d6a4004abf578c142d5290f136c0", size = 227905, upload-time = "2025-01-25T23:42:47.283Z" }, - { url = "https://files.pythonhosted.org/packages/a2/59/86d2d0e4316b8b9288fb714400d828a5dcfeeaa8675753b2c49d7b806301/clickhouse_connect-0.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:d762b987a69feadf91edebe795e81743f5a8e7fbace27188e93ae4d8903b1db9", size = 245488, upload-time = "2025-01-25T23:42:49.825Z" }, ] [[package]] @@ -635,41 +594,41 @@ wheels = [ [[package]] name = "cryptography" -version = "46.0.7" +version = "48.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, - { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, - { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, - { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, - { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, - { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, - { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, - { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, - { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, - { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, - { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, - { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, - { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, - { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, - { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, - { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, - { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, - { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" }, + { url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" }, + { url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" }, + { url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" }, + { url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" }, + { url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" }, + { url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" }, + { url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" }, + { url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" }, ] [[package]] @@ -813,38 +772,43 @@ grpc = [ [[package]] name = "google-auth" -version = "2.49.2" +version = "2.55.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b9/e370d86fea3da13ec0256df30323dd26c0cb9c8c85f0c6ec42ac9df0106b/google_auth-2.55.2.tar.gz", hash = "sha256:97ae7790ff740f2bc9db60eb864a7804f4ac19f5f02c38b3d942f2fea6e9b9ae", size = 361414, upload-time = "2026-07-07T18:43:21.227Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c6/02eb5a337ac316a4c30c012e747bad5cea36e1a876efecdf80865541f7d8/google_auth-2.55.2-py3-none-any.whl", hash = "sha256:d715f265f2cafc6a5f1bf0dc19870d20e3119f6f6682785a250bce3d03d38a3b", size = 256778, upload-time = "2026-07-07T18:43:19.52Z" }, +] + +[package.optional-dependencies] +pyopenssl = [ + { name = "cryptography" }, ] [[package]] name = "google-cloud-bigquery" -version = "3.41.0" +version = "3.42.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, + { name = "google-auth", extra = ["pyopenssl"] }, { name = "google-cloud-core" }, { name = "google-resumable-media" }, { name = "packaging" }, { name = "python-dateutil" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/13/6515c7aab55a4a0cf708ffd309fb9af5bab54c13e32dc22c5acd6497193c/google_cloud_bigquery-3.41.0.tar.gz", hash = "sha256:2217e488b47ed576360c9b2cc07d59d883a54b83167c0ef37f915c26b01a06fe", size = 513434, upload-time = "2026-03-30T22:50:55.347Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/a2/be1cffbb1a9894ecf394ab0096b113ae9e4f73686595d906a9f3082b07c2/google_cloud_bigquery-3.42.1.tar.gz", hash = "sha256:3c6878f424fc2b21f0bb414ca7262abd008465575a7b7c44c552105278a18914", size = 515411, upload-time = "2026-06-22T23:21:05.884Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/33/1d3902efadef9194566d499d61507e1f038454e0b55499d2d7f8ab2a4fee/google_cloud_bigquery-3.41.0-py3-none-any.whl", hash = "sha256:2a5b5a737b401cbd824a6e5eac7554100b878668d908e6548836b5d8aaa4dcaa", size = 262343, upload-time = "2026-03-30T22:48:45.444Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/8b098aeb69ef87de5195d076ce6d82002c3ebf1920373d386ca7b6e63cfa/google_cloud_bigquery-3.42.1-py3-none-any.whl", hash = "sha256:159143c1b7248858f35549c09efea5d031c2883145623419ea7c505a50c0899a", size = 263814, upload-time = "2026-06-22T23:18:42.313Z" }, ] [[package]] name = "google-cloud-compute" -version = "1.47.0" +version = "1.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -853,27 +817,27 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/b9/e9c462aaef5ff2d7abc306821d11ec1f0c8cdfa4840cd26d8fa87f41f5ee/google_cloud_compute-1.47.0.tar.gz", hash = "sha256:f2c7909299f230428b0b12e52e031efe76c39be5d28cae9998fe1130a223fc3a", size = 5084010, upload-time = "2026-03-30T22:51:26.576Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/f8/d0b8f06dd2509e4006ef27bb07f17f9fcc15aedf5093c3fe22574e45eae0/google_cloud_compute-1.48.0.tar.gz", hash = "sha256:670efbc2c5718cb86d3e8cb618afae9fb0c1ea8769c792fb960aabe075ba9e79", size = 5528763, upload-time = "2026-06-03T15:13:20.913Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/37/1b7941d5741096cbdd04e040b16858c9af3ec6a324915994b83ce584ea0f/google_cloud_compute-1.47.0-py3-none-any.whl", hash = "sha256:7e0329d1b226ec948cd6064aa88ba6f16d4556585a13b1ec2494f751783749d3", size = 3846242, upload-time = "2026-03-30T22:49:04.879Z" }, + { url = "https://files.pythonhosted.org/packages/0d/65/ad44edfd133b7166b79f5b03dc0a47d18e6a78fcf2e5cb8baf7985d67474/google_cloud_compute-1.48.0-py3-none-any.whl", hash = "sha256:3b5b01f0b7bc1d4e830f51043545ee28b5add2888aaaddc55e272acb9b4bd657", size = 4173327, upload-time = "2026-06-03T15:12:40.01Z" }, ] [[package]] name = "google-cloud-core" -version = "2.5.1" +version = "2.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/24/6ca08b0a03c7b0c620427503ab00353a4ae806b848b93bcea18b6b76fde6/google_cloud_core-2.5.1.tar.gz", hash = "sha256:3dc94bdec9d05a31d9f355045ed0f369fbc0d8c665076c734f065d729800f811", size = 36078, upload-time = "2026-03-30T22:50:08.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/dd/1eef226e470369b26824a505c34482c0b493bc35fe8e0c6b003b5feca21a/google_cloud_core-2.6.0.tar.gz", hash = "sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83", size = 36001, upload-time = "2026-05-07T08:04:04.124Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/d9/5bb050cb32826466aa9b25f79e2ca2879fe66cb76782d4ed798dd7506151/google_cloud_core-2.5.1-py3-none-any.whl", hash = "sha256:ea62cdf502c20e3e14be8a32c05ed02113d7bef454e40ff3fab6fe1ec9f1f4e7", size = 29452, upload-time = "2026-03-30T22:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/84/4a/98da8930ab109c73d9a5d13782a9ebb81ea8c111f6d534a567b71d23e52b/google_cloud_core-2.6.0-py3-none-any.whl", hash = "sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e", size = 29390, upload-time = "2026-05-07T08:02:34.672Z" }, ] [[package]] name = "google-cloud-iam" -version = "2.22.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -883,14 +847,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/62/e5/07d4f1daf85a2a0bd9f78ad865ea678d7b4e1227ed76f671c7167aae147f/google_cloud_iam-2.22.0.tar.gz", hash = "sha256:203ddfece17e014ee4fbc5c3244daa14a88b7ee57c8e3a7622d0f2a1a3b8d7f3", size = 502498, upload-time = "2026-03-30T22:51:28.878Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/13/d6c3f207c8147768f4b56406c1534bdda034be76712bd960a048412f7001/google_cloud_iam-2.24.0.tar.gz", hash = "sha256:199a2512723abec10a49d581e638ccdf5b8a9671e1d5d6ff3ffeaa727075435f", size = 559063, upload-time = "2026-06-22T23:21:31.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/a8/d721ea11d0eb93803d14cb2e90d0442bb3b269a82f7cb5faff2b98022039/google_cloud_iam-2.22.0-py3-none-any.whl", hash = "sha256:c443b34b5a6a9e51d32cee397879bb781b900af68937c67a275def23bbc025f3", size = 463425, upload-time = "2026-03-30T20:02:42.967Z" }, + { url = "https://files.pythonhosted.org/packages/3b/74/31220c86789d4591aa493652656b83a428dcdd46f62b518e2118f98f76bd/google_cloud_iam-2.24.0-py3-none-any.whl", hash = "sha256:29d52032f774b4d3c01b6d8e1f4a8d029ae61c3bdba60ddac402866be11159db", size = 514860, upload-time = "2026-06-22T23:19:15.287Z" }, ] [[package]] name = "google-cloud-monitoring" -version = "2.30.0" +version = "2.31.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -899,9 +863,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/3f/7bc306ebb006114f58fb9143aec91e1b014a11577350d8bbd6bbc38389f9/google_cloud_monitoring-2.30.0.tar.gz", hash = "sha256:a9530aa9aa246c490810dfa7be32d67e8340d19108acc99cbc02d1ed494fba76", size = 407108, upload-time = "2026-03-26T22:17:10.365Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/9d/9522e169db3887e7f354bb9aa544a6e26c435ce19337e32432598db18c6f/google_cloud_monitoring-2.31.0.tar.gz", hash = "sha256:b4c9d3528c8643d4eb4b9d688cbb3c5914bc5f69b314ff7c5e1b47bdc073a9ae", size = 404747, upload-time = "2026-06-03T15:28:24.938Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/c8/666c21c470b9d6fd62ac9ee74dc265419975228f9b16f8ad72ec22e8d98b/google_cloud_monitoring-2.30.0-py3-none-any.whl", hash = "sha256:2729f3b88a4798b7757b1d9d31b6cb562bb3544e8173765e4e5cd44d8685b1ed", size = 391367, upload-time = "2026-03-26T22:15:04.088Z" }, + { url = "https://files.pythonhosted.org/packages/55/30/aa6635296da9c1c14d2e64f64e1cacd4f4debf8ab7e646c0559545f0f70d/google_cloud_monitoring-2.31.0-py3-none-any.whl", hash = "sha256:64f3d56ead48f0a0674f650cb2828c47b936582a02a27c55f2836681a86281c3", size = 391010, upload-time = "2026-06-03T15:27:39.536Z" }, ] [[package]] @@ -932,35 +896,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740, upload-time = "2025-12-16T00:40:23.96Z" }, { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437, upload-time = "2025-12-16T00:35:21.395Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, ] [[package]] name = "google-resumable-media" -version = "2.8.2" +version = "2.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/d1/b1ea14b93b6b78f57fc580125de44e9f593ab88dd2460f1a8a8d18f74754/google_resumable_media-2.8.2.tar.gz", hash = "sha256:f3354a182ebd193ae3f42e3ef95e6c9b10f128320de23ac7637236713b1acd70", size = 2164510, upload-time = "2026-03-30T23:34:25.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/f8/1ca5781d6be9cb9f73f7d40f4958c4bd1226a60598e3e39e1d6aaf838c4b/google_resumable_media-2.10.0.tar.gz", hash = "sha256:e324bc9d0fdae4c52a08ae90456edc4e71ece858399e1217ac0eb3a51d6bc6ee", size = 2164570, upload-time = "2026-06-03T16:14:26.103Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/f8/50bfaf4658431ff9de45c5c3935af7ab01157a4903c603cd0eee6e78e087/google_resumable_media-2.8.2-py3-none-any.whl", hash = "sha256:82b6d8ccd11765268cdd2a2123f417ec806b8eef3000a9a38dfe3033da5fb220", size = 81511, upload-time = "2026-03-30T23:34:09.671Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d8/00c6854ac1512bb9eaf13bd3f8f28222f7674947fc510a4ff7616f2efc80/google_resumable_media-2.10.0-py3-none-any.whl", hash = "sha256:88152884bee37b2bf36a0ab81ad8c7fd12212c9803dd981d77c1b35b02d34e7c", size = 81533, upload-time = "2026-06-03T16:13:12.51Z" }, ] [[package]] name = "googleapis-common-protos" -version = "1.74.0" +version = "1.75.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/c8/f439cffde755cffa462bfbb156278fa6f9d09119719af9814b858fd4f81f/googleapis_common_protos-1.75.0.tar.gz", hash = "sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd", size = 151035, upload-time = "2026-05-07T08:04:49.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl", hash = "sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5", size = 300743, upload-time = "2026-04-02T21:22:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c8/e2645aa8ed02fd4c7a2f59d68783b65b1f3cbdfe39a6308e156509d1fee8/googleapis_common_protos-1.75.0-py3-none-any.whl", hash = "sha256:961ed60399c457ceb0ee8f285a84c870aabc9c6a832b9d37bb281b5bebde43ed", size = 300631, upload-time = "2026-05-07T08:03:30.345Z" }, ] [package.optional-dependencies] @@ -984,33 +943,23 @@ wheels = [ [[package]] name = "grpcio" -version = "1.80.0" +version = "1.81.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/e8/a2b749265eb3415abc94f2e619bbd9e9707bebdda787e61c593004ec927a/grpcio-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0", size = 6015616, upload-time = "2026-03-30T08:47:13.428Z" }, - { url = "https://files.pythonhosted.org/packages/3e/97/b1282161a15d699d1e90c360df18d19165a045ce1c343c7f313f5e8a0b77/grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2", size = 12014204, upload-time = "2026-03-30T08:47:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/6e/5e/d319c6e997b50c155ac5a8cb12f5173d5b42677510e886d250d50264949d/grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de", size = 6563866, upload-time = "2026-03-30T08:47:18.588Z" }, - { url = "https://files.pythonhosted.org/packages/ae/f6/fdd975a2cb4d78eb67769a7b3b3830970bfa2e919f1decf724ae4445f42c/grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921", size = 7273060, upload-time = "2026-03-30T08:47:21.113Z" }, - { url = "https://files.pythonhosted.org/packages/db/f0/a3deb5feba60d9538a962913e37bd2e69a195f1c3376a3dd44fe0427e996/grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411", size = 6782121, upload-time = "2026-03-30T08:47:23.827Z" }, - { url = "https://files.pythonhosted.org/packages/ca/84/36c6dcfddc093e108141f757c407902a05085e0c328007cb090d56646cdf/grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd", size = 7383811, upload-time = "2026-03-30T08:47:26.517Z" }, - { url = "https://files.pythonhosted.org/packages/7c/ef/f3a77e3dc5b471a0ec86c564c98d6adfa3510d38f8ee99010410858d591e/grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f", size = 8393860, upload-time = "2026-03-30T08:47:29.439Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8d/9d4d27ed7f33d109c50d6b5ce578a9914aa68edab75d65869a17e630a8d1/grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f", size = 7830132, upload-time = "2026-03-30T08:47:33.254Z" }, - { url = "https://files.pythonhosted.org/packages/14/e4/9990b41c6d7a44e1e9dee8ac11d7a9802ba1378b40d77468a7761d1ad288/grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193", size = 4140904, upload-time = "2026-03-30T08:47:35.319Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2c/296f6138caca1f4b92a31ace4ae1b87dab692fc16a7a3417af3bb3c805bf/grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff", size = 4880944, upload-time = "2026-03-30T08:47:37.831Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" }, - { url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" }, - { url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" }, - { url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" }, - { url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" }, - { url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" }, - { url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" }, - { url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" }, - { url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/b0/b5/1ff353970a87eda4c98251e34d2dfd214abd4982dc89119c9252a2a482d2/grpcio-1.81.1.tar.gz", hash = "sha256:6fa10a767143a5e82e8eaab53918af0cd8909a57a27f8cb2288b80a613ac671b", size = 13026582, upload-time = "2026-06-11T12:46:51.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/07/9a979c81738863a738dc23d65177056e71fbb2db817740ed870b33434e7a/grpcio-1.81.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:8b39472beafc0bdcafc4c8c73ad082ebfdb449d566897a61e7acb4fa88089115", size = 6053264, upload-time = "2026-06-11T12:45:21.017Z" }, + { url = "https://files.pythonhosted.org/packages/75/95/539706ca0d3bd40dbad583dc56fd883da941f37556b629132da5762781b9/grpcio-1.81.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:12b7524c88d4026d3dcb7b0ebe16b6714f3b4af402ddd0f0639ab064a00c87c3", size = 12052560, upload-time = "2026-06-11T12:45:23.652Z" }, + { url = "https://files.pythonhosted.org/packages/e0/44/f257b7e0bd69c93b06c6cb8ac8d1b901ccb42bedabd83c1a4c77a71f8810/grpcio-1.81.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1e123f9b37edb8375fd74130d1f69c944bbf0a7b06761ae7211154b8759e94d2", size = 6595983, upload-time = "2026-06-11T12:45:26.963Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f3/19782aa04c960968bef8c5539329d8e3bbc3364e2e46d19eb5e5cc5e43b7/grpcio-1.81.1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2c2e2ae6867c2966b8daccc836d54a13218e0007e9a490aeb81dd05be64d22d7", size = 7303455, upload-time = "2026-06-11T12:45:29.707Z" }, + { url = "https://files.pythonhosted.org/packages/eb/8c/dea020b6d91508cd84463917a63149ec196ee7db505d032ae43fcb3303b9/grpcio-1.81.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:766bc7c9a9c340342f4c864ccbda8e78111e4751f13b895812b9c148fb79e9d0", size = 6809167, upload-time = "2026-06-11T12:45:32.52Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c7/3030dd940408083bd32cd95d634777a71605ade4887154d93e8a89244946/grpcio-1.81.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b259a04a737cb3496be0901328eb8b7552ed8df4865d8c8f1cf1bffcfc0776a3", size = 7412536, upload-time = "2026-06-11T12:45:35.403Z" }, + { url = "https://files.pythonhosted.org/packages/e0/dd/1172a9e42b168edcafefad6115346ef619a3fc02158bb170e66ced24bcdd/grpcio-1.81.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:85b10a45b8993d195c4f3ff57025b8d1e11834909ee475c403bfa60cb4caefaf", size = 8408276, upload-time = "2026-06-11T12:45:37.78Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/71437c7f3596e5246155c515852795a85a1a8d228190212432b13b97a95d/grpcio-1.81.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8ea1936c26b99999b27479853039a7f34713f56c49375ad52b38535ec93a796c", size = 7849660, upload-time = "2026-06-11T12:45:40.627Z" }, + { url = "https://files.pythonhosted.org/packages/65/40/7debc0da45d2efebafb82da75644be347497fe4ee250514b8cd3b86ae8bf/grpcio-1.81.1-cp312-cp312-win32.whl", hash = "sha256:a185a04039df6cae8648bc8ab6d6fde7bf94f7188ecf7828e76ac52eef1e41d6", size = 4185819, upload-time = "2026-06-11T12:45:43.027Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8fe3ba5ed462067774ebc1f9c7f26aa7ebcc280ddd476be107153de1339e/grpcio-1.81.1-cp312-cp312-win_amd64.whl", hash = "sha256:3ad74f8bb1a18963914c5452d289422830b39459e8776ebbcd207be1fbfb1d94", size = 4930461, upload-time = "2026-06-11T12:45:45.775Z" }, ] [[package]] @@ -1048,16 +997,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/d6/965f36cfc367c276799b730d5dd1311b90a54a33726e561393b808339b04/grpcio_tools-1.71.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3e4b4801fabd0427fc61d50d09588a01b1cfab0ec5e8a5f5d515fbdd0891fd11", size = 2913863, upload-time = "2025-06-28T04:21:22.196Z" }, { url = "https://files.pythonhosted.org/packages/8d/f0/c05d5c3d0c1d79ac87df964e9d36f1e3a77b60d948af65bec35d3e5c75a3/grpcio_tools-1.71.2-cp312-cp312-win32.whl", hash = "sha256:84ad86332c44572305138eafa4cc30040c9a5e81826993eae8227863b700b490", size = 945744, upload-time = "2025-06-28T04:21:23.463Z" }, { url = "https://files.pythonhosted.org/packages/e2/e9/c84c1078f0b7af7d8a40f5214a9bdd8d2a567ad6c09975e6e2613a08d29d/grpcio_tools-1.71.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e1108d37eecc73b1c4a27350a6ed921b5dda25091700c1da17cfe30761cd462", size = 1117695, upload-time = "2025-06-28T04:21:25.22Z" }, - { url = "https://files.pythonhosted.org/packages/60/9c/bdf9c5055a1ad0a09123402d73ecad3629f75b9cf97828d547173b328891/grpcio_tools-1.71.2-cp313-cp313-linux_armv7l.whl", hash = "sha256:b0f0a8611614949c906e25c225e3360551b488d10a366c96d89856bcef09f729", size = 2384758, upload-time = "2025-06-28T04:21:26.712Z" }, - { url = "https://files.pythonhosted.org/packages/49/d0/6aaee4940a8fb8269c13719f56d69c8d39569bee272924086aef81616d4a/grpcio_tools-1.71.2-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:7931783ea7ac42ac57f94c5047d00a504f72fbd96118bf7df911bb0e0435fc0f", size = 5443127, upload-time = "2025-06-28T04:21:28.383Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/50a471dcf301b89c0ed5ab92c533baced5bd8f796abfd133bbfadf6b60e5/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:d188dc28e069aa96bb48cb11b1338e47ebdf2e2306afa58a8162cc210172d7a8", size = 2349627, upload-time = "2025-06-28T04:21:30.254Z" }, - { url = "https://files.pythonhosted.org/packages/bb/66/e3dc58362a9c4c2fbe98a7ceb7e252385777ebb2bbc7f42d5ab138d07ace/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f36c4b3cc42ad6ef67430639174aaf4a862d236c03c4552c4521501422bfaa26", size = 2742932, upload-time = "2025-06-28T04:21:32.325Z" }, - { url = "https://files.pythonhosted.org/packages/b7/1e/1e07a07ed8651a2aa9f56095411198385a04a628beba796f36d98a5a03ec/grpcio_tools-1.71.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bd9ed12ce93b310f0cef304176049d0bc3b9f825e9c8c6a23e35867fed6affd", size = 2473627, upload-time = "2025-06-28T04:21:33.752Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f9/3b7b32e4acb419f3a0b4d381bc114fe6cd48e3b778e81273fc9e4748caad/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7ce27e76dd61011182d39abca38bae55d8a277e9b7fe30f6d5466255baccb579", size = 2850879, upload-time = "2025-06-28T04:21:35.241Z" }, - { url = "https://files.pythonhosted.org/packages/1e/99/cd9e1acd84315ce05ad1fcdfabf73b7df43807cf00c3b781db372d92b899/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:dcc17bf59b85c3676818f2219deacac0156492f32ca165e048427d2d3e6e1157", size = 3300216, upload-time = "2025-06-28T04:21:36.826Z" }, - { url = "https://files.pythonhosted.org/packages/9f/c0/66eab57b14550c5b22404dbf60635c9e33efa003bd747211981a9859b94b/grpcio_tools-1.71.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:706360c71bdd722682927a1fb517c276ccb816f1e30cb71f33553e5817dc4031", size = 2913521, upload-time = "2025-06-28T04:21:38.347Z" }, - { url = "https://files.pythonhosted.org/packages/05/9b/7c90af8f937d77005625d705ab1160bc42a7e7b021ee5c788192763bccd6/grpcio_tools-1.71.2-cp313-cp313-win32.whl", hash = "sha256:bcf751d5a81c918c26adb2d6abcef71035c77d6eb9dd16afaf176ee096e22c1d", size = 945322, upload-time = "2025-06-28T04:21:39.864Z" }, - { url = "https://files.pythonhosted.org/packages/5f/80/6db6247f767c94fe551761772f89ceea355ff295fd4574cb8efc8b2d1199/grpcio_tools-1.71.2-cp313-cp313-win_amd64.whl", hash = "sha256:b1581a1133552aba96a730178bc44f6f1a071f0eb81c5b6bc4c0f89f5314e2b8", size = 1117234, upload-time = "2025-06-28T04:21:41.893Z" }, ] [[package]] @@ -1077,23 +1016,23 @@ requires-dist = [ [[package]] name = "httplib2" -version = "0.31.2" +version = "0.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyparsing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800, upload-time = "2026-01-23T11:04:44.165Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/f5/ccf58de92d61e3ad921119668f54ed36ca1d0cf5dcc5c1657dfb164fd78b/httplib2-0.32.0.tar.gz", hash = "sha256:48a0ef30a42db65d8f3399045e1d09ab0ba66e3b9efc360d07f80ea55d286025", size = 254283, upload-time = "2026-06-26T10:13:56.265Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099, upload-time = "2026-01-23T11:04:42.78Z" }, + { url = "https://files.pythonhosted.org/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl", hash = "sha256:dc6705cacdf3fb0a2aba7629fa33c90fd93e30035db0c157325826be177e4816", size = 93148, upload-time = "2026-06-26T10:13:54.985Z" }, ] [[package]] name = "idna" -version = "3.11" +version = "3.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, ] [[package]] @@ -1179,22 +1118,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", size = 88189, upload-time = "2025-11-03T13:01:52.605Z" }, { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", size = 99497, upload-time = "2025-11-03T13:01:53.477Z" }, { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", size = 91279, upload-time = "2025-11-03T13:01:54.419Z" }, - { url = "https://files.pythonhosted.org/packages/2f/46/08fd8ef19b782f301d56a9ccfd7dafec5fd4fc1a9f017cf22a1accb585d7/lz4-4.4.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6bb05416444fafea170b07181bc70640975ecc2a8c92b3b658c554119519716c", size = 207171, upload-time = "2025-11-03T13:01:56.595Z" }, - { url = "https://files.pythonhosted.org/packages/8f/3f/ea3334e59de30871d773963997ecdba96c4584c5f8007fd83cfc8f1ee935/lz4-4.4.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b424df1076e40d4e884cfcc4c77d815368b7fb9ebcd7e634f937725cd9a8a72a", size = 207163, upload-time = "2025-11-03T13:01:57.721Z" }, - { url = "https://files.pythonhosted.org/packages/41/7b/7b3a2a0feb998969f4793c650bb16eff5b06e80d1f7bff867feb332f2af2/lz4-4.4.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:216ca0c6c90719731c64f41cfbd6f27a736d7e50a10b70fad2a9c9b262ec923d", size = 1292136, upload-time = "2025-11-03T13:02:00.375Z" }, - { url = "https://files.pythonhosted.org/packages/89/d1/f1d259352227bb1c185288dd694121ea303e43404aa77560b879c90e7073/lz4-4.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:533298d208b58b651662dd972f52d807d48915176e5b032fb4f8c3b6f5fe535c", size = 1279639, upload-time = "2025-11-03T13:02:01.649Z" }, - { url = "https://files.pythonhosted.org/packages/d2/fb/ba9256c48266a09012ed1d9b0253b9aa4fe9cdff094f8febf5b26a4aa2a2/lz4-4.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:451039b609b9a88a934800b5fc6ee401c89ad9c175abf2f4d9f8b2e4ef1afc64", size = 1368257, upload-time = "2025-11-03T13:02:03.35Z" }, - { url = "https://files.pythonhosted.org/packages/a5/6d/dee32a9430c8b0e01bbb4537573cabd00555827f1a0a42d4e24ca803935c/lz4-4.4.5-cp313-cp313-win32.whl", hash = "sha256:a5f197ffa6fc0e93207b0af71b302e0a2f6f29982e5de0fbda61606dd3a55832", size = 88191, upload-time = "2025-11-03T13:02:04.406Z" }, - { url = "https://files.pythonhosted.org/packages/18/e0/f06028aea741bbecb2a7e9648f4643235279a770c7ffaf70bd4860c73661/lz4-4.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:da68497f78953017deb20edff0dba95641cc86e7423dfadf7c0264e1ac60dc22", size = 99502, upload-time = "2025-11-03T13:02:05.886Z" }, - { url = "https://files.pythonhosted.org/packages/61/72/5bef44afb303e56078676b9f2486f13173a3c1e7f17eaac1793538174817/lz4-4.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:c1cfa663468a189dab510ab231aad030970593f997746d7a324d40104db0d0a9", size = 91285, upload-time = "2025-11-03T13:02:06.77Z" }, - { url = "https://files.pythonhosted.org/packages/49/55/6a5c2952971af73f15ed4ebfdd69774b454bd0dc905b289082ca8664fba1/lz4-4.4.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67531da3b62f49c939e09d56492baf397175ff39926d0bd5bd2d191ac2bff95f", size = 207348, upload-time = "2025-11-03T13:02:08.117Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d7/fd62cbdbdccc35341e83aabdb3f6d5c19be2687d0a4eaf6457ddf53bba64/lz4-4.4.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a1acbbba9edbcbb982bc2cac5e7108f0f553aebac1040fbec67a011a45afa1ba", size = 207340, upload-time = "2025-11-03T13:02:09.152Z" }, - { url = "https://files.pythonhosted.org/packages/77/69/225ffadaacb4b0e0eb5fd263541edd938f16cd21fe1eae3cd6d5b6a259dc/lz4-4.4.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a482eecc0b7829c89b498fda883dbd50e98153a116de612ee7c111c8bcf82d1d", size = 1293398, upload-time = "2025-11-03T13:02:10.272Z" }, - { url = "https://files.pythonhosted.org/packages/c6/9e/2ce59ba4a21ea5dc43460cba6f34584e187328019abc0e66698f2b66c881/lz4-4.4.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e099ddfaa88f59dd8d36c8a3c66bd982b4984edf127eb18e30bb49bdba68ce67", size = 1281209, upload-time = "2025-11-03T13:02:12.091Z" }, - { url = "https://files.pythonhosted.org/packages/80/4f/4d946bd1624ec229b386a3bc8e7a85fa9a963d67d0a62043f0af0978d3da/lz4-4.4.5-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2af2897333b421360fdcce895c6f6281dc3fab018d19d341cf64d043fc8d90d", size = 1369406, upload-time = "2025-11-03T13:02:13.683Z" }, - { url = "https://files.pythonhosted.org/packages/02/a2/d429ba4720a9064722698b4b754fb93e42e625f1318b8fe834086c7c783b/lz4-4.4.5-cp313-cp313t-win32.whl", hash = "sha256:66c5de72bf4988e1b284ebdd6524c4bead2c507a2d7f172201572bac6f593901", size = 88325, upload-time = "2025-11-03T13:02:14.743Z" }, - { url = "https://files.pythonhosted.org/packages/4b/85/7ba10c9b97c06af6c8f7032ec942ff127558863df52d866019ce9d2425cf/lz4-4.4.5-cp313-cp313t-win_amd64.whl", hash = "sha256:cdd4bdcbaf35056086d910d219106f6a04e1ab0daa40ec0eeef1626c27d0fddb", size = 99643, upload-time = "2025-11-03T13:02:15.978Z" }, - { url = "https://files.pythonhosted.org/packages/77/4d/a175459fb29f909e13e57c8f475181ad8085d8d7869bd8ad99033e3ee5fa/lz4-4.4.5-cp313-cp313t-win_arm64.whl", hash = "sha256:28ccaeb7c5222454cd5f60fcd152564205bcb801bd80e125949d2dfbadc76bbd", size = 91504, upload-time = "2025-11-03T13:02:17.313Z" }, ] [[package]] @@ -1593,11 +1516,11 @@ source = { directory = "../tools/optscale_time" } [[package]] name = "packaging" -version = "26.1" +version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] @@ -1622,23 +1545,23 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.9.6" +version = "4.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, ] [[package]] name = "proto-plus" -version = "1.27.2" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/0d/94dfe80193e79d55258345901acd2917523d56e8381bc4dee7fd38e3868a/proto_plus-1.27.2.tar.gz", hash = "sha256:b2adde53adadf75737c44d3dcb0104fde65250dfc83ad59168b4aa3e574b6a24", size = 57204, upload-time = "2026-03-26T22:18:57.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/56/e647b0c675392d2da368da7b6f158f7368b18542fd6f7d7400a2f39de000/proto_plus-1.28.0.tar.gz", hash = "sha256:38e5696342835b08fc116f30a25665b29531cda9d5d5643e9b81fc312385abd9", size = 57221, upload-time = "2026-05-07T08:04:50.811Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/f3/1fba73eeffafc998a25d59703b63f8be4fe8a5cb12eaff7386a0ba0f7125/proto_plus-1.27.2-py3-none-any.whl", hash = "sha256:6432f75893d3b9e70b9c412f1d2f03f65b11fb164b793d14ae2ca01821d22718", size = 50450, upload-time = "2026-03-26T22:13:42.927Z" }, + { url = "https://files.pythonhosted.org/packages/7c/20/b122d4626976acb81132036d2ad1bb35a1a8775fceb837ec30964622516a/proto_plus-1.28.0-py3-none-any.whl", hash = "sha256:a630604310899e73c59ec302e5765c058d412b2f090b9c79c8822589f14955b8", size = 50410, upload-time = "2026-05-07T08:03:31.962Z" }, ] [[package]] @@ -1729,11 +1652,11 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.12.1" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, ] [package.optional-dependencies] @@ -1820,11 +1743,11 @@ sdist = { url = "https://files.pythonhosted.org/packages/a1/da/616a4d073642da5dd [[package]] name = "pytz" -version = "2026.1.post1" +version = "2026.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" }, ] [[package]] @@ -1893,11 +1816,11 @@ wheels = [ [[package]] name = "setuptools" -version = "82.0.1" +version = "83.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +sdist = { url = "https://files.pythonhosted.org/packages/34/26/f5d29e25ffdb535afef2d35cdb55b325298f96debd670da4c325e08d70f4/setuptools-83.0.0.tar.gz", hash = "sha256:025bccbbf0fa05b6192bc64ae1e7b16e001fd6d6d4d5de03c97b1c1ade523bef", size = 1154254, upload-time = "2026-07-04T15:31:22.699Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, + { url = "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl", hash = "sha256:29b23c360f22f414dc7336bb39178cc7bcbf6021ed2733cde173f09dba19abb3", size = 1008090, upload-time = "2026-07-04T15:31:20.885Z" }, ] [[package]] @@ -1911,29 +1834,29 @@ wheels = [ [[package]] name = "tomlkit" -version = "0.14.0" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/db/03eaf4331631ef6b27d6e3c9b68c54dc6f0d63d87201fed600cc409307fd/tomlkit-0.15.0.tar.gz", hash = "sha256:7d1a9ecba3086638211b13814ea79c90dd54dd11993564376f3aa92271f5c7a3", size = 161875, upload-time = "2026-05-10T07:38:22.245Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" }, + { url = "https://files.pythonhosted.org/packages/6a/43/8bd850ee71a191bf072e31302c73a66be413fecdd98fdcd111ecbcce13ca/tomlkit-0.15.0-py3-none-any.whl", hash = "sha256:4dbc8f0fc024412b57ced8757ac7461305126a648ff8c2c807fcb8e133a78738", size = 41328, upload-time = "2026-05-10T07:38:23.517Z" }, ] [[package]] name = "typing-extensions" -version = "4.15.0" +version = "4.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]] name = "tzdata" -version = "2026.1" +version = "2026.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, ] [[package]] @@ -1970,16 +1893,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, - { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, - { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, - { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, - { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, - { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, ] @@ -2005,11 +1918,11 @@ wheels = [ [[package]] name = "zipp" -version = "3.23.1" +version = "4.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, + { url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" }, ] [[package]] @@ -2035,21 +1948,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, - { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, - { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, - { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, - { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, - { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, - { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, - { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, - { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, - { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, - { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, - { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, - { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, - { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, ]